reiserfsprogs-3.x.0j/0000777000076400001440000000000007261220342010434 5reiserfsprogs-3.x.0j/Makefile.in0000644000076400001440000002306507261220333012423 # Makefile.in generated automatically by automake 1.4 from Makefile.am # Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. # This Makefile.in 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. SHELL = @SHELL@ srcdir = @srcdir@ top_srcdir = @top_srcdir@ VPATH = @srcdir@ prefix = @prefix@ exec_prefix = @exec_prefix@ bindir = @bindir@ sbindir = @sbindir@ libexecdir = @libexecdir@ datadir = @datadir@ sysconfdir = @sysconfdir@ sharedstatedir = @sharedstatedir@ localstatedir = @localstatedir@ libdir = @libdir@ infodir = @infodir@ mandir = @mandir@ includedir = @includedir@ oldincludedir = /usr/include DESTDIR = pkgdatadir = $(datadir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ top_builddir = . ACLOCAL = @ACLOCAL@ AUTOCONF = @AUTOCONF@ AUTOMAKE = @AUTOMAKE@ AUTOHEADER = @AUTOHEADER@ INSTALL = @INSTALL@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS) INSTALL_DATA = @INSTALL_DATA@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ transform = @program_transform_name@ NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : CC = @CC@ MAKEINFO = @MAKEINFO@ PACKAGE = @PACKAGE@ RANLIB = @RANLIB@ VERSION = @VERSION@ SUBDIRS = include lib reiserfscore mkreiserfs fsck debugreiserfs resize_reiserfs EXTRA_DIST = version.h reiserfsprogs.spec ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs CONFIG_CLEAN_FILES = DIST_COMMON = README AUTHORS COPYING ChangeLog INSTALL Makefile.am \ Makefile.in NEWS aclocal.m4 configure configure.in install-sh missing \ mkinstalldirs DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) TAR = tar GZIP_ENV = --best all: all-redirect .SUFFIXES: $(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status cd $(top_builddir) \ && CONFIG_FILES=$@ CONFIG_HEADERS= $(SHELL) ./config.status $(ACLOCAL_M4): configure.in cd $(srcdir) && $(ACLOCAL) config.status: $(srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) $(SHELL) ./config.status --recheck $(srcdir)/configure: $(srcdir)/configure.in $(ACLOCAL_M4) $(CONFIGURE_DEPENDENCIES) cd $(srcdir) && $(AUTOCONF) # This directory's subdirectories are mostly independent; you can cd # into them and run `make' without going through this Makefile. # To change the values of `make' variables: instead of editing Makefiles, # (1) if the variable is set in `config.status', edit `config.status' # (which will cause the Makefiles to be regenerated when you run `make'); # (2) otherwise, pass the desired values on the `make' command line. @SET_MAKE@ all-recursive install-data-recursive install-exec-recursive \ installdirs-recursive install-recursive uninstall-recursive \ check-recursive installcheck-recursive info-recursive dvi-recursive: @set fnord $(MAKEFLAGS); amf=$$2; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ list='$(SUBDIRS)'; for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" mostlyclean-recursive clean-recursive distclean-recursive \ maintainer-clean-recursive: @set fnord $(MAKEFLAGS); amf=$$2; \ dot_seen=no; \ rev=''; list='$(SUBDIRS)'; for subdir in $$list; do \ rev="$$subdir $$rev"; \ test "$$subdir" = "." && dot_seen=yes; \ done; \ test "$$dot_seen" = "no" && rev=". $$rev"; \ target=`echo $@ | sed s/-recursive//`; \ for subdir in $$rev; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ done && test -z "$$fail" tags-recursive: list='$(SUBDIRS)'; for subdir in $$list; do \ test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ done tags: TAGS ID: $(HEADERS) $(SOURCES) $(LISP) list='$(SOURCES) $(HEADERS)'; \ unique=`for i in $$list; do echo $$i; done | \ awk ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ here=`pwd` && cd $(srcdir) \ && mkid -f$$here/ID $$unique $(LISP) TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) tags=; \ here=`pwd`; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test -f $$subdir/TAGS && tags="$$tags -i $$here/$$subdir/TAGS"; \ fi; \ done; \ list='$(SOURCES) $(HEADERS)'; \ unique=`for i in $$list; do echo $$i; done | \ awk ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) mostlyclean-tags: clean-tags: distclean-tags: -rm -f TAGS ID maintainer-clean-tags: distdir = $(PACKAGE)-$(VERSION) top_distdir = $(distdir) # This target untars the dist file and tries a VPATH configuration. Then # it guarantees that the distribution is self-contained by making another # tarfile. distcheck: dist -rm -rf $(distdir) GZIP=$(GZIP_ENV) $(TAR) zxf $(distdir).tar.gz mkdir $(distdir)/=build mkdir $(distdir)/=inst dc_install_base=`cd $(distdir)/=inst && pwd`; \ cd $(distdir)/=build \ && ../configure --srcdir=.. --prefix=$$dc_install_base \ && $(MAKE) $(AM_MAKEFLAGS) \ && $(MAKE) $(AM_MAKEFLAGS) dvi \ && $(MAKE) $(AM_MAKEFLAGS) check \ && $(MAKE) $(AM_MAKEFLAGS) install \ && $(MAKE) $(AM_MAKEFLAGS) installcheck \ && $(MAKE) $(AM_MAKEFLAGS) dist -rm -rf $(distdir) @banner="$(distdir).tar.gz is ready for distribution"; \ dashes=`echo "$$banner" | sed s/./=/g`; \ echo "$$dashes"; \ echo "$$banner"; \ echo "$$dashes" dist: distdir -chmod -R a+r $(distdir) GZIP=$(GZIP_ENV) $(TAR) chozf $(distdir).tar.gz $(distdir) -rm -rf $(distdir) dist-all: distdir -chmod -R a+r $(distdir) GZIP=$(GZIP_ENV) $(TAR) chozf $(distdir).tar.gz $(distdir) -rm -rf $(distdir) distdir: $(DISTFILES) -rm -rf $(distdir) mkdir $(distdir) -chmod 777 $(distdir) @for file in $(DISTFILES); do \ d=$(srcdir); \ if test -d $$d/$$file; then \ cp -pr $$/$$file $(distdir)/$$file; \ else \ test -f $(distdir)/$$file \ || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ || cp -p $$d/$$file $(distdir)/$$file || :; \ fi; \ done for subdir in $(SUBDIRS); do \ if test "$$subdir" = .; then :; else \ test -d $(distdir)/$$subdir \ || mkdir $(distdir)/$$subdir \ || exit 1; \ chmod 777 $(distdir)/$$subdir; \ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir=../$(distdir) distdir=../$(distdir)/$$subdir distdir) \ || exit 1; \ fi; \ done info-am: info: info-recursive dvi-am: dvi: dvi-recursive check-am: all-am check: check-recursive installcheck-am: installcheck: installcheck-recursive install-exec-am: install-exec: install-exec-recursive install-data-am: install-data: install-data-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am install: install-recursive uninstall-am: uninstall: uninstall-recursive all-am: Makefile all-redirect: all-recursive install-strip: $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install installdirs: installdirs-recursive installdirs-am: mostlyclean-generic: clean-generic: distclean-generic: -rm -f Makefile $(CONFIG_CLEAN_FILES) -rm -f config.cache config.log stamp-h stamp-h[0-9]* maintainer-clean-generic: mostlyclean-am: mostlyclean-tags mostlyclean-generic mostlyclean: mostlyclean-recursive clean-am: clean-tags clean-generic mostlyclean-am clean: clean-recursive distclean-am: distclean-tags distclean-generic clean-am distclean: distclean-recursive -rm -f config.status maintainer-clean-am: maintainer-clean-tags maintainer-clean-generic \ distclean-am @echo "This command is intended for maintainers to use;" @echo "it deletes files that may require special tools to rebuild." maintainer-clean: maintainer-clean-recursive -rm -f config.status .PHONY: install-data-recursive uninstall-data-recursive \ install-exec-recursive uninstall-exec-recursive installdirs-recursive \ uninstalldirs-recursive all-recursive check-recursive \ installcheck-recursive info-recursive dvi-recursive \ mostlyclean-recursive distclean-recursive clean-recursive \ maintainer-clean-recursive tags tags-recursive mostlyclean-tags \ distclean-tags clean-tags maintainer-clean-tags distdir info-am info \ dvi-am dvi check check-am installcheck-am installcheck install-exec-am \ install-exec install-data-am install-data install-am install \ uninstall-am uninstall all-redirect all-am all installdirs-am \ installdirs mostlyclean-generic distclean-generic clean-generic \ maintainer-clean-generic clean mostlyclean distclean maintainer-clean # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: reiserfsprogs-3.x.0j/README0000644000076400001440000001731207203752366011250 [LICENSING] ReiserFS is hereby licensed under the GNU General Public License version 2. Source code files that contain the phrase "licensing governed by reiserfs/README" are "governed files" throughout this file. Governed files are licensed under the GPL. The portions of them owned by Hans Reiser, or authorized to be licensed by him, have been in the past, and likely will be in the future, licensed to other parties under other licenses. If you add your code to governed files, and don't want it to be owned by Hans Reiser, put your copyright label on that code so the poor blight and his customers can keep things straight. All portions of governed files not labeled otherwise are owned by Hans Reiser, and by adding your code to it, widely distributing it to others or sending us a patch, and leaving the sentence in stating that licensing is governed by the statement in this file, you accept this. It will be a kindness if you identify whether Hans Reiser is allowed to license code labeled as owned by you on your behalf other than under the GPL, because he wants to know if it is okay to do so and put a check in the mail to you (for non-trivial improvements) when he makes his next sale. He makes no guarantees as to the amount if any, though he feels motivated to motivate contributors, and you can surely discuss this with him before or after contributing. You have the right to decline to allow him to license your code contribution other than under the GPL. Further licensing options are available for commercial and/or other interests directly from Hans Reiser: hans@reiser.to. If you interpret the GPL as not allowing those additional licensing options, you read it wrongly, and Richard Stallman agrees with me, when carefully read you can see that those restrictions on additional terms do not apply to the owner of the copyright, and my interpretation of this shall govern for this license. Finally, nothing in this license shall be interpreted to allow you to fail to fairly credit me, or to remove my credits, without my permission, unless you are an end user not redistributing to others. If you have doubts about how to properly do that, or about what is fair, ask. (Last I spoke with him Richard was contemplating how best to address the fair crediting issue in the next GPL version.) [END LICENSING] Reiserfs is a file system based on balanced tree algorithms, which is described at http://www.namesys.com . Stop reading here. Go there, then return. Send bug reports to yura@namesys.botik.ru. mkreiserfs and other utilities are in reiserfs/utils, or wherever your Linux provider put them. There is some disagreement about how useful it is for users to get their fsck and mkreiserfs out of sync with the version of reiserfs that is in their kernel, with many important distributors wanting them out of sync.:-) Please try to remember to recompile and reinstall fsck and mkreiserfs with every update of reiserfs, this is a common source of confusion. Note that some of the utilities cannot be compiled without accessing the balancing code which is in the kernel code, and relocating the utilities may require you to specify where that code can be found. Yes, if you update your reiserfs kernel module you do have to recompile your kernel, most of the time. The errors you get will be quite cryptic if your forget to do so. Real users, as opposed to folks who want to hack and then understand what went wrong, will want REISERFS_CHECK off. Hideous Commercial Pitch: Spread your development costs across other OS vendors. Select from the best in the world, not the best in your building, by buying from third party OS component suppliers. Leverage the software component development power of the internet. Be the most aggressive in taking advantage of the commercial possibilities of decentralized internet development, and add value through your branded integration that you sell as an operating system. Let your competitors be the ones to compete against the entire internet by themselves. Be hip, get with the new economic trend, before your competitors do. Send email to hans@reiser.to. To understand the code, after reading the website, start reading the code by reading reiserfs_fs.h first. Hans Reiser was the project initiator, primary architect, source of all funding for the first 5.5 years, and one of the programmers. He owns the copyright. Vladimir Saveljev was one of the programmers, and he worked long hours writing the cleanest code. He always made the effort to be the best he could be, and to make his code the best that it could be. What resulted was quite remarkable. I don't think that money can ever motivate someone to work the way he did, he is one of the most selfless men I know. Yura helps with benchmarking, coding hashes, and block pre-allocation code. Anatoly Pinchuk is a former member of our team who worked closely with Vladimir throughout the project's development. He wrote a quite substantial portion of the total code. He realized that there was a space problem with packing tails of files for files larger than a node that start on a node aligned boundary (there are reasons to want to node align files), and he invented and implemented indirect items and unformatted nodes as the solution. Konstantin Shvachko, with the help of the Russian version of a VC, tried to put me in a position where I was forced into giving control of the project to him. (Fortunately, as the person paying the money for all salaries from my dayjob I owned all copyrights, and you can't really force takeovers of sole proprietorships.) This was something curious, because he never really understood the value of our project, why we should do what we do, or why innovation was possible in general, but he was sure that he ought to be controlling it. Every innovation had to be forced past him while he was with us. He added two years to the time required to complete reiserfs, and was a net loss for me. Mikhail Gilula was a brilliant innovator who also left in a destructive way that erased the value of his contributions, and that he was shown much generosity just makes it more painful. Grigory Zaigralin was an extremely effective system administrator for our group. Igor Krasheninnikov was wonderful at hardware procurement, repair, and network installation. Jeremy Fitzhardinge wrote the teahash.c code, and he gives credit to a textbook he got the algorithm from in the code. Note that his analysis of how we could use the hashing code in making 32 bit NFS cookies work was probably more important than the actual algorithm. Colin Plumb also contributed to it. Chris Mason dived right into our code, and in just a few months produced the journaling code that dramatically increased the value of ReiserFS. He is just an amazing programmer. Igor Zagorovsky is writing much of the new item handler and extent code for our next major release. Alexander Zarochentcev (sometimes known as zam, or sasha), wrote the resizer, and is hard at work on implementing allocate on flush. SGI implemented allocate on flush before us for XFS, and generously took the time to convince me we should do it also. They are great people, and a great company. Yuri Shevchuk and Nikita Danilov are doing squid cache optimization. Vitaly Fertman is doing fsck. SuSE, IntegratedLinux.com, Ecila, MP3.com, bigstorage.com, and the Alpha PC Company made it possible for me to not have a day job anymore, and to dramatically increase our staffing. Ecila funded hypertext feature development, MP3.com funded journaling, SuSE funded core development, IntegratedLinux.com funded squid web cache appliances, bigstorage.com funded HSM, and the alpha PC company funded the alpha port. Many of these tasks were helped by sponsors other than the ones just named. SuSE has helped in much more than just funding.... reiserfsprogs-3.x.0j/AUTHORS0000644000076400001440000000000007142245353011415 reiserfsprogs-3.x.0j/COPYING0000644000076400001440000004311007142245352011410 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. reiserfsprogs-3.x.0j/ChangeLog0000644000076400001440000000635507261217514012142 2001-03-31 * reiserfsck empty lost directories do not get linked into /lost+found 2001-03-28 * reiserfsck --nolog option is added 2001-03-26 * called 3.x.0j * reiserfsck with -o it tries to fix "objectid sharing" problem * reiserfsprogs.spec (Anthon van der Neut) rpm can be built as non-root link from reiserfsck to fsck.reiserfs rpm -e reiserfsprogs should now work w/o rmdir of / 2001-03-13 * reiserfsck --quiet option is added --fix-bogus-files option is added to fix transprently corrupted modes and to fix sizes which are longer that real file size directory item verifying changed -u has been replaced with -b to pass reiserfsck the list of block to build tree off -c is added to have pass 0 to save bitmap fo leaves found 2001-03-10 * called 3.x.0h * configure.in RPM_OPT_FLASG is added to CFLAGS (Anthon van der Neut) * reiserfsck -u option is added. It should save time when repeating --rebuild-tree hash hits statistic is added on pass 0 2001-03-07 * reiserfsck -V option to print version and exit added --fix-fixable changed: directory's sd_size and st_blocks corrections, removing of entries pointing to nowhere * resize_reiserfs man page is added 2001-03-05 * resize_reiserfs Marcel Waldvogel 's user interface and error messages improvements 2001-03-01 * mkreiserfs -q option is added (Larry Auton ) * reiserfsck --fix-fixable changed: bitmap correction commented out. Correction of broken slots of indirect items and corrections of dir entry state added 2001-02-23 * called 3.x.0e * reiserfsck not tested on 2.2 is now able to work with regular file (2.4.x is needed for that) lost+found fixed: it now first links directories then files. Still not good as it can not pull out deep directory 2001-02-19 * called 3.x.0c * reiserfsck --fix-fixable option is added. So far it only repairs bitmaps and free block count when they mismatch * library reiserfs_find/add_entry added 2001-02-05 * mkreiserfs can make filesystem with 1 data block 3.6 format is now default 2001-01-20 * portability Zam ran the reiserfsprogs on alpha * resizer Zam managed to resize few partitions. * reiserfsck pass0 deletes items which are out of order, tries to fix items with zeroed k_objectid or k_dir_id and to throw items which are transparently out of order and tries to fix "." and ".." of directory items. Pass0 corrects also corruptions in directory items * man pages: get included into dist when doing 'make dist' * mkreisrefs explains what is mininal size of reiserfs partition which can be created 2001-01-12 * reiserfsck: --interactive option is added * debugreiserfs: few bugs fixed 2001-01-07 * reiserfs library: started with reiserfs_open, reiserfs_close, bitmap tools * reiserfsck: filesystem mounted read-only can be checked number of options decreased journal replay fixed pass 0 added. fsck can be stopped after the tree is built. (should safe time when debugging) a lot of work still left * debugreiserfs: metadata packing changed added a feature to intentionally corrupt filesystem (should be useful for fsck debugging) * resizer: not updated yet * man pages: updated for all three progs reiserfsprogs-3.x.0j/INSTALL0000644000076400001440000001722707142245346011423 Basic Installation ================== These are generic installation instructions. The `configure' shell script attempts to guess correct values for various system-dependent variables used during compilation. It uses those values to create a `Makefile' in each directory of the package. It may also create one or more `.h' files containing system-dependent definitions. Finally, it creates a shell script `config.status' that you can run in the future to recreate the current configuration, a file `config.cache' that saves the results of its tests to speed up reconfiguring, and a file `config.log' containing compiler output (useful mainly for debugging `configure'). If you need to do unusual things to compile the package, please try to figure out how `configure' could check whether to do them, and mail diffs or instructions to the address given in the `README' so they can be considered for the next release. If at some point `config.cache' contains results you don't want to keep, you may remove or edit it. The file `configure.in' is used to create `configure' by a program called `autoconf'. You only need `configure.in' if you want to change it or regenerate `configure' using a newer version of `autoconf'. The simplest way to compile this package is: 1. `cd' to the directory containing the package's source code and type `./configure' to configure the package for your system. If you're using `csh' on an old version of System V, you might need to type `sh ./configure' instead to prevent `csh' from trying to execute `configure' itself. Running `configure' takes awhile. While running, it prints some messages telling which features it is checking for. 2. Type `make' to compile the package. 3. Optionally, type `make check' to run any self-tests that come with the package. 4. Type `make install' to install the programs and any data files and documentation. 5. You can remove the program binaries and object files from the source code directory by typing `make clean'. To also remove the files that `configure' created (so you can compile the package for a different kind of computer), type `make distclean'. There is also a `make maintainer-clean' target, but that is intended mainly for the package's developers. If you use it, you may have to get all sorts of other programs in order to regenerate files that came with the distribution. Compilers and Options ===================== Some systems require unusual options for compilation or linking that the `configure' script does not know about. You can give `configure' initial values for variables by setting them in the environment. Using a Bourne-compatible shell, you can do that on the command line like this: CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure Or on systems that have the `env' program, you can do it like this: env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure Compiling For Multiple Architectures ==================================== You can compile the package for more than one kind of computer at the same time, by placing the object files for each architecture in their own directory. To do this, you must use a version of `make' that supports the `VPATH' variable, such as GNU `make'. `cd' to the directory where you want the object files and executables to go and run the `configure' script. `configure' automatically checks for the source code in the directory that `configure' is in and in `..'. If you have to use a `make' that does not supports the `VPATH' variable, you have to compile the package for one architecture at a time in the source code directory. After you have installed the package for one architecture, use `make distclean' before reconfiguring for another architecture. Installation Names ================== By default, `make install' will install the package's files in `/usr/local/bin', `/usr/local/man', etc. You can specify an installation prefix other than `/usr/local' by giving `configure' the option `--prefix=PATH'. You can specify separate installation prefixes for architecture-specific files and architecture-independent files. If you give `configure' the option `--exec-prefix=PATH', the package will use PATH as the prefix for installing programs and libraries. Documentation and other data files will still use the regular prefix. In addition, if you use an unusual directory layout you can give options like `--bindir=PATH' to specify different values for particular kinds of files. Run `configure --help' for a list of the directories you can set and what kinds of files go in them. If the package supports it, you can cause programs to be installed with an extra prefix or suffix on their names by giving `configure' the option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. Optional Features ================= Some packages pay attention to `--enable-FEATURE' options to `configure', where FEATURE indicates an optional part of the package. They may also pay attention to `--with-PACKAGE' options, where PACKAGE is something like `gnu-as' or `x' (for the X Window System). The `README' should mention any `--enable-' and `--with-' options that the package recognizes. For packages that use the X Window System, `configure' can usually find the X include and library files automatically, but if it doesn't, you can use the `configure' options `--x-includes=DIR' and `--x-libraries=DIR' to specify their locations. Specifying the System Type ========================== There may be some features `configure' can not figure out automatically, but needs to determine by the type of host the package will run on. Usually `configure' can figure that out, but if it prints a message saying it can not guess the host type, give it the `--host=TYPE' option. TYPE can either be a short name for the system type, such as `sun4', or a canonical name with three fields: CPU-COMPANY-SYSTEM See the file `config.sub' for the possible values of each field. If `config.sub' isn't included in this package, then this package doesn't need to know the host type. If you are building compiler tools for cross-compiling, you can also use the `--target=TYPE' option to select the type of system they will produce code for and the `--build=TYPE' option to select the type of system on which you are compiling the package. Sharing Defaults ================ If you want to set default values for `configure' scripts to share, you can create a site shell script called `config.site' that gives default values for variables like `CC', `cache_file', and `prefix'. `configure' looks for `PREFIX/share/config.site' if it exists, then `PREFIX/etc/config.site' if it exists. Or, you can set the `CONFIG_SITE' environment variable to the location of the site script. A warning: not all `configure' scripts look for a site script. Operation Controls ================== `configure' recognizes the following options to control how it operates. `--cache-file=FILE' Use and save the results of the tests in FILE instead of `./config.cache'. Set FILE to `/dev/null' to disable caching, for debugging `configure'. `--help' Print a summary of the options to `configure', and exit. `--quiet' `--silent' `-q' Do not print messages saying which checks are being made. To suppress all normal output, redirect it to `/dev/null' (any error messages will still be shown). `--srcdir=DIR' Look for the package's source code in directory DIR. Usually `configure' can determine that directory automatically. `--version' Print the version of Autoconf used to generate the `configure' script, and exit. `configure' also accepts some other, not widely useful, options. reiserfsprogs-3.x.0j/Makefile.am0000644000076400001440000000017507245456125012423 SUBDIRS = include lib reiserfscore mkreiserfs fsck debugreiserfs resize_reiserfs EXTRA_DIST = version.h reiserfsprogs.spec reiserfsprogs-3.x.0j/NEWS0000644000076400001440000000000007142245353011044 reiserfsprogs-3.x.0j/aclocal.m40000644000076400001440000000672307260373644012235 dnl aclocal.m4 generated automatically by aclocal 1.4 dnl Copyright (C) 1994, 1995-8, 1999 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 This program is distributed in the hope that it will be useful, dnl but WITHOUT ANY WARRANTY, to the extent permitted by law; without dnl even the implied warranty of MERCHANTABILITY or FITNESS FOR A dnl PARTICULAR PURPOSE. # Do all the work for Automake. This macro actually does too much -- # some checks are only needed if your package does certain things. # But this isn't really a big deal. # serial 1 dnl Usage: dnl AM_INIT_AUTOMAKE(package,version, [no-define]) AC_DEFUN(AM_INIT_AUTOMAKE, [AC_REQUIRE([AC_PROG_INSTALL]) PACKAGE=[$1] AC_SUBST(PACKAGE) VERSION=[$2] AC_SUBST(VERSION) dnl test to see if srcdir already configured if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) fi ifelse([$3],, AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package]) AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])) AC_REQUIRE([AM_SANITY_CHECK]) AC_REQUIRE([AC_ARG_PROGRAM]) dnl FIXME This is truly gross. missing_dir=`cd $ac_aux_dir && pwd` AM_MISSING_PROG(ACLOCAL, aclocal, $missing_dir) AM_MISSING_PROG(AUTOCONF, autoconf, $missing_dir) AM_MISSING_PROG(AUTOMAKE, automake, $missing_dir) AM_MISSING_PROG(AUTOHEADER, autoheader, $missing_dir) AM_MISSING_PROG(MAKEINFO, makeinfo, $missing_dir) AC_REQUIRE([AC_PROG_MAKE_SET])]) # # Check to make sure that the build environment is sane. # AC_DEFUN(AM_SANITY_CHECK, [AC_MSG_CHECKING([whether build environment is sane]) # Just in case sleep 1 echo timestamp > conftestfile # Do `set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( set X `ls -Lt $srcdir/configure conftestfile 2> /dev/null` if test "[$]*" = "X"; then # -L didn't work. set X `ls -t $srcdir/configure conftestfile` fi if test "[$]*" != "X $srcdir/configure conftestfile" \ && test "[$]*" != "X conftestfile $srcdir/configure"; then # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken alias in your environment]) fi test "[$]2" = conftestfile ) then # Ok. : else AC_MSG_ERROR([newly created file is older than distributed files! Check your system clock]) fi rm -f conftest* AC_MSG_RESULT(yes)]) dnl AM_MISSING_PROG(NAME, PROGRAM, DIRECTORY) dnl The program must properly implement --version. AC_DEFUN(AM_MISSING_PROG, [AC_MSG_CHECKING(for working $2) # Run test in a subshell; some versions of sh will print an error if # an executable is not found, even if stderr is redirected. # Redirect stdin to placate older versions of autoconf. Sigh. if ($2 --version) < /dev/null > /dev/null 2>&1; then $1=$2 AC_MSG_RESULT(found) else $1="$3/missing $2" AC_MSG_RESULT(missing) fi AC_SUBST($1)]) reiserfsprogs-3.x.0j/configure0000755000076400001440000017327307260373646012313 #! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated automatically using autoconf version 2.13 # Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc. # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. # Defaults: ac_help= ac_default_prefix=/usr/local # Any additions from configure.in: ac_default_prefix=/ # Initialize some variables set by options. # The variables have the same names as the options, with # dashes changed to underlines. build=NONE cache_file=./config.cache exec_prefix=NONE host=NONE no_create= nonopt=NONE no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= target=NONE verbose= x_includes=NONE x_libraries=NONE bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datadir='${prefix}/share' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' libdir='${exec_prefix}/lib' includedir='${prefix}/include' oldincludedir='/usr/include' infodir='${prefix}/info' mandir='${prefix}/man' # Initialize some other variables. subdirs= MFLAGS= MAKEFLAGS= SHELL=${CONFIG_SHELL-/bin/sh} # Maximum number of lines to put in a shell here document. ac_max_here_lines=12 ac_prev= 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=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;; *) ac_optarg= ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case "$ac_option" in -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 ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build="$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" ;; -datadir | --datadir | --datadi | --datad | --data | --dat | --da) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ | --da=*) datadir="$ac_optarg" ;; -disable-* | --disable-*) ac_feature=`echo $ac_option|sed -e 's/-*disable-//'` # Reject names that are not valid shell variable names. if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } fi ac_feature=`echo $ac_feature| sed 's/-/_/g'` eval "enable_${ac_feature}=no" ;; -enable-* | --enable-*) ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'` # Reject names that are not valid shell variable names. if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } fi ac_feature=`echo $ac_feature| sed 's/-/_/g'` case "$ac_option" in *=*) ;; *) ac_optarg=yes ;; esac eval "enable_${ac_feature}='$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) # 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 << EOF Usage: configure [options] [host] Options: [defaults in brackets after descriptions] Configuration: --cache-file=FILE cache test results in FILE --help print this message --no-create do not create output files --quiet, --silent do not print \`checking...' messages --version print the version of autoconf that created configure Directory and file names: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [same as prefix] --bindir=DIR user executables in DIR [EPREFIX/bin] --sbindir=DIR system admin executables in DIR [EPREFIX/sbin] --libexecdir=DIR program executables in DIR [EPREFIX/libexec] --datadir=DIR read-only architecture-independent data in DIR [PREFIX/share] --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data in DIR [PREFIX/com] --localstatedir=DIR modifiable single-machine data in DIR [PREFIX/var] --libdir=DIR object code libraries in DIR [EPREFIX/lib] --includedir=DIR C header files in DIR [PREFIX/include] --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include] --infodir=DIR info documentation in DIR [PREFIX/info] --mandir=DIR man documentation in DIR [PREFIX/man] --srcdir=DIR find the sources in DIR [configure dir or ..] --program-prefix=PREFIX prepend PREFIX to installed program names --program-suffix=SUFFIX append SUFFIX to installed program names --program-transform-name=PROGRAM run sed PROGRAM on installed program names EOF cat << EOF Host type: --build=BUILD configure for building on BUILD [BUILD=HOST] --host=HOST configure for HOST [guessed] --target=TARGET configure for TARGET [TARGET=HOST] Features and packages: --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --x-includes=DIR X include files are in DIR --x-libraries=DIR X library files are in DIR EOF if test -n "$ac_help"; then echo "--enable and --with options recognized:$ac_help" fi exit 0 ;; -host | --host | --hos | --ho) ac_prev=host ;; -host=* | --host=* | --hos=* | --ho=*) host="$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" ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst \ | --locals | --local | --loca | --loc | --lo) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* \ | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) 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) 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" ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -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 ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target="$ac_optarg" ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers) echo "configure generated by autoconf version 2.13" exit 0 ;; -with-* | --with-*) ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'` # Reject names that are not valid shell variable names. if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } fi ac_package=`echo $ac_package| sed 's/-/_/g'` case "$ac_option" in *=*) ;; *) ac_optarg=yes ;; esac eval "with_${ac_package}='$ac_optarg'" ;; -without-* | --without-*) ac_package=`echo $ac_option|sed -e 's/-*without-//'` # Reject names that are not valid shell variable names. if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } fi ac_package=`echo $ac_package| sed 's/-/_/g'` eval "with_${ac_package}=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" ;; -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; } ;; *) if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then echo "configure: warning: $ac_option: invalid host type" 1>&2 fi if test "x$nonopt" != xNONE; then { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } fi nonopt="$ac_option" ;; esac done if test -n "$ac_prev"; then { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; } fi trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 # File descriptor usage: # 0 standard input # 1 file creation # 2 errors and warnings # 3 some systems may open it to /dev/tty # 4 used on the Kubota Titan # 6 checking for... messages and results # 5 compiler messages saved in config.log if test "$silent" = yes; then exec 6>/dev/null else exec 6>&1 fi exec 5>./config.log echo "\ This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. " 1>&5 # Strip out --no-create and --no-recursion so they do not pile up. # Also quote any args containing shell metacharacters. ac_configure_args= for ac_arg do case "$ac_arg" in -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c) ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;; *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*) ac_configure_args="$ac_configure_args '$ac_arg'" ;; *) ac_configure_args="$ac_configure_args $ac_arg" ;; esac done # NLS nuisances. # Only set these to C if already set. These must not be set unconditionally # because not all systems understand e.g. LANG=C (notably SCO). # Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'! # Non-C LC_CTYPE values break the ctype check. if test "${LANG+set}" = set; then LANG=C; export LANG; fi if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -rf conftest* confdefs.h # AIX cpp loses on an empty file, so make sure it contains at least a newline. echo > confdefs.h # A filename unique to this package, relative to the directory that # configure is in, which we can look for to find out if srcdir is correct. ac_unique_file=version.h # 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 its parent. ac_prog=$0 ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'` test "x$ac_confdir" = "x$ac_prog" && ac_confdir=. 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 if test "$ac_srcdir_defaulted" = yes; then { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; } else { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; } fi fi srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'` # Prefer explicitly selected file to automatically selected ones. if test -z "$CONFIG_SITE"; then if test "x$prefix" != xNONE; then CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" else CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" fi fi for ac_site_file in $CONFIG_SITE; do if test -r "$ac_site_file"; then echo "loading site script $ac_site_file" . "$ac_site_file" fi done if test -r "$cache_file"; then echo "loading cache $cache_file" . $cache_file else echo "creating cache $cache_file" > $cache_file fi ac_ext=c # CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. ac_cpp='$CPP $CPPFLAGS' ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' cross_compiling=$ac_cv_prog_cc_cross ac_exeext= ac_objext=o if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu. if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then ac_n= ac_c=' ' ac_t=' ' else ac_n=-n ac_c= ac_t= fi else ac_n= ac_c='\c' ac_t= fi ac_aux_dir= for ac_dir in $srcdir $srcdir/.. $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 fi done if test -z "$ac_aux_dir"; then { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; } fi ac_config_guess=$ac_aux_dir/config.guess ac_config_sub=$ac_aux_dir/config.sub ac_configure=$ac_aux_dir/configure # This should be Cygnus configure. # 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 # 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" # ./install, which can be erroneously created by make from ./install.sh. echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6 echo "configure:558: checking for a BSD compatible install" >&5 if test -z "$INSTALL"; then if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else IFS="${IFS= }"; ac_save_IFS="$IFS"; IFS=":" for ac_dir in $PATH; do # Account for people who put trailing slashes in PATH elements. case "$ac_dir/" in /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/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 if test -f $ac_dir/$ac_prog; then if test $ac_prog = install && grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : else ac_cv_path_install="$ac_dir/$ac_prog -c" break 2 fi fi done ;; esac done IFS="$ac_save_IFS" 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. We don't cache a # path for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the path is relative. INSTALL="$ac_install_sh" fi fi echo "$ac_t""$INSTALL" 1>&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_PROGRAM}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' echo $ac_n "checking whether build environment is sane""... $ac_c" 1>&6 echo "configure:611: checking whether build environment is sane" >&5 # Just in case sleep 1 echo timestamp > conftestfile # Do `set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( set X `ls -Lt $srcdir/configure conftestfile 2> /dev/null` if test "$*" = "X"; then # -L didn't work. set X `ls -t $srcdir/configure conftestfile` fi if test "$*" != "X $srcdir/configure conftestfile" \ && test "$*" != "X conftestfile $srcdir/configure"; then # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". { echo "configure: error: ls -t appears to fail. Make sure there is not a broken alias in your environment" 1>&2; exit 1; } fi test "$2" = conftestfile ) then # Ok. : else { echo "configure: error: newly created file is older than distributed files! Check your system clock" 1>&2; exit 1; } fi rm -f conftest* echo "$ac_t""yes" 1>&6 if test "$program_transform_name" = s,x,x,; then program_transform_name= else # Double any \ or $. echo might interpret backslashes. cat <<\EOF_SED > conftestsed s,\\,\\\\,g; s,\$,$$,g EOF_SED program_transform_name="`echo $program_transform_name|sed -f conftestsed`" rm -f conftestsed fi test "$program_prefix" != NONE && program_transform_name="s,^,${program_prefix},; $program_transform_name" # Use a double $ so make ignores it. test "$program_suffix" != NONE && program_transform_name="s,\$\$,${program_suffix},; $program_transform_name" # sed with no file args requires a program. test "$program_transform_name" = "" && program_transform_name="s,x,x," echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6 echo "configure:668: checking whether ${MAKE-make} sets \${MAKE}" >&5 set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftestmake <<\EOF all: @echo 'ac_maketemp="${MAKE}"' EOF # GNU make sometimes prints "make[1]: Entering...", which would confuse us. eval `${MAKE-make} -f conftestmake 2>/dev/null | grep temp=` if test -n "$ac_maketemp"; then eval ac_cv_prog_make_${ac_make}_set=yes else eval ac_cv_prog_make_${ac_make}_set=no fi rm -f conftestmake fi if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then echo "$ac_t""yes" 1>&6 SET_MAKE= else echo "$ac_t""no" 1>&6 SET_MAKE="MAKE=${MAKE-make}" fi PACKAGE=reiserfsprogs VERSION=3.x.0j if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then { echo "configure: error: source directory already configured; run "make distclean" there first" 1>&2; exit 1; } fi cat >> confdefs.h <> confdefs.h <&6 echo "configure:714: checking for working aclocal" >&5 # Run test in a subshell; some versions of sh will print an error if # an executable is not found, even if stderr is redirected. # Redirect stdin to placate older versions of autoconf. Sigh. if (aclocal --version) < /dev/null > /dev/null 2>&1; then ACLOCAL=aclocal echo "$ac_t""found" 1>&6 else ACLOCAL="$missing_dir/missing aclocal" echo "$ac_t""missing" 1>&6 fi echo $ac_n "checking for working autoconf""... $ac_c" 1>&6 echo "configure:727: checking for working autoconf" >&5 # Run test in a subshell; some versions of sh will print an error if # an executable is not found, even if stderr is redirected. # Redirect stdin to placate older versions of autoconf. Sigh. if (autoconf --version) < /dev/null > /dev/null 2>&1; then AUTOCONF=autoconf echo "$ac_t""found" 1>&6 else AUTOCONF="$missing_dir/missing autoconf" echo "$ac_t""missing" 1>&6 fi echo $ac_n "checking for working automake""... $ac_c" 1>&6 echo "configure:740: checking for working automake" >&5 # Run test in a subshell; some versions of sh will print an error if # an executable is not found, even if stderr is redirected. # Redirect stdin to placate older versions of autoconf. Sigh. if (automake --version) < /dev/null > /dev/null 2>&1; then AUTOMAKE=automake echo "$ac_t""found" 1>&6 else AUTOMAKE="$missing_dir/missing automake" echo "$ac_t""missing" 1>&6 fi echo $ac_n "checking for working autoheader""... $ac_c" 1>&6 echo "configure:753: checking for working autoheader" >&5 # Run test in a subshell; some versions of sh will print an error if # an executable is not found, even if stderr is redirected. # Redirect stdin to placate older versions of autoconf. Sigh. if (autoheader --version) < /dev/null > /dev/null 2>&1; then AUTOHEADER=autoheader echo "$ac_t""found" 1>&6 else AUTOHEADER="$missing_dir/missing autoheader" echo "$ac_t""missing" 1>&6 fi echo $ac_n "checking for working makeinfo""... $ac_c" 1>&6 echo "configure:766: checking for working makeinfo" >&5 # Run test in a subshell; some versions of sh will print an error if # an executable is not found, even if stderr is redirected. # Redirect stdin to placate older versions of autoconf. Sigh. if (makeinfo --version) < /dev/null > /dev/null 2>&1; then MAKEINFO=makeinfo echo "$ac_t""found" 1>&6 else MAKEINFO="$missing_dir/missing makeinfo" echo "$ac_t""missing" 1>&6 fi PRESET_CFLAGS=$CFLAGS # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 echo "configure:786: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" ac_dummy="$PATH" for ac_dir in $ac_dummy; do test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$ac_word; then ac_cv_prog_CC="gcc" break fi done IFS="$ac_save_ifs" fi fi CC="$ac_cv_prog_CC" if test -n "$CC"; then echo "$ac_t""$CC" 1>&6 else echo "$ac_t""no" 1>&6 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 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 echo "configure:816: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" ac_prog_rejected=no ac_dummy="$PATH" for ac_dir in $ac_dummy; do test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$ac_word; then if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" break fi done IFS="$ac_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 $# -gt 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 set dummy "$ac_dir/$ac_word" "$@" shift ac_cv_prog_CC="$@" fi fi fi fi CC="$ac_cv_prog_CC" if test -n "$CC"; then echo "$ac_t""$CC" 1>&6 else echo "$ac_t""no" 1>&6 fi if test -z "$CC"; then case "`uname -s`" in *win32* | *WIN32*) # Extract the first word of "cl", so it can be a program name with args. set dummy cl; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 echo "configure:867: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" ac_dummy="$PATH" for ac_dir in $ac_dummy; do test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$ac_word; then ac_cv_prog_CC="cl" break fi done IFS="$ac_save_ifs" fi fi CC="$ac_cv_prog_CC" if test -n "$CC"; then echo "$ac_t""$CC" 1>&6 else echo "$ac_t""no" 1>&6 fi ;; esac fi test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; } fi echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6 echo "configure:899: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5 ac_ext=c # CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. ac_cpp='$CPP $CPPFLAGS' ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' cross_compiling=$ac_cv_prog_cc_cross cat > conftest.$ac_ext << EOF #line 910 "configure" #include "confdefs.h" main(){return(0);} EOF if { (eval echo configure:915: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then ac_cv_prog_cc_works=yes # If we can't run a trivial program, we are probably using a cross compiler. if (./conftest; exit) 2>/dev/null; then ac_cv_prog_cc_cross=no else ac_cv_prog_cc_cross=yes fi else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 ac_cv_prog_cc_works=no fi rm -fr conftest* ac_ext=c # CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. ac_cpp='$CPP $CPPFLAGS' ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' cross_compiling=$ac_cv_prog_cc_cross echo "$ac_t""$ac_cv_prog_cc_works" 1>&6 if test $ac_cv_prog_cc_works = no; then { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; } fi echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6 echo "configure:941: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5 echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6 cross_compiling=$ac_cv_prog_cc_cross echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6 echo "configure:946: checking whether we are using GNU C" >&5 if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.c <&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then ac_cv_prog_gcc=yes else ac_cv_prog_gcc=no fi fi echo "$ac_t""$ac_cv_prog_gcc" 1>&6 if test $ac_cv_prog_gcc = yes; then GCC=yes else GCC= fi ac_test_CFLAGS="${CFLAGS+set}" ac_save_CFLAGS="$CFLAGS" CFLAGS= echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6 echo "configure:974: checking whether ${CC-cc} accepts -g" >&5 if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else echo 'void f(){}' > conftest.c if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then ac_cv_prog_cc_g=yes else ac_cv_prog_cc_g=no fi rm -f conftest* fi echo "$ac_t""$ac_cv_prog_cc_g" 1>&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 if test -z $PRESET_CFLAGS; then CFLAGS="${RPM_OPT_FLAGS} -g -O2 -Wall" fi # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 echo "configure:1012: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test -n "$RANLIB"; then ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. else IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" ac_dummy="$PATH" for ac_dir in $ac_dummy; do test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$ac_word; then ac_cv_prog_RANLIB="ranlib" break fi done IFS="$ac_save_ifs" test -z "$ac_cv_prog_RANLIB" && ac_cv_prog_RANLIB=":" fi fi RANLIB="$ac_cv_prog_RANLIB" if test -n "$RANLIB"; then echo "$ac_t""$RANLIB" 1>&6 else echo "$ac_t""no" 1>&6 fi echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6 echo "configure:1042: checking how to run the C preprocessor" >&5 # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else # This must be in double quotes, not single quotes, because CPP may get # substituted into the Makefile and "${CC-cc}" will confuse make. CPP="${CC-cc} -E" # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. cat > conftest.$ac_ext < Syntax Error EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" { (eval echo configure:1063: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then : else echo "$ac_err" >&5 echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* CPP="${CC-cc} -E -traditional-cpp" cat > conftest.$ac_ext < Syntax Error EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" { (eval echo configure:1080: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then : else echo "$ac_err" >&5 echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* CPP="${CC-cc} -nologo -E" cat > conftest.$ac_ext < Syntax Error EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" { (eval echo configure:1097: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then : else echo "$ac_err" >&5 echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* CPP=/lib/cpp fi rm -f conftest* fi rm -f conftest* fi rm -f conftest* ac_cv_prog_CPP="$CPP" fi CPP="$ac_cv_prog_CPP" else ac_cv_prog_CPP="$CPP" fi echo "$ac_t""$CPP" 1>&6 echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6 echo "configure:1122: checking for ANSI C header files" >&5 if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #include #include #include EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" { (eval echo configure:1135: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* ac_cv_header_stdc=yes else echo "$ac_err" >&5 echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* ac_cv_header_stdc=no fi rm -f conftest* if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat > conftest.$ac_ext < EOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | egrep "memchr" >/dev/null 2>&1; then : else rm -rf conftest* 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 > conftest.$ac_ext < EOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | egrep "free" >/dev/null 2>&1; then : else rm -rf conftest* 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 > conftest.$ac_ext < #define ISLOWER(c) ('a' <= (c) && (c) <= 'z') #define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #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)) exit(2); exit (0); } EOF if { (eval echo configure:1202: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then : else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -fr conftest* ac_cv_header_stdc=no fi rm -fr conftest* fi fi fi echo "$ac_t""$ac_cv_header_stdc" 1>&6 if test $ac_cv_header_stdc = yes; then cat >> confdefs.h <<\EOF #define STDC_HEADERS 1 EOF fi for ac_hdr in fcntl.h limits.h malloc.h sys/ioctl.h unistd.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 echo "configure:1229: checking for $ac_hdr" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" { (eval echo configure:1239: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* eval "ac_cv_header_$ac_safe=yes" else echo "$ac_err" >&5 echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_header_$ac_safe=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then echo "$ac_t""yes" 1>&6 ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` cat >> confdefs.h <&6 fi done echo $ac_n "checking for working const""... $ac_c" 1>&6 echo "configure:1267: checking for working const" >&5 if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <j = 5; } { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ const int foo = 10; } ; return 0; } EOF if { (eval echo configure:1321: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_c_const=yes else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* ac_cv_c_const=no fi rm -f conftest* fi echo "$ac_t""$ac_cv_c_const" 1>&6 if test $ac_cv_c_const = no; then cat >> confdefs.h <<\EOF #define const EOF fi echo $ac_n "checking for inline""... $ac_c" 1>&6 echo "configure:1342: checking for inline" >&5 if eval "test \"`echo '$''{'ac_cv_c_inline'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_cv_c_inline=no for ac_kw in inline __inline__ __inline; do cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_c_inline=$ac_kw; break else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 fi rm -f conftest* done fi echo "$ac_t""$ac_cv_c_inline" 1>&6 case "$ac_cv_c_inline" in inline | yes) ;; no) cat >> confdefs.h <<\EOF #define inline EOF ;; *) cat >> confdefs.h <&6 echo "configure:1382: checking for size_t" >&5 if eval "test \"`echo '$''{'ac_cv_type_size_t'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #if STDC_HEADERS #include #include #endif EOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | egrep "(^|[^a-zA-Z_0-9])size_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then rm -rf conftest* ac_cv_type_size_t=yes else rm -rf conftest* ac_cv_type_size_t=no fi rm -f conftest* fi echo "$ac_t""$ac_cv_type_size_t" 1>&6 if test $ac_cv_type_size_t = no; then cat >> confdefs.h <<\EOF #define size_t unsigned EOF fi echo $ac_n "checking for st_rdev in struct stat""... $ac_c" 1>&6 echo "configure:1415: checking for st_rdev in struct stat" >&5 if eval "test \"`echo '$''{'ac_cv_struct_st_rdev'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #include int main() { struct stat s; s.st_rdev; ; return 0; } EOF if { (eval echo configure:1428: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_struct_st_rdev=yes else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* ac_cv_struct_st_rdev=no fi rm -f conftest* fi echo "$ac_t""$ac_cv_struct_st_rdev" 1>&6 if test $ac_cv_struct_st_rdev = yes; then cat >> confdefs.h <<\EOF #define HAVE_ST_RDEV 1 EOF fi if test $ac_cv_prog_gcc = yes; then echo $ac_n "checking whether ${CC-cc} needs -traditional""... $ac_c" 1>&6 echo "configure:1451: checking whether ${CC-cc} needs -traditional" >&5 if eval "test \"`echo '$''{'ac_cv_prog_gcc_traditional'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_pattern="Autoconf.*'x'" cat > conftest.$ac_ext < Autoconf TIOCGETP EOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | egrep "$ac_pattern" >/dev/null 2>&1; then rm -rf conftest* ac_cv_prog_gcc_traditional=yes else rm -rf conftest* ac_cv_prog_gcc_traditional=no fi rm -f conftest* if test $ac_cv_prog_gcc_traditional = no; then cat > conftest.$ac_ext < Autoconf TCGETA EOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | egrep "$ac_pattern" >/dev/null 2>&1; then rm -rf conftest* ac_cv_prog_gcc_traditional=yes fi rm -f conftest* fi fi echo "$ac_t""$ac_cv_prog_gcc_traditional" 1>&6 if test $ac_cv_prog_gcc_traditional = yes; then CC="$CC -traditional" fi fi echo $ac_n "checking for 8-bit clean memcmp""... $ac_c" 1>&6 echo "configure:1497: checking for 8-bit clean memcmp" >&5 if eval "test \"`echo '$''{'ac_cv_func_memcmp_clean'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test "$cross_compiling" = yes; then ac_cv_func_memcmp_clean=no else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ac_cv_func_memcmp_clean=yes else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -fr conftest* ac_cv_func_memcmp_clean=no fi rm -fr conftest* fi fi echo "$ac_t""$ac_cv_func_memcmp_clean" 1>&6 test $ac_cv_func_memcmp_clean = no && LIBOBJS="$LIBOBJS memcmp.${ac_objext}" echo $ac_n "checking for strftime""... $ac_c" 1>&6 echo "configure:1533: checking for strftime" >&5 if eval "test \"`echo '$''{'ac_cv_func_strftime'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char strftime(); int main() { /* 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_strftime) || defined (__stub___strftime) choke me #else strftime(); #endif ; return 0; } EOF if { (eval echo configure:1561: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_strftime=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_func_strftime=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_func_'strftime`\" = yes"; then echo "$ac_t""yes" 1>&6 cat >> confdefs.h <<\EOF #define HAVE_STRFTIME 1 EOF else echo "$ac_t""no" 1>&6 # strftime is in -lintl on SCO UNIX. echo $ac_n "checking for strftime in -lintl""... $ac_c" 1>&6 echo "configure:1583: checking for strftime in -lintl" >&5 ac_lib_var=`echo intl'_'strftime | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_save_LIBS="$LIBS" LIBS="-lintl $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=no" fi rm -f conftest* LIBS="$ac_save_LIBS" fi if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then echo "$ac_t""yes" 1>&6 cat >> confdefs.h <<\EOF #define HAVE_STRFTIME 1 EOF LIBS="-lintl $LIBS" else echo "$ac_t""no" 1>&6 fi fi echo $ac_n "checking for vprintf""... $ac_c" 1>&6 echo "configure:1629: checking for vprintf" >&5 if eval "test \"`echo '$''{'ac_cv_func_vprintf'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char vprintf(); int main() { /* 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_vprintf) || defined (__stub___vprintf) choke me #else vprintf(); #endif ; return 0; } EOF if { (eval echo configure:1657: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_vprintf=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_func_vprintf=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_func_'vprintf`\" = yes"; then echo "$ac_t""yes" 1>&6 cat >> confdefs.h <<\EOF #define HAVE_VPRINTF 1 EOF else echo "$ac_t""no" 1>&6 fi if test "$ac_cv_func_vprintf" != yes; then echo $ac_n "checking for _doprnt""... $ac_c" 1>&6 echo "configure:1681: checking for _doprnt" >&5 if eval "test \"`echo '$''{'ac_cv_func__doprnt'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char _doprnt(); int main() { /* 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__doprnt) || defined (__stub____doprnt) choke me #else _doprnt(); #endif ; return 0; } EOF if { (eval echo configure:1709: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func__doprnt=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_func__doprnt=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_func_'_doprnt`\" = yes"; then echo "$ac_t""yes" 1>&6 cat >> confdefs.h <<\EOF #define HAVE_DOPRNT 1 EOF else echo "$ac_t""no" 1>&6 fi fi for ac_func in strerror strstr strtol do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 echo "configure:1736: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char $ac_func(); int main() { /* 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_$ac_func) || defined (__stub___$ac_func) choke me #else $ac_func(); #endif ; return 0; } EOF if { (eval echo configure:1764: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_func_$ac_func=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then echo "$ac_t""yes" 1>&6 ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` cat >> confdefs.h <&6 fi done trap '' 1 2 15 cat > confcache <<\EOF # 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. It is not useful on other systems. # If it contains results you don't want to keep, you may remove or edit it. # # By default, configure uses ./config.cache as the cache file, # creating it if it does not exist already. You can give configure # the --cache-file=FILE option to use a different cache file; that is # what configure does when it calls configure scripts in # subdirectories, so they share the cache. # Giving --cache-file=/dev/null disables caching, for debugging configure. # config.status only pays attention to the cache file if you give it the # --recheck option to rerun configure. # EOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, don't put newlines in cache variables' values. # 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. (set) 2>&1 | case `(ac_space=' '; set | grep ac_space) 2>&1` in *ac_space=\ *) # `set' does not quote correctly, so add quotes (double-quote substitution # turns \\\\ into \\, and sed turns \\ into \). sed -n \ -e "s/'/'\\\\''/g" \ -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p" ;; *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p' ;; esac >> confcache if cmp -s $cache_file confcache; then : else if test -w $cache_file; then echo "updating cache $cache_file" cat confcache > $cache_file else echo "not updating unwritable cache $cache_file" fi fi rm -f confcache trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' # Any assignment to VPATH causes Sun make to only execute # the first set of double-colon rules, so remove it if not needed. # If there is a colon in the path, we need to keep it. if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d' fi trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15 # Transform confdefs.h into DEFS. # Protect against shell expansion while executing Makefile rules. # Protect against Makefile macro expansion. cat > conftest.defs <<\EOF s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%-D\1=\2%g s%[ `~#$^&*(){}\\|;'"<>?]%\\&%g s%\[%\\&%g s%\]%\\&%g s%\$%$$%g EOF DEFS=`sed -f conftest.defs confdefs.h | tr '\012' ' '` rm -f conftest.defs # Without the "./", some shells look in PATH for config.status. : ${CONFIG_STATUS=./config.status} echo creating $CONFIG_STATUS rm -f $CONFIG_STATUS cat > $CONFIG_STATUS </dev/null | sed 1q`: # # $0 $ac_configure_args # # Compiler output produced by configure, useful for debugging # configure, is in ./config.log if it exists. ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]" for ac_option do case "\$ac_option" in -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion" exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;; -version | --version | --versio | --versi | --vers | --ver | --ve | --v) echo "$CONFIG_STATUS generated by autoconf version 2.13" exit 0 ;; -help | --help | --hel | --he | --h) echo "\$ac_cs_usage"; exit 0 ;; *) echo "\$ac_cs_usage"; exit 1 ;; esac done ac_given_srcdir=$srcdir ac_given_INSTALL="$INSTALL" trap 'rm -fr `echo "include/Makefile mkreiserfs/Makefile resize_reiserfs/Makefile fsck/Makefile lib/Makefile Makefile reiserfscore/Makefile debugreiserfs/Makefile" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15 EOF cat >> $CONFIG_STATUS < conftest.subs <<\\CEOF $ac_vpsub $extrasub s%@SHELL@%$SHELL%g s%@CFLAGS@%$CFLAGS%g s%@CPPFLAGS@%$CPPFLAGS%g s%@CXXFLAGS@%$CXXFLAGS%g s%@FFLAGS@%$FFLAGS%g s%@DEFS@%$DEFS%g s%@LDFLAGS@%$LDFLAGS%g s%@LIBS@%$LIBS%g s%@exec_prefix@%$exec_prefix%g s%@prefix@%$prefix%g s%@program_transform_name@%$program_transform_name%g s%@bindir@%$bindir%g s%@sbindir@%$sbindir%g s%@libexecdir@%$libexecdir%g s%@datadir@%$datadir%g s%@sysconfdir@%$sysconfdir%g s%@sharedstatedir@%$sharedstatedir%g s%@localstatedir@%$localstatedir%g s%@libdir@%$libdir%g s%@includedir@%$includedir%g s%@oldincludedir@%$oldincludedir%g s%@infodir@%$infodir%g s%@mandir@%$mandir%g s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g s%@INSTALL_SCRIPT@%$INSTALL_SCRIPT%g s%@INSTALL_DATA@%$INSTALL_DATA%g s%@PACKAGE@%$PACKAGE%g s%@VERSION@%$VERSION%g s%@ACLOCAL@%$ACLOCAL%g s%@AUTOCONF@%$AUTOCONF%g s%@AUTOMAKE@%$AUTOMAKE%g s%@AUTOHEADER@%$AUTOHEADER%g s%@MAKEINFO@%$MAKEINFO%g s%@SET_MAKE@%$SET_MAKE%g s%@CC@%$CC%g s%@RANLIB@%$RANLIB%g s%@CPP@%$CPP%g s%@LIBOBJS@%$LIBOBJS%g CEOF EOF cat >> $CONFIG_STATUS <<\EOF # Split the substitutions into bite-sized pieces for seds with # small command number limits, like on Digital OSF/1 and HP-UX. ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script. ac_file=1 # Number of current file. ac_beg=1 # First line for current file. ac_end=$ac_max_sed_cmds # Line after last line for current file. ac_more_lines=: ac_sed_cmds="" while $ac_more_lines; do if test $ac_beg -gt 1; then sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file else sed "${ac_end}q" conftest.subs > conftest.s$ac_file fi if test ! -s conftest.s$ac_file; then ac_more_lines=false rm -f conftest.s$ac_file else if test -z "$ac_sed_cmds"; then ac_sed_cmds="sed -f conftest.s$ac_file" else ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file" fi ac_file=`expr $ac_file + 1` ac_beg=$ac_end ac_end=`expr $ac_end + $ac_max_sed_cmds` fi done if test -z "$ac_sed_cmds"; then ac_sed_cmds=cat fi EOF cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". case "$ac_file" in *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; *) ac_file_in="${ac_file}.in" ;; esac # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories. # Remove last slash and all that follows it. Not all systems have dirname. ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then # The file is in a subdirectory. test ! -d "$ac_dir" && mkdir "$ac_dir" ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`" # A "../" for each directory in $ac_dir_suffix. ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'` else ac_dir_suffix= ac_dots= fi case "$ac_given_srcdir" in .) srcdir=. if test -z "$ac_dots"; then top_srcdir=. else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;; /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;; *) # Relative path. srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix" top_srcdir="$ac_dots$ac_given_srcdir" ;; esac case "$ac_given_INSTALL" in [/$]*) INSTALL="$ac_given_INSTALL" ;; *) INSTALL="$ac_dots$ac_given_INSTALL" ;; esac echo creating "$ac_file" rm -f "$ac_file" configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure." case "$ac_file" in *Makefile*) ac_comsub="1i\\ # $configure_input" ;; *) ac_comsub= ;; esac ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` sed -e "$ac_comsub s%@configure_input@%$configure_input%g s%@srcdir@%$srcdir%g s%@top_srcdir@%$top_srcdir%g s%@INSTALL@%$INSTALL%g " $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file fi; done rm -f conftest.s* EOF cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF exit 0 EOF chmod +x $CONFIG_STATUS rm -fr confdefs* $ac_clean_files test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1 reiserfsprogs-3.x.0j/configure.in0000644000076400001440000000201207260366473012673 dnl Process this file with autoconf to produce a configure script. AC_INIT(version.h) AM_INIT_AUTOMAKE(reiserfsprogs, 3.x.0j) dnl We install in /sbin, the utils are to be available on boot AC_PREFIX_DEFAULT(/) PRESET_CFLAGS=$CFLAGS AC_PROG_CC if test -z $PRESET_CFLAGS; then dnl CFLAGS="${RPM_OPT_FLAGS} $CFLAGS -Wall" CFLAGS="${RPM_OPT_FLAGS} -g -O2 -Wall" fi dnl Checks for programs. AC_PROG_RANLIB dnl AC_PROG_AWK dnl AC_PROG_INSTALL dnl AC_PROG_LN_S dnl Checks for libraries. dnl Checks for header files. AC_HEADER_STDC AC_CHECK_HEADERS(fcntl.h limits.h malloc.h sys/ioctl.h unistd.h) dnl Checks for typedefs, structures, and compiler characteristics. AC_C_CONST AC_C_INLINE AC_TYPE_SIZE_T AC_STRUCT_ST_RDEV dnl Checks for library functions. AC_PROG_GCC_TRADITIONAL AC_FUNC_MEMCMP AC_FUNC_STRFTIME AC_FUNC_VPRINTF AC_CHECK_FUNCS(strerror strstr strtol) AC_OUTPUT(include/Makefile mkreiserfs/Makefile resize_reiserfs/Makefile fsck/Makefile lib/Makefile Makefile reiserfscore/Makefile debugreiserfs/Makefile) reiserfsprogs-3.x.0j/install-sh0000755000076400001440000001273607142245343012373 #!/bin/sh # # install - install a program, script, or datafile # This comes from X11R5 (mit/util/scripts/install.sh). # # Copyright 1991 by the Massachusetts Institute of Technology # # Permission to use, copy, modify, distribute, and sell this software and its # documentation for any purpose is hereby granted without fee, provided that # the above copyright notice appear in all copies and that both that # copyright notice and this permission notice appear in supporting # documentation, and that the name of M.I.T. not be used in advertising or # publicity pertaining to distribution of the software without specific, # written prior permission. M.I.T. makes no representations about the # suitability of this software for any purpose. It is provided "as is" # without express or implied warranty. # # Calling this script install-sh is preferred over install.sh, to prevent # `make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. It can only install one file at a time, a restriction # shared with many OS's install programs. # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit="${DOITPROG-}" # put in absolute paths if you don't have them in your path; or use env. vars. mvprog="${MVPROG-mv}" cpprog="${CPPROG-cp}" chmodprog="${CHMODPROG-chmod}" chownprog="${CHOWNPROG-chown}" chgrpprog="${CHGRPPROG-chgrp}" stripprog="${STRIPPROG-strip}" rmprog="${RMPROG-rm}" mkdirprog="${MKDIRPROG-mkdir}" transformbasename="" transform_arg="" instcmd="$mvprog" chmodcmd="$chmodprog 0755" chowncmd="" chgrpcmd="" stripcmd="" rmcmd="$rmprog -f" mvcmd="$mvprog" src="" dst="" dir_arg="" while [ x"$1" != x ]; do case $1 in -c) instcmd="$cpprog" shift continue;; -d) dir_arg=true shift continue;; -m) chmodcmd="$chmodprog $2" shift shift continue;; -o) chowncmd="$chownprog $2" shift shift continue;; -g) chgrpcmd="$chgrpprog $2" shift shift continue;; -s) stripcmd="$stripprog" shift continue;; -t=*) transformarg=`echo $1 | sed 's/-t=//'` shift continue;; -b=*) transformbasename=`echo $1 | sed 's/-b=//'` shift continue;; *) if [ x"$src" = x ] then src=$1 else # this colon is to work around a 386BSD /bin/sh bug : dst=$1 fi shift continue;; esac done if [ x"$src" = x ] then echo "install: no input file specified" exit 1 else true fi if [ x"$dir_arg" != x ]; then dst=$src src="" if [ -d $dst ]; then instcmd=: chmodcmd="" else instcmd=mkdir fi else # Waiting for this to be detected by the "$instcmd $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if [ -f $src -o -d $src ] then true else echo "install: $src does not exist" exit 1 fi if [ x"$dst" = x ] then echo "install: no destination specified" exit 1 else true fi # If destination is a directory, append the input filename; if your system # does not like double slashes in filenames, you may need to add some logic if [ -d $dst ] then dst="$dst"/`basename $src` else true fi fi ## this sed command emulates the dirname command dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` # Make sure that the destination directory exists. # this part is taken from Noah Friedman's mkinstalldirs script # Skip lots of stat calls in the usual case. if [ ! -d "$dstdir" ]; then defaultIFS=' ' IFS="${IFS-${defaultIFS}}" oIFS="${IFS}" # Some sh's can't handle IFS=/ for some reason. IFS='%' set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` IFS="${oIFS}" pathcomp='' while [ $# -ne 0 ] ; do pathcomp="${pathcomp}${1}" shift if [ ! -d "${pathcomp}" ] ; then $mkdirprog "${pathcomp}" else true fi pathcomp="${pathcomp}/" done fi if [ x"$dir_arg" != x ] then $doit $instcmd $dst && if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi else # If we're going to rename the final executable, determine the name now. if [ x"$transformarg" = x ] then dstfile=`basename $dst` else dstfile=`basename $dst $transformbasename | sed $transformarg`$transformbasename fi # don't allow the sed command to completely eliminate the filename if [ x"$dstfile" = x ] then dstfile=`basename $dst` else true fi # Make a temp file name in the proper directory. dsttmp=$dstdir/#inst.$$# # Move or copy the file name to the temp name $doit $instcmd $src $dsttmp && trap "rm -f ${dsttmp}" 0 && # and set any options; do chmod last to preserve setuid bits # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $instcmd $src $dsttmp" command. if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && # Now rename the file to the real destination. $doit $rmcmd -f $dstdir/$dstfile && $doit $mvcmd $dsttmp $dstdir/$dstfile fi && exit 0 reiserfsprogs-3.x.0j/missing0000755000076400001440000001421307142245342011755 #! /bin/sh # Common stub for a few missing GNU programs while installing. # Copyright (C) 1996, 1997 Free Software Foundation, Inc. # Franc,ois Pinard , 1996. # 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, 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., 59 Temple Place - Suite 330, Boston, MA # 02111-1307, USA. if test $# -eq 0; then echo 1>&2 "Try \`$0 --help' for more information" exit 1 fi case "$1" in -h|--h|--he|--hel|--help) echo "\ $0 [OPTION]... PROGRAM [ARGUMENT]... Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an error status if there is no known handling for PROGRAM. Options: -h, --help display this help and exit -v, --version output version information and exit Supported PROGRAM values: aclocal touch file \`aclocal.m4' autoconf touch file \`configure' autoheader touch file \`config.h.in' automake touch all \`Makefile.in' files bison create \`y.tab.[ch]', if possible, from existing .[ch] flex create \`lex.yy.c', if possible, from existing .c lex create \`lex.yy.c', if possible, from existing .c makeinfo touch the output file yacc create \`y.tab.[ch]', if possible, from existing .[ch]" ;; -v|--v|--ve|--ver|--vers|--versi|--versio|--version) echo "missing - GNU libit 0.0" ;; -*) echo 1>&2 "$0: Unknown \`$1' option" echo 1>&2 "Try \`$0 --help' for more information" exit 1 ;; aclocal) echo 1>&2 "\ WARNING: \`$1' is missing on your system. You should only need it if you modified \`acinclude.m4' or \`configure.in'. You might want to install the \`Automake' and \`Perl' packages. Grab them from any GNU archive site." touch aclocal.m4 ;; autoconf) echo 1>&2 "\ WARNING: \`$1' is missing on your system. You should only need it if you modified \`configure.in'. You might want to install the \`Autoconf' and \`GNU m4' packages. Grab them from any GNU archive site." touch configure ;; autoheader) echo 1>&2 "\ WARNING: \`$1' is missing on your system. You should only need it if you modified \`acconfig.h' or \`configure.in'. You might want to install the \`Autoconf' and \`GNU m4' packages. Grab them from any GNU archive site." files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' configure.in` test -z "$files" && files="config.h" touch_files= for f in $files; do case "$f" in *:*) touch_files="$touch_files "`echo "$f" | sed -e 's/^[^:]*://' -e 's/:.*//'`;; *) touch_files="$touch_files $f.in";; esac done touch $touch_files ;; automake) echo 1>&2 "\ WARNING: \`$1' is missing on your system. You should only need it if you modified \`Makefile.am', \`acinclude.m4' or \`configure.in'. You might want to install the \`Automake' and \`Perl' packages. Grab them from any GNU archive site." find . -type f -name Makefile.am -print | sed 's/\.am$/.in/' | while read f; do touch "$f"; done ;; bison|yacc) echo 1>&2 "\ WARNING: \`$1' is missing on your system. You should only need it if you modified a \`.y' file. You may need the \`Bison' package in order for those modifications to take effect. You can get \`Bison' from any GNU archive site." rm -f y.tab.c y.tab.h if [ $# -ne 1 ]; then eval LASTARG="\${$#}" case "$LASTARG" in *.y) SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'` if [ -f "$SRCFILE" ]; then cp "$SRCFILE" y.tab.c fi SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'` if [ -f "$SRCFILE" ]; then cp "$SRCFILE" y.tab.h fi ;; esac fi if [ ! -f y.tab.h ]; then echo >y.tab.h fi if [ ! -f y.tab.c ]; then echo 'main() { return 0; }' >y.tab.c fi ;; lex|flex) echo 1>&2 "\ WARNING: \`$1' is missing on your system. You should only need it if you modified a \`.l' file. You may need the \`Flex' package in order for those modifications to take effect. You can get \`Flex' from any GNU archive site." rm -f lex.yy.c if [ $# -ne 1 ]; then eval LASTARG="\${$#}" case "$LASTARG" in *.l) SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'` if [ -f "$SRCFILE" ]; then cp "$SRCFILE" lex.yy.c fi ;; esac fi if [ ! -f lex.yy.c ]; then echo 'main() { return 0; }' >lex.yy.c fi ;; makeinfo) echo 1>&2 "\ WARNING: \`$1' is missing on your system. You should only need it if you modified a \`.texi' or \`.texinfo' file, or any other file indirectly affecting the aspect of the manual. The spurious call might also be the consequence of using a buggy \`make' (AIX, DU, IRIX). You might want to install the \`Texinfo' package or the \`GNU make' package. Grab either from any GNU archive site." file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` if test -z "$file"; then file=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $file` fi touch $file ;; *) echo 1>&2 "\ WARNING: \`$1' is needed, and you do not seem to have it handy on your system. You might have modified some files without having the proper tools for further handling them. Check the \`README' file, it often tells you about the needed prerequirements for installing this package. You may also peek at any GNU archive site, in case some other package would contain this missing \`$1' program." exit 1 ;; esac exit 0 reiserfsprogs-3.x.0j/mkinstalldirs0000755000076400001440000000132407142245344013165 #! /bin/sh # mkinstalldirs --- make directory hierarchy # Author: Noah Friedman # Created: 1993-05-16 # Public domain # $Id: mkinstalldirs,v 1.1.1.1 2000/08/03 10:35:16 vs Exp $ errstatus=0 for file do set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'` shift pathcomp= for d do pathcomp="$pathcomp$d" case "$pathcomp" in -* ) pathcomp=./$pathcomp ;; esac if test ! -d "$pathcomp"; then echo "mkdir $pathcomp" mkdir "$pathcomp" || lasterr=$? if test ! -d "$pathcomp"; then errstatus=$lasterr fi fi pathcomp="$pathcomp/" done done exit $errstatus # mkinstalldirs ends here reiserfsprogs-3.x.0j/version.h0000644000076400001440000000033107260366413012214 /* * Copyright 2000 Hans Reiser */ #define REISERFSPROGS_VERSION "3.x.0j" #define print_banner(prog) \ fprintf (stderr, "\n<-------------%s, 2001------------->\nreiserfsprogs %s\n", \ prog, REISERFSPROGS_VERSION) reiserfsprogs-3.x.0j/reiserfsprogs.spec0000644000076400001440000000347207260366403014137 Vendor: Hans Reiser Distribution: Hans Reiser Name: reiserfsprogs Release: 1 Copyright: 2001 Hans Reiser Group: Unsorted Packager: anthon@mnt.org Version: 3.x.0j Summary: utilities belonging to the Reiser filesystem Source: reiserfsprogs-%{version}.tar.gz BuildRoot: /var/tmp/rpm-reiserfsprogs %description The reiserfsprogs package contains programs for creating (mkreiserfs), checking and correcting any inconsistencies (reiserfsck) and resizing (resize_reiserfs) of a reiserfs filesystem. Authors: -------- Hans Reiser Vitaly Fertman Alexander Zarochentcev Vladimir Saveliev %prep %setup -q # %patch %build MANDIR=$(dirname $(dirname $(man -w fsck | cut -d ' ' -f 1))) ./configure --prefix="" --mandir=$MANDIR make all %install mkdir -p $RPM_BUILD_ROOT/sbin make DESTDIR=$RPM_BUILD_ROOT install # do we need this? cd $RPM_BUILD_ROOT/sbin ln -sf reiserfsck fsck.reiserfs # __os_install_post is normally executed after %install disable it %define ___build_post %{nil} # explicitly call it now, so manpages get compressed, exec's stripped etc. %{?__os_install_post} %define __os_install_post %{nil} # now we have all the files execpt for docs, but their owner is unimportant cd $RPM_BUILD_ROOT rm -f rpm-filelist # we do not have special directories to make #find . -type d \ # | sed '1,2d;s,^\.,\%attr(-\,root\,root) \%dir ,' >> rpm-filelist find . -type f \ | sed 's,^\.,\%attr(-\,root\,root) ,' | fgrep -v rpm-filelist >> rpm-filelist find . -type l \ | sed 's,^\.,\%attr(-\,root\,root) ,' >> rpm-filelist %clean # in case some overrides buildroot with / don't remove the whole tree rm -rf /var/tmp/rpm-reiserfsprogs %files -f /var/tmp/rpm-reiserfsprogs/rpm-filelist %doc README reiserfsprogs-3.x.0j/include/0000777000076400001440000000000007261220334012060 5reiserfsprogs-3.x.0j/include/Makefile.in0000644000076400001440000001175407261220334014051 # Makefile.in generated automatically by automake 1.4 from Makefile.am # Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. # This Makefile.in 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. SHELL = @SHELL@ srcdir = @srcdir@ top_srcdir = @top_srcdir@ VPATH = @srcdir@ prefix = @prefix@ exec_prefix = @exec_prefix@ bindir = @bindir@ sbindir = @sbindir@ libexecdir = @libexecdir@ datadir = @datadir@ sysconfdir = @sysconfdir@ sharedstatedir = @sharedstatedir@ localstatedir = @localstatedir@ libdir = @libdir@ infodir = @infodir@ mandir = @mandir@ includedir = @includedir@ oldincludedir = /usr/include DESTDIR = pkgdatadir = $(datadir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ top_builddir = .. ACLOCAL = @ACLOCAL@ AUTOCONF = @AUTOCONF@ AUTOMAKE = @AUTOMAKE@ AUTOHEADER = @AUTOHEADER@ INSTALL = @INSTALL@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS) INSTALL_DATA = @INSTALL_DATA@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ transform = @program_transform_name@ NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : CC = @CC@ MAKEINFO = @MAKEINFO@ PACKAGE = @PACKAGE@ RANLIB = @RANLIB@ VERSION = @VERSION@ noinst_HEADERS = io.h misc.h reiserfs_fs.h reiserfs_lib.h mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs CONFIG_CLEAN_FILES = HEADERS = $(noinst_HEADERS) DIST_COMMON = Makefile.am Makefile.in DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) TAR = tar GZIP_ENV = --best all: all-redirect .SUFFIXES: $(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps include/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status cd $(top_builddir) \ && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status tags: TAGS ID: $(HEADERS) $(SOURCES) $(LISP) list='$(SOURCES) $(HEADERS)'; \ unique=`for i in $$list; do echo $$i; done | \ awk ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ here=`pwd` && cd $(srcdir) \ && mkid -f$$here/ID $$unique $(LISP) TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) tags=; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS)'; \ unique=`for i in $$list; do echo $$i; done | \ awk ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) mostlyclean-tags: clean-tags: distclean-tags: -rm -f TAGS ID maintainer-clean-tags: distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) subdir = include distdir: $(DISTFILES) @for file in $(DISTFILES); do \ d=$(srcdir); \ if test -d $$d/$$file; then \ cp -pr $$/$$file $(distdir)/$$file; \ else \ test -f $(distdir)/$$file \ || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ || cp -p $$d/$$file $(distdir)/$$file || :; \ fi; \ done info-am: info: info-am dvi-am: dvi: dvi-am check-am: all-am check: check-am installcheck-am: installcheck: installcheck-am install-exec-am: install-exec: install-exec-am install-data-am: install-data: install-data-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am install: install-am uninstall-am: uninstall: uninstall-am all-am: Makefile $(HEADERS) all-redirect: all-am install-strip: $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install installdirs: mostlyclean-generic: clean-generic: distclean-generic: -rm -f Makefile $(CONFIG_CLEAN_FILES) -rm -f config.cache config.log stamp-h stamp-h[0-9]* maintainer-clean-generic: mostlyclean-am: mostlyclean-tags mostlyclean-generic mostlyclean: mostlyclean-am clean-am: clean-tags clean-generic mostlyclean-am clean: clean-am distclean-am: distclean-tags distclean-generic clean-am distclean: distclean-am maintainer-clean-am: maintainer-clean-tags maintainer-clean-generic \ distclean-am @echo "This command is intended for maintainers to use;" @echo "it deletes files that may require special tools to rebuild." maintainer-clean: maintainer-clean-am .PHONY: tags mostlyclean-tags distclean-tags clean-tags \ maintainer-clean-tags distdir info-am info dvi-am dvi check check-am \ installcheck-am installcheck install-exec-am install-exec \ install-data-am install-data install-am install uninstall-am uninstall \ all-redirect all-am all installdirs mostlyclean-generic \ distclean-generic clean-generic maintainer-clean-generic clean \ mostlyclean distclean maintainer-clean # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: reiserfsprogs-3.x.0j/include/Makefile.am0000644000076400001440000000007507231645634014045 noinst_HEADERS = io.h misc.h reiserfs_fs.h reiserfs_lib.h reiserfsprogs-3.x.0j/include/io.h0000644000076400001440000000352207255431231012561 struct buffer_head { unsigned long b_blocknr; unsigned short b_dev; unsigned long b_size; char * b_data; unsigned long b_state; unsigned int b_count; unsigned int b_list ; void (*b_end_io)(struct buffer_head *bh, int uptodate); struct buffer_head * b_next; struct buffer_head * b_prev; struct buffer_head * b_hash_next; struct buffer_head * b_hash_prev; }; #define BH_Uptodate 0 #define BH_Dirty 1 #define BH_Lock 2 #define buffer_uptodate(bh) test_bit(BH_Uptodate, &(bh)->b_state) #define buffer_dirty(bh) test_bit(BH_Dirty, &(bh)->b_state) #define buffer_locked(bh) test_bit(BH_Lock, &(bh)->b_state) #define buffer_clean(bh) !test_bit(BH_Dirty, &(bh)->b_state) #define mark_buffer_dirty(bh) set_bit(BH_Dirty, &(bh)->b_state) /* printf ("%s:%s:%u %p %p %p\n", __FILE__, __FUNCTION__, __LINE__, __builtin_return_address (0), __builtin_return_address (1), __builtin_return_address (2)); */ #define mark_buffer_uptodate(bh,i) set_bit(BH_Uptodate, &(bh)->b_state) #define mark_buffer_clean(bh) clear_bit(BH_Dirty, &(bh)->b_state) void __wait_on_buffer (struct buffer_head * bh); struct buffer_head * getblk (int dev, int block, int size); struct buffer_head * reiserfs_getblk (int dev, int block, int size, int *repeat); struct buffer_head * find_buffer (int dev, int block, int size); struct buffer_head * get_hash_table(dev_t dev, int block, int size); struct buffer_head * bread (int dev, unsigned long block, size_t size); struct buffer_head * reiserfs_bread (int dev, int block, int size, int *repeat); int valid_offset (int fd, loff_t offset); int bwrite (struct buffer_head * bh); void brelse (struct buffer_head * bh); void bforget (struct buffer_head * bh); void check_and_free_buffer_mem (void); void flush_buffers (void); void free_buffers (void); loff_t reiserfs_llseek (unsigned int fd, loff_t offset, unsigned int origin); reiserfsprogs-3.x.0j/include/misc.h0000644000076400001440000000234307253747542013122 /* * Copyright 1996-2000 Hans Reiser */ /* nothing abount reiserfs here */ void die (char * fmt, ...); void * getmem (int size); void freemem (void * p); void checkmem (char * p, int size); void * expandmem (void * p, int size, int by); int is_mounted (char * device_name); int is_mounted_read_only (char * device_name); void check_and_free_mem (void); char * kdevname (int dev); int set_bit (int nr, void * addr); int clear_bit (int nr, void * addr); int test_bit(int nr, const void * addr); int find_first_zero_bit (const void *vaddr, unsigned size); int find_next_zero_bit (const void *vaddr, unsigned size, unsigned offset); void print_how_far (unsigned long * passed, unsigned long total, int inc, int quiet); void print_how_fast (unsigned long total, unsigned long passed, int cursor_pos); int user_confirmed (char * q, char * yes); /* int test_and_set_bit (int nr, void * addr); int test_and_clear_bit (int nr, void * addr); */ inline __u32 cpu_to_le32 (__u32 val); inline __u32 le32_to_cpu (__u32 val); inline __u16 cpu_to_le16 (__u16 val); inline __u16 le16_to_cpu (__u16 val); inline __u64 cpu_to_le64 (__u64 val); inline __u64 le64_to_cpu (__u64 val); unsigned long count_blocks (char * filename, int blocksize, int fd); reiserfsprogs-3.x.0j/include/reiserfs_fs.h0000644000076400001440000016351207261107216014472 /* * Copyright 1996-2001 by Hans Reiser, licensing governed by reiserfs/README */ /* * include/linux/reiser_fs.h * * Reiser File System constants and structures * */ /* in reading the #defines, it may help to understand that they employ the following abbreviations: B = Buffer I = Item header H = Height within the tree (should be changed to LEV) N = Number of the item in the node STAT = stat data DEH = Directory Entry Header EC = Entry Count E = Entry number UL = Unsigned Long BLKH = BLocK Header UNFM = UNForMatted node DC = Disk Child P = Path These #defines are named by concatenating these abbreviations, where first comes the arguments, and last comes the return value, of the macro. */ #include /* NEW_GET_NEW_BUFFER will try to allocate new blocks better */ /*#define NEW_GET_NEW_BUFFER*/ #define OLD_GET_NEW_BUFFER /* n must be power of 2 */ #define _ROUND_UP(x,n) (((x)+(n)-1u) & ~((n)-1u)) // to be ok for alpha and others we have to align structures to 8 byte // boundary. // FIXME: do not change 4 by anything else: there is code which relies on that #define ROUND_UP(x) _ROUND_UP(x,8LL) /***************************************************************************/ /* SUPER BLOCK */ /***************************************************************************/ #define UNSET_HASH 0 // read_super will guess about, what hash names // in directories were sorted with #define TEA_HASH 1 #define YURA_HASH 2 #define R5_HASH 3 #define DEFAULT_HASH R5_HASH // can be used only to complete indirect to direct convertion and for // nothing else #define RESERVED_SPACE 20 /* super block of prejournalled version */ struct reiserfs_super_block_v0 { __u32 s_block_count; __u32 s_free_blocks; __u32 s_root_block; __u16 s_blocksize; __u16 s_oid_maxsize; __u16 s_oid_cursize; __u16 s_state; char s_magic[16]; __u16 s_tree_height; __u16 s_bmap_nr; __u16 s_reserved; }; /* this is the super from 3.5.X, where X >= 10 */ struct reiserfs_super_block_v1 { __u32 s_block_count; /* blocks count */ __u32 s_free_blocks; /* free blocks count */ __u32 s_root_block; /* root block number */ __u32 s_journal_block; /* journal block number */ __u32 s_journal_dev; /* journal device number */ __u32 s_orig_journal_size; /* size of the journal on FS creation. used to make sure they don't overflow it */ __u32 s_journal_trans_max ; /* max number of blocks in a transaction. */ __u32 s_journal_block_count ; /* total size of the journal. can change over time */ __u32 s_journal_max_batch ; /* max number of blocks to batch into a trans */ __u32 s_journal_max_commit_age ; /* in seconds, how old can an async commit be */ __u32 s_journal_max_trans_age ; /* in seconds, how old can a transaction be */ __u16 s_blocksize; /* block size */ __u16 s_oid_maxsize; /* max size of object id array, see get_objectid() commentary */ __u16 s_oid_cursize; /* current size of object id array */ __u16 s_state; /* valid or error */ char s_magic[10]; /* reiserfs magic string indicates that file system is reiserfs */ __u16 s_fsck_state; /* when fsck managed to build the tree - it puts */ __u32 s_hash_function_code; /* indicate, what hash fuction is being use to sort names in a directory*/ __u16 s_tree_height; /* height of disk tree */ __u16 s_bmap_nr; /* amount of bitmap blocks needed to address each block of file system */ __u16 s_version; }; #define SB_SIZE_V1 (sizeof(struct reiserfs_super_block_v1)) /* 76 bytes */ /* Structure of super block on disk, a version of which in RAM is often accessed as s->u.reiserfs_sb.s_rs the version in RAM is part of a larger structure containing fields never written to disk. */ struct reiserfs_super_block { struct reiserfs_super_block_v1 s_v1; char s_unused[128] ; /* zero filled by mkreiserfs */ }; #define SB_SIZE (sizeof(struct reiserfs_super_block)) /* 204 bytes */ typedef __u32 (*hashf_t) (const char *, int); #define SB_BUFFER_WITH_SB(s) ((s)->s_sbh) #define SB_AP_BITMAP(s) ((s)->s_ap_bitmap) #define SB_DISK_SUPER_BLOCK(s) (&((s)->s_rs->s_v1)) #define SB_JOURNAL_BLOCK(s) le32_to_cpu ((SB_DISK_SUPER_BLOCK(s)->s_journal_block)) #define SB_JOURNAL_SIZE(s) le32_to_cpu ((SB_DISK_SUPER_BLOCK(s)->s_orig_journal_size)) #define SB_BLOCK_COUNT(s) le32_to_cpu ((SB_DISK_SUPER_BLOCK(s)->s_block_count)) #define SB_FREE_BLOCKS(s) le32_to_cpu ((SB_DISK_SUPER_BLOCK(s)->s_free_blocks)) #define SB_REISERFS_MAGIC(s) (SB_DISK_SUPER_BLOCK(s)->s_magic) #define SB_ROOT_BLOCK(s) le32_to_cpu ((SB_DISK_SUPER_BLOCK(s)->s_root_block)) #define SB_TREE_HEIGHT(s) le16_to_cpu ((SB_DISK_SUPER_BLOCK(s)->s_tree_height)) #define SB_REISERFS_STATE(s) le16_to_cpu ((SB_DISK_SUPER_BLOCK(s)->s_state)) #define SB_VERSION(s) le16_to_cpu ((SB_DISK_SUPER_BLOCK(s)->s_version)) #define SB_BMAP_NR(s) le16_to_cpu ((SB_DISK_SUPER_BLOCK(s)->s_bmap_nr)) #define SB_OBJECTID_MAP_SIZE(s) le16_to_cpu ((SB_DISK_SUPER_BLOCK(s)->s_oid_cursize)) #define SB_OBJECTID_MAP_MAXSIZE(s) le16_to_cpu ((SB_DISK_SUPER_BLOCK(s)->s_oid_maxsize)) #define rs_blocksize(rs) le16_to_cpu ((rs)->s_v1.s_blocksize) #define set_blocksize(rs,n) ((rs)->s_v1.s_blocksize = cpu_to_le16 (n)) #define rs_block_count(rs) le32_to_cpu ((rs)->s_v1.s_block_count) #define set_block_count(rs,n) ((rs)->s_v1.s_block_count = cpu_to_le32 (n)) #define rs_journal_dev(rs) le32_to_cpu ((rs)->s_v1.s_journal_dev) #define set_journal_dev(rs,n) ((rs)->s_v1.s_journal_dev = cpu_to_le32 (n)) #define rs_journal_start(rs) le32_to_cpu ((rs)->s_v1.s_journal_block) #define set_journal_start(rs,n) ((rs)->s_v1.s_journal_block = cpu_to_le32 (n)) #define rs_journal_size(rs) le32_to_cpu((rs)->s_v1.s_orig_journal_size) #define set_journal_size(rs,n) ((rs)->s_v1.s_orig_journal_size = cpu_to_le32(n)) #define rs_root_block(rs) le32_to_cpu ((rs)->s_v1.s_root_block) #define set_root_block(rs,n) ((rs)->s_v1.s_root_block = cpu_to_le32 (n)) #define rs_tree_height(rs) le16_to_cpu ((rs)->s_v1.s_tree_height) #define set_tree_height(rs,n) ((rs)->s_v1.s_tree_height = cpu_to_le16 (n)) #define rs_free_blocks(rs) le32_to_cpu ((rs)->s_v1.s_free_blocks) #define set_free_blocks(rs,n) ((rs)->s_v1.s_free_blocks = cpu_to_le32 (n)) #define rs_bmap_nr(rs) le16_to_cpu ((rs)->s_v1.s_bmap_nr) #define set_bmap_nr(rs,n) ((rs)->s_v1.s_bmap_nr = cpu_to_le16 (n)) #define rs_state(rs) le16_to_cpu ((rs)->s_v1.s_state) #define set_state(rs,n) ((rs)->s_v1.s_state = cpu_to_le16 (n)) #define rs_objectid_map_size(rs) (le16_to_cpu ((rs)->s_v1.s_oid_cursize)) #define set_objectid_map_size(rs,n) ((rs)->s_v1.s_oid_cursize = cpu_to_le16 (n)) #define rs_objectid_map_max_size(rs) (le16_to_cpu ((rs)->s_v1.s_oid_maxsize)) #define set_objectid_map_max_size(rs,n) ((rs)->s_v1.s_oid_maxsize = cpu_to_le16 (n)) #define rs_hash(rs) (le32_to_cpu ((rs)->s_v1.s_hash_function_code)) #define set_hash(rs,n) ((rs)->s_v1.s_hash_function_code = cpu_to_le32 (n)) #define rs_version(rs) (le16_to_cpu ((rs)->s_v1.s_version)) #define set_version(rs,n) ((rs)->s_v1.s_version = cpu_to_le16 (n)) #define TREE_IS_BUILT 0xfaaf #define fsck_state(rs) le16_to_cpu (((rs)->s_v1.s_fsck_state)) #define set_fsck_state(rs,n) ((rs)->s_v1.s_fsck_state = cpu_to_le16 (n)) #define sb_size(fs) (fs->s_version == REISERFS_VERSION_2) ? SB_SIZE : SB_SIZE_V1 /* struct stat_data* access macros */ /* v1 */ #define sd_v1_mode(sd) (le16_to_cpu((sd)->sd_mode)) #define set_sd_v1_mode(sd,n) ((sd)->sd_mode = cpu_to_le16((n))) #define sd_v1_nlink(sd) (le16_to_cpu((sd)->sd_nlink)) #define set_sd_v1_nlink(sd,n) ((sd)->sd_nlink = cpu_to_le16((n))) #define sd_v1_uid(sd) (le16_to_cpu((sd)->sd_uid)) #define set_sd_v1_uid(sd,n) ((sd)->sd_uid = cpu_to_le16((n))) #define sd_v1_gid(sd) (le16_to_cpu((sd)->sd_gid)) #define set_sd_v1_gid(sd,n) ((sd)->sd_gid = cpu_to_le16((n))) #define sd_v1_size(sd) (le32_to_cpu((sd)->sd_size)) #define set_sd_v1_size(sd,n) ((sd)->sd_size = cpu_to_le32((n))) #define sd_v1_atime(sd) (le32_to_cpu((sd)->sd_atime)) #define set_sd_v1_atime(sd,n) ((sd)->sd_atime = cpu_to_le32((n))) #define sd_v1_mtime(sd) (le32_to_cpu((sd)->sd_mtime)) #define set_sd_v1_mtime(sd,n) ((sd)->sd_mtime = cpu_to_le32((n))) #define sd_v1_ctime(sd) (le32_to_cpu((sd)->sd_ctime)) #define set_sd_v1_ctime(sd,n) ((sd)->sd_ctime = cpu_to_le32((n))) #define sd_v1_blocks(sd) (le32_to_cpu((sd)->u.sd_blocks)) #define set_sd_v1_blocks(sd,n) ((sd)->u.sd_blocks = cpu_to_le32((n))) #define sd_v1_rdev(sd) (le32_to_cpu((sd)->u.sd_rdev)) #define set_sd_v1_rdev(sd,n) ((sd)->u.sd_rdev = cpu_to_le32((n))) #define sd_v1_first_direct_byte(sd) (le32_to_cpu((sd)->sd_first_direct_byte)) #define set_sd_v1_first_direct_byte(sd,n) \ ((sd)->sd_first_direct_byte = cpu_to_le32((n))) /* v2 */ #define sd_v2_mode(sd) (le16_to_cpu((sd)->sd_mode)) #define set_sd_v2_mode(sd,n) ((sd)->sd_mode = cpu_to_le16((n))) #define sd_v2_reserved(sd) (le16_to_cpu((sd)->sd_reserved)) #define set_sd_v2_reserved(sd,n) ((sd)->sd_reserved = cpu_to_le16((n))) #define sd_v2_nlink(sd) (le32_to_cpu((sd)->sd_nlink)) #define set_sd_v2_nlink(sd,n) ((sd)->sd_nlink = cpu_to_le32((n))) #define sd_v2_size(sd) (le64_to_cpu((sd)->sd_size)) #define set_sd_v2_size(sd,n) ((sd)->sd_size = cpu_to_le64((n))) #define sd_v2_uid(sd) (le32_to_cpu((sd)->sd_uid)) #define set_sd_v2_uid(sd,n) ((sd)->sd_uid = cpu_to_le32((n))) #define sd_v2_gid(sd) (le32_to_cpu((sd)->sd_gid)) #define set_sd_v2_gid(sd,n) ((sd)->sd_gid = cpu_to_le32((n))) #define sd_v2_atime(sd) (le32_to_cpu((sd)->sd_atime)) #define set_sd_v2_atime(sd,n) ((sd)->sd_atime = cpu_to_le32((n))) #define sd_v2_mtime(sd) (le32_to_cpu((sd)->sd_mtime)) #define set_sd_v2_mtime(sd,n) ((sd)->sd_mtime = cpu_to_le32((n))) #define sd_v2_ctime(sd) (le32_to_cpu((sd)->sd_ctime)) #define set_sd_v2_ctime(sd,n) ((sd)->sd_ctime = cpu_to_le32((n))) #define sd_v2_blocks(sd) (le32_to_cpu((sd)->sd_blocks)) #define set_sd_v2_blocks(sd,n) ((sd)->sd_blocks = cpu_to_le32((n))) #define sd_v2_rdev(sd) (le32_to_cpu((sd)->u.sd_rdev)) #define set_sd_v2_rdev(sd,n) ((sd)->u.sd_rdev = cpu_to_le32((n))) /* ReiserFS leaves the first 64k unused, so that partition labels have enough space. If someone wants to write a fancy bootloader that needs more than 64k, let us know, and this will be increased in size. This number must be larger than than the largest block size on any platform, or code will break. -Hans */ #define REISERFS_DISK_OFFSET_IN_BYTES (64 * 1024) /* the spot for the super in versions 3.5 - 3.5.11 (inclusive) */ #define REISERFS_OLD_DISK_OFFSET_IN_BYTES (8 * 1024) /* prejournalled reiserfs had signature in the other place in super block */ #define REISERFS_SUPER_MAGIC_STRING_OFFSET_NJ 20 /* f_type of struct statfs will be set at this value by statfs(2) */ #define REISERFS_SUPER_MAGIC 0x52654973 /* various reiserfs signatures. We have 2 so far. ReIsErFs for the system which is not able to deal with long files and ReIsEr2Fs for another. Those signature should be looked for at the 64-th and at the 8-th 1k block of the device */ #define REISERFS_SUPER_MAGIC_STRING "ReIsErFs" #define REISER2FS_SUPER_MAGIC_STRING "ReIsEr2Fs" /* values for s_version field of struct reiserfs_super_block */ #define REISERFS_VERSION_1 0 /* old (short) super block, all keys in old format */ #define REISERFS_VERSION_2 2 /* new super block, keys may be in new format */ /* * values for s_state field */ #define REISERFS_VALID_FS 1 #define REISERFS_ERROR_FS 2 /***************************************************************************/ /* JOURNAL */ /***************************************************************************/ #define JOURNAL_DESC_MAGIC "ReIsErLB" /* ick. magic string to find desc blocks in the journal */ #define JOURNAL_TRANS_MAX 1024 /* biggest possible single transaction, don't change for now (8/3/99) */ /* journal.c see journal.c for all the comments here */ #define JOURNAL_TRANS_HALF 1018 /* must be correct to keep the desc and commit structs at 4k */ /* first block written in a commit. BUG, not 64bit safe */ struct reiserfs_journal_desc { __u32 j_trans_id ; /* id of commit */ __u32 j_len ; /* length of commit. len +1 is the commit block */ __u32 j_mount_id ; /* mount id of this trans*/ __u32 j_realblock[JOURNAL_TRANS_HALF] ; /* real locations for each block */ char j_magic[12] ; } ; /* last block written in a commit BUG, not 64bit safe */ struct reiserfs_journal_commit { __u32 j_trans_id ; /* must match j_trans_id from the desc block */ __u32 j_len ; /* ditto */ __u32 j_realblock[JOURNAL_TRANS_HALF] ; /* real locations for each block */ char j_digest[16] ; /* md5 sum of all the blocks involved, including desc and commit. not used, kill it */ } ; /* this header block gets written whenever a transaction is considered fully flushed, and is more recent than the ** last fully flushed transaction. fully flushed means all the log blocks and all the real blocks are on disk, ** and this transaction does not need to be replayed. */ struct reiserfs_journal_header { __u32 j_last_flush_trans_id ; /* id of last fully flushed transaction */ __u32 j_first_unflushed_offset ; /* offset in the log of where to start replay after a crash */ __u32 j_mount_id ; } ; #define JOURNAL_BLOCK_COUNT 8192 /* number of blocks in the journal */ #define bh_desc(bh) ((struct reiserfs_journal_desc *)((bh)->b_data)) #define bh_commit(bh) ((struct reiserfs_journal_commit *)((bh)->b_data)) /***************************************************************************/ /* KEY & ITEM HEAD */ /***************************************************************************/ struct offset_v1 { __u32 k_offset; __u32 k_uniqueness; } __attribute__ ((__packed__)); struct offset_v2 { __u64 k_offset:60; __u64 k_type: 4; // TYPE_STAT_DATA | TYPE_INDIRECT | TYPE_DIRECT | TYPE_DIRENTRY } __attribute__ ((__packed__)); /* Key of the object drop determines its location in the S+tree, and is composed of 4 components */ struct key { __u32 k_dir_id; /* packing locality: by default parent directory object id */ __u32 k_objectid; /* object identifier */ union { struct offset_v1 k_offset_v1; struct offset_v2 k_offset_v2; } u; } __attribute__ ((__packed__)); #define key_dir_id(key) (le32_to_cpu((key)->k_dir_id)) #define set_key_dir_id(key,n) ((key)->k_dir_id = cpu_to_le32((n))) #define key_objectid(key) (le32_to_cpu((key)->k_objectid)) #define set_key_objectid(key,n) ((key)->k_objectid = cpu_to_le32((n))) #define KEY_SIZE (sizeof(struct key)) #define SHORT_KEY_SIZE 8 // values for k_uniqueness field of the struct key #define V1_SD_UNIQUENESS 0 #define V1_DIRENTRY_UNIQUENESS 500 #define DIRENTRY_UNIQUENESS 500 #define V1_DIRECT_UNIQUENESS 0xffffffff #define V1_INDIRECT_UNIQUENESS 0xfffffffe #define V1_UNKNOWN_UNIQUENESS 555 // values for k_type field of the struct key #define TYPE_STAT_DATA 0 #define TYPE_INDIRECT 1 #define TYPE_DIRECT 2 #define TYPE_DIRENTRY 3 #define TYPE_UNKNOWN 15 #define KEY_FORMAT_1 0 #define KEY_FORMAT_2 1 /* Our function for comparing keys can compare keys of different lengths. It takes as a parameter the length of the keys it is to compare. These defines are used in determining what is to be passed to it as that parameter. */ #define REISERFS_FULL_KEY_LEN 4 #define REISERFS_SHORT_KEY_LEN 2 /* Everything in the filesystem is stored as a set of items. The item head contains the key of the item, its free space (for indirect items) and specifies the location of the item itself within the block. */ struct item_head { struct key ih_key; /* Everything in the tree is found by searching for it based on its key.*/ union { __u16 ih_free_space1; /* The free space in the last unformatted node of an indirect item if this is an indirect item. This equals 0xFFFF iff this is a direct item or stat data item. Note that the key, not this field, is used to determine the item type, and thus which field this union contains. */ __u16 ih_entry_count; /* Iff this is a directory item, this field equals the number of directory entries in the directory item. */ } u; __u16 ih_item_len; /* total size of the item body */ __u16 ih_item_location; /* an offset to the item body within the block */ struct { __u16 key_format : 12; /* KEY_FORMAT_1 or KEY_FORMAT_2. This is not necessary, but we have space, let use it */ __u16 fsck_need : 4; /* fsck set here its flag (reachable/unreachable) */ } ih_format; } __attribute__ ((__packed__)); /* size of item header */ #define IH_SIZE (sizeof(struct item_head)) #define ih_item_len(ih) (le16_to_cpu((ih)->ih_item_len)) #define set_ih_item_len(ih,x) ((ih)->ih_item_len = cpu_to_le16 (x)) #define ih_location(ih) (le16_to_cpu ((ih)->ih_item_location)) #define set_ih_location(ih,x) ((ih)->ih_item_location = cpu_to_le16 (x)) #define ih_key_format(ih) (le16_to_cpu ((ih)->ih_format.key_format)) #define set_key_format(ih,x) ((ih)->ih_format.key_format = cpu_to_le16 (x)) // FIXME: ih_free_space does not appear to be very important, but we // have to make sure that earlier version have no trouble when // ih_free_space is 0 #define ih_free_space(ih) 0 // le16_to_cpu (ih->u.ih_free_space) #define set_free_space(ih,val) ((ih)->u.ih_free_space1 = 0)//val) //#define get_ih_free_space(ih) 0 //(ih_key_format (ih) == KEY_FORMAT ? 0 : ih_free_space (ih)) //#define set_ih_free_space(ih,val) // (ih_free_space (ih) = (ih_version (ih) == ITEM_VERSION_2 ? 0 : val)) #define ih_entry_count(ih) (le16_to_cpu ((ih)->u.ih_entry_count)) //#define set_ih_free_space(ih,x) ((ih)->u.ih_free_space = cpu_to_le16(x)) #define set_entry_count(ih,x) ((ih)->u.ih_entry_count = cpu_to_le16(x)) #define I_K_KEY_IN_ITEM(p_s_ih, p_s_key, n_blocksize) \ ( ! not_of_one_file(p_s_ih, p_s_key) && \ I_OFF_BYTE_IN_ITEM(p_s_ih, get_offset (p_s_key), n_blocksize) ) #define IH_Bad 0 #define IH_Unreachable 1 /* Bad item flag is set temporary by recover_leaf */ #define mark_ih_bad(ih) ((ih)->ih_format.fsck_need |= IH_Bad) #define ih_bad(ih) test_bit (IH_Bad, &((ih)->ih_format.fsck_need)) #define unmark_item_bad(ih) clear_bit (IH_Bad, &((ih)->ih_format.fsck_need)) /* Unreachable bit is set on tree rebuilding and is cleared in semantic pass */ #define mark_ih_ok(ih) ((ih)->ih_format.fsck_need = 0) #define ih_reachable(ih) (!(ih)->ih_format.fsck_need & IH_Unreachable) #define mark_ih_unreachable(ih) ((ih)->ih_format.fsck_need |= IH_Unreachable) /* maximal length of item */ #define MAX_ITEM_LEN(block_size) (block_size - BLKH_SIZE - IH_SIZE) #define MIN_ITEM_LEN 1 /* object identifier for root dir */ #define REISERFS_ROOT_OBJECTID 2 #define REISERFS_ROOT_PARENT_OBJECTID 1 /*extern struct key root_key;*/ /* * Picture represents a leaf of the S+tree * ______________________________________________________ * | | Array of | | | * |Block | Object-Item | F r e e | Objects- | * | head | Headers | S p a c e | Items | * |______|_______________|___________________|___________| */ /* Header of a disk block. More precisely, header of a formatted leaf or internal node, and not the header of an unformatted node. */ struct block_head { __u16 blk_level; /* Level of a block in the tree. */ __u16 blk_nr_item; /* Number of keys/items in a block. */ __u16 blk_free_space; /* Block free space in bytes. */ __u16 blk_reserved; struct key not_used; /* Right delimiting key for this block (supported for leaf level nodes only) */ }; #define BLKH_SIZE (sizeof(struct block_head)) /* * values for blk_type field */ #define FREE_LEVEL 0 /* Node of this level is out of the tree. */ #define DISK_LEAF_NODE_LEVEL 1 /* Leaf node level. */ #define is_leaf_block_head(buf) (le16_to_cpu (((struct block_head *)(buf))->blk_level) == DISK_LEAF_NODE_LEVEL) #define is_internal_block_head(buf) \ ((le16_to_cpu (((struct block_head *)(buf))->blk_level) > DISK_LEAF_NODE_LEVEL) &&\ (le16_to_cpu (((struct block_head *)(buf))->blk_level) <= MAX_HEIGHT)) /* Given the buffer head of a formatted node, resolve to the block head of that node. */ #define B_BLK_HEAD(p_s_bh) ((struct block_head *)((p_s_bh)->b_data)) /* Number of items that are in buffer. */ #define node_item_number(bh) (le16_to_cpu ( B_BLK_HEAD(bh)->blk_nr_item )) #define node_pointer_number(bh) (node_item_number(bh) + 1) #define node_level(bh) (le16_to_cpu ( B_BLK_HEAD(bh)->blk_level )) #define node_free_space(bh) (le16_to_cpu ( B_BLK_HEAD(bh)->blk_free_space )) #define set_node_item_number(bh,n) (B_BLK_HEAD(bh)->blk_nr_item = cpu_to_le16 (n)) #define set_node_free_space(bh,n) (B_BLK_HEAD(bh)->blk_free_space = cpu_to_le16 (n)) #define set_node_level(bh,n) (B_BLK_HEAD(bh)->blk_level = cpu_to_le16 (n)) #define set_leaf_node_level(bh) set_node_level (bh, DISK_LEAF_NODE_LEVEL) #define B_NR_ITEMS(bh) node_item_number(bh) #define B_LEVEL(bh) node_level(bh) #define B_FREE_SPACE(bh) node_free_space(bh) #define is_leaf_node(bh) is_leaf_block_head ((bh)->b_data) #define is_internal_node(bh) is_internal_block_head ((bh)->b_data) /***************************************************************************/ /* STAT DATA */ /***************************************************************************/ /* Stat Data on disk (reiserfs version of UFS disk inode minus the address blocks) */ /* The sense of adding union to stat data is to keep a value of real number of blocks used by file. The necessity of adding such information is caused by existing of files with holes. Reiserfs should keep number of used blocks for file, but not calculate it from file size (that is not correct for holed files). Thus we have to add additional information to stat data. When we have a device special file, there is no need to get number of used blocks for them, and, accordingly, we doesn't need to keep major and minor numbers for regular files, which might have holes. So this field is being overloaded. */ struct stat_data_v1 { __u16 sd_mode; /* file type, permissions */ __u16 sd_nlink; /* number of hard links */ __u16 sd_uid; /* owner */ __u16 sd_gid; /* group */ __u32 sd_size; /* file size */ __u32 sd_atime; /* time of last access */ __u32 sd_mtime; /* time file was last modified */ __u32 sd_ctime; /* time inode (stat data) was last changed (except changes to sd_atime and sd_mtime) */ union { __u32 sd_rdev; __u32 sd_blocks; /* number of blocks file uses */ } u; __u32 sd_first_direct_byte; /* first byte of file which is stored in a direct item: except that if it equals 1 it is a symlink and if it equals MAX_KEY_OFFSET there is no direct item. The existence of this field really grates on me. Let's replace it with a macro based on sd_size and our tail suppression policy. Someday. -Hans */ } __attribute__ ((__packed__)); #define SD_V1_SIZE (sizeof(struct stat_data_v1)) /* this is used to check sd_size of stat data v1 */ #define MAX_FILE_SIZE_V1 0x7fffffff // sd_first_direct_byte is set to this when there are no direct items in a // file #define NO_BYTES_IN_DIRECT_ITEM 0xffffffff /* Stat Data on disk (reiserfs version of UFS disk inode minus the address blocks) */ struct stat_data { __u16 sd_mode; /* file type, permissions */ __u16 sd_reserved; __u32 sd_nlink; /* 32 bit nlink! */ __u64 sd_size; /* 64 bit size!*/ __u32 sd_uid; /* 32 bit uid! */ __u32 sd_gid; /* 32 bit gid! */ __u32 sd_atime; /* time of last access */ __u32 sd_mtime; /* time file was last modified */ __u32 sd_ctime; /* time inode (stat data) was last changed (except changes to sd_atime and sd_mtime) */ __u32 sd_blocks; union { __u32 sd_rdev; //__u32 sd_first_direct_byte; /* first byte of file which is stored in a direct item: except that if it equals 1 it is a symlink and if it equals ~(__u32)0 there is no direct item. The existence of this field really grates on me. Let's replace it with a macro based on sd_size and our tail suppression policy? */ } u; } __attribute__ ((__packed__)); // // this is 44 bytes long // #define SD_SIZE (sizeof(struct stat_data)) // there are two ways: to check length of item or ih_version field // (for old stat data it is set to 0 (KEY_FORMAT_1)) #define stat_data_v1(ih) (ih_key_format (ih) == KEY_FORMAT_1) /* this is used to check sd_size of stat data v2: max offset which can be reached with a key of format 2 is 60 bits */ #define MAX_FILE_SIZE_V2 0xfffffffffffffffLL /***************************************************************************/ /* DIRECTORY STRUCTURE */ /***************************************************************************/ /* Picture represents the structure of directory items ________________________________________________ | Array of | | | | | | | directory |N-1| N-2 | .... | 1st |0th| | entry headers | | | | | | |_______________|___|_____|________|_______|___| <---- directory entries ------> First directory item has k_offset component 1. We store "." and ".." in one item, always, we never split "." and ".." into differing items. This makes, among other things, the code for removing directories simpler. */ #define SD_OFFSET 0 #define DOT_OFFSET 1 #define DOT_DOT_OFFSET 2 /* */ #define FIRST_ITEM_OFFSET 1 /* Q: How to get key of object pointed to by entry from entry? A: Each directory entry has its header. This header has deh_dir_id and deh_objectid fields, those are key of object, entry points to */ /* NOT IMPLEMENTED: Directory will someday contain stat data of object */ struct reiserfs_de_head { __u32 deh_offset; /* third component of the directory entry key */ __u32 deh_dir_id; /* objectid of the parent directory of the object, that is referenced by directory entry */ __u32 deh_objectid;/* objectid of the object, that is referenced by directory entry */ __u16 deh_location;/* offset of name in the whole item */ __u16 deh_state; /* whether 1) entry contains stat data (for future), and 2) whether entry is hidden (unlinked) */ } __attribute__ ((__packed__)); #define DEH_SIZE sizeof(struct reiserfs_de_head) #define deh_offset(deh) (le32_to_cpu ((deh)->deh_offset)) #define deh_dir_id(deh) (le32_to_cpu ((deh)->deh_dir_id)) #define deh_objectid(deh) (le32_to_cpu ((deh)->deh_objectid)) #define deh_location(deh) (le16_to_cpu ((deh)->deh_location)) #define deh_state(deh) (le16_to_cpu ((deh)->deh_state)) /* empty directory contains two entries "." and ".." and their headers */ #define EMPTY_DIR_SIZE \ (DEH_SIZE * 2 + ROUND_UP (strlen (".")) + ROUND_UP (strlen (".."))) /* old format directories have this size when empty */ #define EMPTY_DIR_SIZE_V1 (DEH_SIZE * 2 + 3) #define DEH_Statdata 0 /* not used now */ #define DEH_Visible 2 #define DEH_Bad_offset 4 /* fsck marks entries to be deleted with this flag */ #define DEH_Bad_location 5 #define mark_de_with_sd(deh) set_bit (DEH_Statdata, &((deh)->deh_state)) #define mark_de_without_sd(deh) clear_bit (DEH_Statdata, &((deh)->deh_state)) #define mark_de_visible(deh) set_bit (DEH_Visible, &((deh)->deh_state)) #define mark_de_hidden(deh) clear_bit (DEH_Visible, &((deh)->deh_state)) #define mark_de_lost_found(deh) set_bit (DEH_Lost_Found, &((deh)->deh_state)) #define unmark_de_lost_found(deh) clear_bit (DEH_Lost_Found, &((deh)->deh_state)) #define de_with_sd(deh) test_bit (DEH_Statdata, &((deh)->deh_state)) #define de_visible(deh) test_bit (DEH_Visible, &((deh)->deh_state)) #define de_hidden(deh) !test_bit (DEH_Visible, &((deh)->deh_state)) /* Bad means "hashed unproperly or/and invalid location" */ #define de_bad_location(deh) test_bit (DEH_Bad_location, &((deh)->deh_state)) #define mark_de_bad_location(deh) set_bit (DEH_Bad_location, &((deh)->deh_state)) #define mark_de_good_location(deh) clear_bit (DEH_Bad_location, &((deh)->deh_state)) #define de_bad_offset(deh) test_bit (DEH_Bad_offset, &((deh)->deh_state)) #define mark_de_bad_offset(deh) set_bit (DEH_Bad_offset, &((deh)->deh_state)) #define de_bad(deh) (de_bad_location(deh) || de_bad_offset(deh)) /* for directories st_blocks is number of 512 byte units which fit into dir size round up to blocksize */ #define dir_size2st_blocks(blocksize,size) \ ((((size) + (blocksize) - 1) / (blocksize)) * ((blocksize) / 512)) /* array of the entry headers */ #define B_I_DEH(bh,ih) ((struct reiserfs_de_head *)(B_I_PITEM(bh,ih))) #define REISERFS_MAX_NAME_LEN(block_size) (block_size - BLKH_SIZE - IH_SIZE - DEH_SIZE) /* -SD_SIZE when entry will contain stat data */ /* this structure is used for operations on directory entries. It is not a disk structure. */ /* When reiserfs_find_entry or search_by_entry_key find directory entry, they return filled reiserfs_dir_entry structure */ struct reiserfs_dir_entry { struct buffer_head * de_bh; int de_item_num; struct item_head * de_ih; int de_entry_num; struct reiserfs_de_head * de_deh; int de_entrylen; int de_namelen; char * de_name; char * de_gen_number_bit_string; __u32 de_dir_id; __u32 de_objectid; struct key de_entry_key; }; /* hash value occupies 24 bits starting from 7 up to 30 */ #define GET_HASH_VALUE(offset) ((offset) & 0x7fffff80) /* generation number occupies 7 bits starting from 0 up to 6 */ #define GET_GENERATION_NUMBER(offset) ((offset) & 0x0000007f) /* * Picture represents an internal node of the reiserfs tree * ______________________________________________________ * | | Array of | Array of | Free | * |block | keys | pointers | space | * | head | N | N+1 | | * |______|_______________|___________________|___________| */ /***************************************************************************/ /* DISK CHILD */ /***************************************************************************/ /* Disk child pointer: The pointer from an internal node of the tree to a node that is on disk. */ struct disk_child { __u32 dc_block_number; /* Disk child's block number. */ __u16 dc_size; /* Disk child's used space. */ __u16 dc_reserved; }; #define DC_SIZE (sizeof(struct disk_child)) /* Get disk child by buffer header and position in the tree node. */ #define B_N_CHILD(p_s_bh,n_pos) ((struct disk_child *)\ ((p_s_bh)->b_data + BLKH_SIZE + B_NR_ITEMS(p_s_bh) \ * KEY_SIZE + DC_SIZE * (n_pos))) /* Get disk child number by buffer header and position in the tree node. */ #define B_N_CHILD_NUM(p_s_bh,n_pos) (B_N_CHILD(p_s_bh,n_pos)->dc_block_number) #define child_block_number(bh,pos) le32_to_cpu (B_N_CHILD(bh,pos)->dc_block_number) #define child_block_size(bh,pos) le16_to_cpu (B_N_CHILD(bh,pos)->dc_size) #define set_dc_block_number(bh,pos,block) (B_N_CHILD (bh, pos)->dc_block_number = cpu_to_le32 (block)) /* maximal value of field child_size in structure disk_child */ /* child size is the combined size of all items and their headers */ #define MAX_CHILD_SIZE(bh) ((int)( (bh)->b_size - BLKH_SIZE )) /* amount of used space in buffer (not including block head) */ #define B_CHILD_SIZE(cur) (MAX_CHILD_SIZE(cur)-(B_FREE_SPACE(cur))) /* max and min number of keys in internal node */ #define MAX_NR_KEY(bh) ( (MAX_CHILD_SIZE(bh)-DC_SIZE)/(KEY_SIZE+DC_SIZE) ) #define MIN_NR_KEY(bh) (MAX_NR_KEY(bh)/2) /***************************************************************************/ /* PATH STRUCTURES AND DEFINES */ /***************************************************************************/ /* Search_by_key fills up the path from the root to the leaf as it descends the tree looking for the key. It uses reiserfs_bread to try to find buffers in the cache given their block number. If it does not find them in the cache it reads them from disk. For each node search_by_key finds using reiserfs_bread it then uses bin_search to look through that node. bin_search will find the position of the block_number of the next node if it is looking through an internal node. If it is looking through a leaf node bin_search will find the position of the item which has key either equal to given key, or which is the maximal key less than the given key. */ struct path_element { struct buffer_head * pe_buffer; /* Pointer to the buffer at the path in the tree. */ int pe_position; /* Position in the tree node which is placed in the buffer above. */ }; #define MAX_HEIGHT 5 /* maximal height of a tree. don't change this without changing JOURNAL_PER_BALANCE_CNT */ #define EXTENDED_MAX_HEIGHT 7 /* Must be equals MAX_HEIGHT + FIRST_PATH_ELEMENT_OFFSET */ #define FIRST_PATH_ELEMENT_OFFSET 2 /* Must be equal to at least 2. */ #define ILLEGAL_PATH_ELEMENT_OFFSET 1 /* Must be equal to FIRST_PATH_ELEMENT_OFFSET - 1 */ #define MAX_FEB_SIZE 6 /* this MUST be MAX_HEIGHT + 1. See about FEB below */ /* We need to keep track of who the ancestors of nodes are. When we perform a search we record which nodes were visited while descending the tree looking for the node we searched for. This list of nodes is called the path. This information is used while performing balancing. Note that this path information may become invalid, and this means we must check it when using it to see if it is still valid. You'll need to read search_by_key and the comments in it, especially about decrement_counters_in_path(), to understand this structure. */ struct path { int path_length; /* Length of the array above. */ struct path_element path_elements[EXTENDED_MAX_HEIGHT]; /* Array of the path elements. */ int pos_in_item; }; #define INITIALIZE_PATH(var) \ struct path var = {ILLEGAL_PATH_ELEMENT_OFFSET, } /* Get path element by path and path position. */ #define PATH_OFFSET_PELEMENT(p_s_path,n_offset) ((p_s_path)->path_elements +(n_offset)) /* Get buffer header at the path by path and path position. */ #define PATH_OFFSET_PBUFFER(p_s_path,n_offset) (PATH_OFFSET_PELEMENT(p_s_path,n_offset)->pe_buffer) /* Get position in the element at the path by path and path position. */ #define PATH_OFFSET_POSITION(p_s_path,n_offset) (PATH_OFFSET_PELEMENT(p_s_path,n_offset)->pe_position) #define PATH_PLAST_BUFFER(p_s_path) (PATH_OFFSET_PBUFFER((p_s_path), (p_s_path)->path_length)) #define PATH_LAST_POSITION(p_s_path) (PATH_OFFSET_POSITION((p_s_path), (p_s_path)->path_length)) #define PATH_PITEM_HEAD(p_s_path) B_N_PITEM_HEAD(PATH_PLAST_BUFFER(p_s_path),PATH_LAST_POSITION(p_s_path)) /* in do_balance leaf has h == 0 in contrast with path structure, where root has level == 0. That is why we need these defines */ #define PATH_H_PBUFFER(p_s_path, h) PATH_OFFSET_PBUFFER (p_s_path, p_s_path->path_length - (h)) /* tb->S[h] */ #define PATH_H_PPARENT(path, h) PATH_H_PBUFFER (path, (h) + 1) /* tb->F[h] or tb->S[0]->b_parent */ #define PATH_H_POSITION(path, h) PATH_OFFSET_POSITION (path, path->path_length - (h)) #define PATH_H_B_ITEM_ORDER(path, h) PATH_H_POSITION(path, h + 1) /* tb->S[h]->b_item_order */ #define PATH_H_PATH_OFFSET(p_s_path, n_h) ((p_s_path)->path_length - (n_h)) #define get_bh(path) PATH_PLAST_BUFFER(path) #define get_ih(path) PATH_PITEM_HEAD(path) #define get_item_pos(path) PATH_LAST_POSITION(path) #define get_item(path) ((void *)B_N_PITEM(PATH_PLAST_BUFFER(path), PATH_LAST_POSITION (path))) #define item_moved(ih,path) comp_items(ih, path) #define path_changed(ih,path) comp_items (ih, path) /***************************************************************************/ /* MISC */ /***************************************************************************/ // search_by_key (and clones) and fix_nodes error code #define CARRY_ON 0 #define SCHEDULE_OCCURRED 1 #define PATH_INCORRECT 2 #define IO_ERROR 3 #define NO_DISK_SPACE 4 #define NO_BALANCING_NEEDED 5 #define ITEM_FOUND 6 #define ITEM_NOT_FOUND 7 #define POSITION_FOUND 8 #define POSITION_NOT_FOUND 9 #define GOTO_PREVIOUS_ITEM 10 #define POSITION_FOUND_INVISIBLE 11 #define FILE_NOT_FOUND 12 // used by fsck #define DIRECTORY_NOT_FOUND 13 #define REGULAR_FILE_FOUND 14 #define DIRECTORY_FOUND 15 typedef unsigned long b_blocknr_t; typedef __u32 unp_t; struct unfm_nodeinfo { __u32 unfm_nodenum; unsigned short unfm_freespace; }; /* when reiserfs_file_write is called with a byte count >= MIN_PACK_ON_CLOSE, ** it sets the inode to pack on close, and when extending the file, will only ** use unformatted nodes. ** ** This is a big speed up for the journal, which is badly hurt by direct->indirect ** conversions (they must be logged). */ #define MIN_PACK_ON_CLOSE 512 /* This is an aggressive tail suppression policy, I am hoping it improves our benchmarks. The principle behind it is that percentage space saving is what matters, not absolute space saving. This is non-intuitive, but it helps to understand it if you consider that the cost to access 4 blocks is not much more than the cost to access 1 block, if you have to do a seek and rotate. A tail risks a non-linear disk access that is significant as a percentage of total time cost for a 4 block file and saves an amount of space that is less significant as a percentage of space, or so goes the hypothesis. -Hans */ #define STORE_TAIL_IN_UNFM(n_file_size,n_tail_size,n_block_size) \ \ ( ((n_tail_size) > MAX_DIRECT_ITEM_LEN(n_block_size)) || \ ( (n_file_size) >= (n_block_size) * 4 ) || \ ( ( (n_file_size) >= (n_block_size) * 3 ) && \ ( (n_tail_size) >= (MAX_DIRECT_ITEM_LEN(n_block_size))/4) ) || \ ( ( (n_file_size) >= (n_block_size) * 2 ) && \ ( (n_tail_size) >= (MAX_DIRECT_ITEM_LEN(n_block_size))/2) ) || \ ( ( (n_file_size) >= (n_block_size) ) && \ ( (n_tail_size) >= (MAX_DIRECT_ITEM_LEN(n_block_size) * 3)/4) ) ) #define first_direct_byte(inode) ((inode)->u.reiserfs_i.i_first_direct_byte) #define has_tail(inode) (first_direct_byte(inode) != NO_BYTES_IN_DIRECT_ITEM) #define tail_offset(inode) (first_direct_byte(inode) - 1) // mark file as not having tail stored in direct item #define file_has_no_tail(inode) (first_direct_byte (inode) = NO_BYTES_IN_DIRECT_ITEM) #define block_size(inode) ((inode)->i_sb->s_blocksize) #define file_size(inode) ((inode)->i_size) #define tail_size(inode) (file_size (inode) & (block_size (inode) - 1)) #define tail_has_to_be_packed(inode) (!dont_have_tails ((inode)->i_sb) &&\ !STORE_TAIL_IN_UNFM(file_size (inode), tail_size(inode), block_size (inode))) /* Size of pointer to the unformatted node. */ #define UNFM_P_SIZE (sizeof(__u32)) #define INODE_PKEY(inode) ((struct key *)((inode)->u.reiserfs_i.i_key)) #define inode_key_format(inode) ((inode)->u.reiserfs_i.i_key_format) //#define MAX_UL_INT ULONG_MAX //#define MAX_INT INT_MAX //#define MAX_US_INT USHRT_MAX #define MAX_KEY1_OFFSET INT_MAX #define MAX_KEY2_OFFSET 0xfffffffffffffffLL #define MAX_KEY_UNIQUENESS UINT_MAX #define MAX_KEY_OBJECTID UINT_MAX #define MAX_B_NUM UINT_MAX #define MAX_FC_NUM USHRT_MAX /* the purpose is to detect overflow of an unsigned short */ #define REISERFS_LINK_MAX (USHRT_MAX - 1000) /* The following defines are used in reiserfs_insert_item and reiserfs_append_item */ #define REISERFS_KERNEL_MEM 0 /* reiserfs kernel memory mode */ #define REISERFS_USER_MEM 1 /* reiserfs user memory mode */ /***************************************************************************/ /* FIXATE NODES */ /***************************************************************************/ #define VI_TYPE_STAT_DATA 1 #define VI_TYPE_DIRECT 2 #define VI_TYPE_INDIRECT 4 #define VI_TYPE_DIRECTORY 8 #define VI_TYPE_FIRST_DIRECTORY_ITEM 16 #define VI_TYPE_INSERTED_DIRECTORY_ITEM 32 #define VI_TYPE_LEFT_MERGEABLE 64 #define VI_TYPE_RIGHT_MERGEABLE 128 /* To make any changes in the tree we always first find node, that contains item to be changed/deleted or place to insert a new item. We call this node S. To do balancing we need to decide what we will shift to left/right neighbor, or to a new node, where new item will be etc. To make this analysis simpler we build virtual node. Virtual node is an array of items, that will replace items of node S. (For instance if we are going to delete an item, virtual node does not contain it). Virtual node keeps information about item sizes and types, mergeability of first and last items, sizes of all entries in directory item. We use this array of items when calculating what we can shift to neighbors and how many nodes we have to have if we do not any shiftings, if we shift to left/right neighbor or to both. */ struct virtual_item { unsigned short vi_type; /* item type, mergeability */ unsigned short vi_item_len; /* length of item that it will have after balancing */ short vi_entry_count; /* number of entries in directory item (including the new one if any, or excluding entry if it must be cut) */ unsigned short * vi_entry_sizes; /* array of entry lengths for directory item */ }; struct virtual_node { char * vn_free_ptr; /* this is a pointer to the free space in the buffer */ unsigned short vn_nr_item; /* number of items in virtual node */ short vn_size; /* size of node , that node would have if it has unlimited size and no balancing is performed */ short vn_mode; /* mode of balancing (paste, insert, delete, cut) */ short vn_affected_item_num; short vn_pos_in_item; struct item_head * vn_ins_ih; /* item header of inserted item, 0 for other modes */ struct virtual_item * vn_vi; /* array of items (including a new one, excluding item to be deleted) */ }; /***************************************************************************/ /* TREE BALANCE */ /***************************************************************************/ /* This temporary structure is used in tree balance algorithms, and constructed as we go to the extent that its various parts are needed. It contains arrays of nodes that can potentially be involved in the balancing of node S, and parameters that define how each of the nodes must be balanced. Note that in these algorithms for balancing the worst case is to need to balance the current node S and the left and right neighbors and all of their parents plus create a new node. We implement S1 balancing for the leaf nodes and S0 balancing for the internal nodes (S1 and S0 are defined in our papers.)*/ #define MAX_FREE_BLOCK 7 /* size of the array of buffers to free at end of do_balance */ /* maximum number of FEB blocknrs on a single level */ #define MAX_AMOUNT_NEEDED 2 /* someday somebody will prefix every field in this struct with tb_ */ struct tree_balance { struct reiserfs_transaction_handle *transaction_handle ; struct super_block * tb_sb; struct path * tb_path; struct buffer_head * L[MAX_HEIGHT]; /* array of left neighbors of nodes in the path */ struct buffer_head * R[MAX_HEIGHT]; /* array of right neighbors of nodes in the path*/ struct buffer_head * FL[MAX_HEIGHT]; /* array of fathers of the left neighbors */ struct buffer_head * FR[MAX_HEIGHT]; /* array of fathers of the right neighbors */ struct buffer_head * CFL[MAX_HEIGHT]; /* array of common parents of center node and its left neighbor */ struct buffer_head * CFR[MAX_HEIGHT]; /* array of common parents of center node and its right neighbor */ /* array of blocknr's that are free and are the nearest to the left node that are usable for writing dirty formatted leaves, using the write_next_to algorithm. */ /*unsigned long free_and_near[MAX_DIRTIABLE];*/ struct buffer_head * FEB[MAX_FEB_SIZE]; /* array of empty buffers. Number of buffers in array equals cur_blknum. */ struct buffer_head * used[MAX_FEB_SIZE]; short int lnum[MAX_HEIGHT]; /* array of number of items which must be shifted to the left in order to balance the current node; for leaves includes item that will be partially shifted; for internal nodes, it is the number of child pointers rather than items. It includes the new item being created. For preserve_shifted() purposes the code sometimes subtracts one from this number to get the number of currently existing items being shifted, and even more often for leaves it subtracts one to get the number of wholly shifted items for other purposes. */ short int rnum[MAX_HEIGHT]; /* substitute right for left in comment above */ short int lkey[MAX_HEIGHT]; /* array indexed by height h mapping the key delimiting L[h] and S[h] to its item number within the node CFL[h] */ short int rkey[MAX_HEIGHT]; /* substitute r for l in comment above */ short int insert_size[MAX_HEIGHT]; /* the number of bytes by we are trying to add or remove from S[h]. A negative value means removing. */ short int blknum[MAX_HEIGHT]; /* number of nodes that will replace node S[h] after balancing on the level h of the tree. If 0 then S is being deleted, if 1 then S is remaining and no new nodes are being created, if 2 or 3 then 1 or 2 new nodes is being created */ /* fields that are used only for balancing leaves of the tree */ short int cur_blknum; /* number of empty blocks having been already allocated */ short int s0num; /* number of items that fall into left most node when S[0] splits */ short int s1num; /* number of items that fall into first new node when S[0] splits */ short int s2num; /* number of items that fall into second new node when S[0] splits */ short int lbytes; /* number of bytes which can flow to the left neighbor from the left */ /* most liquid item that cannot be shifted from S[0] entirely */ /* if -1 then nothing will be partially shifted */ short int rbytes; /* number of bytes which will flow to the right neighbor from the right */ /* most liquid item that cannot be shifted from S[0] entirely */ /* if -1 then nothing will be partially shifted */ short int s1bytes; /* number of bytes which flow to the first new node when S[0] splits */ /* note: if S[0] splits into 3 nodes, then items do not need to be cut */ short int s2bytes; struct buffer_head * buf_to_free[MAX_FREE_BLOCK]; /* buffers which are to be freed after do_balance finishes by unfix_nodes */ char * vn_buf; /* kmalloced memory. Used to create virtual node and keep map of dirtied bitmap blocks */ int vn_buf_size; /* size of the vn_buf */ struct virtual_node * tb_vn; /* VN starts after bitmap of bitmap blocks */ } ; /* These are modes of balancing */ /* When inserting an item. */ #define M_INSERT 'i' /* When inserting into (directories only) or appending onto an already existant item. */ #define M_PASTE 'p' /* When deleting an item. */ #define M_DELETE 'd' /* When truncating an item or removing an entry from a (directory) item. */ #define M_CUT 'c' /* used when balancing on leaf level skipped (in reiserfsck) */ #define M_INTERNAL 'n' /* When further balancing is not needed, then do_balance does not need to be called. */ #define M_SKIP_BALANCING 's' #define M_CONVERT 'v' /* modes of leaf_move_items */ #define LEAF_FROM_S_TO_L 0 #define LEAF_FROM_S_TO_R 1 #define LEAF_FROM_R_TO_L 2 #define LEAF_FROM_L_TO_R 3 #define LEAF_FROM_S_TO_SNEW 4 #define FIRST_TO_LAST 0 #define LAST_TO_FIRST 1 /* used in do_balance for passing parent of node information that has been gotten from tb struct */ struct buffer_info { struct buffer_head * bi_bh; struct buffer_head * bi_parent; int bi_position; }; /* there are 4 types of items: stat data, directory item, indirect, direct. FIXME: This table does not describe new key format +-------------------+------------+--------------+------------+ | | k_offset | k_uniqueness | mergeable? | +-------------------+------------+--------------+------------+ | stat data | 0 | 0 | no | +-------------------+------------+--------------+------------+ | 1st directory item| DOT_OFFSET |DIRENTRY_UNIQUENESS| no | | non 1st directory | hash value | | yes | | item | | | | +-------------------+------------+--------------+------------+ | indirect item | offset + 1 |TYPE_INDIRECT | if this is not the first indirect item of the object +-------------------+------------+--------------+------------+ | direct item | offset + 1 |TYPE_DIRECT | if not this is not the first direct item of the object +-------------------+------------+--------------+------------+ */ #define KEY_IS_STAT_DATA_KEY(p_s_key) ( get_type (p_s_key) == TYPE_STAT_DATA ) #define KEY_IS_DIRECTORY_KEY(p_s_key) ( get_type (p_s_key) == TYPE_DIRENTRY ) #define KEY_IS_DIRECT_KEY(p_s_key) ( get_type (p_s_key) == TYPE_DIRECT ) #define KEY_IS_INDIRECT_KEY(p_s_key) ( get_type (p_s_key) == TYPE_INDIRECT ) #define I_IS_STAT_DATA_ITEM(p_s_ih) KEY_IS_STAT_DATA_KEY(&((p_s_ih)->ih_key)) #define I_IS_DIRECTORY_ITEM(p_s_ih) KEY_IS_DIRECTORY_KEY(&((p_s_ih)->ih_key)) #define I_IS_DIRECT_ITEM(p_s_ih) KEY_IS_DIRECT_KEY(&((p_s_ih)->ih_key)) #define I_IS_INDIRECT_ITEM(p_s_ih) KEY_IS_INDIRECT_KEY(&((p_s_ih)->ih_key)) #define is_indirect_ih(ih) I_IS_INDIRECT_ITEM(ih) #define is_direct_ih(ih) I_IS_DIRECT_ITEM(ih) #define is_direntry_ih(ih) I_IS_DIRECTORY_ITEM(ih) #define is_stat_data_ih(ih) I_IS_STAT_DATA_ITEM(ih) #define is_indirect_key(key) KEY_IS_INDIRECT_KEY(key) #define is_direct_key(key) KEY_IS_DIRECT_KEY(key) #define is_direntry_key(key) KEY_IS_DIRECTORY_KEY(key) #define is_stat_data_key(key) KEY_IS_STAT_DATA_KEY(key) #define COMP_KEYS comp_keys //#define COMP_SHORT_KEYS comp_short_keys #define not_of_one_file comp_short_keys /* number of blocks pointed to by the indirect item */ #define I_UNFM_NUM(p_s_ih) ( (p_s_ih)->ih_item_len / UNFM_P_SIZE ) /* the used space within the unformatted node corresponding to pos within the item pointed to by ih */ #define I_POS_UNFM_SIZE(ih,pos,size) (((pos) == I_UNFM_NUM(ih) - 1 ) ? (size) - ih_free_space (ih) : (size)) /* check whether byte number 'offset' is in this item */ #define I_OFF_BYTE_IN_ITEM(p_s_ih, n_offset, n_blocksize) \ ( get_offset(&(p_s_ih)->ih_key) <= (n_offset) && \ get_offset(&(p_s_ih)->ih_key) + get_bytes_number(p_s_ih,n_blocksize) > (n_offset) ) /* get the item header */ #define B_N_PITEM_HEAD(bh,item_num) ( (struct item_head * )((bh)->b_data + BLKH_SIZE) + (item_num) ) /* get key */ #define B_N_PDELIM_KEY(bh,item_num) ( (struct key * )((bh)->b_data + BLKH_SIZE) + (item_num) ) /* get the key */ #define B_N_PKEY(bh,item_num) ( &(B_N_PITEM_HEAD(bh,item_num)->ih_key) ) /* get item body */ #define B_N_PITEM(bh,item_num) ( (bh)->b_data + B_N_PITEM_HEAD((bh),(item_num))->ih_item_location) /* get the stat data by the buffer header and the item order */ #define B_N_STAT_DATA(bh,nr) \ ( (struct stat_data *)((bh)->b_data+B_N_PITEM_HEAD((bh),(nr))->ih_item_location ) ) /* following defines use reiserfs buffer header and item header */ /* get item body */ #define B_I_PITEM(bh,ih) ( (bh)->b_data + ih_location(ih)) /* get stat-data */ #define B_I_STAT_DATA(bh, ih) ( (struct stat_data * )B_I_PITEM(bh,ih) ) #define MAX_DIRECT_ITEM_LEN(size) ((size) - BLKH_SIZE - 2*IH_SIZE - SD_SIZE - UNFM_P_SIZE) /* indirect items consist of entries which contain blocknrs, pos indicates which entry, and B_I_POS_UNFM_POINTER resolves to the blocknr contained by the entry pos points to */ #define B_I_POS_UNFM_POINTER(bh,ih,pos) (*(((__u32 *)B_I_PITEM(bh,ih)) + (pos))) /***************************************************************************/ /* FUNCTION DECLARATIONS */ /***************************************************************************/ /* objectid.c */ __u32 reiserfs_get_unused_objectid (struct reiserfs_transaction_handle *th); void reiserfs_release_objectid (struct reiserfs_transaction_handle *th, __u32 objectid_to_release); int reiserfs_convert_objectid_map_v1(struct super_block *s); /* stree.c */ void padd_item (char * item, int total_length, int length); int B_IS_IN_TREE(struct buffer_head *); struct key * get_rkey (struct path * p_s_chk_path, struct super_block * p_s_sb); int bin_search (void * p_v_key, void * p_v_base, int p_n_num, int p_n_width, int * p_n_pos); int search_by_key (struct super_block *, struct key *, struct path *, int * , int); int search_by_entry_key (struct super_block * sb, struct key * key, struct path * path); int search_for_position_by_key (struct super_block * p_s_sb, struct key * p_s_key, struct path * p_s_search_path); int search_by_objectid (struct super_block *, struct key *, struct path *, int *); void decrement_counters_in_path (struct path * p_s_search_path); void pathrelse (struct path * p_s_search_path); int is_left_mergeable (struct super_block * s, struct path * path); int is_right_mergeable (struct super_block * s, struct path * path); int are_items_mergeable (struct item_head * left, struct item_head * right, int bsize); /* fix_nodes.c */ void * reiserfs_kmalloc (size_t size, int flags, struct super_block * s); void reiserfs_kfree (/*const*/ void * vp, size_t size, struct super_block * s); int fix_nodes (/*struct reiserfs_transaction_handle *th,*/ int n_op_mode, struct tree_balance * p_s_tb, /*int n_pos_in_item,*/ struct item_head * p_s_ins_ih); void unfix_nodes (/*struct reiserfs_transaction_handle *th,*/ struct tree_balance *); void free_buffers_in_tb (struct tree_balance * p_s_tb); void init_path (struct path *); /* prints.c */ #define PRINT_LEAF_ITEMS 1 /* print all items */ #define PRINT_ITEM_DETAILS 2 /* print contents of directory items and stat data items and indirect items */ #define PRINT_DIRECT_ITEMS 4 /* print contents of direct items */ void print_tb (int mode, int item_pos, int pos_in_item, struct tree_balance * tb, char * mes); void print_bmap (FILE * fp, reiserfs_filsys_t fs, int silent); void print_objectid_map (FILE * fp, reiserfs_filsys_t fs); /* lbalance.c */ int leaf_move_items (int shift_mode, struct tree_balance * tb, int mov_num, int mov_bytes, struct buffer_head * Snew); int leaf_shift_left (struct tree_balance * tb, int shift_num, int shift_bytes); int leaf_shift_right (struct tree_balance * tb, int shift_num, int shift_bytes); void leaf_delete_items (reiserfs_filsys_t, struct buffer_info * cur_bi, int last_first, int first, int del_num, int del_bytes); void leaf_insert_into_buf (reiserfs_filsys_t, struct buffer_info * bi, int before, struct item_head * inserted_item_ih, const char * inserted_item_body, int zeros_number); void leaf_paste_in_buffer (reiserfs_filsys_t, struct buffer_info * bi, int pasted_item_num, int pos_in_item, int paste_size, const char * body, int zeros_number); void leaf_cut_from_buffer (reiserfs_filsys_t, struct buffer_info * bi, int cut_item_num, int pos_in_item, int cut_size); void leaf_paste_entries (struct buffer_head * bh, int item_num, int before, int new_entry_count, struct reiserfs_de_head * new_dehs, const char * records, int paste_size); void delete_item (reiserfs_filsys_t fs, struct buffer_head * bh, int item_num); void cut_entry (reiserfs_filsys_t fs, struct buffer_head * bh, int item_num, int entry_num, int del_count); /* ibalance.c */ int balance_internal (struct tree_balance * , int, int, struct item_head * , struct buffer_head **); /* do_balance.c */ void do_balance (struct tree_balance * tb, struct item_head * ih, const char * body, int flag, int zeros_num); void reiserfs_invalidate_buffer (struct tree_balance * tb, struct buffer_head * bh, int); int get_left_neighbor_position (struct tree_balance * tb, int h); int get_right_neighbor_position (struct tree_balance * tb, int h); void replace_key (reiserfs_filsys_t, struct buffer_head *, int, struct buffer_head *, int); void replace_lkey (struct tree_balance *, int, struct item_head *); void replace_rkey (struct tree_balance *, int, struct item_head *); void make_empty_node (struct buffer_info *); struct buffer_head * get_FEB (struct tree_balance *); __u64 get_bytes_number (struct item_head * ih, int blocksize); /* hashes.c */ __u32 keyed_hash (const char *msg, int len); __u32 yura_hash (const char *msg, int len); __u32 r5_hash (const char *msg, int len); /* node_format.c */ int get_journal_old_start_must (struct reiserfs_super_block * rs); int get_journal_start_must (int blocksize); /*extern hashf_t hashes [];*/ reiserfsprogs-3.x.0j/include/reiserfs_lib.h0000644000076400001440000001702007257654516014637 /* * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README */ #ifndef REISERFS_LIB_H #define REISERFS_LIB_H typedef struct super_block * reiserfs_filsys_t; #include "reiserfs_fs.h" struct _bitmap { unsigned long bm_byte_size; unsigned long bm_bit_size; char * bm_map; unsigned long bm_set_bits; }; typedef struct _bitmap * reiserfs_bitmap_t; struct super_block { int s_version; /* on-disk format version */ reiserfs_bitmap_t bitmap; /* copy of reiserfs on-disk bitmap */ int s_dev; /* descriptor of opened block device file */ int s_blocksize; struct buffer_head ** s_ap_bitmap; /* array of buffers containing bitmap blocks */ struct buffer_head * s_sbh; /* buffer containing super block */ struct reiserfs_super_block * s_rs; /* pointer to its b_data */ int s_dirt; hashf_t s_hash_function; /* pointer to function which is used to sort names in directory. It is set by reiserfs_open if it is set in the super block, otherwise it is set by first is_properly_hashed */ char * file_name; /* file name of underlying device */ int s_flags; void * s_vp; int (*block_allocator) (reiserfs_filsys_t fs, unsigned long * free_blocknrs, unsigned long start, int amount_needed); int (*block_deallocator) (reiserfs_filsys_t fs, unsigned long block); }; /* reiserfslib.c */ reiserfs_filsys_t reiserfs_open (char * filename, int flags, int * error, void * vp); void reiserfs_read_bitmap_blocks (reiserfs_filsys_t); void reiserfs_free_bitmap_blocks (reiserfs_filsys_t); int no_reiserfs_found (reiserfs_filsys_t fs); void reiserfs_reopen (reiserfs_filsys_t fs, int flags); void reiserfs_flush (reiserfs_filsys_t fs); void reiserfs_free (reiserfs_filsys_t fs); void reiserfs_close (reiserfs_filsys_t fs); int reiserfs_new_blocknrs (reiserfs_filsys_t fs, unsigned long * free_blocknrs, unsigned long start, int amount_needed); int reiserfs_free_block (reiserfs_filsys_t fs, unsigned long block); int spread_bitmaps (reiserfs_filsys_t fs); int filesystem_dirty (reiserfs_filsys_t fs); void mark_filesystem_dirty (reiserfs_filsys_t fs); void reiserfs_paste_into_item (reiserfs_filsys_t fs, struct path * path, const void * body, int size); void reiserfs_insert_item (reiserfs_filsys_t fs, struct path * path, struct item_head * ih, const void * body); int reiserfs_find_entry (reiserfs_filsys_t fs, struct key * dir, char * name, int * min_gen_counter); int reiserfs_add_entry (reiserfs_filsys_t fs, struct key * dir, char * name, struct key * key, int fsck_need); int _search_by_entry_key (reiserfs_filsys_t fs, struct key * key, struct path * path); void copy_key (void * to, void * from); void copy_short_key (void * to, void * from); void copy_item_head(void * p_v_to, void * p_v_from); int comp_keys (void * k1, void * k2); int comp_short_keys (void * p_s_key1, void * p_s_key2); int comp_items (struct item_head * p_s_ih, struct path * p_s_path); /* bitmap.c */ reiserfs_bitmap_t reiserfs_create_bitmap (unsigned int bit_count); int reiserfs_expand_bitmap (reiserfs_bitmap_t bm, unsigned int bit_count); void reiserfs_delete_bitmap (reiserfs_bitmap_t bm); void reiserfs_bitmap_copy (reiserfs_bitmap_t to, reiserfs_bitmap_t from); int reiserfs_bitmap_compare (reiserfs_bitmap_t bm1, reiserfs_bitmap_t bm2); void reiserfs_bitmap_set_bit (reiserfs_bitmap_t bm, unsigned int bit_number); void reiserfs_bitmap_clear_bit (reiserfs_bitmap_t bm, unsigned int bit_number); int reiserfs_bitmap_test_bit (reiserfs_bitmap_t bm, unsigned int bit_number); int reiserfs_bitmap_find_zero_bit (reiserfs_bitmap_t bm, unsigned long * start); int reiserfs_fetch_disk_bitmap (reiserfs_bitmap_t bm, reiserfs_filsys_t fs); int reiserfs_flush_bitmap (reiserfs_bitmap_t bm, reiserfs_filsys_t fs); void reiserfs_bitmap_zero (reiserfs_bitmap_t bm); void reiserfs_bitmap_fill (reiserfs_bitmap_t bm); int reiserfs_bitmap_ones (reiserfs_bitmap_t bm); int reiserfs_bitmap_zeros (reiserfs_bitmap_t bm); void reiserfs_bitmap_save (char * filename, reiserfs_bitmap_t bm); reiserfs_bitmap_t reiserfs_bitmap_load (char * filename); void reiserfs_bitmap_invert (reiserfs_bitmap_t bm); int reiserfs_remove_entry (reiserfs_filsys_t fs, struct key * key); /* node_formats.c */ #define THE_LEAF 1 #define THE_INTERNAL 2 #define THE_SUPER 3 #define THE_JDESC 4 #define THE_UNKNOWN 5 int is_reiserfs_magic_string (struct reiserfs_super_block * rs); int is_reiser2fs_magic_string (struct reiserfs_super_block * rs); int is_prejournaled_reiserfs (struct reiserfs_super_block * rs); int does_desc_match_commit (struct reiserfs_journal_desc *desc, struct reiserfs_journal_commit *commit); int who_is_this (char * buf, int blocksize); int journal_size (struct super_block * s); int not_data_block (struct super_block * s, unsigned long block); int not_journalable (reiserfs_filsys_t fs, unsigned long block); int block_of_bitmap (reiserfs_filsys_t fs, unsigned long block); int block_of_journal (reiserfs_filsys_t fs, unsigned long block); int is_tree_node (struct buffer_head * bh, int level); int is_properly_hashed (reiserfs_filsys_t fs, char * name, int namelen, __u32 offset); int dir_entry_bad_location (struct reiserfs_de_head * deh, struct item_head * ih, int first); void make_dir_stat_data (int blocksize, int key_format, __u32 dirid, __u32 objectid, struct item_head * ih, void * sd); void make_empty_dir_item_v1 (char * body, __u32 dirid, __u32 objid, __u32 par_dirid, __u32 par_objid); void make_empty_dir_item (char * body, __u32 dirid, __u32 objid, __u32 par_dirid, __u32 par_objid); typedef void (*item_action_t) (struct buffer_head * bh, struct item_head * ih); typedef void (*item_head_action_t) (struct item_head * ih); void for_every_item (struct buffer_head * bh, item_head_action_t action, item_action_t * actions); int key_format (const struct key * key); loff_t get_offset (const struct key * key); int uniqueness2type (__u32 uniqueness); __u32 type2uniqueness (int type); int get_type (const struct key * key); char * key_of_what (const struct key * key); int type_unknown (struct key * key); void set_type (int format, struct key * key, int type); void set_offset (int format, struct key * key, loff_t offset); void set_type_and_offset (int format, struct key * key, loff_t offset, int type); typedef int (*check_unfm_func_t) (reiserfs_filsys_t fs, __u32); int is_it_bad_item (reiserfs_filsys_t, struct item_head *, char *, check_unfm_func_t, int bad_dir); #define hash_func_is_unknown(fs) ((fs)->s_hash_function == 0) #define reiserfs_hash(fs) ((fs)->s_hash_function) int known_hashes (void); char * code2name (int code); int func2code (hashf_t func); hashf_t code2func (int code); int find_hash_in_use (char * name, int namelen, __u32 hash_value_masked, int code_to_try_first); int entry_length (struct item_head * ih, struct reiserfs_de_head * deh, int pos_in_item); char * name_in_entry (struct reiserfs_de_head * deh, int pos_in_item); int name_length (struct item_head * ih, struct reiserfs_de_head * deh, int pos_in_item); /* prints.c */ void print_indirect_item (FILE * fp, struct buffer_head * bh, int item_num); void print_block (FILE * fp, reiserfs_filsys_t, struct buffer_head * bh, ...);//int print_mode, int first, int last); void reiserfs_warning (FILE * fp, const char * fmt, ...); char ftypelet (mode_t mode); #define reiserfs_panic(fmt, list...) \ {\ fprintf (stderr, "%s %d %s\n", __FILE__, __LINE__, __FUNCTION__);\ reiserfs_warning (stderr, fmt, ## list);\ exit(4);\ } #endif /* REISERFS_LIB_H */ reiserfsprogs-3.x.0j/lib/0000777000076400001440000000000007261220335011204 5reiserfsprogs-3.x.0j/lib/Makefile.in0000644000076400001440000001463007261220335013171 # Makefile.in generated automatically by automake 1.4 from Makefile.am # Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. # This Makefile.in 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. SHELL = @SHELL@ srcdir = @srcdir@ top_srcdir = @top_srcdir@ VPATH = @srcdir@ prefix = @prefix@ exec_prefix = @exec_prefix@ bindir = @bindir@ sbindir = @sbindir@ libexecdir = @libexecdir@ datadir = @datadir@ sysconfdir = @sysconfdir@ sharedstatedir = @sharedstatedir@ localstatedir = @localstatedir@ libdir = @libdir@ infodir = @infodir@ mandir = @mandir@ includedir = @includedir@ oldincludedir = /usr/include DESTDIR = pkgdatadir = $(datadir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ top_builddir = .. ACLOCAL = @ACLOCAL@ AUTOCONF = @AUTOCONF@ AUTOMAKE = @AUTOMAKE@ AUTOHEADER = @AUTOHEADER@ INSTALL = @INSTALL@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS) INSTALL_DATA = @INSTALL_DATA@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ transform = @program_transform_name@ NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : CC = @CC@ MAKEINFO = @MAKEINFO@ PACKAGE = @PACKAGE@ RANLIB = @RANLIB@ VERSION = @VERSION@ noinst_LIBRARIES = libmisc.a libmisc_a_SOURCES = io.c misc.c INCLUDES = -I$(top_srcdir)/include mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs CONFIG_CLEAN_FILES = LIBRARIES = $(noinst_LIBRARIES) DEFS = @DEFS@ -I. -I$(srcdir) CPPFLAGS = @CPPFLAGS@ LDFLAGS = @LDFLAGS@ LIBS = @LIBS@ libmisc_a_LIBADD = libmisc_a_OBJECTS = io.o misc.o AR = ar CFLAGS = @CFLAGS@ COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ DIST_COMMON = Makefile.am Makefile.in DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) TAR = tar GZIP_ENV = --best SOURCES = $(libmisc_a_SOURCES) OBJECTS = $(libmisc_a_OBJECTS) all: all-redirect .SUFFIXES: .SUFFIXES: .S .c .o .s $(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps lib/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status cd $(top_builddir) \ && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status mostlyclean-noinstLIBRARIES: clean-noinstLIBRARIES: -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) distclean-noinstLIBRARIES: maintainer-clean-noinstLIBRARIES: .c.o: $(COMPILE) -c $< .s.o: $(COMPILE) -c $< .S.o: $(COMPILE) -c $< mostlyclean-compile: -rm -f *.o core *.core clean-compile: distclean-compile: -rm -f *.tab.c maintainer-clean-compile: libmisc.a: $(libmisc_a_OBJECTS) $(libmisc_a_DEPENDENCIES) -rm -f libmisc.a $(AR) cru libmisc.a $(libmisc_a_OBJECTS) $(libmisc_a_LIBADD) $(RANLIB) libmisc.a tags: TAGS ID: $(HEADERS) $(SOURCES) $(LISP) list='$(SOURCES) $(HEADERS)'; \ unique=`for i in $$list; do echo $$i; done | \ awk ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ here=`pwd` && cd $(srcdir) \ && mkid -f$$here/ID $$unique $(LISP) TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) tags=; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS)'; \ unique=`for i in $$list; do echo $$i; done | \ awk ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) mostlyclean-tags: clean-tags: distclean-tags: -rm -f TAGS ID maintainer-clean-tags: distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) subdir = lib distdir: $(DISTFILES) @for file in $(DISTFILES); do \ d=$(srcdir); \ if test -d $$d/$$file; then \ cp -pr $$/$$file $(distdir)/$$file; \ else \ test -f $(distdir)/$$file \ || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ || cp -p $$d/$$file $(distdir)/$$file || :; \ fi; \ done io.o: io.c ../include/io.h ../include/misc.h misc.o: misc.c ../include/io.h info-am: info: info-am dvi-am: dvi: dvi-am check-am: all-am check: check-am installcheck-am: installcheck: installcheck-am install-exec-am: install-exec: install-exec-am install-data-am: install-data: install-data-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am install: install-am uninstall-am: uninstall: uninstall-am all-am: Makefile $(LIBRARIES) all-redirect: all-am install-strip: $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install installdirs: mostlyclean-generic: clean-generic: distclean-generic: -rm -f Makefile $(CONFIG_CLEAN_FILES) -rm -f config.cache config.log stamp-h stamp-h[0-9]* maintainer-clean-generic: mostlyclean-am: mostlyclean-noinstLIBRARIES mostlyclean-compile \ mostlyclean-tags mostlyclean-generic mostlyclean: mostlyclean-am clean-am: clean-noinstLIBRARIES clean-compile clean-tags clean-generic \ mostlyclean-am clean: clean-am distclean-am: distclean-noinstLIBRARIES distclean-compile \ distclean-tags distclean-generic clean-am distclean: distclean-am maintainer-clean-am: maintainer-clean-noinstLIBRARIES \ maintainer-clean-compile maintainer-clean-tags \ maintainer-clean-generic distclean-am @echo "This command is intended for maintainers to use;" @echo "it deletes files that may require special tools to rebuild." maintainer-clean: maintainer-clean-am .PHONY: mostlyclean-noinstLIBRARIES distclean-noinstLIBRARIES \ clean-noinstLIBRARIES maintainer-clean-noinstLIBRARIES \ mostlyclean-compile distclean-compile clean-compile \ maintainer-clean-compile tags mostlyclean-tags distclean-tags \ clean-tags maintainer-clean-tags distdir info-am info dvi-am dvi check \ check-am installcheck-am installcheck install-exec-am install-exec \ install-data-am install-data install-am install uninstall-am uninstall \ all-redirect all-am all installdirs mostlyclean-generic \ distclean-generic clean-generic maintainer-clean-generic clean \ mostlyclean distclean maintainer-clean # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: reiserfsprogs-3.x.0j/lib/Makefile.am0000644000076400001440000000020107142245375013156 noinst_LIBRARIES = libmisc.a libmisc_a_SOURCES = io.c misc.c ##reiserfs.c INCLUDES = -I$(top_srcdir)/include reiserfsprogs-3.x.0j/lib/io.c0000644000076400001440000002645607255431232011713 /* * Copyright 1996, 1997 Hans Reiser, see reiserfs/README for licensing and copyright details */ #define _GNU_SOURCE #include #include #include #include #include #include /*#include */ #include "io.h" #include "misc.h" /* All buffers are in double linked cycled list. Buffers of tree are hashed by their block number. If getblk found buffer with wanted block number in hash queue it moves buffer to the end of list */ #define BLOCK_SIZE 1024 #define MAX_NR_BUFFERS 16384 static int g_nr_buffers; #define NR_HASH_QUEUES 4096 static struct buffer_head * g_a_hash_queues [NR_HASH_QUEUES]; static struct buffer_head * g_buffer_list_head; static struct buffer_head * g_buffer_heads; static void show_buffers (int dev, int size) { int all = 0; int dirty = 0; int in_use = 0; /* count != 0 */ int free = 0; struct buffer_head * next = g_buffer_list_head; for (;;) { if (!next) die ("show_buffers: buffer list is corrupted"); if (next->b_dev == dev && next->b_size == size) { all ++; if (next->b_count != 0) { in_use ++; } if (buffer_dirty (next)) { dirty ++; } if (buffer_clean (next) && next->b_count == 0) { free ++; } } next = next->b_next; if (next == g_buffer_list_head) break; } printf ("show_buffers (dev %d, size %d): free %d, count != 0 %d, dirty %d, all %d\n", dev, size, free, in_use, dirty, all); } static void insert_into_hash_queue (struct buffer_head * bh) { int index = bh->b_blocknr % NR_HASH_QUEUES; if (bh->b_hash_prev || bh->b_hash_next) die ("insert_into_hash_queue: hash queue corrupted"); if (g_a_hash_queues[index]) { g_a_hash_queues[index]->b_hash_prev = bh; bh->b_hash_next = g_a_hash_queues[index]; } g_a_hash_queues[index] = bh; } static void remove_from_hash_queue (struct buffer_head * bh) { if (bh->b_hash_next == 0 && bh->b_hash_prev == 0 && bh != g_a_hash_queues[bh->b_blocknr % NR_HASH_QUEUES]) /* (b_dev == 0) ? */ return; if (bh == g_a_hash_queues[bh->b_blocknr % NR_HASH_QUEUES]) { if (bh->b_hash_prev != 0) die ("remove_from_hash_queue: hash queue corrupted"); g_a_hash_queues[bh->b_blocknr % NR_HASH_QUEUES] = bh->b_hash_next; } if (bh->b_hash_next) bh->b_hash_next->b_hash_prev = bh->b_hash_prev; if (bh->b_hash_prev) bh->b_hash_prev->b_hash_next = bh->b_hash_next; bh->b_hash_prev = bh->b_hash_next = 0; } static void put_buffer_list_end (struct buffer_head * bh) { struct buffer_head * last = 0; if (bh->b_prev || bh->b_next) die ("put_buffer_list_end: buffer list corrupted"); if (g_buffer_list_head == 0) { bh->b_next = bh; bh->b_prev = bh; g_buffer_list_head = bh; } else { last = g_buffer_list_head->b_prev; bh->b_next = last->b_next; bh->b_prev = last; last->b_next->b_prev = bh; last->b_next = bh; } } static void remove_from_buffer_list (struct buffer_head * bh) { if (bh == bh->b_next) { g_buffer_list_head = 0; } else { bh->b_prev->b_next = bh->b_next; bh->b_next->b_prev = bh->b_prev; if (bh == g_buffer_list_head) g_buffer_list_head = bh->b_next; } bh->b_next = bh->b_prev = 0; } static void put_buffer_list_head (struct buffer_head * bh) { put_buffer_list_end (bh); g_buffer_list_head = bh; } #define GROW_BUFFERS__NEW_BUFERS_PER_CALL 10 /* creates number of new buffers and insert them into head of buffer list */ static int grow_buffers (int size) { int i; struct buffer_head * bh, * tmp; if (g_nr_buffers + GROW_BUFFERS__NEW_BUFERS_PER_CALL > MAX_NR_BUFFERS) return 0; /* get memory for array of buffer heads */ bh = (struct buffer_head *)getmem (GROW_BUFFERS__NEW_BUFERS_PER_CALL * sizeof (struct buffer_head) + sizeof (struct buffer_head *)); if (g_buffer_heads == 0) g_buffer_heads = bh; else { /* link new array to the end of array list */ tmp = g_buffer_heads; while (*(struct buffer_head **)(tmp + GROW_BUFFERS__NEW_BUFERS_PER_CALL) != 0) tmp = *(struct buffer_head **)(tmp + GROW_BUFFERS__NEW_BUFERS_PER_CALL); *(struct buffer_head **)(tmp + GROW_BUFFERS__NEW_BUFERS_PER_CALL) = bh; } for (i = 0; i < GROW_BUFFERS__NEW_BUFERS_PER_CALL; i ++) { tmp = bh + i; memset (tmp, 0, sizeof (struct buffer_head)); tmp->b_data = getmem (size); if (tmp->b_data == 0) die ("grow_buffers: no memory for new buffer data"); tmp->b_dev = 0; tmp->b_size = size; put_buffer_list_head (tmp); g_nr_buffers ++; } return GROW_BUFFERS__NEW_BUFERS_PER_CALL; } struct buffer_head * find_buffer (int dev, int block, int size) { struct buffer_head * next; next = g_a_hash_queues[block % NR_HASH_QUEUES]; for (;;) { struct buffer_head *tmp = next; if (!next) break; next = tmp->b_hash_next; if (tmp->b_blocknr != block || tmp->b_size != size || tmp->b_dev != dev) continue; next = tmp; break; } return next; } void __wait_on_buffer (struct buffer_head * bh) { } struct buffer_head * get_hash_table(dev_t dev, int block, int size) { struct buffer_head * bh; bh = find_buffer (dev, block, size); if (bh) { bh->b_count ++; } return bh; } static struct buffer_head * get_free_buffer (int size) { struct buffer_head * next = g_buffer_list_head; if (!next) return 0; for (;;) { if (!next) die ("get_free_buffer: buffer list is corrupted"); if (next->b_count == 0 && buffer_clean (next) && next->b_size == size) { remove_from_hash_queue (next); remove_from_buffer_list (next); put_buffer_list_end (next); return next; } next = next->b_next; if (next == g_buffer_list_head) break; } return 0; } static void sync_buffers (int size, int to_write) { struct buffer_head * next = g_buffer_list_head; int written = 0; for (;;) { if (!next) die ("flush_buffer: buffer list is corrupted"); if ((!size || next->b_size == size) && buffer_dirty (next) && buffer_uptodate (next)) { written ++; bwrite (next); if (written == to_write) return; } next = next->b_next; if (next == g_buffer_list_head) break; } } void flush_buffers (void) { sync_buffers (0, 0); } struct buffer_head * getblk (int dev, int block, int size) { struct buffer_head * bh; bh = find_buffer (dev, block, size); if (bh) { if (0 && !buffer_uptodate (bh)) die ("getblk: buffer must be uptodate"); // move the buffer to the end of list /*checkmem (bh->b_data, bh->b_size);*/ remove_from_buffer_list (bh); put_buffer_list_end (bh); bh->b_count ++; return bh; } bh = get_free_buffer (size); if (bh == 0) { if (grow_buffers (size) == 0) { sync_buffers (size, 10); } bh = get_free_buffer (size); if (bh == 0) { show_buffers (dev, size); die ("getblk: no free buffers after grow_buffers and refill (%d)", g_nr_buffers); } } bh->b_count = 1; bh->b_dev = dev; bh->b_size = size; bh->b_blocknr = block; bh->b_end_io = NULL ; memset (bh->b_data, 0, size); clear_bit(BH_Dirty, &bh->b_state); clear_bit(BH_Uptodate, &bh->b_state); insert_into_hash_queue (bh); /*checkmem (bh->b_data, bh->b_size);*/ return bh; } struct buffer_head * reiserfs_getblk (int dev, int block, int size, int *repeat) { return getblk (dev, block, size); } void brelse (struct buffer_head * bh) { if (bh == 0) return; if (bh->b_count == 0) { die ("brelse: can not free a free buffer %lu", bh->b_blocknr); } /*checkmem (bh->b_data, bh->b_size);*/ bh->b_count --; } void bforget (struct buffer_head * bh) { if (bh) { brelse (bh); remove_from_hash_queue (bh); remove_from_buffer_list (bh); put_buffer_list_head (bh); } } #if 0 #if ! ( defined __USE_LARGEFILE64 || defined __USE_FILE_OFFSET64 ) _syscall5 (int, _llseek, uint, fd, ulong, hi, ulong, lo, loff_t *, res, uint, wh); #endif loff_t reiserfs_llseek (unsigned int fd, loff_t offset, unsigned int origin) { #if defined __USE_FILE_OFFSET64 return lseek(fd, offset, origin); #elif defined __USE_LARGEFILE64 return lseek64(fd, offset, origin); #else loff_t retval, result; retval = _llseek (fd, ((unsigned long long) offset) >> 32, ((unsigned long long) offset) & 0xffffffff, &result, origin); return (retval != 0 ? (loff_t)-1 : result); #endif } #endif static int f_read(struct buffer_head * bh) { loff_t offset; ssize_t bytes; offset = (loff_t)bh->b_size * (loff_t)bh->b_blocknr; /*if (reiserfs_llseek (bh->b_dev, offset, SEEK_SET) == (loff_t)-1)*/ if (lseek64 (bh->b_dev, offset, SEEK_SET) == (loff_t)-1) return 0; bytes = read (bh->b_dev, bh->b_data, bh->b_size); if (bytes != (ssize_t)bh->b_size) return 0; return 1; } struct buffer_head * bread (int dev, unsigned long block, size_t size) { struct buffer_head * bh; /* if ((size == 32768 && (block == 16 || 1026)) || (size == 4096 && (block == 128 || block == 8211))) { size = 10; return 0; } */ bh = getblk (dev, block, size); if (buffer_uptodate (bh)) return bh; if (f_read(bh) == 0) { brelse(bh); return 0; } mark_buffer_uptodate (bh, 0); return bh; } int valid_offset( int fd, loff_t offset) { char ch; loff_t res; /*res = reiserfs_llseek (fd, offset, 0);*/ res = lseek64 (fd, offset, 0); if (res < 0) return 0; if (read (fd, &ch, 1) < 1) return 0; return 1; } struct buffer_head * reiserfs_bread (int dev, int block, int size, int *repeat) { return bread (dev, block, size); } int bwrite (struct buffer_head * bh) { loff_t offset; ssize_t bytes; size_t size; if (!buffer_dirty (bh) || !buffer_uptodate (bh)) return 0; size = bh->b_size; offset = (loff_t)size * (loff_t)bh->b_blocknr; if (lseek64 (bh->b_dev, offset, SEEK_SET) == (loff_t)-1){ fprintf (stderr, "bwrite: lseek to position %Ld (block=%lu, dev=%d): %s\n", offset, bh->b_blocknr, bh->b_dev, strerror (errno)); exit (4); /* File system errors left uncorrected */ } bytes = write (bh->b_dev, bh->b_data, size); if (bytes != (ssize_t)size) { fprintf (stderr, "bwrite: write %d bytes returned %d (block=%ld, dev=%d): %s\n", size, bytes, bh->b_blocknr, bh->b_dev, strerror (errno)); exit (4); } mark_buffer_clean (bh); if (bh->b_end_io) { bh->b_end_io(bh, 1) ; } return 0; } void check_and_free_buffer_mem (void) { int i = 0; struct buffer_head * next = g_buffer_list_head; //sync_buffers (0, 0); for (;;) { if (!next) die ("check_and_free_buffer_mem: buffer list is corrupted"); if (next->b_count != 0) fprintf (stderr, "check_and_free_buffer_mem: not free buffer (%ld, %ld, %d)", next->b_blocknr, next->b_size, next->b_count); if (buffer_dirty (next) && buffer_uptodate (next)) fprintf (stderr, "check_and_free_buffer_mem: dirty buffer %lu found\n", next->b_blocknr); freemem (next->b_data); i ++; next = next->b_next; if (next == g_buffer_list_head) break; } if (i != g_nr_buffers) die ("check_and_free_buffer_mem: found %d buffers, must be %d", i, g_nr_buffers); /* free buffer heads */ while ((next = g_buffer_heads)) { g_buffer_heads = *(struct buffer_head **)(next + GROW_BUFFERS__NEW_BUFERS_PER_CALL); freemem (next); } return; } /* */ void free_buffers (void) { check_and_free_buffer_mem (); } reiserfsprogs-3.x.0j/lib/misc.c0000644000076400001440000003050207257136743012235 /* * Copyright 1996, 1997, 1998 Hans Reiser */ /*#define _GNU_SOURCE*/ /*#define _FILE_OFFSET_BITS 64*/ #include #include #include #include #include #include #include #include #include #include #include #include #include "io.h" /* * These have been stolen somewhere from linux */ int set_bit (int nr, void * addr) { __u8 * p, mask; int retval; p = (__u8 *)addr; p += nr >> 3; mask = 1 << (nr & 0x7); /*cli();*/ retval = (mask & *p) != 0; *p |= mask; /*sti();*/ return retval; } int clear_bit (int nr, void * addr) { __u8 * p, mask; int retval; p = (__u8 *)addr; p += nr >> 3; mask = 1 << (nr & 0x7); /*cli();*/ retval = (mask & *p) != 0; *p &= ~mask; /*sti();*/ return retval; } int test_bit(int nr, const void * addr) { __u8 * p, mask; p = (__u8 *)addr; p += nr >> 3; mask = 1 << (nr & 0x7); return ((mask & *p) != 0); } int find_first_zero_bit (const void *vaddr, unsigned size) { const __u8 *p = vaddr, *addr = vaddr; int res; if (!size) return 0; size = (size >> 3) + ((size & 0x7) > 0); while (*p++ == 255) { if (--size == 0) return (p - addr) << 3; } --p; for (res = 0; res < 8; res++) if (!test_bit (res, p)) break; return (p - addr) * 8 + res; } int find_next_zero_bit (const void *vaddr, unsigned size, unsigned offset) { const __u8 *addr = vaddr; const __u8 *p = addr + (offset >> 3); int bit = offset & 7, res; if (offset >= size) return size; if (bit) { /* Look for zero in first char */ for (res = bit; res < 8; res++) if (!test_bit (res, p)) return (p - addr) * 8 + res; p++; } /* No zero yet, search remaining full bytes for a zero */ res = find_first_zero_bit (p, size - 8 * (p - addr)); return (p - addr) * 8 + res; } /*int test_and_set_bit (int nr, void * addr) { int oldbit = test_bit (nr, addr); set_bit (nr, addr); return oldbit; } int test_and_clear_bit (int nr, void * addr) { int oldbit = test_bit (nr, addr); clear_bit (nr, addr); return oldbit; }*/ void die (char * fmt, ...) { static char buf[1024]; va_list args; va_start (args, fmt); vsprintf (buf, fmt, args); va_end (args); fprintf (stderr, "\n%s\n\n\n", buf); exit (-1); } #define MEM_BEGIN "_mem_begin_" #define MEM_END "mem_end" #define MEM_FREED "__free_" #define CONTROL_SIZE (strlen (MEM_BEGIN) + 1 + sizeof (int) + strlen (MEM_END) + 1) static int get_mem_size (char * p) { char * begin; begin = p - strlen (MEM_BEGIN) - 1 - sizeof (int); return *(int *)(begin + strlen (MEM_BEGIN) + 1); } void checkmem (char * p, int size) { char * begin; char * end; begin = p - strlen (MEM_BEGIN) - 1 - sizeof (int); if (strcmp (begin, MEM_BEGIN)) die ("checkmem: memory corrupted - invalid head sign"); if (*(int *)(begin + strlen (MEM_BEGIN) + 1) != size) die ("checkmem: memory corrupted - invalid size"); end = begin + size + CONTROL_SIZE - strlen (MEM_END) - 1; if (strcmp (end, MEM_END)) die ("checkmem: memory corrupted - invalid end sign"); } void * getmem (int size) { char * p; char * mem; p = (char *)malloc (CONTROL_SIZE + size); if (!p) die ("getmem: no more memory (%d)", size); strcpy (p, MEM_BEGIN); p += strlen (MEM_BEGIN) + 1; *(int *)p = size; p += sizeof (int); mem = p; memset (mem, 0, size); p += size; strcpy (p, MEM_END); checkmem (mem, size); return mem; } void * expandmem (void * vp, int size, int by) { int allocated; char * mem, * p = vp; int expand_by = by; if (p) { checkmem (p, size); allocated = CONTROL_SIZE + size; p -= (strlen (MEM_BEGIN) + 1 + sizeof (int)); } else { allocated = 0; /* add control bytes to the new allocated area */ expand_by += CONTROL_SIZE; } p = realloc (p, allocated + expand_by); if (!p) die ("expandmem: no more memory (%d)", size); if (!vp) { strcpy (p, MEM_BEGIN); } mem = p + strlen (MEM_BEGIN) + 1 + sizeof (int); *(int *)(p + strlen (MEM_BEGIN) + 1) = size + by; /* fill new allocated area by 0s */ if(by > 0) memset (mem + size, 0, by); strcpy (mem + size + by, MEM_END); checkmem (mem, size + by); return mem; } void freemem (void * vp) { char * p = vp; int size; if (!p) return; size = get_mem_size (vp); checkmem (p, size); p -= (strlen (MEM_BEGIN) + 1 + sizeof (int)); strcpy (p, MEM_FREED); strcpy (p + size + CONTROL_SIZE - strlen (MEM_END) - 1, MEM_FREED); free (p); } typedef int (*func_t) (char *); static int is_readonly_dir (char * dir) { char * name; FILE * f; name = tempnam (dir, 0); if (!name) { fprintf (stderr, "is_readonly: tempnam failed, think fs is not readonly\n"); return 0; } f = fopen (name, "w"); if (f) { unlink (name); free (name); return 0; } free (name); return (errno == EROFS) ? 1 : 0; } int user_confirmed (char * q, char * yes) { char * answer = 0; size_t n = 0; fprintf (stderr, "%s", q); if (getline (&answer, &n, stdin) != strlen (yes) || strcmp (yes, answer)) return 0; return 1; } #include #include #define __NR_stat64 195 _syscall2(long, stat64, char *, filename, struct stat *, statbuf); static int _is_mounted (char * device_name, func_t f) { int retval; FILE *fp; struct mntent *mnt; struct statfs stfs; struct stat root_st; struct stat device_st; /* struct stat64 device_st64;*/ int used_stat64 = 1; if (stat ("/", &root_st) == -1) die ("is_mounted: could not stat \"/\": %m\n"); if (stat64 (device_name, &device_st) == -1) { used_stat64 = 0; if (stat (device_name, &device_st) == -1) die ("is_mounted: could not stat file \"%s\": %m", device_name); } if ((used_stat64 && !S_ISBLK (device_st.st_mode)) || !S_ISBLK (device_st.st_mode)) /* not block device file could not be mounted */ return 0; if ((used_stat64 && root_st.st_dev == device_st.st_rdev) || root_st.st_dev == device_st.st_rdev) { /* device is mounted as root */ return (f ? f ("/") : 1); } /* if proc filesystem is mounted */ if (statfs ("/proc", &stfs) == -1 || stfs.f_type != 0x9fa0/*procfs magic*/ || (fp = setmntent ("/proc/mounts", "r")) == NULL) { /* proc filesystem is not mounted, or /proc/mounts does not exist */ if (f) return (user_confirmed (" (could not figure out) Is filesystem mounted read-only? (Yes)", "Yes\n")); else return (user_confirmed (" (could not figure out) Is filesystem mounted? (Yes)", "Yes\n")); } retval = 0; while ((mnt = getmntent (fp)) != NULL) if (strcmp (device_name, mnt->mnt_fsname) == 0) { retval = (f ? f (mnt->mnt_dir) : 1); break; } endmntent (fp); return retval; } int is_mounted_read_only (char * device_name) { return _is_mounted (device_name, is_readonly_dir); } int is_mounted (char * device_name) { return _is_mounted (device_name, 0); } char buf1 [100]; char buf2 [100]; void print_how_fast (unsigned long passed, unsigned long total, int cursor_pos, int reset_time) { static time_t t0, t1; int speed; int indent; if (reset_time) time (&t0); time (&t1); if (t1 != t0) speed = passed / (t1 - t0); else speed = 0; /* what has to be written */ if (total) sprintf (buf1, "left %lu, %d /sec", total - passed, speed); else { /*(*passed) ++;*/ sprintf (buf1, "done %lu, %d /sec", passed, speed); } /* make indent */ indent = 79 - cursor_pos - strlen (buf1); memset (buf2, ' ', indent); buf2[indent] = 0; fprintf (stderr, "%s%s", buf2, buf1); memset (buf2, '\b', indent + strlen (buf1)); buf2 [indent + strlen (buf1)] = 0; fprintf (stderr, "%s", buf2); fflush (stderr); } static char * strs[] = {"0%",".",".",".",".","20%",".",".",".",".","40%",".",".",".",".","60%",".",".",".",".","80%",".",".",".",".","100%"}; static char progress_to_be[1024]; static char current_progress[1024]; static void str_to_be (char * buf, int prosents) { int i; prosents -= prosents % 4; buf[0] = 0; for (i = 0; i <= prosents / 4; i ++) strcat (buf, strs[i]); } void print_how_far (unsigned long * passed, unsigned long total, int inc, int quiet) { int percent; if (*passed == 0) current_progress[0] = 0; (*passed) += inc; if (*passed > total) { fprintf (stderr, "\nprint_how_far: total %lu has been reached already. cur=%lu\n", total, *passed); return; } percent = ((*passed) * 100) / total; str_to_be (progress_to_be, percent); if (strlen (current_progress) != strlen (progress_to_be)) { fprintf (stderr, "%s", progress_to_be + strlen (current_progress)); } strcat (current_progress, progress_to_be + strlen (current_progress)); if (!quiet) print_how_fast (*passed/* - inc*/, total, strlen (progress_to_be), (*passed == inc) ? 1 : 0); fflush (stderr); } #define ENDIANESS_NOT_DEFINED 0 #define LITTLE_ENDIAN_ARCH 1 #define BIG_ENDIAN_ARCH 2 static int endianess = ENDIANESS_NOT_DEFINED; static void find_endianess (void) { __u32 x = 0x0f0d0b09; char * s; s = (char *)&x; // little-endian is 1234 if (s[0] == '\11' && s[1] == '\13' && s[2] == '\15' && s[3] == '\17') endianess = LITTLE_ENDIAN_ARCH; // big-endian is 4321 if (s[0] == '\17' && s[1] == '\15' && s[2] == '\13' && s[3] == '\11') die ("big-endian archs are not supported"); // nuxi/pdp-endian is 3412 if (s[0] == '\15' && s[1] == '\17' && s[2] == '\11' && s[3] == '\13') die ("nuxi/pdp-endian archs are not supported"); } // we used to use such function in the kernel stuff of reiserfs. Lets // have them in utils as well inline __u32 cpu_to_le32 (__u32 val) { if (endianess == ENDIANESS_NOT_DEFINED) find_endianess (); if (endianess == LITTLE_ENDIAN_ARCH) return val; die ("neither big- nor any other endian archs are supported yet "); return ((val>>24) | ((val>>8)&0xFF00) | ((val<<8)&0xFF0000) | (val<<24)); } inline __u32 le32_to_cpu (__u32 val) { return cpu_to_le32 (val); } inline __u16 cpu_to_le16 (__u16 val) { return val; if (endianess == ENDIANESS_NOT_DEFINED) find_endianess (); if (endianess == LITTLE_ENDIAN_ARCH) return val; die ("neither big- nor pdp- endian arch are supported yet "); return (val >> 8) | (val << 8); } inline __u16 le16_to_cpu (__u16 val) { /*printf ("%s:%u %p %p %p\n", __FILE__, __LINE__, __builtin_return_address (0), __builtin_return_address (1), __builtin_return_address (2));*/ return val; return cpu_to_le16 (val); } inline __u64 cpu_to_le64 (__u64 val) { if (endianess == ENDIANESS_NOT_DEFINED) find_endianess (); if (endianess == LITTLE_ENDIAN_ARCH) return val; die ("neither big- nor pdp- endian arch are supported yet "); return 0; } inline __u64 le64_to_cpu (__u64 val) { return cpu_to_le64 (val); } /* Given a file descriptor and an offset, check whether the offset is a valid offset for the file - return 0 if it isn't valid or 1 if it is */ loff_t reiserfs_llseek (unsigned int fd, loff_t offset, unsigned int origin); #if 0 static int valid_offset( int fd, loff_t offset ) { char ch; loff_t res; /*res = reiserfs_llseek (fd, offset, 0);*/ res = lseek64 (fd, offset, 0); if (res < 0) return 0; if (read (fd, &ch, 1) < 1) return 0; return 1; } #endif /* calculates number of blocks on device */ unsigned long count_blocks (char * filename, int blocksize, int fd) { loff_t high, low; int opened_here = 0; if (fd < 0) { fd = open (filename, O_RDONLY); opened_here = 1; } if (fd < 0) die ("count_blocks: open failed (%s)", strerror (errno)); #ifdef BLKGETSIZE { long size; if (ioctl (fd, BLKGETSIZE, &size) >= 0) { if (opened_here) close (fd); return size / (blocksize / 512); } } #endif low = 0; for( high = 1; valid_offset (fd, high); high *= 2 ) low = high; while (low < high - 1) { const loff_t mid = ( low + high ) / 2; if (valid_offset (fd, mid)) low = mid; else high = mid; } valid_offset (fd, 0); if (opened_here) close (fd); return (low + 1) / (blocksize); } reiserfsprogs-3.x.0j/reiserfscore/0000777000076400001440000000000007261220336013132 5reiserfsprogs-3.x.0j/reiserfscore/Makefile.in0000644000076400001440000001720207261220336015115 # Makefile.in generated automatically by automake 1.4 from Makefile.am # Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. # This Makefile.in 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. SHELL = @SHELL@ srcdir = @srcdir@ top_srcdir = @top_srcdir@ VPATH = @srcdir@ prefix = @prefix@ exec_prefix = @exec_prefix@ bindir = @bindir@ sbindir = @sbindir@ libexecdir = @libexecdir@ datadir = @datadir@ sysconfdir = @sysconfdir@ sharedstatedir = @sharedstatedir@ localstatedir = @localstatedir@ libdir = @libdir@ infodir = @infodir@ mandir = @mandir@ includedir = @includedir@ oldincludedir = /usr/include DESTDIR = pkgdatadir = $(datadir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ top_builddir = .. ACLOCAL = @ACLOCAL@ AUTOCONF = @AUTOCONF@ AUTOMAKE = @AUTOMAKE@ AUTOHEADER = @AUTOHEADER@ INSTALL = @INSTALL@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS) INSTALL_DATA = @INSTALL_DATA@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ transform = @program_transform_name@ NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : CC = @CC@ MAKEINFO = @MAKEINFO@ PACKAGE = @PACKAGE@ RANLIB = @RANLIB@ VERSION = @VERSION@ noinst_LIBRARIES = libcore.a libcore_a_SOURCES = do_balan.c fix_node.c hashes.c ibalance.c lbalance.c prints.c stree.c node_formats.c reiserfslib.c bitmap.c includes.h INCLUDES = -I../include mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs CONFIG_CLEAN_FILES = LIBRARIES = $(noinst_LIBRARIES) DEFS = @DEFS@ -I. -I$(srcdir) CPPFLAGS = @CPPFLAGS@ LDFLAGS = @LDFLAGS@ LIBS = @LIBS@ libcore_a_LIBADD = libcore_a_OBJECTS = do_balan.o fix_node.o hashes.o ibalance.o \ lbalance.o prints.o stree.o node_formats.o reiserfslib.o bitmap.o AR = ar CFLAGS = @CFLAGS@ COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ DIST_COMMON = Makefile.am Makefile.in DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) TAR = tar GZIP_ENV = --best SOURCES = $(libcore_a_SOURCES) OBJECTS = $(libcore_a_OBJECTS) all: all-redirect .SUFFIXES: .SUFFIXES: .S .c .o .s $(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps reiserfscore/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status cd $(top_builddir) \ && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status mostlyclean-noinstLIBRARIES: clean-noinstLIBRARIES: -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) distclean-noinstLIBRARIES: maintainer-clean-noinstLIBRARIES: .c.o: $(COMPILE) -c $< .s.o: $(COMPILE) -c $< .S.o: $(COMPILE) -c $< mostlyclean-compile: -rm -f *.o core *.core clean-compile: distclean-compile: -rm -f *.tab.c maintainer-clean-compile: libcore.a: $(libcore_a_OBJECTS) $(libcore_a_DEPENDENCIES) -rm -f libcore.a $(AR) cru libcore.a $(libcore_a_OBJECTS) $(libcore_a_LIBADD) $(RANLIB) libcore.a tags: TAGS ID: $(HEADERS) $(SOURCES) $(LISP) list='$(SOURCES) $(HEADERS)'; \ unique=`for i in $$list; do echo $$i; done | \ awk ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ here=`pwd` && cd $(srcdir) \ && mkid -f$$here/ID $$unique $(LISP) TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) tags=; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS)'; \ unique=`for i in $$list; do echo $$i; done | \ awk ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) mostlyclean-tags: clean-tags: distclean-tags: -rm -f TAGS ID maintainer-clean-tags: distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) subdir = reiserfscore distdir: $(DISTFILES) @for file in $(DISTFILES); do \ d=$(srcdir); \ if test -d $$d/$$file; then \ cp -pr $$/$$file $(distdir)/$$file; \ else \ test -f $(distdir)/$$file \ || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ || cp -p $$d/$$file $(distdir)/$$file || :; \ fi; \ done bitmap.o: bitmap.c includes.h ../include/io.h ../include/misc.h \ ../include/reiserfs_lib.h ../include/reiserfs_fs.h do_balan.o: do_balan.c includes.h ../include/io.h ../include/misc.h \ ../include/reiserfs_lib.h ../include/reiserfs_fs.h fix_node.o: fix_node.c includes.h ../include/io.h ../include/misc.h \ ../include/reiserfs_lib.h ../include/reiserfs_fs.h hashes.o: hashes.c ibalance.o: ibalance.c includes.h ../include/io.h ../include/misc.h \ ../include/reiserfs_lib.h ../include/reiserfs_fs.h lbalance.o: lbalance.c includes.h ../include/io.h ../include/misc.h \ ../include/reiserfs_lib.h ../include/reiserfs_fs.h node_formats.o: node_formats.c includes.h ../include/io.h \ ../include/misc.h ../include/reiserfs_lib.h \ ../include/reiserfs_fs.h prints.o: prints.c includes.h ../include/io.h ../include/misc.h \ ../include/reiserfs_lib.h ../include/reiserfs_fs.h reiserfslib.o: reiserfslib.c includes.h ../include/io.h \ ../include/misc.h ../include/reiserfs_lib.h \ ../include/reiserfs_fs.h stree.o: stree.c includes.h ../include/io.h ../include/misc.h \ ../include/reiserfs_lib.h ../include/reiserfs_fs.h info-am: info: info-am dvi-am: dvi: dvi-am check-am: all-am check: check-am installcheck-am: installcheck: installcheck-am install-exec-am: install-exec: install-exec-am install-data-am: install-data: install-data-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am install: install-am uninstall-am: uninstall: uninstall-am all-am: Makefile $(LIBRARIES) all-redirect: all-am install-strip: $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install installdirs: mostlyclean-generic: clean-generic: distclean-generic: -rm -f Makefile $(CONFIG_CLEAN_FILES) -rm -f config.cache config.log stamp-h stamp-h[0-9]* maintainer-clean-generic: mostlyclean-am: mostlyclean-noinstLIBRARIES mostlyclean-compile \ mostlyclean-tags mostlyclean-generic mostlyclean: mostlyclean-am clean-am: clean-noinstLIBRARIES clean-compile clean-tags clean-generic \ mostlyclean-am clean: clean-am distclean-am: distclean-noinstLIBRARIES distclean-compile \ distclean-tags distclean-generic clean-am distclean: distclean-am maintainer-clean-am: maintainer-clean-noinstLIBRARIES \ maintainer-clean-compile maintainer-clean-tags \ maintainer-clean-generic distclean-am @echo "This command is intended for maintainers to use;" @echo "it deletes files that may require special tools to rebuild." maintainer-clean: maintainer-clean-am .PHONY: mostlyclean-noinstLIBRARIES distclean-noinstLIBRARIES \ clean-noinstLIBRARIES maintainer-clean-noinstLIBRARIES \ mostlyclean-compile distclean-compile clean-compile \ maintainer-clean-compile tags mostlyclean-tags distclean-tags \ clean-tags maintainer-clean-tags distdir info-am info dvi-am dvi check \ check-am installcheck-am installcheck install-exec-am install-exec \ install-data-am install-data install-am install uninstall-am uninstall \ all-redirect all-am all installdirs mostlyclean-generic \ distclean-generic clean-generic maintainer-clean-generic clean \ mostlyclean distclean maintainer-clean # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: reiserfsprogs-3.x.0j/reiserfscore/Makefile.am0000644000076400001440000000030207226223043015074 noinst_LIBRARIES = libcore.a libcore_a_SOURCES = do_balan.c fix_node.c hashes.c ibalance.c lbalance.c prints.c stree.c node_formats.c reiserfslib.c bitmap.c includes.h INCLUDES = -I../include reiserfsprogs-3.x.0j/reiserfscore/do_balan.c0000644000076400001440000016431507260373642014773 /* * Copyright 1996, 1997, 1998 Hans Reiser, see reiserfs/README for licensing and copyright details */ /* Now we have all buffers that must be used in balancing of the tree */ /* Further calculations can not cause schedule(), and thus the buffer */ /* tree will be stable until the balancing will be finished */ /* balance the tree according to the analysis made before, */ /* and using buffers obtained after all above. */ /** ** balance_leaf_when_delete ** balance_leaf ** do_balance ** **/ #include "includes.h" #ifdef CONFIG_REISERFS_CHECK struct tree_balance * cur_tb = NULL; /* detects whether more than one copy of tb exists as a means of checking whether schedule is interrupting do_balance */ struct tree_balance init_tb; /* Sometimes used to store a snapshot of tb during debugging. */ int init_item_pos, init_pos_in_item, init_mode; /* Sometimes used to store a snapshot of tb during debugging. */ #endif /* CONFIG_REISERFS_CHECK */ /* summary: if deleting something ( tb->insert_size[0] < 0 ) return(balance_leaf_when_delete()); (flag d handled here) else if lnum is larger than 0 we put items into the left node if rnum is larger than 0 we put items into the right node if snum1 is larger than 0 we put items into the new node s1 if snum2 is larger than 0 we put items into the new node s2 Note that all *num* count new items being created. It would be easier to read balance_leaf() if each of these summary lines was a separate procedure rather than being inlined. I think that there are many passages here and in balance_leaf_when_delete() in which two calls to one procedure can replace two passages, and it might save cache space and improve software maintenance costs to do so. Vladimir made the perceptive comment that we should offload most of the decision making in this function into fix_nodes/check_balance, and then create some sort of structure in tb that says what actions should be performed by do_balance. -Hans */ /* Balance leaf node in case of delete or cut: insert_size[0] < 0 * * lnum, rnum can have values >= -1 * -1 means that the neighbor must be joined with S * 0 means that nothing should be done with the neighbor * >0 means to shift entirely or partly the specified number of items to the neighbor */ static int balance_leaf_when_delete (/*struct reiserfs_transaction_handle *th,*/ struct tree_balance * tb, int flag) { struct buffer_head * tbS0 = PATH_PLAST_BUFFER (tb->tb_path); int item_pos = PATH_LAST_POSITION (tb->tb_path); int pos_in_item = tb->tb_path->pos_in_item; struct buffer_info bi; int n; struct item_head * ih; #ifdef CONFIG_REISERFS_CHECK if ( tb->FR[0] && B_BLK_HEAD(tb->FR[0])->blk_level <= DISK_LEAF_NODE_LEVEL ) reiserfs_panic (tb->tb_sb, "balance_leaf_when_delete: 11999:level == %u\n", B_BLK_HEAD(tb->FR[0])->blk_level); if ( tb->blknum[0] > 1 ) reiserfs_panic (tb->tb_sb, "PAP-12005: balance_leaf_when_delete: tb->blknum == %d, can not be > 1", tb->blknum[0]); if ( ! tb->blknum[0] && ! PATH_H_PPARENT(tb->tb_path, 0)) reiserfs_panic (tb->tb_sb, "PAP-12010: balance_leaf_when_delete: tree can not be empty"); #endif ih = B_N_PITEM_HEAD (tbS0, item_pos); /* Delete or truncate the item */ switch (flag) { case M_DELETE: /* delete item in S[0] */ bi.bi_bh = tbS0; bi.bi_parent = PATH_H_PPARENT (tb->tb_path, 0); bi.bi_position = PATH_H_POSITION (tb->tb_path, 1); leaf_delete_items (tb->tb_sb, &bi, 0, item_pos, 1, -1); #ifdef CONFIG_REISERFS_CHECK if (! item_pos && !tb->CFL[0]) reiserfs_panic (tb->tb_sb, "PAP-12020: balance_leaf_when_delete: " "tb->CFL[0]==0 when item_pos == 0"); #endif if ( ! item_pos ) { // we have removed first item in the node - update left delimiting key if ( B_NR_ITEMS(tbS0) ) { replace_key(tb->tb_sb, tb->CFL[0],tb->lkey[0],tbS0,0); } else { if ( ! PATH_H_POSITION (tb->tb_path, 1) ) replace_key(tb->tb_sb, tb->CFL[0],tb->lkey[0],PATH_H_PPARENT(tb->tb_path, 0),0); } } break; case M_CUT: { /* cut item in S[0] */ bi.bi_bh = tbS0; bi.bi_parent = PATH_H_PPARENT (tb->tb_path, 0); bi.bi_position = PATH_H_POSITION (tb->tb_path, 1); if (I_IS_DIRECTORY_ITEM (ih)) { /* UFS unlink semantics are such that you can only delete one directory entry at a time. */ /* when we cut a directory tb->insert_size[0] means number of entries to be cut (always 1) */ tb->insert_size[0] = -1; leaf_cut_from_buffer (tb->tb_sb, &bi, item_pos, pos_in_item, -tb->insert_size[0]); #ifdef CONFIG_REISERFS_CHECK if (! item_pos && ! pos_in_item && ! tb->CFL[0]) reiserfs_panic (tb->tb_sb, "PAP-12030: balance_leaf_when_delete: can not change delimiting key. CFL[0]=%p", tb->CFL[0]); #endif /* CONFIG_REISERFS_CHECK */ if ( ! item_pos && ! pos_in_item ) { replace_key(tb->tb_sb, tb->CFL[0],tb->lkey[0],tbS0,0); } } else { leaf_cut_from_buffer (tb->tb_sb, &bi, item_pos, pos_in_item, -tb->insert_size[0]); #ifdef CONFIG_REISERFS_CHECK if (! ih->ih_item_len) reiserfs_panic (tb->tb_sb, "PAP-12035: balance_leaf_when_delete: cut must leave non-zero dynamic length of item"); #endif /* CONFIG_REISERFS_CHECK */ } break; } default: print_tb(flag, item_pos, pos_in_item, tb,"when_del"); reiserfs_panic ("PAP-12040: balance_leaf_when_delete: unexpectable mode: %s(%d)", (flag == M_PASTE) ? "PASTE" : ((flag == M_INSERT) ? "INSERT" : "UNKNOWN"), flag); } /* the rule is that no shifting occurs unless by shifting a node can be freed */ n = B_NR_ITEMS(tbS0); if ( tb->lnum[0] ) /* L[0] takes part in balancing */ { if ( tb->lnum[0] == -1 ) /* L[0] must be joined with S[0] */ { if ( tb->rnum[0] == -1 ) /* R[0] must be also joined with S[0] */ { if ( tb->FR[0] == PATH_H_PPARENT(tb->tb_path, 0) ) { /* all contents of all the 3 buffers will be in L[0] */ if ( PATH_H_POSITION (tb->tb_path, 1) == 0 && 1 < B_NR_ITEMS(tb->FR[0]) ) replace_key(tb->tb_sb, tb->CFL[0],tb->lkey[0],tb->FR[0],1); leaf_move_items (LEAF_FROM_S_TO_L, tb, n, -1, 0); leaf_move_items (LEAF_FROM_R_TO_L, tb, B_NR_ITEMS(tb->R[0]), -1, 0); reiserfs_invalidate_buffer (tb, tbS0, 1/*do_free_block*/); reiserfs_invalidate_buffer (tb, tb->R[0], 1/*do_free_block*/); return 0; } /* all contents of all the 3 buffers will be in R[0] */ leaf_move_items(LEAF_FROM_S_TO_R, tb, n, -1, 0); leaf_move_items(LEAF_FROM_L_TO_R, tb, B_NR_ITEMS(tb->L[0]), -1, 0); /* right_delimiting_key is correct in R[0] */ replace_key(tb->tb_sb, tb->CFR[0],tb->rkey[0],tb->R[0],0); reiserfs_invalidate_buffer (tb, tbS0, 1/*do_free_block*/); reiserfs_invalidate_buffer (tb, tb->L[0], 1/*do_free_block*/); return -1; } #ifdef CONFIG_REISERFS_CHECK if ( tb->rnum[0] != 0 ) reiserfs_panic (tb->tb_sb, "PAP-12045: balance_leaf_when_delete: rnum must be 0 (%d)", tb->rnum[0]); #endif /* CONFIG_REISERFS_CHECK */ /* all contents of L[0] and S[0] will be in L[0] */ leaf_shift_left(tb, n, -1); reiserfs_invalidate_buffer (tb, tbS0, 1/*do_free_block*/); return 0; } /* a part of contents of S[0] will be in L[0] and the rest part of S[0] will be in R[0] */ #ifdef CONFIG_REISERFS_CHECK if (( tb->lnum[0] + tb->rnum[0] < n ) || ( tb->lnum[0] + tb->rnum[0] > n+1 )) reiserfs_panic (tb->tb_sb, "PAP-12050: balance_leaf_when_delete: rnum(%d) and lnum(%d) and item number in S[0] are not consistent", tb->rnum[0], tb->lnum[0], n); if (( tb->lnum[0] + tb->rnum[0] == n ) && (tb->lbytes != -1 || tb->rbytes != -1)) reiserfs_panic (tb->tb_sb, "PAP-12055: balance_leaf_when_delete: bad rbytes (%d)/lbytes (%d) parameters when items are not split", tb->rbytes, tb->lbytes); if (( tb->lnum[0] + tb->rnum[0] == n + 1 ) && (tb->lbytes < 1 || tb->rbytes != -1)) reiserfs_panic (tb->tb_sb, "PAP-12060: balance_leaf_when_delete: bad rbytes (%d)/lbytes (%d) parameters when items are split", tb->rbytes, tb->lbytes); #endif leaf_shift_left (tb, tb->lnum[0], tb->lbytes); leaf_shift_right(tb, tb->rnum[0], tb->rbytes); reiserfs_invalidate_buffer (tb, tbS0, 1/*do_free_block*/); return 0; } if ( tb->rnum[0] == -1 ) { /* all contents of R[0] and S[0] will be in R[0] */ leaf_shift_right(tb, n, -1); reiserfs_invalidate_buffer (tb, tbS0, 1/*do_free_block*/); return 0; } #ifdef CONFIG_REISERFS_CHECK if ( tb->rnum[0] ) reiserfs_panic (tb->tb_sb, "PAP-12065: balance_leaf_when_delete: bad rnum parameter must be 0 (%d)", tb->rnum[0]); #endif return 0; } static int balance_leaf(/*struct reiserfs_transaction_handle *th, */ struct tree_balance * tb, /* see reiserfs_fs.h */ struct item_head * ih, /* item header of inserted item */ const char * body, /* body of inserted item or bytes to paste */ int flag, /* i - insert, d - delete, c - cut, p - paste (see comment to do_balance) */ int zeros_number, /* will be commented later */ struct item_head * insert_key, /* in our processing of one level we sometimes determine what must be inserted into the next higher level. This insertion consists of a key or two keys and their corresponding pointers */ struct buffer_head ** insert_ptr /* inserted node-ptrs for the next level */ ) { int pos_in_item = tb->tb_path->pos_in_item; /* position in item, in bytes for direct and indirect items, in entries for directories (for which it is an index into the array of directory entry headers.) */ struct buffer_head * tbS0 = PATH_PLAST_BUFFER (tb->tb_path); /* struct buffer_head * tbF0 = PATH_H_PPARENT (tb->tb_path, 0); int S0_b_item_order = PATH_H_B_ITEM_ORDER (tb->tb_path, 0);*/ int item_pos = PATH_LAST_POSITION (tb->tb_path); /* index into the array of item headers in S[0] of the affected item */ struct buffer_info bi; struct buffer_head *S_new[2]; /* new nodes allocated to hold what could not fit into S */ int snum[2]; /* number of items that will be placed into S_new (includes partially shifted items) */ int sbytes[2]; /* if an item is partially shifted into S_new then if it is a directory item it is the number of entries from the item that are shifted into S_new else it is the number of bytes from the item that are shifted into S_new */ int n, i; int ret_val; /* Make balance in case insert_size[0] < 0 */ if ( tb->insert_size[0] < 0 ) return balance_leaf_when_delete (/*th,*/ tb, flag); /* for indirect item pos_in_item is measured in unformatted node pointers. Recalculate to bytes */ if (flag != M_INSERT && I_IS_INDIRECT_ITEM (B_N_PITEM_HEAD (tbS0, item_pos))) pos_in_item *= UNFM_P_SIZE; if ( tb->lnum[0] > 0 ) { /* Shift lnum[0] items from S[0] to the left neighbor L[0] */ if ( item_pos < tb->lnum[0] ) { /* new item or it part falls to L[0], shift it too */ n = B_NR_ITEMS(tb->L[0]); switch (flag) { case M_INSERT: /* insert item into L[0] */ if ( item_pos == tb->lnum[0] - 1 && tb->lbytes != -1 ) { /* part of new item falls into L[0] */ int new_item_len; #ifdef CONFIG_REISERFS_CHECK if (!I_IS_DIRECT_ITEM (ih)) reiserfs_panic (tb->tb_sb, "PAP-12075: balance_leaf: " "this item (%h) can not be split on insertion", ih); #endif ret_val = leaf_shift_left (/*th,*/ tb, tb->lnum[0]-1, -1); /* Calculate item length to insert to S[0] */ new_item_len = ih->ih_item_len - tb->lbytes; /* Calculate and check item length to insert to L[0] */ ih->ih_item_len -= new_item_len; #ifdef CONFIG_REISERFS_CHECK if ( (int)(ih->ih_item_len) <= 0 ) reiserfs_panic(tb->tb_sb, "PAP-12080: balance_leaf: " "there is nothing to insert into L[0]: ih_item_len=%d", (int)ih->ih_item_len); #endif /* Insert new item into L[0] */ bi.bi_bh = tb->L[0]; bi.bi_parent = tb->FL[0]; bi.bi_position = get_left_neighbor_position (tb, 0); leaf_insert_into_buf (tb->tb_sb, &bi, n + item_pos - ret_val, ih, body, zeros_number > ih->ih_item_len ? ih->ih_item_len : zeros_number); /* Calculate key component, item length and body to insert into S[0] */ //ih->ih_key.k_offset += tb->lbytes; set_offset (key_format (&ih->ih_key), &ih->ih_key, get_offset (&ih->ih_key) + tb->lbytes); ih->ih_item_len = new_item_len; if ( tb->lbytes > zeros_number ) { body += (tb->lbytes - zeros_number); zeros_number = 0; } else zeros_number -= tb->lbytes; #ifdef CONFIG_REISERFS_CHECK if ( (int)(ih->ih_item_len) <= 0 ) reiserfs_panic(tb->tb_sb, "PAP-12085: balance_leaf: " "there is nothing to insert into S[0]: ih_item_len=%d", (int)ih->ih_item_len); #endif } else { /* new item in whole falls into L[0] */ /* Shift lnum[0]-1 items to L[0] */ ret_val = leaf_shift_left(tb, tb->lnum[0]-1, tb->lbytes); /* Insert new item into L[0] */ bi.bi_bh = tb->L[0]; bi.bi_parent = tb->FL[0]; bi.bi_position = get_left_neighbor_position (tb, 0); leaf_insert_into_buf (tb->tb_sb, &bi, n + item_pos - ret_val, ih, body, zeros_number); tb->insert_size[0] = 0; zeros_number = 0; } break; case M_PASTE: /* append item in L[0] */ if ( item_pos == tb->lnum[0] - 1 && tb->lbytes != -1 ) { /* we must shift the part of the appended item */ if ( I_IS_DIRECTORY_ITEM (B_N_PITEM_HEAD (tbS0, item_pos))) { #ifdef CONFIG_REISERFS_CHECK if ( zeros_number ) reiserfs_panic(tb->tb_sb, "PAP-12090: balance_leaf: illegal parameter in case of a directory"); #endif /* directory item */ if ( tb->lbytes > pos_in_item ) { /* new directory entry falls into L[0] */ struct item_head * pasted; int l_pos_in_item = pos_in_item; /* Shift lnum[0] - 1 items in whole. Shift lbytes - 1 entries from given directory item */ ret_val = leaf_shift_left(tb, tb->lnum[0], tb->lbytes - 1); if ( ret_val && ! item_pos ) { pasted = B_N_PITEM_HEAD(tb->L[0],B_NR_ITEMS(tb->L[0])-1); l_pos_in_item += ih_entry_count(pasted) - (tb->lbytes-1); } /* Append given directory entry to directory item */ bi.bi_bh = tb->L[0]; bi.bi_parent = tb->FL[0]; bi.bi_position = get_left_neighbor_position (tb, 0); leaf_paste_in_buffer (tb->tb_sb, &bi, n + item_pos - ret_val, l_pos_in_item, tb->insert_size[0], body, zeros_number); /* previous string prepared space for pasting new entry, following string pastes this entry */ /* when we have merge directory item, pos_in_item has been changed too */ /* paste new directory entry. 1 is entry number */ leaf_paste_entries (bi.bi_bh, n + item_pos - ret_val, l_pos_in_item, 1, (struct reiserfs_de_head *)body, body + DEH_SIZE, tb->insert_size[0] ); tb->insert_size[0] = 0; } else { /* new directory item doesn't fall into L[0] */ /* Shift lnum[0]-1 items in whole. Shift lbytes directory entries from directory item number lnum[0] */ leaf_shift_left (tb, tb->lnum[0], tb->lbytes); } /* Calculate new position to append in item body */ pos_in_item -= tb->lbytes; } else { /* regular object */ #ifdef CONFIG_REISERFS_CHECK if ( tb->lbytes <= 0 ) reiserfs_panic(tb->tb_sb, "PAP-12095: balance_leaf: " "there is nothing to shift to L[0]. lbytes=%d", tb->lbytes); if ( pos_in_item != B_N_PITEM_HEAD(tbS0, item_pos)->ih_item_len ) reiserfs_panic(tb->tb_sb, "PAP-12100: balance_leaf: " "incorrect position to paste: item_len=%d, pos_in_item=%d", B_N_PITEM_HEAD(tbS0,item_pos)->ih_item_len, pos_in_item); #endif if ( tb->lbytes >= pos_in_item ) { /* appended item will be in L[0] in whole */ int l_n; struct key * key; /* this bytes number must be appended to the last item of L[h] */ l_n = tb->lbytes - pos_in_item; /* Calculate new insert_size[0] */ tb->insert_size[0] -= l_n; #ifdef CONFIG_REISERFS_CHECK if ( tb->insert_size[0] <= 0 ) reiserfs_panic(tb->tb_sb, "PAP-12105: balance_leaf: " "there is nothing to paste into L[0]. insert_size=%d", tb->insert_size[0]); #endif ret_val = leaf_shift_left(tb, tb->lnum[0], B_N_PITEM_HEAD(tbS0,item_pos)->ih_item_len); /* Append to body of item in L[0] */ bi.bi_bh = tb->L[0]; bi.bi_parent = tb->FL[0]; bi.bi_position = get_left_neighbor_position (tb, 0); leaf_paste_in_buffer(tb->tb_sb, &bi,n + item_pos - ret_val, B_N_PITEM_HEAD(tb->L[0],n+item_pos-ret_val)->ih_item_len, l_n,body, zeros_number > l_n ? l_n : zeros_number ); #ifdef CONFIG_REISERFS_CHECK if (l_n && I_IS_INDIRECT_ITEM(B_N_PITEM_HEAD(tb->L[0], n + item_pos - ret_val))) reiserfs_panic(tb->tb_sb, "PAP-12110: balance_leaf: " "pasting more than 1 unformatted node pointer into indirect item"); #endif /* 0-th item in S0 can be only of DIRECT type when l_n != 0*/ //B_N_PKEY (tbS0, 0)->k_offset += l_n; key = B_N_PKEY (tbS0, 0); set_offset (key_format (key), key, get_offset (key) + l_n); //B_N_PDELIM_KEY(tb->CFL[0],tb->lkey[0])->k_offset += l_n; key = B_N_PDELIM_KEY(tb->CFL[0],tb->lkey[0]); set_offset (key_format (key), key, get_offset (key) + l_n); /* Calculate new body, position in item and insert_size[0] */ if ( l_n > zeros_number ) { body += (l_n - zeros_number); zeros_number = 0; } else zeros_number -= l_n; pos_in_item = 0; #ifdef CONFIG_REISERFS_CHECK if (not_of_one_file (B_N_PKEY(tbS0,0), B_N_PKEY(tb->L[0],B_NR_ITEMS(tb->L[0])-1)) || !is_left_mergeable (B_N_PITEM_HEAD (tbS0, 0), tbS0->b_size) || !is_left_mergeable((struct item_head *)B_N_PDELIM_KEY(tb->CFL[0],tb->lkey[0]), tbS0->b_size)) reiserfs_panic (tb->tb_sb, "PAP-12120: balance_leaf: " "item must be merge-able with left neighboring item"); #endif } else { /* only part of the appended item will be in L[0] */ /* Calculate position in item for append in S[0] */ pos_in_item -= tb->lbytes; #ifdef CONFIG_REISERFS_CHECK if ( pos_in_item <= 0 ) reiserfs_panic(tb->tb_sb, "PAP-12125: balance_leaf: " "no place for paste. pos_in_item=%d", pos_in_item); #endif /* Shift lnum[0] - 1 items in whole. Shift lbytes - 1 byte from item number lnum[0] */ leaf_shift_left(tb,tb->lnum[0],tb->lbytes); } } } else { /* appended item will be in L[0] in whole */ struct item_head * pasted; #ifndef FU//REISERFS_FSCK // this works if ( ! item_pos && is_left_mergeable (tb->tb_sb, tb->tb_path) == 1 ) #else if ( ! item_pos && is_left_mergeable (B_N_PITEM_HEAD (tbS0, 0), tbS0->b_size) ) #endif { /* if we paste into first item of S[0] and it is left mergable */ /* then increment pos_in_item by the size of the last item in L[0] */ pasted = B_N_PITEM_HEAD(tb->L[0],n-1); if ( I_IS_DIRECTORY_ITEM(pasted) ) pos_in_item += ih_entry_count (pasted); else pos_in_item += pasted->ih_item_len; } /* Shift lnum[0] - 1 items in whole. Shift lbytes - 1 byte from item number lnum[0] */ ret_val = leaf_shift_left(tb, tb->lnum[0], tb->lbytes); /* Append to body of item in L[0] */ bi.bi_bh = tb->L[0]; bi.bi_parent = tb->FL[0]; bi.bi_position = get_left_neighbor_position (tb, 0); leaf_paste_in_buffer (tb->tb_sb, &bi, n + item_pos - ret_val, pos_in_item, tb->insert_size[0], body, zeros_number); /* if appended item is directory, paste entry */ pasted = B_N_PITEM_HEAD (tb->L[0], n + item_pos - ret_val); if (I_IS_DIRECTORY_ITEM (pasted)) leaf_paste_entries (bi.bi_bh, n + item_pos - ret_val, pos_in_item, 1, (struct reiserfs_de_head *)body, body + DEH_SIZE, tb->insert_size[0]); /* if appended item is indirect item, put unformatted node into un list */ if (I_IS_INDIRECT_ITEM (pasted)) set_free_space (pasted, ((struct unfm_nodeinfo*)body)->unfm_freespace); //pasted->u.ih_free_space = ((struct unfm_nodeinfo*)body)->unfm_freespace; tb->insert_size[0] = 0; zeros_number = 0; } break; default: /* cases d and t */ reiserfs_panic ("PAP-12130: balance_leaf: lnum > 0: unexpectable mode: %s(%d)", (flag == M_DELETE) ? "DELETE" : ((flag == M_CUT) ? "CUT" : "UNKNOWN"), flag); } } else { /* new item doesn't fall into L[0] */ leaf_shift_left (tb, tb->lnum[0], tb->lbytes); } } /* tb->lnum[0] > 0 */ /* Calculate new item position */ item_pos -= ( tb->lnum[0] - (( tb->lbytes != -1 ) ? 1 : 0)); if ( tb->rnum[0] > 0 ) { /* shift rnum[0] items from S[0] to the right neighbor R[0] */ n = B_NR_ITEMS(tbS0); switch ( flag ) { case M_INSERT: /* insert item */ if ( n - tb->rnum[0] < item_pos ) { /* new item or its part falls to R[0] */ if ( item_pos == n - tb->rnum[0] + 1 && tb->rbytes != -1 ) { /* part of new item falls into R[0] */ int old_key_comp, old_len, r_zeros_number; const char * r_body; #ifdef CONFIG_REISERFS_CHECK if ( !I_IS_DIRECT_ITEM(ih) ) reiserfs_panic(tb->tb_sb, "PAP-12135: balance_leaf: " "this item (%h) can not be split", ih); #endif leaf_shift_right(tb, tb->rnum[0] - 1, -1); /* Remember key component and item length */ old_key_comp = get_offset (&ih->ih_key); old_len = ih->ih_item_len; /* Calculate key component and item length to insert into R[0] */ //ih->ih_key.k_offset += (old_len - tb->rbytes); set_offset (key_format (&ih->ih_key), &ih->ih_key, old_key_comp + old_len - tb->rbytes); ih->ih_item_len = tb->rbytes; /* Insert part of the item into R[0] */ bi.bi_bh = tb->R[0]; bi.bi_parent = tb->FR[0]; bi.bi_position = get_right_neighbor_position (tb, 0); if ( get_offset (&ih->ih_key) - old_key_comp > zeros_number ) { r_zeros_number = 0; r_body = body + get_offset (&ih->ih_key) - old_key_comp - zeros_number; } else { r_body = body; r_zeros_number = zeros_number - (get_offset (&ih->ih_key) - old_key_comp); zeros_number -= r_zeros_number; } leaf_insert_into_buf (tb->tb_sb, &bi, 0, ih, r_body, r_zeros_number); /* Replace right delimiting key by first key in R[0] */ replace_key(tb->tb_sb, tb->CFR[0],tb->rkey[0],tb->R[0],0); /* Calculate key component and item length to insert into S[0] */ //ih->ih_key.k_offset = old_key_comp; set_offset (key_format (&ih->ih_key), &ih->ih_key, old_key_comp); ih->ih_item_len = old_len - tb->rbytes; tb->insert_size[0] -= tb->rbytes; } else { /* whole new item falls into R[0] */ /* Shift rnum[0]-1 items to R[0] */ ret_val = leaf_shift_right(tb, tb->rnum[0] - 1, tb->rbytes); /* Insert new item into R[0] */ bi.bi_bh = tb->R[0]; bi.bi_parent = tb->FR[0]; bi.bi_position = get_right_neighbor_position (tb, 0); leaf_insert_into_buf (tb->tb_sb, &bi, item_pos - n + tb->rnum[0] - 1, ih, body, zeros_number); /* If we insert new item in the begin of R[0] change the right delimiting key */ if ( item_pos - n + tb->rnum[0] - 1 == 0 ) { replace_key (tb->tb_sb, tb->CFR[0],tb->rkey[0],tb->R[0],0); } zeros_number = tb->insert_size[0] = 0; } } else { /* new item or part of it doesn't fall into R[0] */ leaf_shift_right (tb, tb->rnum[0], tb->rbytes); } break; case M_PASTE: /* append item */ if ( n - tb->rnum[0] <= item_pos ) { /* pasted item or part of it falls to R[0] */ if ( item_pos == n - tb->rnum[0] && tb->rbytes != -1 ) { /* we must shift the part of the appended item */ if ( I_IS_DIRECTORY_ITEM (B_N_PITEM_HEAD(tbS0, item_pos))) { /* we append to directory item */ int entry_count; #ifdef CONFIG_REISERFS_CHECK if ( zeros_number ) reiserfs_panic(tb->tb_sb, "PAP-12145: balance_leaf: " "illegal parameter in case of a directory"); #endif entry_count = ih_entry_count (B_N_PITEM_HEAD(tbS0, item_pos)); if ( entry_count - tb->rbytes < pos_in_item ) { /* new directory entry falls into R[0] */ int paste_entry_position; #ifdef CONFIG_REISERFS_CHECK if ( tb->rbytes - 1 >= entry_count || ! tb->insert_size[0] ) reiserfs_panic(tb->tb_sb, "PAP-12150: balance_leaf: " "no enough of entries to shift to R[0]: rbytes=%d, entry_count=%d", tb->rbytes, entry_count); #endif /* Shift rnum[0]-1 items in whole. Shift rbytes-1 directory entries from directory item number rnum[0] */ leaf_shift_right (tb, tb->rnum[0], tb->rbytes - 1); /* Paste given directory entry to directory item */ paste_entry_position = pos_in_item - entry_count + tb->rbytes - 1; bi.bi_bh = tb->R[0]; bi.bi_parent = tb->FR[0]; bi.bi_position = get_right_neighbor_position (tb, 0); leaf_paste_in_buffer (tb->tb_sb, &bi, 0, paste_entry_position, tb->insert_size[0],body,zeros_number); /* paste entry */ leaf_paste_entries ( bi.bi_bh, 0, paste_entry_position, 1, (struct reiserfs_de_head *)body, body + DEH_SIZE, tb->insert_size[0] ); if ( paste_entry_position == 0 ) { /* change delimiting keys */ replace_key(tb->tb_sb, tb->CFR[0],tb->rkey[0],tb->R[0],0); } tb->insert_size[0] = 0; pos_in_item++; } else { /* new directory entry doesn't fall into R[0] */ leaf_shift_right (tb, tb->rnum[0],tb->rbytes); } } else { /* regular object */ int n_shift, n_rem, r_zeros_number; const char * r_body; struct key * key; /* Calculate number of bytes which must be shifted from appended item */ if ( (n_shift = tb->rbytes - tb->insert_size[0]) < 0 ) n_shift = 0; #ifdef CONFIG_REISERFS_CHECK if (pos_in_item != B_N_PITEM_HEAD (tbS0, item_pos)->ih_item_len) reiserfs_panic(tb->tb_sb,"PAP-12155: balance_leaf: invalid position %d to paste item %h", pos_in_item, B_N_PITEM_HEAD(tbS0,item_pos)); #endif leaf_shift_right (tb, tb->rnum[0], n_shift); /* Calculate number of bytes which must remain in body after appending to R[0] */ if ( (n_rem = tb->insert_size[0] - tb->rbytes) < 0 ) n_rem = 0; //B_N_PKEY(tb->R[0],0)->k_offset += n_rem; key = B_N_PKEY(tb->R[0],0); set_offset (key_format (key), key, get_offset (key) + n_rem); //B_N_PDELIM_KEY(tb->CFR[0],tb->rkey[0])->k_offset += n_rem; key = B_N_PDELIM_KEY(tb->CFR[0],tb->rkey[0]); set_offset (key_format (key), key, get_offset (key) + n_rem); mark_buffer_dirty (tb->CFR[0]); /* Append part of body into R[0] */ bi.bi_bh = tb->R[0]; bi.bi_parent = tb->FR[0]; bi.bi_position = get_right_neighbor_position (tb, 0); if ( n_rem > zeros_number ) { r_zeros_number = 0; r_body = body + n_rem - zeros_number; } else { r_body = body; r_zeros_number = zeros_number - n_rem; zeros_number -= r_zeros_number; } leaf_paste_in_buffer(tb->tb_sb, &bi, 0, n_shift, tb->insert_size[0] - n_rem, r_body, r_zeros_number); if (I_IS_INDIRECT_ITEM(B_N_PITEM_HEAD(tb->R[0],0))) { #ifdef CONFIG_REISERFS_CHECK if (n_rem) reiserfs_panic(tb->tb_sb, "PAP-12160: balance_leaf: paste more than one unformatted node pointer"); #endif set_free_space (B_N_PITEM_HEAD(tb->R[0],0), ((struct unfm_nodeinfo*)body)->unfm_freespace); //B_N_PITEM_HEAD(tb->R[0],0)->u.ih_free_space = ((struct unfm_nodeinfo*)body)->unfm_freespace; } tb->insert_size[0] = n_rem; if ( ! n_rem ) pos_in_item ++; } } else { /* pasted item falls into R[0] entirely */ struct item_head * pasted; ret_val = leaf_shift_right (tb, tb->rnum[0], tb->rbytes); /* append item in R[0] */ if ( pos_in_item >= 0 ) { bi.bi_bh = tb->R[0]; bi.bi_parent = tb->FR[0]; bi.bi_position = get_right_neighbor_position (tb, 0); leaf_paste_in_buffer(tb->tb_sb, &bi,item_pos - n + tb->rnum[0], pos_in_item, tb->insert_size[0],body, zeros_number); } /* paste new entry, if item is directory item */ pasted = B_N_PITEM_HEAD(tb->R[0], item_pos - n + tb->rnum[0]); if (I_IS_DIRECTORY_ITEM (pasted) && pos_in_item >= 0 ) { leaf_paste_entries (bi.bi_bh, item_pos - n + tb->rnum[0], pos_in_item, 1, (struct reiserfs_de_head *)body, body + DEH_SIZE, tb->insert_size[0]); if ( ! pos_in_item ) { #ifdef CONFIG_REISERFS_CHECK if ( item_pos - n + tb->rnum[0] ) reiserfs_panic (tb->tb_sb, "PAP-12165: balance_leaf: " "directory item must be first item of node when pasting is in 0th position"); #endif /* update delimiting keys */ replace_key (tb->tb_sb, tb->CFR[0],tb->rkey[0],tb->R[0],0); } } if (I_IS_INDIRECT_ITEM (pasted)) //pasted->u.ih_free_space = ((struct unfm_nodeinfo*)body)->unfm_freespace; set_free_space (pasted, ((struct unfm_nodeinfo*)body)->unfm_freespace); zeros_number = tb->insert_size[0] = 0; } } else { /* new item doesn't fall into R[0] */ leaf_shift_right (tb, tb->rnum[0], tb->rbytes); } break; default: /* cases d and t */ reiserfs_panic ("PAP-12175: balance_leaf: rnum > 0: unexpectable mode: %s(%d)", (flag == M_DELETE) ? "DELETE" : ((flag == M_CUT) ? "CUT" : "UNKNOWN"), flag); } } /* tb->rnum[0] > 0 */ #ifdef CONFIG_REISERFS_CHECK if ( tb->blknum[0] > 3 ) reiserfs_panic (tb->tb_sb, "PAP-12180: balance_leaf: " "blknum can not be %d. It must be <= 3", tb->blknum[0]); if ( tb->blknum[0] < 0 ) reiserfs_panic (tb->tb_sb, "PAP-12185: balance_leaf: " "blknum can not be %d. It must be >= 0", tb->blknum[0]); if ( tb->blknum[0] == 0 && (! tb->lnum[0] || ! tb->rnum[0]) ) reiserfs_panic(tb->tb_sb, "PAP-12190: balance_leaf: lnum and rnum must not be zero"); #endif /* if while adding to a node we discover that it is possible to split it in two, and merge the left part into the left neighbor and the right part into the right neighbor, eliminating the node */ if ( tb->blknum[0] == 0 ) { /* node S[0] is empty now */ #ifdef CONFIG_REISERFS_CHECK if (!tb->CFL[0] || !tb->CFR[0] || !tb->R[0] || !tb->R[0] || COMP_KEYS (B_N_PDELIM_KEY (tb->CFR[0], tb->rkey[0]), B_N_PKEY (tb->R[0], 0))) reiserfs_panic (tb->tb_sb, "vs-12195: balance_leaf: " "right delim key (%k) is not set properly (%k)", B_N_PDELIM_KEY (tb->CFR[0], tb->rkey[0]), B_N_PKEY (tb->R[0], 0)); #endif reiserfs_invalidate_buffer(tb,tbS0, 1); return 0; } /* Fill new nodes that appear in place of S[0] */ /* I am told that this copying is because we need an array to enable the looping code. -Hans */ snum[0] = tb->s1num, snum[1] = tb->s2num; sbytes[0] = tb->s1bytes; sbytes[1] = tb->s2bytes; for( i = tb->blknum[0] - 2; i >= 0; i-- ) { #ifdef CONFIG_REISERFS_CHECK if (!snum[i]) reiserfs_panic(tb->tb_sb,"PAP-12200: balance_leaf: snum[%d] == %d. Must be > 0", i, snum[i]); #endif /* CONFIG_REISERFS_CHECK */ /* here we shift from S to S_new nodes */ S_new[i] = get_FEB(tb); /* set block level */ set_leaf_node_level (S_new[i]); n = B_NR_ITEMS(tbS0); switch (flag) { case M_INSERT: /* insert item */ if ( n - snum[i] < item_pos ) { /* new item or it's part falls to first new node S_new[i]*/ if ( item_pos == n - snum[i] + 1 && sbytes[i] != -1 ) { /* part of new item falls into S_new[i] */ int old_key_comp, old_len, r_zeros_number; const char * r_body; #ifdef CONFIG_REISERFS_CHECK if ( !I_IS_DIRECT_ITEM(ih) ) /* The items which can be inserted are: Stat_data item, direct item, indirect item and directory item which consist of only two entries "." and "..". These items must not be broken except for a direct one. */ reiserfs_panic(tb->tb_sb, "PAP-12205: balance_leaf: " "this item %h can not be broken when inserting", ih); #endif /* Move snum[i]-1 items from S[0] to S_new[i] */ leaf_move_items (LEAF_FROM_S_TO_SNEW, tb, snum[i] - 1, -1, S_new[i]); /* Remember key component and item length */ old_key_comp = get_offset (&ih->ih_key); old_len = ih->ih_item_len; /* Calculate key component and item length to insert into S_new[i] */ //ih->ih_key.k_offset += (old_len - sbytes[i]); set_offset (key_format (&ih->ih_key), &ih->ih_key, old_key_comp + old_len - sbytes[i]); ih->ih_item_len = sbytes[i]; /* Insert part of the item into S_new[i] before 0-th item */ bi.bi_bh = S_new[i]; bi.bi_parent = 0; bi.bi_position = 0; if ( get_offset (&ih->ih_key) - old_key_comp > zeros_number ) { r_zeros_number = 0; r_body = body + (get_offset (&ih->ih_key) - old_key_comp) - zeros_number; } else { r_body = body; r_zeros_number = zeros_number - (get_offset (&ih->ih_key) - old_key_comp); zeros_number -= r_zeros_number; } leaf_insert_into_buf (tb->tb_sb, &bi, 0, ih, r_body, r_zeros_number); /* Calculate key component and item length to insert into S[i] */ //ih->ih_key.k_offset = old_key_comp; set_offset (key_format (&ih->ih_key), &ih->ih_key, old_key_comp); ih->ih_item_len = old_len - sbytes[i]; tb->insert_size[0] -= sbytes[i]; } else /* whole new item falls into S_new[i] */ { /* Shift snum[0] - 1 items to S_new[i] (sbytes[i] of split item) */ leaf_move_items (LEAF_FROM_S_TO_SNEW, tb, snum[i] - 1, sbytes[i], S_new[i]); /* Insert new item into S_new[i] */ bi.bi_bh = S_new[i]; bi.bi_parent = 0; bi.bi_position = 0; leaf_insert_into_buf (tb->tb_sb, &bi, item_pos - n + snum[i] - 1, ih, body, zeros_number); zeros_number = tb->insert_size[0] = 0; } } else /* new item or it part don't falls into S_new[i] */ { leaf_move_items (LEAF_FROM_S_TO_SNEW, tb, snum[i], sbytes[i], S_new[i]); } break; case M_PASTE: /* append item */ if ( n - snum[i] <= item_pos ) /* pasted item or part if it falls to S_new[i] */ { if ( item_pos == n - snum[i] && sbytes[i] != -1 ) { /* we must shift part of the appended item */ struct item_head * aux_ih; #ifdef CONFIG_REISERFS_CHECK if ( ih ) reiserfs_panic (tb->tb_sb, "PAP-12210: balance_leaf: ih must be 0"); #endif /* CONFIG_REISERFS_CHECK */ if ( I_IS_DIRECTORY_ITEM (aux_ih = B_N_PITEM_HEAD(tbS0,item_pos))) { /* we append to directory item */ int entry_count; entry_count = ih_entry_count(aux_ih); if ( entry_count - sbytes[i] < pos_in_item && pos_in_item <= entry_count ) { /* new directory entry falls into S_new[i] */ #ifdef CONFIG_REISERFS_CHECK if ( ! tb->insert_size[0] ) reiserfs_panic (tb->tb_sb, "PAP-12215: balance_leaif: insert_size is already 0"); if ( sbytes[i] - 1 >= entry_count ) reiserfs_panic (tb->tb_sb, "PAP-12220: balance_leaf: " "there are no so much entries (%d), only %d", sbytes[i] - 1, entry_count); #endif /* Shift snum[i]-1 items in whole. Shift sbytes[i] directory entries from directory item number snum[i] */ leaf_move_items (LEAF_FROM_S_TO_SNEW, tb, snum[i], sbytes[i]-1, S_new[i]); /* Paste given directory entry to directory item */ bi.bi_bh = S_new[i]; bi.bi_parent = 0; bi.bi_position = 0; leaf_paste_in_buffer (tb->tb_sb, &bi, 0, pos_in_item - entry_count + sbytes[i] - 1, tb->insert_size[0], body,zeros_number); /* paste new directory entry */ leaf_paste_entries ( bi.bi_bh, 0, pos_in_item - entry_count + sbytes[i] - 1, 1, (struct reiserfs_de_head *)body, body + DEH_SIZE, tb->insert_size[0] ); tb->insert_size[0] = 0; pos_in_item++; } else { /* new directory entry doesn't fall into S_new[i] */ leaf_move_items (LEAF_FROM_S_TO_SNEW, tb, snum[i], sbytes[i], S_new[i]); } } else /* regular object */ { int n_shift, n_rem, r_zeros_number; const char * r_body; struct item_head * tmp; #ifdef CONFIG_REISERFS_CHECK if ( pos_in_item != B_N_PITEM_HEAD(tbS0,item_pos)->ih_item_len || tb->insert_size[0] <= 0 ) reiserfs_panic (tb->tb_sb, "PAP-12225: balance_leaf: item too short or insert_size <= 0"); #endif /* Calculate number of bytes which must be shifted from appended item */ n_shift = sbytes[i] - tb->insert_size[0]; if ( n_shift < 0 ) n_shift = 0; leaf_move_items (LEAF_FROM_S_TO_SNEW, tb, snum[i], n_shift, S_new[i]); /* Calculate number of bytes which must remain in body after append to S_new[i] */ n_rem = tb->insert_size[0] - sbytes[i]; if ( n_rem < 0 ) n_rem = 0; /* Append part of body into S_new[0] */ bi.bi_bh = S_new[i]; bi.bi_parent = 0; bi.bi_position = 0; if ( n_rem > zeros_number ) { r_zeros_number = 0; r_body = body + n_rem - zeros_number; } else { r_body = body; r_zeros_number = zeros_number - n_rem; zeros_number -= r_zeros_number; } leaf_paste_in_buffer(tb->tb_sb, &bi, 0, n_shift, tb->insert_size[0]-n_rem, r_body,r_zeros_number); tmp = B_N_PITEM_HEAD (S_new[i], 0); if (I_IS_INDIRECT_ITEM(tmp)) { if (n_rem) reiserfs_panic ("PAP-12230: balance_leaf: " "invalid action with indirect item"); //tmp->u.ih_free_space = ((struct unfm_nodeinfo*)body)->unfm_freespace; set_free_space (tmp, ((struct unfm_nodeinfo*)body)->unfm_freespace); } //B_N_PKEY(S_new[i],0)->k_offset += n_rem; set_offset (key_format (&tmp->ih_key), &tmp->ih_key, get_offset (&tmp->ih_key) + n_rem); tb->insert_size[0] = n_rem; if ( ! n_rem ) pos_in_item++; } } else /* item falls wholly into S_new[i] */ { int ret_val; struct item_head * pasted; #ifdef CONFIG_REISERFS_CHECK struct item_head * ih = B_N_PITEM_HEAD(tbS0,item_pos); if ( ! I_IS_DIRECTORY_ITEM(ih) && (pos_in_item != ih->ih_item_len || tb->insert_size[0] <= 0) ) reiserfs_panic (tb->tb_sb, "PAP-12235: balance_leaf: pos_in_item must be equal to ih_item_len"); #endif /* CONFIG_REISERFS_CHECK */ ret_val = leaf_move_items (LEAF_FROM_S_TO_SNEW, tb, snum[i], sbytes[i], S_new[i]); #ifdef CONFIG_REISERFS_CHECK if ( ret_val ) reiserfs_panic (tb->tb_sb, "PAP-12240: balance_leaf: " "unexpected value returned by leaf_move_items (%d)", ret_val); #endif /* CONFIG_REISERFS_CHECK */ /* paste into item */ bi.bi_bh = S_new[i]; bi.bi_parent = 0; bi.bi_position = 0; leaf_paste_in_buffer(tb->tb_sb, &bi, item_pos - n + snum[i], pos_in_item, tb->insert_size[0], body, zeros_number); pasted = B_N_PITEM_HEAD(S_new[i], item_pos - n + snum[i]); if (I_IS_DIRECTORY_ITEM (pasted)) { leaf_paste_entries (bi.bi_bh, item_pos - n + snum[i], pos_in_item, 1, (struct reiserfs_de_head *)body, body + DEH_SIZE, tb->insert_size[0]); } /* if we paste to indirect item update ih_free_space */ if (I_IS_INDIRECT_ITEM (pasted)) //pasted->u.ih_free_space = ((struct unfm_nodeinfo*)body)->unfm_freespace; set_free_space (pasted, ((struct unfm_nodeinfo*)body)->unfm_freespace); zeros_number = tb->insert_size[0] = 0; } } else { /* pasted item doesn't fall into S_new[i] */ leaf_move_items (LEAF_FROM_S_TO_SNEW, tb, snum[i], sbytes[i], S_new[i]); } break; default: /* cases d and t */ reiserfs_panic ("PAP-12245: balance_leaf: blknum > 2: unexpectable mode: %s(%d)", (flag == M_DELETE) ? "DELETE" : ((flag == M_CUT) ? "CUT" : "UNKNOWN"), flag); } memcpy (insert_key + i,B_N_PKEY(S_new[i],0),KEY_SIZE); insert_ptr[i] = S_new[i]; #ifdef CONFIG_REISERFS_CHECK if (S_new[i]->b_count != 1) { if (buffer_journaled(S_new[i]) || buffer_journal_dirty(S_new[i])) { ; } else { reiserfs_panic (tb->tb_sb, "PAP-12247: balance_leaf: S_new[%d]->b_count=%u blocknr = %lu\n", i, S_new[i]->b_count, S_new[i]->b_blocknr); } } #endif } /* if the affected item was not wholly shifted then we perform all necessary operations on that part or whole of the affected item which remains in S */ if ( 0 <= item_pos && item_pos < tb->s0num ) { /* if we must insert or append into buffer S[0] */ switch (flag) { case M_INSERT: /* insert item into S[0] */ bi.bi_bh = tbS0; bi.bi_parent = PATH_H_PPARENT (tb->tb_path, 0); bi.bi_position = PATH_H_POSITION (tb->tb_path, 1); leaf_insert_into_buf (tb->tb_sb, &bi, item_pos, ih, body, zeros_number); /* If we insert the first key change the delimiting key */ if( item_pos == 0 ) { if (tb->CFL[0]) /* can be 0 in reiserfsck */ replace_key (tb->tb_sb, tb->CFL[0], tb->lkey[0],tbS0,0); } break; case M_PASTE: { /* append item in S[0] */ struct item_head * pasted; pasted = B_N_PITEM_HEAD (tbS0, item_pos); /* when directory, may be new entry already pasted */ if (I_IS_DIRECTORY_ITEM (pasted)) { if ( pos_in_item >= 0 && pos_in_item <= ih_entry_count (pasted) ) { #ifdef CONFIG_REISERFS_CHECK if ( ! tb->insert_size[0] ) reiserfs_panic (tb->tb_sb, "PAP-12260: balance_leaf: insert_size is 0 already"); #endif /* CONFIG_REISERFS_CHECK */ /* prepare space */ bi.bi_bh = tbS0; bi.bi_parent = PATH_H_PPARENT (tb->tb_path, 0); bi.bi_position = PATH_H_POSITION (tb->tb_path, 1); leaf_paste_in_buffer(tb->tb_sb, &bi, item_pos, pos_in_item, tb->insert_size[0], body, zeros_number); /* paste entry */ leaf_paste_entries (bi.bi_bh, item_pos, pos_in_item, 1, (struct reiserfs_de_head *)body, body + DEH_SIZE, tb->insert_size[0]); if ( ! item_pos && ! pos_in_item ) { #ifdef CONFIG_REISERFS_CHECK if (!tb->CFL[0]) reiserfs_panic (tb->tb_sb, "PAP-12270: balance_leaf: " "is not able to update left dkey"); #endif /* CONFIG_REISERFS_CHECK */ if (tb->CFL[0]) // can be 0 in reiserfsck replace_key(tb->tb_sb, tb->CFL[0], tb->lkey[0],tbS0,0); } tb->insert_size[0] = 0; } } else { /* regular object */ if ( pos_in_item == pasted->ih_item_len ) { #ifdef CONFIG_REISERFS_CHECK if ( tb->insert_size[0] <= 0 ) reiserfs_panic (tb->tb_sb, "PAP-12275: balance_leaf: insert size must not be %d", tb->insert_size[0]); #endif /* CONFIG_REISERFS_CHECK */ bi.bi_bh = tbS0; bi.bi_parent = PATH_H_PPARENT (tb->tb_path, 0); bi.bi_position = PATH_H_POSITION (tb->tb_path, 1); leaf_paste_in_buffer (tb->tb_sb, &bi, item_pos, pos_in_item, tb->insert_size[0], body, zeros_number); if (I_IS_INDIRECT_ITEM (pasted)) { #ifdef CONFIG_REISERFS_CHECK if ( tb->insert_size[0] != UNFM_P_SIZE ) reiserfs_panic (tb->tb_sb, "PAP-12280: balance_leaf: insert_size for indirect item must be %d, not %d", UNFM_P_SIZE, tb->insert_size[0]); #endif /* CONFIG_REISERFS_CHECK */ //pasted->u.ih_free_space = ((struct unfm_nodeinfo*)body)->unfm_freespace; set_free_space (pasted, ((struct unfm_nodeinfo*)body)->unfm_freespace); } tb->insert_size[0] = 0; } #ifdef CONFIG_REISERFS_CHECK else { if ( tb->insert_size[0] ) { print_tb (init_mode, init_item_pos, init_pos_in_item, &init_tb, "12285"); reiserfs_panic (tb->tb_sb, "PAP-12285: balance_leaf: " "insert_size must be 0 (%d), pos_in_item %d. (%h)", tb->insert_size[0], pos_in_item, pasted); } } #endif /* CONFIG_REISERFS_CHECK */ } } /* case M_PASTE: */ } } #ifdef CONFIG_REISERFS_CHECK if ( flag == M_PASTE && tb->insert_size[0] ) { print_tb (M_PASTE, item_pos, pos_in_item, tb, "balance"); reiserfs_panic (tb->tb_sb, "PAP-12290: balance_leaf: insert_size is still not 0 (%d)", tb->insert_size[0]); } #endif /* CONFIG_REISERFS_CHECK */ return 0; } /* Leaf level of the tree is balanced (end of balance_leaf) */ /* Make empty node */ void make_empty_node (struct buffer_info * bi) { struct block_head * blkh; #ifdef CONFIG_REISERFS_CHECK if (bi->bi_bh == NULL) reiserfs_panic (0, "PAP-12295: make_empty_node: pointer to the buffer is NULL"); #endif (blkh = B_BLK_HEAD(bi->bi_bh))->blk_nr_item = 0; blkh->blk_free_space = MAX_CHILD_SIZE(bi->bi_bh); if (bi->bi_parent) B_N_CHILD (bi->bi_parent, bi->bi_position)->dc_size = 0; } /* Get first empty buffer */ struct buffer_head * get_FEB (struct tree_balance * tb) { int i; struct buffer_head * first_b; struct buffer_info bi; for (i = 0; i < MAX_FEB_SIZE; i ++) if (tb->FEB[i] != 0) break; if (i == MAX_FEB_SIZE) reiserfs_panic("vs-12300: get_FEB: FEB list is empty"); bi.bi_bh = first_b = tb->FEB[i]; bi.bi_parent = 0; bi.bi_position = 0; make_empty_node (&bi); set_bit(BH_Uptodate, &first_b->b_state); tb->FEB[i] = 0; tb->used[i] = first_b; return(first_b); } /* Replace n_dest'th key in buffer dest by n_src'th key of buffer src.*/ void replace_key (reiserfs_filsys_t fs, struct buffer_head * dest, int n_dest, struct buffer_head * src, int n_src) { #ifdef CONFIG_REISERFS_CHECK if (dest == NULL || src == NULL) reiserfs_panic (0, "vs-12305: replace_key: sourse or destination buffer is 0 (src=%p, dest=%p)", src, dest); if ( ! B_IS_KEYS_LEVEL (dest) ) reiserfs_panic (0, "vs-12310: replace_key: invalid level (%d) for destination buffer. Must be > %d", B_BLK_HEAD(dest)->blk_level, DISK_LEAF_NODE_LEVEL); if (n_dest < 0 || n_src < 0) reiserfs_panic (0, "vs-12315: replace_key: src(%d) or dest(%d) key number less than 0", n_src, n_dest); if (n_dest >= B_NR_ITEMS(dest) || n_src >= B_NR_ITEMS(src)) reiserfs_panic (0, "vs-12320: replace_key: src(%d(%d)) or dest(%d(%d)) key number is too big", n_src, B_NR_ITEMS(src), n_dest, B_NR_ITEMS(dest)); #endif /* CONFIG_REISERFS_CHECK */ if (dest) { if (is_leaf_node (src)) /* source buffer contains leaf node */ memcpy (B_N_PDELIM_KEY(dest,n_dest), B_N_PITEM_HEAD(src,n_src), KEY_SIZE); else memcpy (B_N_PDELIM_KEY(dest,n_dest), B_N_PDELIM_KEY(src,n_src), KEY_SIZE); mark_buffer_dirty(dest); } } void reiserfs_invalidate_buffer (struct tree_balance * tb, struct buffer_head * bh, int do_free_block) { B_BLK_HEAD (bh)->blk_level = FREE_LEVEL; clear_bit(BH_Dirty, &bh->b_state); #ifdef CONFIG_REISERFS_CHECK B_NR_ITEMS (bh) = 0; #endif if (do_free_block) { struct buffer_head * to_be_forgotten; to_be_forgotten = find_buffer (bh->b_dev, bh->b_blocknr, bh->b_size); if (to_be_forgotten) { to_be_forgotten->b_count ++; bforget (to_be_forgotten); } reiserfs_free_block (tb->tb_sb, bh->b_blocknr); } } int get_left_neighbor_position ( struct tree_balance * tb, int h ) { int Sh_position = PATH_H_POSITION (tb->tb_path, h + 1); #ifdef CONFIG_REISERFS_CHECK if (PATH_H_PPARENT (tb->tb_path, h) == 0 || tb->FL[h] == 0) reiserfs_panic (tb->tb_sb, "vs-12325: get_left_neighbor_position: FL[%d](%p) or F[%d](%p) does not exist", h, tb->FL[h], h, PATH_H_PPARENT (tb->tb_path, h)); #endif if (Sh_position == 0) return B_NR_ITEMS (tb->FL[h]); else return Sh_position - 1; } int get_right_neighbor_position (struct tree_balance * tb, int h) { int Sh_position = PATH_H_POSITION (tb->tb_path, h + 1); #ifdef CONFIG_REISERFS_CHECK if (PATH_H_PPARENT (tb->tb_path, h) == 0 || tb->FR[h] == 0) reiserfs_panic (tb->tb_sb, "vs-12330: get_right_neighbor_position: F[%d](%p) or FR[%d](%p) does not exist", h, PATH_H_PPARENT (tb->tb_path, h), h, tb->FR[h]); #endif if (Sh_position == B_NR_ITEMS (PATH_H_PPARENT (tb->tb_path, h))) return 0; else return Sh_position + 1; } #ifdef CONFIG_REISERFS_CHECK int is_reusable (struct super_block * s, unsigned long block, int bit_value); static void check_internal_node (struct super_block * s, struct buffer_head * bh, char * mes) { struct disk_child * dc; int i; if (!bh) reiserfs_panic (s, "PAP-12336: check_internal_node: bh == 0"); if (!bh || !B_IS_IN_TREE (bh)) return; if (!buffer_dirty (bh) && !buffer_journaled(bh) ) { print_tb (init_mode, init_item_pos, init_pos_in_item, &init_tb, mes); reiserfs_panic (s, "PAP-12337: check_internal_node: buffer (%b) must be dirty", bh); } dc = B_N_CHILD (bh, 0); for (i = 0; i <= B_NR_ITEMS (bh); i ++, dc ++) { if (!is_reusable (s, dc->dc_block_number, 1) ) { print_tb (init_mode, init_item_pos, init_pos_in_item, &init_tb, mes); reiserfs_panic (s, "PAP-12338: check_internal_node: invalid child pointer %y in %b", dc, bh); } if (dc->dc_size <= BLKH_SIZE) { print_tb (init_mode, init_item_pos, init_pos_in_item, &init_tb, mes); reiserfs_panic (s, "PAP-12338: check_internal_node: empty node in the tree? %y", dc); } } } static int locked_or_not_in_tree (struct buffer_head * bh, char * which) { if ( buffer_locked (bh) || !B_IS_IN_TREE (bh) ) { reiserfs_warning ("vs-12339: locked_or_not_in_tree: %s (%b)\n", which, bh); return 1; } return 0; } static int check_before_balancing (struct tree_balance * tb, int mode) { int retval = 0; int pos_in_item = tb->tb_path->pos_in_item; if (mode == M_PASTE) { // make sure paste can be performed with given parameters struct item_head * ih; ih = get_ih (tb->tb_path); if (I_IS_INDIRECT_ITEM (ih)) { // we can paste only to the end for now if (pos_in_item != I_UNFM_NUM (ih)) reiserfs_panic (tb->tb_sb, "vs-12333: check_before_balancing: " "pos_in_item %d set improperly to paste indirect item %h", pos_in_item, ih); } if (I_IS_DIRECT_ITEM (ih)) { // we can paste only to the end for now if (pos_in_item != ih_item_len (ih)) reiserfs_panic (tb->tb_sb, "vs-12334: check_before_balancing: " "pos_in_item %d set improperly to paste direct item %h", pos_in_item, ih); } } if ( cur_tb ) { reiserfs_panic (tb->tb_sb, "vs-12335: check_before_balancing: " "suspect that schedule occurred based on cur_tb not being null at this point in code. " "do_balance cannot properly handle schedule occuring while it runs."); } /* double check that buffers that we will modify are unlocked. (fix_nodes should already have prepped all of these for us). */ if ( tb->lnum[0] ) { retval |= locked_or_not_in_tree (tb->L[0], "L[0]"); retval |= locked_or_not_in_tree (tb->FL[0], "FL[0]"); retval |= locked_or_not_in_tree (tb->CFL[0], "CFL[0]"); check_leaf (tb->L[0]); } if ( tb->rnum[0] ) { retval |= locked_or_not_in_tree (tb->R[0], "R[0]"); retval |= locked_or_not_in_tree (tb->FR[0], "FR[0]"); retval |= locked_or_not_in_tree (tb->CFR[0], "CFR[0]"); check_leaf (tb->R[0]); } retval |= locked_or_not_in_tree (PATH_PLAST_BUFFER (tb->tb_path), "S[0]"); check_leaf (PATH_PLAST_BUFFER (tb->tb_path)); return retval; } static void check_after_balance_leaf (struct tree_balance * tb) { if (tb->lnum[0]) { if (B_BLK_HEAD (tb->L[0])->blk_free_space != MAX_CHILD_SIZE (tb->L[0]) - B_N_CHILD (tb->FL[0], get_left_neighbor_position (tb, 0))->dc_size) { print_tb (init_mode, init_item_pos, init_pos_in_item, &init_tb, "12221"); reiserfs_panic (tb->tb_sb, "PAP-12355: check_after_balance_leaf: shift to left was incorrect"); } } if (tb->rnum[0]) { if (B_BLK_HEAD (tb->R[0])->blk_free_space != MAX_CHILD_SIZE (tb->R[0]) - B_N_CHILD (tb->FR[0], get_right_neighbor_position (tb, 0))->dc_size) { print_tb (init_mode, init_item_pos, init_pos_in_item, &init_tb, "12222"); reiserfs_panic (tb->tb_sb, "PAP-12360: check_after_balance_leaf: shift to right was incorrect"); } } if (PATH_H_PBUFFER(tb->tb_path,1) && B_BLK_HEAD (PATH_H_PBUFFER(tb->tb_path,0))->blk_free_space != MAX_CHILD_SIZE (PATH_H_PBUFFER(tb->tb_path,0)) - B_N_CHILD (PATH_H_PBUFFER(tb->tb_path,1), PATH_H_POSITION (tb->tb_path, 1))->dc_size) { print_tb (init_mode, init_item_pos, init_pos_in_item, &init_tb, "12223"); reiserfs_panic (tb->tb_sb, "PAP-12365: check_after_balance_leaf: S is incorrect"); } } static void compare_pair (struct buffer_head * bh1, struct buffer_head * bh2) { int cur_free, node_size; if (!bh1 || !bh2) return; cur_free = node_free_space (bh1); node_size = bh1->b_size - BLKH_SIZE - ((is_left_mergeable (B_N_PITEM_HEAD (bh2, 0), bh1->b_size)) ? IH_SIZE : 0); if (cur_free >= node_size) { print_tb (init_mode, init_item_pos, init_pos_in_item, &init_tb, "12366"); reiserfs_panic (0, "vs-12366: check_leaf_level: balance condition denied bh1 %z, bh2 %z", bh1, bh2); } } static void check_leaf_level (struct tree_balance * tb) { struct buffer_head * S0 = get_bh (tb->tb_path); struct buffer_head * bhs[5] = {0, }; int i; // check item types, internal structures of items, etc check_leaf (tb->L[0]); check_leaf (tb->R[0]); check_leaf (S0); if (tb->blknum[0] > 2) { reiserfs_warning ("More than one new node on the leaf level\n"); return; } // check balance condition for any neighboring buffers i = 0; if (tb->L[0] && B_IS_IN_TREE (tb->L[0])) bhs[i ++] = tb->L[0]; if (B_IS_IN_TREE (S0)) bhs[i ++] = S0; if (tb->blknum[0] == 2) { if (!B_IS_ITEMS_LEVEL(tb->used[0])) { reiserfs_warning ("can not find new node\n"); return; } bhs[i ++] = tb->used[0]; } if (tb->R[0] && B_IS_IN_TREE (tb->R[0])) { bhs[i ++] = tb->R[0]; } for (i = 0; i < 4; i ++) { compare_pair (bhs[i], bhs[i + 1]); } } static void check_after_balancing (struct tree_balance * tb) { int h; check_leaf_level (tb); /* check all internal nodes */ for (h = 1; tb->insert_size[h]; h ++) { check_internal_node (tb->tb_sb, PATH_H_PBUFFER (tb->tb_path, h), "BAD BUFFER ON PATH"); if (tb->lnum[h]) check_internal_node (tb->tb_sb, tb->L[h], "BAD L"); if (tb->rnum[h]) check_internal_node (tb->tb_sb, tb->R[h], "BAD R"); } } #endif /* Now we have all of the buffers that must be used in balancing of the tree. We rely on the assumption that schedule() will not occur while do_balance works. ( Only interrupt handlers are acceptable.) We balance the tree according to the analysis made before this, using buffers already obtained. For SMP support it will someday be necessary to add ordered locking of tb. */ /* Some interesting rules of balancing: we delete a maximum of two nodes per level per balancing: we never delete R, when we delete two of three nodes L, S, R then we move them into R. we only delete L if we are deleting two nodes, if we delete only one node we delete S if we shift leaves then we shift as much as we can: this is a deliberate policy of extremism in node packing which results in higher average utilization after repeated random balance operations at the cost of more memory copies and more balancing as a result of small insertions to full nodes. if we shift internal nodes we try to evenly balance the node utilization, with consequent less balancing at the cost of lower utilization. one could argue that the policy for directories in leaves should be that of internal nodes, but we will wait until another day to evaluate this.... It would be nice to someday measure and prove these assumptions as to what is optimal.... */ void do_balance (struct tree_balance * tb, /* tree_balance structure */ struct item_head * ih, /* item header of inserted item */ const char * body, /* body of inserted item or bytes to paste */ int flag, /* i - insert, d - delete c - cut, p - paste Cut means delete part of an item (includes removing an entry from a directory). Delete means delete whole item. Insert means add a new item into the tree. Paste means to append to the end of an existing file or to insert a directory entry. */ int zeros_num) { //int pos_in_item = tb->tb_path->pos_in_item; int child_pos, /* position of a child node in its parent */ h; /* level of the tree being processed */ struct item_head insert_key[2]; /* in our processing of one level we sometimes determine what must be inserted into the next higher level. This insertion consists of a key or two keys and their corresponding pointers */ struct buffer_head *insert_ptr[2]; /* inserted node-ptrs for the next level */ #ifdef CONFIG_REISERFS_CHECK memcpy(&init_tb, tb, sizeof(struct tree_balance)); init_item_pos = PATH_LAST_POSITION (tb->tb_path); init_pos_in_item = tb->tb_path->pos_in_item;//pos_in_item; init_mode = flag; /* do not delete, just comment it out */ /*print_tb(flag, PATH_LAST_POSITION(tb->tb_path), pos_in_item, tb, "check");*/ if (check_before_balancing (tb/*, pos_in_item*/, flag)) reiserfs_panic (tb->tb_sb, "PAP-12340: do_balance: " "balancing can not be performed"); cur_tb = tb; #endif /* CONFIG_REISERFS_CHECK */ /* if we have no real work to do */ if ( ! tb->insert_size[0] ) { #ifdef CONFIG_REISERFS_CHECK cur_tb = NULL; if (flag != M_CUT) reiserfs_panic (tb->tb_sb, "PAP-12350: do_balance: insert_size == 0, mode == %c", flag); #endif unfix_nodes(/*th,*/ tb); return; } #ifndef FU //REISERFS_FSCK if (flag == M_INTERNAL) { insert_ptr[0] = (struct buffer_head *)body; /* we must prepare insert_key */ if (PATH_H_B_ITEM_ORDER (tb->tb_path, 0)/*LAST_POSITION (tb->tb_path)*//*item_pos*/ == -1) { /* get delimiting key from buffer in tree */ copy_key (&insert_key[0].ih_key, B_N_PKEY (PATH_PLAST_BUFFER (tb->tb_path), 0)); /*insert_ptr[0]->b_item_order = 0;*/ } else { /* get delimiting key from new buffer */ copy_key (&insert_key[0].ih_key, B_N_PKEY((struct buffer_head *)body,0)); /*insert_ptr[0]->b_item_order = item_pos;*/ } /* and insert_ptr instead of balance_leaf */ child_pos = PATH_H_B_ITEM_ORDER (tb->tb_path, 0)/*item_pos*/; } else #endif /* balance leaf returns 0 except if combining L R and S into one node. see balance_internal() for explanation of this line of code.*/ child_pos = PATH_H_B_ITEM_ORDER (tb->tb_path, 0) + balance_leaf (/*th,*/ tb/*, pos_in_item*/, ih, body, flag, zeros_num, insert_key, insert_ptr); #ifdef CONFIG_REISERFS_CHECK check_after_balance_leaf (tb); #endif /* Balance internal level of the tree. */ for ( h = 1; h < MAX_HEIGHT && tb->insert_size[h]; h++ ) child_pos = balance_internal (/*th,*/ tb, h, child_pos, insert_key, insert_ptr); #ifdef CONFIG_REISERFS_CHECK cur_tb = NULL; check_after_balancing (tb); #endif /* Release all (except for S[0]) non NULL buffers fixed by fix_nodes() */ unfix_nodes(/*th,*/ tb); #ifdef CONFIG_REISERFS_CHECK tb->tb_sb->u.reiserfs_sb.s_do_balance ++; #endif } reiserfsprogs-3.x.0j/reiserfscore/fix_node.c0000644000076400001440000027417207251213115015016 /* * Copyright 1996, 1997, 1998 Hans Reiser, see reiserfs/README for licensing and copyright details */ /** ** old_item_num ** old_entry_num ** set_entry_sizes ** create_virtual_node ** check_left ** check_right ** directory_part_size ** get_num_ver ** item_length ** set_parameters ** is_leaf_removable ** are_leaves_removable ** get_empty_nodes ** get_lfree ** get_rfree ** is_left_neighbor_in_cache ** decrement_key ** get_far_parent ** get_parents ** can_node_be_removed ** ip_check_balance ** dc_check_balance_internal ** dc_check_balance_leaf ** dc_check_balance ** check_balance ** get_direct_parent ** get_neighbors ** fix_nodes ** ** **/ #include "includes.h" __u64 get_bytes_number (struct item_head * ih, int blocksize) { switch (get_type (&ih->ih_key)) { case TYPE_DIRECT: return ih_item_len (ih); case TYPE_INDIRECT: return I_UNFM_NUM(ih) * blocksize - ih_free_space (ih); case TYPE_STAT_DATA: return 0; } reiserfs_warning (stderr, "get_bytes_number: called for wrong type of item %h", ih); return 0; } /* To make any changes in the tree we find a node, that contains item to be changed/deleted or position in the node we insert a new item to. We call this node S. To do balancing we need to decide what we will shift to left/right neighbor, or to a new node, where new item will be etc. To make this analysis simpler we build virtual node. Virtual node is an array of items, that will replace items of node S. (For instance if we are going to delete an item, virtual node does not contain it). Virtual node keeps information about item sizes and types, mergeability of first and last items, sizes of all entries in directory item. We use this array of items when calculating what we can shift to neighbors and how many nodes we have to have if we do not any shiftings, if we shift to left/right neighbor or to both. */ /* taking item number in virtual node, returns number of item, that it has in source buffer */ static inline int old_item_num (int new_num, int affected_item_num, int mode) { if (mode == M_PASTE || mode == M_CUT || new_num < affected_item_num) return new_num; if (mode == M_INSERT) { #ifdef CONFIG_REISERFS_CHECK if (new_num == 0) reiserfs_panic (0,"vs-8005: old_item_num: for INSERT mode and item number of inserted item"); #endif return new_num - 1; } #ifdef CONFIG_REISERFS_CHECK if (mode != M_DELETE) reiserfs_panic (0, "vs-8010: old_item_num: mode must be M_DELETE (mode = \'%c\'", mode); #endif /* delete mode */ return new_num + 1; } /* * function returns old entry number in directory item in real node * using new entry number in virtual item in virtual node */ static inline int old_entry_num (int new_num, int affected_item_num, int new_entry_num, int pos_in_item, int mode) { if ( mode == M_INSERT || mode == M_DELETE) return new_entry_num; if (new_num != affected_item_num) { /* cut or paste is applied to another item */ return new_entry_num; } if (new_entry_num < pos_in_item) return new_entry_num; if (mode == M_CUT) return new_entry_num + 1; #ifdef CONFIG_REISERFS_CHECK if (mode != M_PASTE) reiserfs_panic (0, "vs-8015: old_entry_num: mode must be M_PASTE (mode = \'%c\'", mode); #endif return new_entry_num - 1; } /* * Create an array of sizes of directory entries for virtual item */ static void set_entry_sizes (struct tree_balance * tb, int old_num, int new_num, struct buffer_head * bh, struct item_head * ih ) { struct virtual_node * vn = tb->tb_vn; int i; struct reiserfs_de_head * deh; struct virtual_item * vi; deh = B_I_DEH (bh, ih); /* seek to given virtual item in array of virtual items */ vi = vn->vn_vi + new_num; /* virtual directory item have this amount of entry after */ vi->vi_entry_count = ih_entry_count (ih) + ((old_num == vn->vn_affected_item_num) ? ((vn->vn_mode == M_CUT) ? -1 : (vn->vn_mode == M_PASTE ? 1 : 0)) : 0); #ifdef CONFIG_REISERFS_CHECK /* check whether we have enough space for array of entry sizes */ if (tb->vn_buf + tb->vn_buf_size - vn->vn_free_ptr < vi->vi_entry_count * sizeof (__u16)) reiserfs_panic (tb->tb_sb, "vs-8020: set_entry_sizes: " "no enough space for %d entries of virtual item", vi->vi_entry_count); #endif vi->vi_entry_sizes = (__u16 *)vn->vn_free_ptr; vn->vn_free_ptr += vi->vi_entry_count * sizeof (__u16); /* set sizes of old entries */ for (i = 0; i < vi->vi_entry_count; i ++) { int j; j = old_entry_num (old_num, vn->vn_affected_item_num, i, vn->vn_pos_in_item, vn->vn_mode); vi->vi_entry_sizes[i] = entry_length (ih, &(deh[j]), j) + DEH_SIZE; } /* set size of pasted entry */ if (old_num == vn->vn_affected_item_num && vn->vn_mode == M_PASTE) vi->vi_entry_sizes[vn->vn_pos_in_item] = tb->insert_size[0]; #ifdef CONFIG_REISERFS_CHECK /* compare total size of entries with item length */ { int k, l; l = 0; for (k = 0; k < vi->vi_entry_count; k ++) l += vi->vi_entry_sizes[k]; if (l + IH_SIZE != vi->vi_item_len + ((old_num == vn->vn_affected_item_num && (vn->vn_mode == M_PASTE || vn->vn_mode == M_CUT)) ? tb->insert_size[0] : 0) ) { reiserfs_panic (0, "vs-8025: set_entry_sizes: (mode==%c, old_num==%d, aff_num==%d, insert_size==%d), invalid length of directory item", vn->vn_mode, old_num, vn->vn_affected_item_num, tb->insert_size[0]); } } #endif } static void create_virtual_node (struct tree_balance * tb, int h) { struct item_head * ih; struct virtual_node * vn = tb->tb_vn; int new_num; struct buffer_head * Sh; /* this comes from tb->S[h] */ struct item_head * temp_ih; Sh = PATH_H_PBUFFER (tb->tb_path, h); temp_ih = B_N_PITEM_HEAD (PATH_PLAST_BUFFER (tb->tb_path), B_NR_ITEMS (PATH_PLAST_BUFFER (tb->tb_path)) - 1); /* size of changed node */ vn->vn_size = MAX_CHILD_SIZE (Sh) - B_BLK_HEAD (Sh)->blk_free_space + tb->insert_size[h]; /* for internal nodes array if virtual items is not created */ if (h) { vn->vn_nr_item = (vn->vn_size - DC_SIZE) / (DC_SIZE + KEY_SIZE); return; } /* number of items in virtual node */ vn->vn_nr_item = B_NR_ITEMS (Sh) + ((vn->vn_mode == M_INSERT)? 1 : 0) - ((vn->vn_mode == M_DELETE)? 1 : 0); /* first virtual item */ vn->vn_vi = (struct virtual_item *)(tb->tb_vn + 1); memset (vn->vn_vi, 0, vn->vn_nr_item * sizeof (struct virtual_item)); vn->vn_free_ptr += vn->vn_nr_item * sizeof (struct virtual_item); /* first item in the node */ ih = B_N_PITEM_HEAD (Sh, 0); /* define the mergeability for 0-th item (if it is not being deleted) */ #ifndef FU //REISERFS_FSCK if (is_left_mergeable (tb->tb_sb, tb->tb_path) == 1 && (vn->vn_mode != M_DELETE || vn->vn_affected_item_num)) #else if (is_left_mergeable (ih, Sh->b_size) && (vn->vn_mode != M_DELETE || vn->vn_affected_item_num)) #endif vn->vn_vi[0].vi_type |= VI_TYPE_LEFT_MERGEABLE; /* go through all items those remain in the virtual node (except for the new (inserted) one) */ for (new_num = 0; new_num < vn->vn_nr_item; new_num ++) { int j; if (vn->vn_affected_item_num == new_num && vn->vn_mode == M_INSERT) continue; /* get item number in source node */ j = old_item_num (new_num, vn->vn_affected_item_num, vn->vn_mode); vn->vn_vi[new_num].vi_item_len += ih[j].ih_item_len + IH_SIZE; if (I_IS_STAT_DATA_ITEM (ih + j)) { vn->vn_vi[new_num].vi_type |= VI_TYPE_STAT_DATA; #ifdef CONFIG_REISERFS_CHECK if (new_num == vn->vn_affected_item_num && (vn->vn_mode == M_CUT || vn->vn_mode == M_PASTE)) reiserfs_panic (0, "vs-8035: create_virtual_node: stat data cannot be affected item"); #endif continue; } /* set type of item */ if (I_IS_DIRECT_ITEM (ih + j)) vn->vn_vi[new_num].vi_type |= VI_TYPE_DIRECT; if (I_IS_INDIRECT_ITEM (ih + j)) vn->vn_vi[new_num].vi_type |= VI_TYPE_INDIRECT; if (I_IS_DIRECTORY_ITEM (ih + j)) { set_entry_sizes (tb, j, new_num, Sh, ih + j); vn->vn_vi[new_num].vi_type |= VI_TYPE_DIRECTORY; if (ih[j].ih_key.u.k_offset_v1.k_offset == DOT_OFFSET) vn->vn_vi[new_num].vi_type |= VI_TYPE_FIRST_DIRECTORY_ITEM; } if (new_num != vn->vn_affected_item_num) /* this is not being changed */ continue; if (vn->vn_mode == M_PASTE || vn->vn_mode == M_CUT) vn->vn_vi[new_num].vi_item_len += tb->insert_size[0]; } /* virtual inserted item is not defined yet */ if (vn->vn_mode == M_INSERT) { #ifdef CONFIG_REISERFS_CHECK if (vn->vn_ins_ih == 0) reiserfs_panic (0, "vs-8040: create_virtual_node: item header of inserted item is not specified"); #endif vn->vn_vi[vn->vn_affected_item_num].vi_item_len = tb->insert_size[0]; switch (get_type (&vn->vn_ins_ih->ih_key)) { case TYPE_STAT_DATA: vn->vn_vi[vn->vn_affected_item_num].vi_type |= VI_TYPE_STAT_DATA; break; case TYPE_DIRECT: vn->vn_vi[vn->vn_affected_item_num].vi_type |= VI_TYPE_DIRECT; break; case TYPE_INDIRECT: vn->vn_vi[vn->vn_affected_item_num].vi_type |= VI_TYPE_INDIRECT; break; default: /* inseted item is directory (it must be item with "." and "..") */ vn->vn_vi[vn->vn_affected_item_num].vi_type |= (VI_TYPE_DIRECTORY | VI_TYPE_FIRST_DIRECTORY_ITEM | VI_TYPE_INSERTED_DIRECTORY_ITEM); /* this directory item can not be split, so do not set sizes of entries */ break; } } /* set right merge flag we take right delimiting key and check whether it is a mergeable item */ if (tb->CFR[0]) { ih = (struct item_head *)B_N_PDELIM_KEY (tb->CFR[0], tb->rkey[0]); #ifndef FU //REISERFS_FSCK if (is_right_mergeable (tb->tb_sb, tb->tb_path) == 1 && (vn->vn_mode != M_DELETE || vn->vn_affected_item_num != B_NR_ITEMS (Sh) - 1)) #else if (is_left_mergeable (ih, Sh->b_size) && (vn->vn_mode != M_DELETE || vn->vn_affected_item_num != B_NR_ITEMS (Sh) - 1)) #endif vn->vn_vi[vn->vn_nr_item-1].vi_type |= VI_TYPE_RIGHT_MERGEABLE; #ifdef CONFIG_REISERFS_CHECK if (is_left_mergeable (ih, Sh->b_size) && !(vn->vn_mode != M_DELETE || vn->vn_affected_item_num != B_NR_ITEMS (Sh) - 1) ) { /* we delete last item and it could be merged with right neighbor's first item */ if (!(B_NR_ITEMS (Sh) == 1 && I_IS_DIRECTORY_ITEM (B_N_PITEM_HEAD (Sh, 0)) && ih_entry_count (B_N_PITEM_HEAD (Sh, 0)) == 1)) { /* node contains more than 1 item, or item is not directory item, or this item contains more than 1 entry */ print_block (Sh, 0, -1, -1); reiserfs_panic (tb->tb_sb, "vs-8045: create_virtual_node: rdkey %k, affected item==%d (mode==%c) Must be %c", &(ih->ih_key), vn->vn_affected_item_num, vn->vn_mode, M_DELETE); } else /* we can delete directory item, that has only one directory entry in it */ ; } #endif } } /* using virtual node check, how many items can be shifted to left neighbor */ static int check_left (struct tree_balance * tb, int h, int cur_free) { int i; struct virtual_node * vn = tb->tb_vn; int d_size, ih_size, bytes = -1; #ifdef CONFIG_REISERFS_CHECK if (cur_free < 0) reiserfs_panic (0, "vs-8050: check_left: cur_free (%d) < 0", cur_free); #endif /* internal level */ if (h > 0) { if (!cur_free ) { tb->lnum[h] = 0; return 0; } tb->lnum[h] = cur_free / (DC_SIZE + KEY_SIZE); return -1; } /* leaf level */ if (!cur_free || !vn->vn_nr_item) { /* no free space */ tb->lnum[h] = 0; tb->lbytes = -1; return 0; } #ifdef CONFIG_REISERFS_CHECK if (!PATH_H_PPARENT (tb->tb_path, 0)) reiserfs_panic (0, "vs-8055: check_left: parent does not exist or invalid"); #endif if ((unsigned int)cur_free >= (vn->vn_size - ((vn->vn_vi[0].vi_type & VI_TYPE_LEFT_MERGEABLE) ? IH_SIZE : 0))) { /* all contents of S[0] fits into L[0] */ #ifdef CONFIG_REISERFS_CHECK if (vn->vn_mode == M_INSERT || vn->vn_mode == M_PASTE) { reiserfs_panic (0, "vs-8055: check_left: invalid mode or balance condition failed (cur_free %d)vn->vn_size %d", cur_free, vn->vn_size); } #endif tb->lnum[0] = vn->vn_nr_item; tb->lbytes = -1; return -1; } d_size = 0, ih_size = IH_SIZE; /* first item may be merge with last item in left neighbor */ if (vn->vn_vi[0].vi_type & VI_TYPE_LEFT_MERGEABLE) d_size = -((int)IH_SIZE), ih_size = 0; tb->lnum[0] = 0; for (i = 0; i < vn->vn_nr_item; i ++, ih_size = IH_SIZE, d_size = 0) { d_size += vn->vn_vi[i].vi_item_len; if (cur_free >= d_size) { /* the item can be shifted entirely */ cur_free -= d_size; tb->lnum[0] ++; continue; } /* the item cannot be shifted entirely, try to split it */ /* check whether L[0] can hold ih and at least one byte of the item body */ if (cur_free <= ih_size) { /* cannot shift even a part of the current item */ tb->lbytes = -1; return -1; } cur_free -= ih_size; if (vn->vn_vi[i].vi_type & VI_TYPE_STAT_DATA || vn->vn_vi[i].vi_type & VI_TYPE_INSERTED_DIRECTORY_ITEM) { /* virtual item is a stat_data or empty directory body ("." and ".."), that is not split able */ tb->lbytes = -1; return -1; } if (vn->vn_vi[i].vi_type & VI_TYPE_DIRECT) /* body of a direct item can be split at any byte */ tb->lbytes = bytes = cur_free; if (vn->vn_vi[i].vi_type & VI_TYPE_INDIRECT) /* body of a indirect item can be split at unformatted pointer bound */ tb->lbytes = bytes = cur_free - cur_free % UNFM_P_SIZE; /* item is of directory type */ if (vn->vn_vi[i].vi_type & VI_TYPE_DIRECTORY) { /* directory entries are the solid granules of the directory item, they cannot be split in the middle */ /* calculate number of dir entries that can be shifted, and their total size */ int j; struct virtual_item * vi; tb->lbytes = 0; bytes = 0; vi = &vn->vn_vi[i]; for (j = 0; j < vi->vi_entry_count; j ++) { if (vi->vi_entry_sizes[j] > cur_free) /* j-th entry doesn't fit into L[0] */ break; bytes += vi->vi_entry_sizes[j]; cur_free -= vi->vi_entry_sizes[j]; tb->lbytes ++; } /* "." can not be cut from first directory item */ if ((vn->vn_vi[i].vi_type & VI_TYPE_FIRST_DIRECTORY_ITEM) && tb->lbytes < 2) tb->lbytes = 0; } if (tb->lbytes <= 0) { /* nothing can flow from the item */ tb->lbytes = -1; return -1; } /* something can flow from the item */ tb->lnum[0] ++; #ifdef CONFIG_REISERFS_CHECK if (bytes == -1) reiserfs_panic (tb->tb_sb, "vs-8060: check_left: bytes is not initialized"); #endif return bytes; /* part of split item in bytes */ } reiserfs_panic (0, "vs: 8065: check_left: all items fit in the left neighbor"); return 0; } /* using virtual node check, how many items can be shifted to right neighbor */ static int check_right (struct tree_balance * tb, int h, int cur_free) { int i; struct virtual_node * vn = tb->tb_vn; int d_size, ih_size, bytes = -1; #ifdef CONFIG_REISERFS_CHECK if (cur_free < 0) reiserfs_panic (tb->tb_sb, "vs-8070: check_right: cur_free < 0"); #endif /* internal level */ if (h > 0) { if (!cur_free) { tb->rnum[h] = 0; return 0; } tb->rnum[h] = cur_free / (DC_SIZE + KEY_SIZE); return -1; } /* leaf level */ if (!cur_free || !vn->vn_nr_item) { /* no free space */ tb->rnum[h] = 0; tb->rbytes = -1; return 0; } #ifdef CONFIG_REISERFS_CHECK if (!PATH_H_PPARENT (tb->tb_path, 0)) reiserfs_panic (tb->tb_sb, "vs-8075: check_right: parent does not exist or invalid"); #endif if ((unsigned int)cur_free >= (vn->vn_size - ((vn->vn_vi[vn->vn_nr_item-1].vi_type & VI_TYPE_RIGHT_MERGEABLE) ? IH_SIZE : 0))) { /* all contents of S[0] fits into R[0] */ #ifdef CONFIG_REISERFS_CHECK if (vn->vn_mode == M_INSERT || vn->vn_mode == M_PASTE) reiserfs_panic (tb->tb_sb, "vs-8080: check_right: invalid mode or balance condition failed"); #endif tb->rnum[h] = vn->vn_nr_item; tb->rbytes = -1; return -1; } d_size = 0, ih_size = IH_SIZE; /* last item may be merge with first item in right neighbor */ if (vn->vn_vi[vn->vn_nr_item - 1].vi_type & VI_TYPE_RIGHT_MERGEABLE) d_size = -(int)IH_SIZE, ih_size = 0; tb->rnum[0] = 0; for (i = vn->vn_nr_item - 1; i >= 0; i --, d_size = 0, ih_size = IH_SIZE) { d_size += vn->vn_vi[i].vi_item_len; if (cur_free >= d_size) { /* the item can be shifted entirely */ cur_free -= d_size; tb->rnum[0] ++; continue; } /* the item cannot be shifted entirely, try to split it */ if (vn->vn_vi[i].vi_type & VI_TYPE_STAT_DATA || vn->vn_vi[i].vi_type & VI_TYPE_INSERTED_DIRECTORY_ITEM) { /* virtual item is a stat_data or empty directory body ("." and "..), that is not split able */ tb->rbytes = -1; return -1; } /* check whether R[0] can hold ih and at least one byte of the item body */ if ( cur_free <= ih_size ) /* cannot shift even a part of the current item */ { tb->rbytes = -1; return -1; } /* R[0] can hold the header of the item and at least one byte of its body */ cur_free -= ih_size; /* cur_free is still > 0 */ /* item is of direct type */ if (vn->vn_vi[i].vi_type & VI_TYPE_DIRECT) /* body of a direct item can be split at any byte */ tb->rbytes = bytes = cur_free; /* item is of indirect type */ if (vn->vn_vi[i].vi_type & VI_TYPE_INDIRECT) /* an unformatted node pointer (having size long) is a solid granule of the item */ tb->rbytes = bytes = cur_free - cur_free % UNFM_P_SIZE; /* item is of directory type */ if (vn->vn_vi[i].vi_type & VI_TYPE_DIRECTORY) { int j; struct virtual_item * vi; tb->rbytes = 0; bytes = 0; vi = &vn->vn_vi[i]; for (j = vi->vi_entry_count - 1; j >= 0; j --) { if (vi->vi_entry_sizes[j] > cur_free) /* j-th entry doesn't fit into L[0] */ break; bytes += vi->vi_entry_sizes[j]; cur_free -= vi->vi_entry_sizes[j]; tb->rbytes ++; } /* ".." can not be cut from first directory item */ if ((vn->vn_vi[i].vi_type & VI_TYPE_FIRST_DIRECTORY_ITEM) && tb->rbytes > vi->vi_entry_count - 2) { #ifdef CONFIG_REISERFS_CHECK if (tb->rbytes > vi->vi_entry_count - 1) { reiserfs_panic (tb->tb_sb, "vs-8085: check_right: all entries can be shifted to right neighbor"); } #endif tb->rbytes = vi->vi_entry_count - 2; } } if ( tb->rbytes <= 0 ) { /* nothing can flow from the item */ tb->rbytes = -1; return -1; } /* something can flow from the item */ tb->rnum[0] ++; #ifdef CONFIG_REISERFS_CHECK if (bytes == -1) reiserfs_panic (tb->tb_sb, "vs-8090: check_right: bytes is not initialized"); #endif return bytes; /* part of split item in bytes */ } reiserfs_panic ("vs-8095: check_right: all items fit in the left neighbor"); return 0; } /* sum of entry sizes between from-th and to-th entries including both edges */ static int directory_part_size (struct virtual_item * vi, int from, int to) { int i, retval; retval = 0; for (i = from; i <= to; i ++) retval += vi->vi_entry_sizes[i]; return retval; } /* * from - number of items, which are shifted to left neighbor entirely * to - number of item, which are shifted to right neighbor entirely * from_bytes - number of bytes of boundary item (or directory entries) which are shifted to left neighbor * to_bytes - number of bytes of boundary item (or directory entries) which are shifted to right neighbor */ static int get_num_ver (int mode, struct tree_balance * tb, int h, int from, int from_bytes, int to, int to_bytes, short * snum012, int flow ) { int i; int bytes; struct virtual_node * vn = tb->tb_vn; struct virtual_item * vi; int total_node_size, max_node_size, current_item_size; int needed_nodes; int start_item, /* position of item we start filling node from */ end_item, /* position of item we finish filling node by */ start_bytes,/* number of first bytes (entries for directory) of start_item-th item we do not include into node that is being filled */ end_bytes; /* number of last bytes (entries for directory) of end_item-th item we do node include into node that is being filled */ int splitted_item_positions[2]; /* these are positions in virtual item of items, that are splitted between S[0] and S1new and S1new and S2new */ #ifdef CONFIG_REISERFS_CHECK /* We only create additional nodes if we are in insert or paste mode or we are in replace mode at the internal level. If h is 0 and the mode is M_REPLACE then in fix_nodes we change the mode to paste or insert before we get here in the code. */ if ( tb->insert_size[h] < 0 || (mode != M_INSERT && mode != M_PASTE)) reiserfs_panic (0, "vs-8100: get_num_ver: insert_size < 0 in overflow"); #endif max_node_size = MAX_CHILD_SIZE (PATH_H_PBUFFER (tb->tb_path, h)); /* snum012 [0-2] - number of items, that lay to S[0], first new node and second new node */ snum012[3] = -1; /* s1bytes */ snum012[4] = -1; /* s2bytes */ /* internal level */ if (h > 0) { i = ((to - from) * (KEY_SIZE + DC_SIZE) + DC_SIZE); if (i == max_node_size) return 1; return (i / max_node_size + 1); } /* leaf level */ needed_nodes = 1; total_node_size = 0; start_item = from; start_bytes = from_bytes; end_item = vn->vn_nr_item - to - 1; end_bytes = to_bytes; /* go through all items begining from the start_item-th item and ending by the end_item-th item. If start_bytes != -1 we skip first start_bytes item units (entries in case of directory). If end_bytes != -1 we skip end_bytes units of the end_item-th item. */ for (i = start_item; i <= end_item; i ++) { #ifdef CONFIG_REISERFS_CHECK if (needed_nodes > 3) reiserfs_panic (0, "vs-8105: get_num_ver: too many nodes are needed"); #endif /* get size of current item */ current_item_size = (vi = &vn->vn_vi[i])->vi_item_len; /* do not take in calculation head part (from_bytes) of from-th item */ if (i == start_item && start_bytes != -1) { if (vi->vi_type & VI_TYPE_DIRECTORY) current_item_size -= directory_part_size (vi, 0, start_bytes - 1); else current_item_size -= start_bytes; } /* do not take in calculation tail part of (to-1)-th item */ if (i == end_item && end_bytes != -1) { if (vi->vi_type & VI_TYPE_DIRECTORY) /* first entry, that is not included */ current_item_size -= directory_part_size (vi, vi->vi_entry_count - end_bytes, vi->vi_entry_count - 1); else current_item_size -= end_bytes; } /* if item fits into current node entirely */ if (total_node_size + current_item_size <= max_node_size) { snum012[needed_nodes - 1] ++; total_node_size += current_item_size; continue; } if (current_item_size > max_node_size) { /* virtual item length is longer, than max size of item in a node. It is impossible for direct item */ #ifdef CONFIG_REISERFS_CHECK if (vi->vi_type & VI_TYPE_DIRECT) reiserfs_panic (0, "vs-8110: get_num_ver: direct item length is %d. It can not be longer than %d", current_item_size, max_node_size); #endif /* we will try to split it */ flow = 1; } if (!flow) { /* as we do not split items, take new node and continue */ needed_nodes ++; i --; total_node_size = 0; continue; } if (total_node_size + (int)IH_SIZE >= max_node_size) { /* even minimal item does not fit into current node, take new node and continue */ needed_nodes ++, i--, total_node_size = 0; continue; } if (vi->vi_type & VI_TYPE_STAT_DATA) { /* stat data can not be split */ needed_nodes ++, i--, total_node_size = 0; continue; } /* body of a direct item can be split at any byte */ /* bytes is free space in filled node */ bytes = max_node_size - total_node_size - IH_SIZE; /* item is of indirect type */ if (vi->vi_type & VI_TYPE_INDIRECT) /* an unformatted node pointer (having size long) is a solid granule of the item */ /* bytes of unformatted node pointers fits into free space of filled node */ bytes -= (bytes) % UNFM_P_SIZE; /* S1bytes or S2bytes. It depends from needed_nodes */ snum012[needed_nodes - 1 + 3] = bytes; /* item is of directory type */ if (vi->vi_type & VI_TYPE_DIRECTORY) { /* calculate, how many entries can be put into current node */ int j; int end_entry; snum012[needed_nodes - 1 + 3] = 0; total_node_size += IH_SIZE; if (start_bytes == -1 || i != start_item) start_bytes = 0; end_entry = vi->vi_entry_count - ((i == end_item && end_bytes != -1) ? end_bytes : 0); for (j = start_bytes; j < end_entry; j ++) { /* j-th entry doesn't fit into current node */ if (total_node_size + vi->vi_entry_sizes[j] > max_node_size) break; snum012[needed_nodes - 1 + 3] ++; bytes += vi->vi_entry_sizes[j]; total_node_size += vi->vi_entry_sizes[j]; } /* "." can not be cut from first directory item */ if (start_bytes == 0 && (vn->vn_vi[i].vi_type & VI_TYPE_FIRST_DIRECTORY_ITEM) && snum012[needed_nodes - 1 + 3] < 2) snum012[needed_nodes - 1 + 3] = 0; #ifdef CONFIG_REISERFS_CHECK if (vi->vi_entry_count && vi->vi_entry_count - ((i == end_item && end_bytes != -1) ? end_bytes : 0) - (start_bytes) <= snum012[needed_nodes - 1 + 3]) reiserfs_panic (0, "vs-8115: get_num_ver: required part of directory fits into current node"); #endif } if (snum012[needed_nodes-1+3] <= 0 ) { /* nothing fits into current node, take new node and continue */ needed_nodes ++, i--, total_node_size = 0; continue; } /* something fits into the current node */ if (vi->vi_type & VI_TYPE_DIRECTORY) start_bytes += snum012[needed_nodes - 1 + 3]; else start_bytes = bytes; snum012[needed_nodes - 1] ++; splitted_item_positions[needed_nodes - 1] = i; needed_nodes ++; /* continue from the same item with start_bytes != -1 */ start_item = i; i --; total_node_size = 0; } /* snum012[3] and snum012[4] contain how many bytes (entries) of split item can be in S[0] and S1new. s1bytes and s2bytes are how many bytes (entries) can be in S1new and S2new. Recalculate it */ if (snum012[4] > 0) { /* s2bytes */ /* get number of item that is split between S1new and S2new */ int split_item_num; int bytes_to_r, bytes_to_l; split_item_num = splitted_item_positions[1]; bytes_to_l = ((from == split_item_num && from_bytes != -1) ? from_bytes : 0); bytes_to_r = ((end_item == split_item_num && end_bytes != -1) ? end_bytes : 0); if (vn->vn_vi[split_item_num].vi_type & VI_TYPE_DIRECTORY) { int entries_to_S2new; /* calculate number of entries fit into S2new */ entries_to_S2new = vn->vn_vi[split_item_num].vi_entry_count - snum012[4] - bytes_to_r - bytes_to_l; if (snum012[3] != -1 && snum012[1] == 1) { /* directory split into 3 nodes */ int entries_to_S1new; entries_to_S2new -= snum012[3]; entries_to_S1new = snum012[4]; snum012[3] = entries_to_S1new; snum012[4] = entries_to_S2new; return needed_nodes; } snum012[4] = entries_to_S2new; } else { /* item is not of directory type */ int bytes_to_S2new; bytes_to_S2new = vn->vn_vi[split_item_num].vi_item_len - IH_SIZE - snum012[4] - bytes_to_r - bytes_to_l; snum012[4] = bytes_to_S2new; } } /* now we know S2bytes, calculate S1bytes */ if (snum012[3] > 0) { /* s1bytes */ /* get number of item that is split between S0 and S1new */ int split_item_num; int bytes_to_r, bytes_to_l; split_item_num = splitted_item_positions[0]; bytes_to_l = ((from == split_item_num && from_bytes != -1) ? from_bytes : 0); bytes_to_r = ((end_item == split_item_num && end_bytes != -1) ? end_bytes : 0); if (vn->vn_vi[split_item_num].vi_type & VI_TYPE_DIRECTORY) { /* entries, who go to S1new node */ snum012[3] = vn->vn_vi[split_item_num].vi_entry_count - snum012[3] - bytes_to_r - bytes_to_l; } else /* bytes, who go to S1new node (not including HI_SIZE) */ snum012[3] = vn->vn_vi[split_item_num].vi_item_len - IH_SIZE - snum012[3] - bytes_to_r - bytes_to_l; } return needed_nodes; } #ifdef CONFIG_REISERFS_CHECK extern struct tree_balance * cur_tb; #endif /* size of item_num-th item in bytes when regular and in entries when item is directory */ static int item_length (struct tree_balance * tb, int item_num) { struct virtual_node * vn = tb->tb_vn; #ifdef CONFIG_REISERFS_CHECK if (item_num >= vn->vn_nr_item) reiserfs_panic (tb->tb_sb, "vs-8120: item_length: invalid index of item: index = %d (item number = %d)", item_num, vn->vn_nr_item); #endif if (vn->vn_vi[item_num].vi_type & VI_TYPE_DIRECTORY) return vn->vn_vi[item_num].vi_entry_count; return vn->vn_vi[item_num].vi_item_len - IH_SIZE; } /* Set parameters for balancing. * Performs write of results of analysis of balancing into structure tb, * where it will later be used by the functions that actually do the balancing. * Parameters: * tb tree_balance structure; * h current level of the node; * lnum number of items from S[h] that must be shifted to L[h]; * rnum number of items from S[h] that must be shifted to R[h]; * blk_num number of blocks that S[h] will be splitted into; * s012 number of items that fall into splitted nodes. * lbytes number of bytes which flow to the left neighbor from the item that is not * not shifted entirely * rbytes number of bytes which flow to the right neighbor from the item that is not * not shifted entirely * s1bytes number of bytes which flow to the first new node when S[0] splits (this number is contained in s012 array) */ static void set_parameters (struct tree_balance * tb, int h, int lnum, int rnum, int blk_num, short * s012, int lb, int rb) { tb->lnum[h] = lnum; tb->rnum[h] = rnum; tb->blknum[h] = blk_num; if (h == 0) { /* only for leaf level */ if (s012 != NULL) { tb->s0num = * s012 ++, tb->s1num = * s012 ++, tb->s2num = * s012 ++; tb->s1bytes = * s012 ++; tb->s2bytes = * s012; } tb->lbytes = lb; tb->rbytes = rb; } } static void decrement_key (struct key * p_s_key) { int type; type = get_type (p_s_key); switch (type) { case TYPE_STAT_DATA: p_s_key->k_objectid --; set_type_and_offset (key_format (p_s_key), p_s_key, (loff_t)MAX_FILE_SIZE_V2, TYPE_INDIRECT); return; case TYPE_INDIRECT: case TYPE_DIRECT: case TYPE_DIRENTRY: set_offset (key_format (p_s_key), p_s_key, get_offset (p_s_key) - 1); if (get_offset (p_s_key) == 0) set_type (key_format (p_s_key), p_s_key, TYPE_STAT_DATA); return; } reiserfs_warning (stderr, "vs-8125: decrement_key: item of wrong type found %k", p_s_key); #if 0 unsigned long * p_n_key_field = (unsigned long *)p_s_key + REISERFS_FULL_KEY_LEN - 1; int n_counter; for( n_counter = 0; n_counter < REISERFS_FULL_KEY_LEN; n_counter++, p_n_key_field-- ) if ( *p_n_key_field ) { (*p_n_key_field)--; break; } #ifdef CONFIG_REISERFS_CHECK if ( n_counter == REISERFS_FULL_KEY_LEN ) reiserfs_panic(NULL, "PAP-8175: decrement_key: zero key"); #endif #endif } #ifdef FU //REISERFS_FSCK inline int is_left_mergeable (struct item_head * ih, unsigned long bsize) { if (I_IS_DIRECT_ITEM (ih)) return ((get_offset (&ih->ih_key) & (bsize - 1)) != 1); if (I_IS_INDIRECT_ITEM (ih)) return (get_offset (&ih->ih_key) != 1); if (I_IS_DIRECTORY_ITEM (ih)) return ((ih)->ih_key.u.k_offset_v1.k_offset != DOT_OFFSET); #ifdef CONFIG_REISERFS_CHECK if ( ! I_IS_STAT_DATA_ITEM (ih)) reiserfs_panic (0, "vs-16060: is_left_mergeable: item [%h] must be a stat data", ih); #endif return 0; } #else int are_items_mergeable (struct item_head * left, struct item_head * right, int bsize) { if (comp_keys (&left->ih_key, &right->ih_key) != -1) { reiserfs_panic (0, "vs-16070: are_items_mergeable: left %k, right %k", &(left->ih_key), &(right->ih_key)); } if (not_of_one_file (&left->ih_key, &right->ih_key)) return 0; if (I_IS_DIRECTORY_ITEM (left)) { return 1; } if ((I_IS_DIRECT_ITEM (left) && I_IS_DIRECT_ITEM (right)) || (I_IS_INDIRECT_ITEM (left) && I_IS_INDIRECT_ITEM (right))) return (get_offset (&left->ih_key) + get_bytes_number (left, bsize) == get_offset (&right->ih_key)) ? 1 : 0; return 0; } /* get left neighbor of the leaf node */ static struct buffer_head * get_left_neighbor (struct super_block * s, struct path * path) { struct key key; struct path path_to_left_neighbor; struct buffer_head * bh; int repeat; copy_key (&key, B_N_PKEY (PATH_PLAST_BUFFER (path), 0)); decrement_key (&key); init_path (&path_to_left_neighbor); search_by_key (s, &key, &path_to_left_neighbor, &repeat, DISK_LEAF_NODE_LEVEL); if (PATH_LAST_POSITION (&path_to_left_neighbor) == 0) { pathrelse (&path_to_left_neighbor); return 0; } bh = PATH_PLAST_BUFFER (&path_to_left_neighbor); bh->b_count ++; pathrelse (&path_to_left_neighbor); return bh; } extern struct key MIN_KEY; static struct buffer_head * get_right_neighbor (struct super_block * s, struct path * path) { struct key key; struct key * rkey; int repeat; struct path path_to_right_neighbor; struct buffer_head * bh; rkey = get_rkey (path, s); if (comp_keys (rkey, &MIN_KEY) == 0) reiserfs_panic ("vs-16080: get_right_neighbor: get_rkey returned min key (path has changed)"); copy_key (&key, rkey); init_path (&path_to_right_neighbor); search_by_key (s, &key, &path_to_right_neighbor, &repeat, DISK_LEAF_NODE_LEVEL); if (PATH_PLAST_BUFFER (&path_to_right_neighbor) == PATH_PLAST_BUFFER (path)) { pathrelse (&path_to_right_neighbor); return 0; } bh = PATH_PLAST_BUFFER (&path_to_right_neighbor); bh->b_count ++; pathrelse (&path_to_right_neighbor); return bh; } int is_left_mergeable (struct super_block * s, struct path * path) { struct item_head * right; struct buffer_head * bh; int retval; right = B_N_PITEM_HEAD (PATH_PLAST_BUFFER (path), 0); bh = get_left_neighbor (s, path); if (bh == 0) { return 0; } retval = are_items_mergeable (B_N_PITEM_HEAD (bh, B_NR_ITEMS (bh) - 1), right, bh->b_size); brelse (bh); return retval; } int is_right_mergeable (struct super_block * s, struct path * path) { struct item_head * left; struct buffer_head * bh; int retval; left = B_N_PITEM_HEAD (PATH_PLAST_BUFFER (path), B_NR_ITEMS (PATH_PLAST_BUFFER (path)) - 1); bh = get_right_neighbor (s, path); if (bh == 0) { return 0; } retval = are_items_mergeable (left, B_N_PITEM_HEAD (bh, 0), bh->b_size); brelse (bh); return retval; } #endif /* REISERFS_FSCK */ /* check, does node disappear if we shift tb->lnum[0] items to left neighbor and tb->rnum[0] to the right one. */ static int is_leaf_removable (struct tree_balance * tb) { struct virtual_node * vn = tb->tb_vn; int to_left, to_right; int size; int remain_items; /* number of items, that will be shifted to left (right) neighbor entirely */ to_left = tb->lnum[0] - ((tb->lbytes != -1) ? 1 : 0); to_right = tb->rnum[0] - ((tb->rbytes != -1) ? 1 : 0); remain_items = vn->vn_nr_item; /* how many items remain in S[0] after shiftings to neighbors */ remain_items -= (to_left + to_right); if (remain_items < 1) { /* all content of node can be shifted to neighbors */ set_parameters (tb, 0, to_left, vn->vn_nr_item - to_left, 0, NULL, -1, -1); return 1; } if (remain_items > 1 || tb->lbytes == -1 || tb->rbytes == -1) /* S[0] is not removable */ return 0; /* check, whether we can divide 1 remaining item between neighbors */ /* get size of remaining item (in directory entry count if directory) */ size = item_length (tb, to_left); if (tb->lbytes + tb->rbytes >= size) { set_parameters (tb, 0, to_left + 1, to_right + 1, 0, NULL, tb->lbytes, -1); return 1; } return 0; } /* check whether L, S, R can be joined in one node */ static int are_leaves_removable (struct tree_balance * tb, int lfree, int rfree) { struct virtual_node * vn = tb->tb_vn; int ih_size; struct buffer_head *S0; S0 = PATH_H_PBUFFER (tb->tb_path, 0); ih_size = 0; if (vn->vn_nr_item) { if (vn->vn_vi[0].vi_type & VI_TYPE_LEFT_MERGEABLE) ih_size += IH_SIZE; if (vn->vn_vi[vn->vn_nr_item-1].vi_type & VI_TYPE_RIGHT_MERGEABLE) ih_size += IH_SIZE; } else { /* there was only one item and it will be deleted */ struct item_head * ih; #ifdef CONFIG_REISERFS_CHECK if (B_NR_ITEMS (S0) != 1) reiserfs_panic (0, "vs-8125: are_leaves_removable: item number must be 1: it is %d", B_NR_ITEMS(S0)); #endif ih = B_N_PITEM_HEAD (S0, 0); if (tb->CFR[0] && !not_of_one_file (&(ih->ih_key), B_N_PDELIM_KEY (tb->CFR[0], tb->rkey[0]))) if (I_IS_DIRECTORY_ITEM(ih)) { #ifdef FU //REISERFS_FSCK /* Directory must be in correct state here: that is somewhere at the left side should exist first directory item. But the item being deleted can not be that first one because its right neighbor is item of the same directory. (But first item always gets deleted in last turn). So, neighbors of deleted item can be merged, so we can save ih_size */ ih_size = IH_SIZE; #ifdef CONFIG_REISERFS_CHECK /* we might check that left neighbor exists and is of the same directory */ if (get_offset (&ih->ih_key) == DOT_OFFSET) reiserfs_panic (tb->tb_sb, "vs-8130: are_leaves_removable: " "first directory item can not be removed until directory is not empty"); #endif #else /* REISERFS_FSCK */ /* we can delete any directory item in fsck (if it is unreachable) */ if (get_offset (&ih->ih_key) != DOT_OFFSET) { /* must get left neighbor here to make sure, that left neighbor is of the same directory */ struct buffer_head * left; left = get_left_neighbor (tb->tb_sb, tb->tb_path); if (left) { struct item_head * last; if (B_NR_ITEMS (left) == 0) reiserfs_panic ("vs-8135: are_leaves_removable: " "empty node in the tree"); last = B_N_PITEM_HEAD (left, B_NR_ITEMS (left) - 1); if (!comp_short_keys (&last->ih_key, &ih->ih_key)) ih_size = IH_SIZE; brelse (left); } } #endif } } if (MAX_CHILD_SIZE (S0) + vn->vn_size <= rfree + lfree + ih_size) { set_parameters (tb, 0, -1, -1, -1, NULL, -1, -1); return 1; } return 0; } /* when we do not split item, lnum and rnum are numbers of entire items */ #define SET_PAR_SHIFT_LEFT \ if (h)\ {\ int to_l;\ \ to_l = (MAX_NR_KEY(Sh)+1 - lpar + vn->vn_nr_item + 1) / 2 -\ (MAX_NR_KEY(Sh) + 1 - lpar);\ \ set_parameters (tb, h, to_l, 0, lnver, NULL, -1, -1);\ }\ else \ {\ if (lset==LEFT_SHIFT_FLOW)\ set_parameters (tb, h, lpar, 0, lnver, snum012+lset,\ tb->lbytes, -1);\ else\ set_parameters (tb, h, lpar - (tb->lbytes!=-1), 0, lnver, snum012+lset,\ -1, -1);\ } #define SET_PAR_SHIFT_RIGHT \ if (h)\ {\ int to_r;\ \ to_r = (MAX_NR_KEY(Sh)+1 - rpar + vn->vn_nr_item + 1) / 2 - (MAX_NR_KEY(Sh) + 1 - rpar);\ \ set_parameters (tb, h, 0, to_r, rnver, NULL, -1, -1);\ }\ else \ {\ if (rset==RIGHT_SHIFT_FLOW)\ set_parameters (tb, h, 0, rpar, rnver, snum012+rset,\ -1, tb->rbytes);\ else\ set_parameters (tb, h, 0, rpar - (tb->rbytes!=-1), rnver, snum012+rset,\ -1, -1);\ } #if 0 void free_buffers_in_tb ( struct tree_balance * p_s_tb ) { int n_counter; decrement_counters_in_path(p_s_tb->tb_path); for ( n_counter = 0; n_counter < MAX_HEIGHT; n_counter++ ) { decrement_bcount(p_s_tb->L[n_counter]); p_s_tb->L[n_counter] = NULL; decrement_bcount(p_s_tb->R[n_counter]); p_s_tb->R[n_counter] = NULL; decrement_bcount(p_s_tb->FL[n_counter]); p_s_tb->FL[n_counter] = NULL; decrement_bcount(p_s_tb->FR[n_counter]); p_s_tb->FR[n_counter] = NULL; decrement_bcount(p_s_tb->CFL[n_counter]); p_s_tb->CFL[n_counter] = NULL; decrement_bcount(p_s_tb->CFR[n_counter]); p_s_tb->CFR[n_counter] = NULL; } } #endif /* Get new buffers for storing new nodes that are created while balancing. * Returns: SCHEDULE_OCCURED - schedule occured while the function worked; * CARRY_ON - schedule didn't occur while the function worked; * NO_DISK_SPACE - no disk space. */ static int get_empty_nodes (struct tree_balance * p_s_tb, int n_h) { struct buffer_head * p_s_new_bh, * p_s_Sh = PATH_H_PBUFFER (p_s_tb->tb_path, n_h); unsigned long * p_n_blocknr, a_n_blocknrs[MAX_AMOUNT_NEEDED] = {0, }; int n_counter, n_number_of_freeblk, n_amount_needed,/* number of needed empty blocks */ n_repeat1, n_repeat; struct super_block * p_s_sb = p_s_tb->tb_sb; //#ifndef FU //REISERFS_FSCK if (n_h == 0 && p_s_tb->insert_size[n_h] == 0x7fff) return CARRY_ON; //#endif /* number_of_freeblk is the number of empty blocks which have been acquired for use by the balancing algorithm minus the number of empty blocks used in the previous levels of the analysis, number_of_freeblk = tb->cur_blknum can be non-zero if a schedule occurs after empty blocks are acquired, and the balancing analysis is then restarted, amount_needed is the number needed by this level (n_h) of the balancing analysis. Note that for systems with many processes writing, it would be more layout optimal to calculate the total number needed by all levels and then to run reiserfs_new_blocks to get all of them at once. */ /* Initiate number_of_freeblk to the amount acquired prior to the restart of the analysis or 0 if not restarted, then subtract the amount needed by all of the levels of the tree below n_h. */ /* blknum includes S[n_h], so we subtract 1 in this calculation */ for ( n_counter = 0, n_number_of_freeblk = p_s_tb->cur_blknum; n_counter < n_h; n_counter++ ) n_number_of_freeblk -= ( p_s_tb->blknum[n_counter] ) ? (p_s_tb->blknum[n_counter] - 1) : 0; /* Allocate missing empty blocks. */ /* if p_s_Sh == 0 then we are getting a new root */ n_amount_needed = ( p_s_Sh ) ? (p_s_tb->blknum[n_h] - 1) : 1; /* Amount_needed = the amount that we need more than the amount that we have. */ if ( n_amount_needed > n_number_of_freeblk ) n_amount_needed -= n_number_of_freeblk; else /* If we have enough already then there is nothing to do. */ return CARRY_ON; if ( (n_repeat = reiserfs_new_blocknrs (p_s_tb->tb_sb, a_n_blocknrs, PATH_PLAST_BUFFER(p_s_tb->tb_path)->b_blocknr, n_amount_needed)) != CARRY_ON ) { return n_repeat; /* Out of disk space or schedule() occured. */ } /* for each blocknumber we just got, get a buffer and stick it on FEB */ for ( p_n_blocknr = a_n_blocknrs, n_counter = 0; n_counter < n_amount_needed; p_n_blocknr++, n_counter++ ) { #ifdef CONFIG_REISERFS_CHECK if ( ! *p_n_blocknr ) reiserfs_panic(p_s_sb, "PAP-8135: get_empty_nodes: reiserfs_new_blocknrs failed when got new blocks"); #endif n_repeat1 = CARRY_ON; p_s_new_bh = reiserfs_getblk(p_s_sb->s_dev, *p_n_blocknr, p_s_sb->s_blocksize, &n_repeat1); n_repeat |= n_repeat1; if (p_s_new_bh->b_count > 1) { die ("get_empty_nodes: not free empty buffer"); } #ifdef CONFIG_REISERFS_CHECK_NOCHECK if ((p_s_new_bh->b_count != 1 && !buffer_journaled(p_s_new_bh)) || (buffer_dirty (p_s_new_bh) && !buffer_journal_dirty(p_s_new_bh))) { reiserfs_panic(p_s_sb,"PAP-8140: get_empty_nodes: not free or dirty buffer %b for the new block", p_s_new_bh); } #endif //mark_buffer_journal_new(p_s_new_bh) ; /* Put empty buffers into the array. */ p_s_tb->FEB[p_s_tb->cur_blknum++] = p_s_new_bh; } return n_repeat; } /* Get free space of the left neighbor, * which is stored in the parent node of the left neighbor. */ static int get_lfree (struct tree_balance * tb, int h) { struct buffer_head * l, * f; int order; if ((f = PATH_H_PPARENT (tb->tb_path, h)) == 0 || (l = tb->FL[h]) == 0) return 0; if (f == l) order = PATH_H_B_ITEM_ORDER (tb->tb_path, h) - 1; else { order = B_BLK_HEAD(l)->blk_nr_item; f = l; } if (B_N_CHILD(f,order)->dc_size == 0) { reiserfs_warning (stderr, "get_lfree: block %u block_head %z has bad child pointer %y, order %d\n", l->b_blocknr, l, B_N_CHILD(f,order), order); } return (MAX_CHILD_SIZE(f) - B_N_CHILD(f,order)->dc_size); } /* Get free space of the right neighbor, * which is stored in the parent node of the right neighbor. */ static int get_rfree (struct tree_balance * tb, int h) { struct buffer_head * r, * f; int order; if ((f = PATH_H_PPARENT (tb->tb_path, h)) == 0 || (r = tb->FR[h]) == 0) return 0; if (f == r) order = PATH_H_B_ITEM_ORDER (tb->tb_path, h) + 1; else { order = 0; f = r; } return (MAX_CHILD_SIZE(f) - B_N_CHILD(f,order)->dc_size); } /* Check whether left neighbor is in memory. */ static int is_left_neighbor_in_cache( struct tree_balance * p_s_tb, int n_h ) { struct buffer_head * p_s_father; struct super_block * p_s_sb = p_s_tb->tb_sb; unsigned long n_left_neighbor_blocknr; int n_left_neighbor_position; if ( ! p_s_tb->FL[n_h] ) /* Father of the left neighbor does not exist. */ return 0; /* Calculate father of the node to be balanced. */ p_s_father = PATH_H_PBUFFER(p_s_tb->tb_path, n_h + 1); #ifdef CONFIG_REISERFS_CHECK if ( ! p_s_father || ! B_IS_IN_TREE (p_s_father) || ! B_IS_IN_TREE (p_s_tb->FL[n_h]) || ! buffer_uptodate (p_s_father) || ! buffer_uptodate (p_s_tb->FL[n_h]) ) { reiserfs_panic (p_s_sb, "vs-8165: is_left_neighbor_in_cache: F[h] (%b) or FL[h] (%b) is invalid", p_s_father, p_s_tb->FL[n_h]); } #endif /* Get position of the pointer to the left neighbor into the left father. */ n_left_neighbor_position = ( p_s_father == p_s_tb->FL[n_h] ) ? p_s_tb->lkey[n_h] : B_BLK_HEAD(p_s_tb->FL[n_h])->blk_nr_item; /* Get left neighbor block number. */ n_left_neighbor_blocknr = B_N_CHILD_NUM(p_s_tb->FL[n_h], n_left_neighbor_position); /* Look for the left neighbor in the cache. */ if ( (p_s_father = find_buffer(p_s_sb->s_dev, n_left_neighbor_blocknr, p_s_sb->s_blocksize)) ) { #ifdef CONFIG_REISERFS_CHECK if ( buffer_uptodate (p_s_father) && ! B_IS_IN_TREE(p_s_father) ) { reiserfs_panic(p_s_sb, "vs-8170: is_left_neighbor_in_cache: left neighbor (%b %z) is not in the tree", p_s_father, p_s_father); } #endif return 1; } return 0; } #define LEFT_PARENTS 'l' #define RIGHT_PARENTS 'r' void init_path (struct path * path) { path->path_length = ILLEGAL_PATH_ELEMENT_OFFSET; } /* Calculate far left/right parent of the left/right neighbor of the current node, that * is calculate the left/right (FL[h]/FR[h]) neighbor of the parent F[h]. * Calculate left/right common parent of the current node and L[h]/R[h]. * Calculate left/right delimiting key position. * Returns: PATH_INCORRECT - path in the tree is not correct; SCHEDULE_OCCURRED - schedule occured while the function worked; * CARRY_ON - schedule didn't occur while the function worked; */ static int get_far_parent( struct tree_balance * p_s_tb, int n_h, struct buffer_head ** pp_s_father, struct buffer_head ** pp_s_com_father, char c_lr_par ) { struct buffer_head * p_s_parent; struct path s_path_to_neighbor_father, * p_s_path = p_s_tb->tb_path; struct key s_lr_father_key; int n_counter, n_position = INT_MAX, n_repeat, n_first_last_position = 0, n_path_offset = PATH_H_PATH_OFFSET(p_s_path, n_h); /* Starting from F[n_h] go upwards in the tree, and look for the common ancestor of F[n_h], and its neighbor l/r, that should be obtained. */ n_counter = n_path_offset; #ifdef CONFIG_REISERFS_CHECK if ( n_counter < FIRST_PATH_ELEMENT_OFFSET ) reiserfs_panic(p_s_tb->tb_sb, "PAP-8180: get_far_parent: invalid path length"); #endif for ( ; n_counter > FIRST_PATH_ELEMENT_OFFSET; n_counter-- ) { /* Check whether parent of the current buffer in the path is really parent in the tree. */ if ( ! B_IS_IN_TREE(p_s_parent = PATH_OFFSET_PBUFFER(p_s_path, n_counter - 1)) ) return PATH_INCORRECT; /* Check whether position in the parent is correct. */ if ( (n_position = PATH_OFFSET_POSITION(p_s_path, n_counter - 1)) > B_NR_ITEMS(p_s_parent) ) return PATH_INCORRECT; /* Check whether parent at the path really points to the child. */ if ( B_N_CHILD_NUM(p_s_parent, n_position) != PATH_OFFSET_PBUFFER(p_s_path, n_counter)->b_blocknr ) return PATH_INCORRECT; /* Return delimiting key if position in the parent is not equal to first/last one. */ if ( c_lr_par == RIGHT_PARENTS ) n_first_last_position = B_BLK_HEAD(p_s_parent)->blk_nr_item; if ( n_position != n_first_last_position ) { (*pp_s_com_father = p_s_parent)->b_count++; break; } } /* Hopefully we are in the root of the tree. */ if ( n_counter == FIRST_PATH_ELEMENT_OFFSET ) { /* Check whether first buffer in the path is the root of the tree. */ if ( PATH_OFFSET_PBUFFER(p_s_tb->tb_path, FIRST_PATH_ELEMENT_OFFSET)->b_blocknr == SB_ROOT_BLOCK (p_s_tb->tb_sb) ) { *pp_s_father = *pp_s_com_father = NULL; return CARRY_ON; } return PATH_INCORRECT; } #ifdef CONFIG_REISERFS_CHECK if ( B_BLK_HEAD(*pp_s_com_father)->blk_level <= DISK_LEAF_NODE_LEVEL ) { reiserfs_panic(p_s_tb->tb_sb, "PAP-8185: get_far_parent: (%b %z) level too small", *pp_s_com_father, *pp_s_com_father); } #endif /* Check whether the common parent is locked. */ #if 0 if ( test_and_wait_on_buffer(*pp_s_com_father) == SCHEDULE_OCCURRED ) { decrement_bcount(*pp_s_com_father); return SCHEDULE_OCCURRED; /* schedule() occured */ } #endif /* So, we got common parent of the current node and its left/right neighbor. Now we are geting the parent of the left/right neighbor. */ /* Form key to get parent of the left/right neighbor. */ copy_key(&s_lr_father_key, B_N_PDELIM_KEY(*pp_s_com_father, ( c_lr_par == LEFT_PARENTS ) ? (p_s_tb->lkey[n_h - 1] = n_position - 1) : (p_s_tb->rkey[n_h - 1] = n_position))); if ( c_lr_par == LEFT_PARENTS ) { //reiserfs_warning ("decrememnting key %k\n", &s_lr_father_key); decrement_key(&s_lr_father_key); //reiserfs_warning ("done: %k\n", &s_lr_father_key); } init_path (&s_path_to_neighbor_father); if (search_by_key(p_s_tb->tb_sb, &s_lr_father_key, &s_path_to_neighbor_father, &n_repeat, n_h + 1) == IO_ERROR) return IO_ERROR; if ( n_repeat != CARRY_ON ) { pathrelse (&s_path_to_neighbor_father); //decrement_counters_in_path(&s_path_to_neighbor_father); brelse (*pp_s_com_father); //decrement_bcount(*pp_s_com_father); return n_repeat; } *pp_s_father = PATH_PLAST_BUFFER(&s_path_to_neighbor_father); #ifdef CONFIG_REISERFS_CHECK if ( B_BLK_HEAD(*pp_s_father)->blk_level != n_h + 1 ) { reiserfs_panic(p_s_tb->tb_sb, "PAP-8190: get_far_parent: (%b %z) level too small", *pp_s_father, *pp_s_father); } if ( s_path_to_neighbor_father.path_length < FIRST_PATH_ELEMENT_OFFSET ) reiserfs_panic(0, "PAP-8192: get_far_parent: path length is too small"); #endif s_path_to_neighbor_father.path_length--; pathrelse (&s_path_to_neighbor_father); //decrement_counters_in_path(&s_path_to_neighbor_father); return CARRY_ON; } /* Get parents of neighbors of node in the path(S[n_path_offset]) and common parents of * S[n_path_offset] and L[n_path_offset]/R[n_path_offset]: F[n_path_offset], FL[n_path_offset], * FR[n_path_offset], CFL[n_path_offset], CFR[n_path_offset]. * Calculate numbers of left and right delimiting keys position: lkey[n_path_offset], rkey[n_path_offset]. * Returns: SCHEDULE_OCCURRED - schedule occured while the function worked; * CARRY_ON - schedule didn't occur while the function worked; */ static int get_parents (struct tree_balance * p_s_tb, int n_h) { struct path * p_s_path = p_s_tb->tb_path; int n_position, n_ret_value, n_path_offset = PATH_H_PATH_OFFSET(p_s_tb->tb_path, n_h); struct buffer_head * p_s_curf, * p_s_curcf; /* Current node is the root of the tree or will be root of the tree */ if ( n_path_offset <= FIRST_PATH_ELEMENT_OFFSET ) { /* The root can not have parents. Release nodes which previously were obtained as parents of the current node neighbors. */ brelse(p_s_tb->FL[n_h]); brelse(p_s_tb->CFL[n_h]); brelse(p_s_tb->FR[n_h]); brelse(p_s_tb->CFR[n_h]); //decrement_bcount(p_s_tb->FL[n_h]); //decrement_bcount(p_s_tb->CFL[n_h]); //decrement_bcount(p_s_tb->FR[n_h]); //decrement_bcount(p_s_tb->CFR[n_h]); p_s_tb->FL[n_h] = p_s_tb->CFL[n_h] = p_s_tb->FR[n_h] = p_s_tb->CFR[n_h] = NULL; return CARRY_ON; } /* Get parent FL[n_path_offset] of L[n_path_offset]. */ if ( (n_position = PATH_OFFSET_POSITION(p_s_path, n_path_offset - 1)) ) { /* Current node is not the first child of its parent. */ (p_s_curf = p_s_curcf = PATH_OFFSET_PBUFFER(p_s_path, n_path_offset - 1))->b_count += 2; p_s_tb->lkey[n_h] = n_position - 1; } else { /* Calculate current parent of L[n_path_offset], which is the left neighbor of the current node. Calculate current common parent of L[n_path_offset] and the current node. Note that CFL[n_path_offset] not equal FL[n_path_offset] and CFL[n_path_offset] not equal F[n_path_offset]. Calculate lkey[n_path_offset]. */ if ( (n_ret_value = get_far_parent(p_s_tb, n_h + 1, &p_s_curf, &p_s_curcf, LEFT_PARENTS)) != CARRY_ON ) return n_ret_value; /*schedule() occured or path is not correct*/ #ifdef CONFIG_REISERFS_CHECK if (p_s_curf == PATH_OFFSET_PBUFFER(p_s_path, n_path_offset - 1)) { reiserfs_panic (p_s_tb->tb_sb, "vs-8194: get_parents: " "get_far_parent fails"); } #endif } brelse(p_s_tb->FL[n_h]); p_s_tb->FL[n_h] = p_s_curf; /* New initialization of FL[n_h]. */ brelse(p_s_tb->CFL[n_h]); p_s_tb->CFL[n_h] = p_s_curcf; /* New initialization of CFL[n_h]. */ #ifdef CONFIG_REISERFS_CHECK if ((p_s_curf && !B_IS_IN_TREE (p_s_curf)) || (p_s_curcf && !B_IS_IN_TREE (p_s_curcf))) { reiserfs_panic (p_s_tb->tb_sb, "PAP-8195: get_parents: FL (%b) or CFL (%b) is invalid", p_s_curf, p_s_curcf); } #endif /* Get parent FR[n_h] of R[n_h]. */ /* Current node is the last child of F[n_h]. FR[n_h] != F[n_h]. */ if ( n_position == B_BLK_HEAD(PATH_H_PBUFFER(p_s_path, n_h + 1))->blk_nr_item ) { /* Calculate current parent of R[n_h], which is the right neighbor of F[n_h]. Calculate current common parent of R[n_h] and current node. Note that CFR[n_h] not equal FR[n_path_offset] and CFR[n_h] not equal F[n_h]. */ if ( (n_ret_value = get_far_parent(p_s_tb, n_h + 1, &p_s_curf, &p_s_curcf, RIGHT_PARENTS)) != CARRY_ON ) return n_ret_value; /*schedule() occured while get_far_parent() worked.*/ } else { /* Current node is not the last child of its parent F[n_h]. */ (p_s_curf = p_s_curcf = PATH_OFFSET_PBUFFER(p_s_path, n_path_offset - 1))->b_count += 2; p_s_tb->rkey[n_h] = n_position; } brelse/*decrement_bcount*/(p_s_tb->FR[n_h]); p_s_tb->FR[n_h] = p_s_curf; /* New initialization of FR[n_path_offset]. */ brelse/*decrement_bcount*/(p_s_tb->CFR[n_h]); p_s_tb->CFR[n_h] = p_s_curcf; /* New initialization of CFR[n_path_offset]. */ #ifdef CONFIG_REISERFS_CHECK if ((p_s_curf && !B_IS_IN_TREE (p_s_curf)) || (p_s_curcf && !B_IS_IN_TREE (p_s_curcf))) { reiserfs_panic (p_s_tb->tb_sb, "PAP-8205: get_parents: FR (%b) or CFR (%b) is invalid", p_s_curf, p_s_curcf); } #endif return CARRY_ON; /* schedule not occured while get_parents() worked. */ } /* it is possible to remove node as result of shiftings to neighbors even when we insert or paste item. */ static inline int can_node_be_removed (int mode, int lfree, int sfree, int rfree, struct tree_balance * tb, int h) { struct buffer_head * Sh = PATH_H_PBUFFER (tb->tb_path, h); int levbytes = tb->insert_size[h]; struct item_head * ih; struct item_head * r_ih = NULL; ih = B_N_PITEM_HEAD (Sh, 0); if ( tb->CFR[h] ) r_ih = (struct item_head *)B_N_PDELIM_KEY(tb->CFR[h],tb->rkey[h]); if ( lfree + rfree + sfree < MAX_CHILD_SIZE(Sh) + levbytes /* shifting may merge items which might save space */ #ifndef FU //REISERFS_FSCK - (( ! h && is_left_mergeable (tb->tb_sb, tb->tb_path) == 1 ) ? IH_SIZE : 0) - (( ! h && r_ih && is_right_mergeable (tb->tb_sb, tb->tb_path) == 1 ) ? IH_SIZE : 0) #else - (( ! h && is_left_mergeable (ih, Sh->b_size) ) ? IH_SIZE : 0) - (( ! h && r_ih && is_left_mergeable (r_ih, Sh->b_size) ) ? IH_SIZE : 0) #endif + (( h ) ? KEY_SIZE : 0)) { /* node can not be removed */ if (sfree >= levbytes ) /* new item fits into node S[h] without any shifting */ { if ( ! h ) tb->s0num = B_NR_ITEMS(Sh) + ((mode == M_INSERT ) ? 1 : 0); set_parameters (tb, h, 0, 0, 1, NULL, -1, -1); return NO_BALANCING_NEEDED; } } return !NO_BALANCING_NEEDED; } /* Check whether current node S[h] is balanced when increasing its size by * Inserting or Pasting. * Calculate parameters for balancing for current level h. * Parameters: * tb tree_balance structure; * h current level of the node; * inum item number in S[h]; * mode i - insert, p - paste; * Returns: 1 - schedule occured; * 0 - balancing for higher levels needed; * -1 - no balancing for higher levels needed; * -2 - no disk space. */ /* ip means Inserting or Pasting */ static int ip_check_balance (/*struct reiserfs_transaction_handle *th,*/ struct tree_balance * tb, int h) { struct virtual_node * vn = tb->tb_vn; int levbytes, /* Number of bytes that must be inserted into (value is negative if bytes are deleted) buffer which contains node being balanced. The mnemonic is that the attempted change in node space used level is levbytes bytes. */ n_ret_value; int lfree, sfree, rfree /* free space in L, S and R */; /* nver is short for number of vertixes, and lnver is the number if we shift to the left, rnver is the number if we shift to the right, and lrnver is the number if we shift in both directions. The goal is to minimize first the number of vertixes, and second, the number of vertixes whose contents are changed by shifting, and third the number of uncached vertixes whose contents are changed by shifting and must be read from disk. */ int nver, lnver, rnver, lrnver; /* used at leaf level only, S0 = S[0] is the node being balanced, sInum [ I = 0,1,2 ] is the number of items that will remain in node SI after balancing. S1 and S2 are new nodes that might be created. */ /* we perform 8 calls to get_num_ver(). For each call we calculate five parameters. where 4th parameter is s1bytes and 5th - s2bytes */ short snum012[40] = {0,}; /* s0num, s1num, s2num for 8 cases 0,1 - do not shift and do not shift but bottle 2 - shift only whole item to left 3 - shift to left and bottle as much as possible 4,5 - shift to right (whole items and as much as possible 6,7 - shift to both directions (whole items and as much as possible) */ /* Sh is the node whose balance is currently being checked */ struct buffer_head * Sh; #ifndef FU //REISERFS_FSCK /* special mode for insert pointer to the most low internal node */ if (h == 0 && vn->vn_mode == M_INTERNAL) { /* blk_num == 2 is to get pointer inserted to the next level */ set_parameters (tb, h, 0, 0, 2, NULL, -1, -1); return 0; } #endif Sh = PATH_H_PBUFFER (tb->tb_path, h); levbytes = tb->insert_size[h]; /* Calculate balance parameters for creating new root. */ if ( ! Sh ) { if ( ! h ) reiserfs_panic ("vs-8210: ip_check_balance: S[0] can not be 0"); switch ( n_ret_value = get_empty_nodes (tb, h) ) { case CARRY_ON: set_parameters (tb, h, 0, 0, 1, NULL, -1, -1); return NO_BALANCING_NEEDED; /* no balancing for higher levels needed */ case NO_DISK_SPACE: case SCHEDULE_OCCURRED: return n_ret_value; default: reiserfs_panic("vs-8215: ip_check_balance: incorrect return value of get_empty_nodes"); } } if ( (n_ret_value = get_parents (tb, h)) != CARRY_ON ) /* get parents of S[h] neighbors. */ return n_ret_value; sfree = B_BLK_HEAD(Sh)->blk_free_space; /* get free space of neighbors */ rfree = get_rfree (tb, h); lfree = get_lfree (tb, h); if (can_node_be_removed (vn->vn_mode, lfree, sfree, rfree, tb, h) == NO_BALANCING_NEEDED) /* and new item fits into node S[h] without any shifting */ return NO_BALANCING_NEEDED; create_virtual_node (tb, h); /* determine maximal number of items we can shift to the left neighbor (in tb structure) and the maximal number of bytes that can flow to the left neighbor from the left most liquid item that cannot be shifted from S[0] entirely (returned value) */ check_left (tb, h, lfree); /* determine maximal number of items we can shift to the right neighbor (in tb structure) and the maximal number of bytes that can flow to the right neighbor from the right most liquid item that cannot be shifted from S[0] entirely (returned value) */ check_right (tb, h, rfree); /* all contents of internal node S[h] can be moved into its neighbors, S[h] will be removed after balancing */ if (h && (tb->rnum[h] + tb->lnum[h] >= vn->vn_nr_item + 1)) { int to_r; /* Since we are working on internal nodes, and our internal nodes have fixed size entries, then we can balance by the number of items rather than the space they consume. In this routine we set the left node equal to the right node, allowing a difference of less than or equal to 1 child pointer. */ to_r = ((MAX_NR_KEY(Sh)<<1)+2-tb->lnum[h]-tb->rnum[h]+vn->vn_nr_item+1)/2 - (MAX_NR_KEY(Sh) + 1 - tb->rnum[h]); set_parameters (tb, h, vn->vn_nr_item + 1 - to_r, to_r, 0, NULL, -1, -1); return CARRY_ON; } #ifdef CONFIG_REISERFS_CHECK /* this checks balance condition, that any two neighboring nodes can not fit in one node */ if ( h && ( tb->lnum[h] >= vn->vn_nr_item + 1 || tb->rnum[h] >= vn->vn_nr_item + 1) ) reiserfs_panic (tb->tb_sb, "vs-8220: ip_check_balance: tree is not balanced on internal level"); if ( ! h && ((tb->lnum[h] >= vn->vn_nr_item && (tb->lbytes == -1)) || (tb->rnum[h] >= vn->vn_nr_item && (tb->rbytes == -1)) )) reiserfs_panic(tb->tb_sb, "vs-8225: ip_check_balance: tree is not balanced on leaf level"); #endif /* all contents of S[0] can be moved into its neighbors S[0] will be removed after balancing. */ if (!h && is_leaf_removable (tb)) return CARRY_ON; /* why do we perform this check here rather than earlier?? Answer: we can win 1 node in some cases above. Moreover we checked it above, when we checked, that S[0] is not removable in principle */ if (sfree >= levbytes) { /* new item fits into node S[h] without any shifting */ if ( ! h ) tb->s0num = vn->vn_nr_item; set_parameters (tb, h, 0, 0, 1, NULL, -1, -1); return NO_BALANCING_NEEDED; } { int lpar, rpar, nset, lset, rset, lrset; /* * regular overflowing of the node */ /* get_num_ver works in 2 modes (FLOW & NO_FLOW) lpar, rpar - number of items we can shift to left/right neighbor (including splitting item) nset, lset, rset, lrset - shows, whether flowing items give better packing */ #define FLOW 1 #define NO_FLOW 0 /* do not any splitting */ /* we choose one the following */ #define NOTHING_SHIFT_NO_FLOW 0 #define NOTHING_SHIFT_FLOW 5 #define LEFT_SHIFT_NO_FLOW 10 #define LEFT_SHIFT_FLOW 15 #define RIGHT_SHIFT_NO_FLOW 20 #define RIGHT_SHIFT_FLOW 25 #define LR_SHIFT_NO_FLOW 30 #define LR_SHIFT_FLOW 35 lpar = tb->lnum[h]; rpar = tb->rnum[h]; /* calculate number of blocks S[h] must be split into when nothing is shifted to the neighbors, as well as number of items in each part of the split node (s012 numbers), and number of bytes (s1bytes) of the shared drop which flow to S1 if any */ nset = NOTHING_SHIFT_NO_FLOW; nver = get_num_ver (vn->vn_mode, tb, h, 0, -1, h?vn->vn_nr_item:0, -1, snum012, NO_FLOW); if (!h) { int nver1; /* note, that in this case we try to bottle between S[0] and S1 (S1 - the first new node) */ nver1 = get_num_ver (vn->vn_mode, tb, h, 0, -1, 0, -1, snum012 + NOTHING_SHIFT_FLOW, FLOW); if (nver > nver1) nset = NOTHING_SHIFT_FLOW, nver = nver1; } /* calculate number of blocks S[h] must be split into when l_shift_num first items and l_shift_bytes of the right most liquid item to be shifted are shifted to the left neighbor, as well as number of items in each part of the splitted node (s012 numbers), and number of bytes (s1bytes) of the shared drop which flow to S1 if any */ lset = LEFT_SHIFT_NO_FLOW; lnver = get_num_ver (vn->vn_mode, tb, h, lpar - (( h || tb->lbytes == -1 ) ? 0 : 1), -1, h ? vn->vn_nr_item:0, -1, snum012 + LEFT_SHIFT_NO_FLOW, NO_FLOW); if (!h) { int lnver1; lnver1 = get_num_ver (vn->vn_mode, tb, h, lpar - ((tb->lbytes != -1) ? 1 : 0), tb->lbytes, 0, -1, snum012 + LEFT_SHIFT_FLOW, FLOW); if (lnver > lnver1) lset = LEFT_SHIFT_FLOW, lnver = lnver1; } /* calculate number of blocks S[h] must be split into when r_shift_num first items and r_shift_bytes of the left most liquid item to be shifted are shifted to the right neighbor, as well as number of items in each part of the splitted node (s012 numbers), and number of bytes (s1bytes) of the shared drop which flow to S1 if any */ rset = RIGHT_SHIFT_NO_FLOW; rnver = get_num_ver (vn->vn_mode, tb, h, 0, -1, h ? (vn->vn_nr_item-rpar) : (rpar - (( tb->rbytes != -1 ) ? 1 : 0)), -1, snum012 + RIGHT_SHIFT_NO_FLOW, NO_FLOW); if (!h) { int rnver1; rnver1 = get_num_ver (vn->vn_mode, tb, h, 0, -1, (rpar - ((tb->rbytes != -1) ? 1 : 0)), tb->rbytes, snum012 + RIGHT_SHIFT_FLOW, FLOW); if (rnver > rnver1) rset = RIGHT_SHIFT_FLOW, rnver = rnver1; } /* calculate number of blocks S[h] must be split into when items are shifted in both directions, as well as number of items in each part of the splitted node (s012 numbers), and number of bytes (s1bytes) of the shared drop which flow to S1 if any */ lrset = LR_SHIFT_NO_FLOW; lrnver = get_num_ver (vn->vn_mode, tb, h, lpar - ((h || tb->lbytes == -1) ? 0 : 1), -1, h ? (vn->vn_nr_item-rpar):(rpar - ((tb->rbytes != -1) ? 1 : 0)), -1, snum012 + LR_SHIFT_NO_FLOW, NO_FLOW); if (!h) { int lrnver1; lrnver1 = get_num_ver (vn->vn_mode, tb, h, lpar - ((tb->lbytes != -1) ? 1 : 0), tb->lbytes, (rpar - ((tb->rbytes != -1) ? 1 : 0)), tb->rbytes, snum012 + LR_SHIFT_FLOW, FLOW); if (lrnver > lrnver1) lrset = LR_SHIFT_FLOW, lrnver = lrnver1; } /* Our general shifting strategy is: 1) to minimized number of new nodes; 2) to minimized number of neighbors involved in shifting; 3) to minimized number of disk reads; */ /* we can win TWO or ONE nodes by shifting in both directions */ if (lrnver < lnver && lrnver < rnver) { #ifdef CONFIG_REISERFS_CHECK if (h && (tb->lnum[h] != 1 || tb->rnum[h] != 1 || lrnver != 1 || rnver != 2 || lnver != 2 || h != 1)) reiserfs_panic (0, "vs-8230: check_balance: bad h"); #endif if (lrset == LR_SHIFT_FLOW) set_parameters (tb, h, tb->lnum[h], tb->rnum[h], lrnver, snum012 + lrset, tb->lbytes, tb->rbytes); else set_parameters (tb, h, tb->lnum[h] - ((tb->lbytes == -1) ? 0 : 1), tb->rnum[h] - ((tb->rbytes == -1) ? 0 : 1), lrnver, snum012 + lrset, -1, -1); return CARRY_ON; } /* if shifting doesn't lead to better packing then don't shift */ if (nver == lrnver) { set_parameters (tb, h, 0, 0, nver, snum012 + nset, -1, -1); return CARRY_ON; } /* now we know that for better packing shifting in only one direction either to the left or to the right is required */ /* if shifting to the left is better than shifting to the right */ if (lnver < rnver) { SET_PAR_SHIFT_LEFT; return CARRY_ON; } /* if shifting to the right is better than shifting to the left */ if (lnver > rnver) { SET_PAR_SHIFT_RIGHT; return CARRY_ON; } /* now shifting in either direction gives the same number of nodes and we can make use of the cached neighbors */ if (is_left_neighbor_in_cache (tb,h)) { SET_PAR_SHIFT_LEFT; return CARRY_ON; } /* shift to the right independently on whether the right neighbor in cache or not */ SET_PAR_SHIFT_RIGHT; return CARRY_ON; } } /* Check whether current node S[h] is balanced when Decreasing its size by * Deleting or Cutting for INTERNAL node of S+tree. * Calculate parameters for balancing for current level h. * Parameters: * tb tree_balance structure; * h current level of the node; * inum item number in S[h]; * mode i - insert, p - paste; * Returns: 1 - schedule occured; * 0 - balancing for higher levels needed; * -1 - no balancing for higher levels needed; * -2 - no disk space. * * Note: Items of internal nodes have fixed size, so the balance condition for * the internal part of S+tree is as for the B-trees. */ static int dc_check_balance_internal (struct tree_balance * tb, int h) { struct virtual_node * vn = tb->tb_vn; /* Sh is the node whose balance is currently being checked, and Fh is its father. */ struct buffer_head * Sh, * Fh; int maxsize, n_ret_value; int lfree, rfree /* free space in L and R */; Sh = PATH_H_PBUFFER (tb->tb_path, h); Fh = PATH_H_PPARENT (tb->tb_path, h); maxsize = MAX_CHILD_SIZE(Sh); /* using tb->insert_size[h], which is negative in this case, create_virtual_node calculates: */ /* new_nr_item = number of items node would have if operation is */ /* performed without balancing (new_nr_item); */ create_virtual_node (tb, h); if ( ! Fh ) { /* S[h] is the root. */ if ( vn->vn_nr_item > 0 ) { set_parameters (tb, h, 0, 0, 1, NULL, -1, -1); return NO_BALANCING_NEEDED; /* no balancing for higher levels needed */ } /* new_nr_item == 0. * Current root will be deleted resulting in * decrementing the tree height. */ set_parameters (tb, h, 0, 0, 0, NULL, -1, -1); return CARRY_ON; } if ( (n_ret_value = get_parents(tb,h)) != CARRY_ON ) return n_ret_value; /* get free space of neighbors */ rfree = get_rfree (tb, h); lfree = get_lfree (tb, h); /* determine maximal number of items we can fit into neighbors */ check_left (tb, h, lfree); check_right (tb, h, rfree); if ( vn->vn_nr_item >= MIN_NR_KEY(Sh) ) { /* Balance condition for the internal node is valid. * In this case we balance only if it leads to better packing. */ if ( vn->vn_nr_item == MIN_NR_KEY(Sh) ) { /* Here we join S[h] with one of its neighbors, * which is impossible with greater values of new_nr_item. */ if ( tb->lnum[h] >= vn->vn_nr_item + 1 ) { /* All contents of S[h] can be moved to L[h]. */ int n; int order_L; order_L = ((n=PATH_H_B_ITEM_ORDER(tb->tb_path, h))==0) ? B_NR_ITEMS(tb->FL[h]) : n - 1; n = B_N_CHILD(tb->FL[h],order_L)->dc_size / (DC_SIZE + KEY_SIZE); set_parameters (tb, h, -n-1, 0, 0, NULL, -1, -1); return CARRY_ON; } if ( tb->rnum[h] >= vn->vn_nr_item + 1 ) { /* All contents of S[h] can be moved to R[h]. */ int n; int order_R; order_R = ((n=PATH_H_B_ITEM_ORDER(tb->tb_path, h))==B_NR_ITEMS(Fh)) ? 0 : n + 1; n = B_N_CHILD(tb->FR[h],order_R)->dc_size / (DC_SIZE + KEY_SIZE); set_parameters (tb, h, 0, -n-1, 0, NULL, -1, -1); return CARRY_ON; } } if (tb->rnum[h] + tb->lnum[h] >= vn->vn_nr_item + 1) { /* All contents of S[h] can be moved to the neighbors (L[h] & R[h]). */ int to_r; to_r = ((MAX_NR_KEY(Sh)<<1)+2-tb->lnum[h]-tb->rnum[h]+vn->vn_nr_item+1)/2 - (MAX_NR_KEY(Sh) + 1 - tb->rnum[h]); set_parameters (tb, h, vn->vn_nr_item + 1 - to_r, to_r, 0, NULL, -1, -1); return CARRY_ON; } /* Balancing does not lead to better packing. */ set_parameters (tb, h, 0, 0, 1, NULL, -1, -1); return NO_BALANCING_NEEDED; } /* Current node contain insufficient number of items. Balancing is required. */ /* Check whether we can merge S[h] with left neighbor. */ if (tb->lnum[h] >= vn->vn_nr_item + 1) if (is_left_neighbor_in_cache (tb,h) || tb->rnum[h] < vn->vn_nr_item + 1 || !tb->FR[h]) { int n; int order_L; order_L = ((n=PATH_H_B_ITEM_ORDER(tb->tb_path, h))==0) ? B_NR_ITEMS(tb->FL[h]) : n - 1; n = B_N_CHILD(tb->FL[h],order_L)->dc_size / (DC_SIZE + KEY_SIZE); set_parameters (tb, h, -n-1, 0, 0, NULL, -1, -1); return CARRY_ON; } /* Check whether we can merge S[h] with right neighbor. */ if (tb->rnum[h] >= vn->vn_nr_item + 1) { int n; int order_R; order_R = ((n=PATH_H_B_ITEM_ORDER(tb->tb_path, h))==B_NR_ITEMS(Fh)) ? 0 : (n + 1); n = B_N_CHILD(tb->FR[h],order_R)->dc_size / (DC_SIZE + KEY_SIZE); set_parameters (tb, h, 0, -n-1, 0, NULL, -1, -1); return CARRY_ON; } /* All contents of S[h] can be moved to the neighbors (L[h] & R[h]). */ if (tb->rnum[h] + tb->lnum[h] >= vn->vn_nr_item + 1) { int to_r; to_r = ((MAX_NR_KEY(Sh)<<1)+2-tb->lnum[h]-tb->rnum[h]+vn->vn_nr_item+1)/2 - (MAX_NR_KEY(Sh) + 1 - tb->rnum[h]); set_parameters (tb, h, vn->vn_nr_item + 1 - to_r, to_r, 0, NULL, -1, -1); return CARRY_ON; } /* For internal nodes try to borrow item from a neighbor */ #ifdef CONFIG_REISERFS_CHECK if (!tb->FL[h] && !tb->FR[h]) reiserfs_panic (0, "vs-8235: dc_check_balance_internal: trying to borrow for root"); #endif /* Borrow one or two items from caching neighbor */ if (is_left_neighbor_in_cache (tb,h) || !tb->FR[h]) { int from_l; from_l = (MAX_NR_KEY(Sh) + 1 - tb->lnum[h] + vn->vn_nr_item + 1) / 2 - (vn->vn_nr_item + 1); set_parameters (tb, h, -from_l, 0, 1, NULL, -1, -1); return CARRY_ON; } set_parameters (tb, h, 0, -((MAX_NR_KEY(Sh)+1-tb->rnum[h]+vn->vn_nr_item+1)/2-(vn->vn_nr_item+1)), 1, NULL, -1, -1); return CARRY_ON; } /* Check whether current node S[h] is balanced when Decreasing its size by * Deleting or Truncating for LEAF node of S+tree. * Calculate parameters for balancing for current level h. * Parameters: * tb tree_balance structure; * h current level of the node; * inum item number in S[h]; * mode i - insert, p - paste; * Returns: 1 - schedule occured; * 0 - balancing for higher levels needed; * -1 - no balancing for higher levels needed; * -2 - no disk space. */ static int dc_check_balance_leaf (struct tree_balance * tb, int h) { struct virtual_node * vn = tb->tb_vn; /* Number of bytes that must be deleted from (value is negative if bytes are deleted) buffer which contains node being balanced. The mnemonic is that the attempted change in node space used level is levbytes bytes. */ int levbytes; /* the maximal item size */ int maxsize, n_ret_value; /* S0 is the node whose balance is currently being checked, and F0 is its father. */ struct buffer_head * S0, * F0; int lfree, rfree /* free space in L and R */; S0 = PATH_H_PBUFFER (tb->tb_path, 0); F0 = PATH_H_PPARENT (tb->tb_path, 0); levbytes = tb->insert_size[h]; maxsize = MAX_CHILD_SIZE(S0); /* maximal possible size of an item */ if ( ! F0 ) { /* S[0] is the root now. */ #ifdef CONFIG_REISERFS_CHECK if ( -levbytes >= maxsize - B_BLK_HEAD(S0)->blk_free_space ) reiserfs_panic (tb->tb_sb, "vs-8240: dc_check_balance_leaf: attempt to create empty buffer tree"); #endif set_parameters (tb, h, 0, 0, 1, NULL, -1, -1); return NO_BALANCING_NEEDED; } if ( (n_ret_value = get_parents(tb,h)) != CARRY_ON ) return n_ret_value; /* get free space of neighbors */ rfree = get_rfree (tb, h); lfree = get_lfree (tb, h); create_virtual_node (tb, h); /* if 3 leaves can be merge to one, set parameters and return */ if (are_leaves_removable (tb, lfree, rfree)) return CARRY_ON; /* determine maximal number of items we can shift to the left/right neighbor and the maximal number of bytes that can flow to the left/right neighbor from the left/right most liquid item that cannot be shifted from S[0] entirely */ check_left (tb, h, lfree); check_right (tb, h, rfree); /* check whether we can merge S with left neighbor. */ if (tb->lnum[0] >= vn->vn_nr_item && tb->lbytes == -1) if (is_left_neighbor_in_cache (tb,h) || ((tb->rnum[0] - ((tb->rbytes == -1) ? 0 : 1)) < vn->vn_nr_item) || /* S can not be merged with R */ !tb->FR[h]) { #ifdef CONFIG_REISERFS_CHECK if (!tb->FL[h]) reiserfs_panic (0, "vs-8245: dc_check_balance_leaf: FL[h] must exist"); #endif /* set parameter to merge S[0] with its left neighbor */ set_parameters (tb, h, -1, 0, 0, NULL, -1, -1); return CARRY_ON; } /* check whether we can merge S[0] with right neighbor. */ if (tb->rnum[0] >= vn->vn_nr_item && tb->rbytes == -1) { set_parameters (tb, h, 0, -1, 0, NULL, -1, -1); return CARRY_ON; } /* All contents of S[0] can be moved to the neighbors (L[0] & R[0]). Set parameters and return */ if (is_leaf_removable (tb)) return CARRY_ON; /* Balancing is not required. */ tb->s0num = vn->vn_nr_item; set_parameters (tb, h, 0, 0, 1, NULL, -1, -1); return NO_BALANCING_NEEDED; } /* Check whether current node S[h] is balanced when Decreasing its size by * Deleting or Cutting. * Calculate parameters for balancing for current level h. * Parameters: * tb tree_balance structure; * h current level of the node; * inum item number in S[h]; * mode d - delete, c - cut. * Returns: 1 - schedule occured; * 0 - balancing for higher levels needed; * -1 - no balancing for higher levels needed; * -2 - no disk space. */ static int dc_check_balance (struct tree_balance * tb, int h) { #ifdef CONFIG_REISERFS_CHECK if ( ! (PATH_H_PBUFFER (tb->tb_path, h)) ) reiserfs_panic(tb->tb_sb, "vs-8250: dc_check_balance: S is not initialized"); #endif if ( h ) return dc_check_balance_internal (tb, h); else return dc_check_balance_leaf (tb, h); } /* Check whether current node S[h] is balanced. * Calculate parameters for balancing for current level h. * Parameters: * * tb tree_balance structure: * * tb is a large structure that must be read about in the header file * at the same time as this procedure if the reader is to successfully * understand this procedure * * h current level of the node; * inum item number in S[h]; * mode i - insert, p - paste, d - delete, c - cut. * Returns: 1 - schedule occured; * 0 - balancing for higher levels needed; * -1 - no balancing for higher levels needed; * -2 - no disk space. */ static int check_balance (int mode, struct tree_balance * tb, int h, int inum, int pos_in_item, struct item_head * ins_ih) { struct virtual_node * vn; vn = tb->tb_vn = (struct virtual_node *)(tb->vn_buf);// + ROUND_UP(SB_BMAP_NR (tb->tb_sb) * 2 / 8 + 1, 4)); vn->vn_free_ptr = (char *)(tb->tb_vn + 1); vn->vn_mode = mode; vn->vn_affected_item_num = inum; vn->vn_pos_in_item = pos_in_item; vn->vn_ins_ih = ins_ih; #ifdef CONFIG_REISERFS_CHECK if (mode == M_INSERT && !vn->vn_ins_ih) reiserfs_panic (0, "vs-8255: check_balance: ins_ih can not be 0 in insert mode"); #endif if ( tb->insert_size[h] > 0 ) /* Calculate balance parameters when size of node is increasing. */ return ip_check_balance (tb, h); /* Calculate balance parameters when size of node is decreasing. */ return dc_check_balance (tb, h); } /* Check whether parent at the path is the really parent of the current node.*/ static int get_direct_parent( struct tree_balance * p_s_tb, int n_h ) { struct buffer_head * p_s_bh; struct path * p_s_path = p_s_tb->tb_path; int n_position, n_path_offset = PATH_H_PATH_OFFSET(p_s_tb->tb_path, n_h); /* We are in the root or in the new root. */ if ( n_path_offset <= FIRST_PATH_ELEMENT_OFFSET ) { #ifdef CONFIG_REISERFS_CHECK if ( n_path_offset < FIRST_PATH_ELEMENT_OFFSET - 1 ) reiserfs_panic(p_s_tb->tb_sb, "PAP-8260: get_direct_parent: illegal offset in the path"); #endif if ( PATH_OFFSET_PBUFFER(p_s_path, FIRST_PATH_ELEMENT_OFFSET)->b_blocknr == SB_ROOT_BLOCK (p_s_tb->tb_sb) ) { /* Root is not changed. */ PATH_OFFSET_PBUFFER(p_s_path, n_path_offset - 1) = NULL; PATH_OFFSET_POSITION(p_s_path, n_path_offset - 1) = 0; return CARRY_ON; } return PATH_INCORRECT; /* Root is changed and we must recalculate the path. */ } if ( ! B_IS_IN_TREE(p_s_bh = PATH_OFFSET_PBUFFER(p_s_path, n_path_offset - 1)) ) return PATH_INCORRECT; /* Parent in the path is not in the tree. */ if ( (n_position = PATH_OFFSET_POSITION(p_s_path, n_path_offset - 1)) > B_NR_ITEMS(p_s_bh) ) return PATH_INCORRECT; if ( B_N_CHILD_NUM(p_s_bh, n_position) != PATH_OFFSET_PBUFFER(p_s_path, n_path_offset)->b_blocknr ) /* Parent in the path is not parent of the current node in the tree. */ return PATH_INCORRECT; #if 0 if ( test_and_wait_on_buffer(p_s_bh) == SCHEDULE_OCCURRED ) /* Buffer was locked. */ return SCHEDULE_OCCURRED; #endif return CARRY_ON; /* Parent in the path is unlocked and really parent of the current node. */ } /* Using lnum[n_h] and rnum[n_h] we should determine what neighbors * of S[n_h] we * need in order to balance S[n_h], and get them if necessary. * Returns: SCHEDULE_OCCURRED - schedule occured while the function worked; * CARRY_ON - schedule didn't occur while the function worked; */ static int get_neighbors(struct tree_balance * p_s_tb, int n_h) { int n_child_position, n_repeat, n_path_offset = PATH_H_PATH_OFFSET(p_s_tb->tb_path, n_h + 1); unsigned long n_son_number; struct super_block * p_s_sb = p_s_tb->tb_sb; struct buffer_head * p_s_bh; /*struct virtual_node * vn = p_s_tb->tb_vn;*/ if ( p_s_tb->lnum[n_h] ) { #ifdef CONFIG_REISERFS_CHECK if ( ! p_s_tb->lnum[n_h] && vn->vn_mode == M_CUT && ! (vn->vn_vi[0].vi_type & VI_TYPE_DIRECTORY) ) reiserfs_panic (p_s_tb->tb_sb, "PAP-8265: get_neighbors: item must be directory item"); #endif /* We need left neighbor to balance S[n_h]. */ p_s_bh = PATH_OFFSET_PBUFFER(p_s_tb->tb_path, n_path_offset); #ifdef CONFIG_REISERFS_CHECK if ( p_s_bh == p_s_tb->FL[n_h] && ! PATH_OFFSET_POSITION(p_s_tb->tb_path, n_path_offset) ) reiserfs_panic (p_s_tb->tb_sb, "PAP-8270: get_neighbors: invalid position in the parent"); #endif n_child_position = ( p_s_bh == p_s_tb->FL[n_h] ) ? p_s_tb->lkey[n_h] : B_BLK_HEAD(p_s_tb->FL[n_h])->blk_nr_item; n_son_number = B_N_CHILD_NUM(p_s_tb->FL[n_h], n_child_position); n_repeat = CARRY_ON; p_s_bh = reiserfs_bread(p_s_sb->s_dev, n_son_number, p_s_sb->s_blocksize, &n_repeat); if (!p_s_bh) return IO_ERROR; if ( n_repeat != CARRY_ON ) { brelse /*decrement_bcount*/(p_s_bh); return SCHEDULE_OCCURRED; } #ifdef CONFIG_REISERFS_CHECK if ( ! B_IS_IN_TREE(p_s_tb->FL[n_h]) || n_child_position > B_NR_ITEMS(p_s_tb->FL[n_h]) || B_N_CHILD_NUM(p_s_tb->FL[n_h], n_child_position) != p_s_bh->b_blocknr ) reiserfs_panic (p_s_tb->tb_sb, "PAP-8275: get_neighbors: invalid parent"); if ( ! B_IS_IN_TREE(p_s_bh) ) reiserfs_panic (p_s_tb->tb_sb, "PAP-8280: get_neighbors: invalid child"); if (! n_h && node_free_space (p_s_bh) != MAX_CHILD_SIZE (p_s_bh) - B_N_CHILD (p_s_tb->FL[0],n_child_position)->dc_size) { reiserfs_panic (p_s_tb->tb_sb, "PAP-8290: get_neighbors: invalid child size of left neighbor"); } #endif brelse /*decrement_bcount*/(p_s_tb->L[n_h]); p_s_tb->L[n_h] = p_s_bh; } if ( p_s_tb->rnum[n_h] ) { /* We need right neighbor to balance S[n_path_offset]. */ p_s_bh = PATH_OFFSET_PBUFFER(p_s_tb->tb_path, n_path_offset); #ifdef CONFIG_REISERFS_CHECK if ( p_s_bh == p_s_tb->FR[n_h] && PATH_OFFSET_POSITION(p_s_tb->tb_path, n_path_offset) >= B_NR_ITEMS(p_s_bh) ) reiserfs_panic (p_s_tb->tb_sb, "PAP-8295: get_neighbors: invalid position in the parent"); #endif n_child_position = ( p_s_bh == p_s_tb->FR[n_h] ) ? p_s_tb->rkey[n_h] + 1 : 0; n_son_number = B_N_CHILD_NUM(p_s_tb->FR[n_h], n_child_position); n_repeat = CARRY_ON; p_s_bh = reiserfs_bread(p_s_sb->s_dev, n_son_number, p_s_sb->s_blocksize, &n_repeat); if (!p_s_bh) return IO_ERROR; if ( n_repeat != CARRY_ON ) { brelse/*decrement_bcount*/(p_s_bh); return SCHEDULE_OCCURRED; } brelse/*decrement_bcount*/(p_s_tb->R[n_h]); p_s_tb->R[n_h] = p_s_bh; #ifdef CONFIG_REISERFS_CHECK if (! n_h && node_free_space (p_s_bh) != MAX_CHILD_SIZE (p_s_bh) - B_N_CHILD (p_s_tb->FR[0],n_child_position)->dc_size) { reiserfs_panic (p_s_tb->tb_sb, "PAP-8300: get_neighbors: invalid child size of right neighbor (%d != %d - %d)", node_free_space (p_s_bh), MAX_CHILD_SIZE (p_s_bh), B_N_CHILD (p_s_tb->FR[0],n_child_position)->dc_size); } #endif } return CARRY_ON; } void * reiserfs_kmalloc (size_t size, int flags, struct super_block * s) { void * vp; vp = getmem (size); return vp; } void reiserfs_kfree (/*const */void * vp, size_t size, struct super_block * s) { freemem (vp); #if 0 kfree (vp); s->u.reiserfs_sb.s_kmallocs -= size; if (s->u.reiserfs_sb.s_kmallocs < 0) reiserfs_warning ("vs-8302: reiserfs_kfree: allocated memory %d\n", s->u.reiserfs_sb.s_kmallocs); #endif } static int get_virtual_node_size (struct super_block * sb, struct buffer_head * bh) { //int size = sizeof (struct virtual_item); /* for new item in case of insert */ //int i, nr_items; //struct item_head * ih; return sb->s_blocksize; #if 0 size = sizeof (struct virtual_node) + sizeof (struct virtual_item); ih = B_N_PITEM_HEAD (bh, 0); nr_items = B_NR_ITEMS (bh); for (i = 0; i < nr_items; i ++, ih ++) { /* each item occupies some space in virtual node */ size += sizeof (struct virtual_item); if (I_IS_DIRECTORY_ITEM (ih)) /* each entry and new one occupeis 2 byte in the virtual node */ size += (ih_entry_count (ih) + 1) * sizeof (__u16); } /* 1 bit for each bitmap block to note whether bitmap block was dirtied in the operation */ size += (SB_BMAP_NR (sb) * 2 / 8 + 4); return size; #endif } static int get_mem_for_virtual_node (struct tree_balance * tb) { int size; size = get_virtual_node_size (tb->tb_sb, PATH_PLAST_BUFFER(tb->tb_path)); tb->vn_buf = getmem (size); return CARRY_ON; } /* Prepare for balancing, that is * get all necessary parents, and neighbors; * analyze what and where should be moved; * get sufficient number of new nodes; * Balancing will start only after all resources will be collected at a time. * * When ported to SMP kernels, only at the last moment after all needed nodes * are collected in cache, will the resources be locked using the usual * textbook ordered lock acquisition algorithms. Note that ensuring that * this code neither write locks what it does not need to write lock nor locks out of order * will be a pain in the butt that could have been avoided. Grumble grumble. -Hans * * fix is meant in the sense of render unchanging * * Latency might be improved by first gathering a list of what buffers are needed * and then getting as many of them in parallel as possible? -Hans * * Parameters: * op_mode i - insert, d - delete, c - cut (truncate), p - paste (append) * tb tree_balance structure; * inum item number in S[h]; * pos_in_item - comment this if you can * ins_ih & ins_sd are used when inserting * Returns: 1 - schedule occurred while the function worked; * 0 - schedule didn't occur while the function worked; * -1 - if no_disk_space */ int fix_nodes (/*struct reiserfs_transaction_handle *th,*/ int n_op_mode, struct tree_balance * p_s_tb, struct item_head * p_s_ins_ih) { int n_pos_in_item = p_s_tb->tb_path->pos_in_item; int n_ret_value, n_h, n_item_num = get_item_pos (p_s_tb->tb_path); struct buffer_head * p_s_tbS0 = get_bh (p_s_tb->tb_path); // struct item_head * ih = get_ih (p_s_tb->tb_path); /* if it possible in indirect_to_direct conversion */ if (buffer_locked (p_s_tbS0)) { return SCHEDULE_OCCURRED; } #ifdef CONFIG_REISERFS_CHECK if ( cur_tb ) { print_tb (n_op_mode, n_item_num, n_pos_in_item, cur_tb,"fix_nodes"); reiserfs_panic(p_s_tb->tb_sb,"PAP-8305: fix_nodes: there is pending do_balance"); } if (!buffer_uptodate (p_s_tbS0) || !B_IS_IN_TREE (p_s_tbS0)) { reiserfs_panic (p_s_tb->tb_sb, "PAP-8320: fix_nodes: S[0] (%b %z) is not uptodate " "at the beginning of fix_nodes or not in tree (mode %c)", p_s_tbS0, p_s_tbS0, n_op_mode); } /* Check parameters. */ switch (n_op_mode) { #ifndef FU //REISERFS_FSCK // FIXME: REISERFS_CHECK can not be turned on for utils case M_INTERNAL: break; case M_INSERT: if ( n_item_num < 0 || n_item_num > B_NR_ITEMS(p_s_tbS0) ) reiserfs_panic(p_s_tb->tb_sb,"PAP-8325: fix_nodes: Incorrect item number %d (in S0 - %d) in case of insert", n_item_num, B_NR_ITEMS(p_s_tbS0)); #else case M_INSERT: if ( n_item_num <= 0 || n_item_num > B_NR_ITEMS(p_s_tbS0) ) reiserfs_panic(p_s_tb->tb_sb,"PAP-8330: fix_nodes: Incorrect item number %d (in S0 - %d) in case of insert", n_item_num, B_NR_ITEMS(p_s_tbS0)); #endif break; case M_PASTE: if (I_IS_DIRECT_ITEM (get_ih (p_s_tb->tb_path))) { // we can paste only to the end for now if (n_pos_in_item != ih_item_len (get_ih (p_s_tb->tb_path))) reiserfs_panic (th->t_super, "vs-8332: fix_nodes: " "pos_in_item %d set improperly to paste direct item %h", n_pos_in_item, get_ih (p_s_tb->tb_path)); } // fall through case M_DELETE: case M_CUT: if ( n_item_num < 0 || n_item_num >= B_NR_ITEMS(p_s_tbS0) ) { print_block (p_s_tbS0, 0, -1, -1); printk("mode = %c insert_size = %d\n", n_op_mode, p_s_tb->insert_size[0]); reiserfs_panic(p_s_tb->tb_sb,"PAP-8335: fix_nodes: Incorrect item number(%d)", n_item_num); } break; default: reiserfs_panic(p_s_tb->tb_sb,"PAP-8340: fix_nodes: Incorrect mode of operation"); } #endif if (get_mem_for_virtual_node (p_s_tb) == SCHEDULE_OCCURRED) { return SCHEDULE_OCCURRED; } /* Starting from the leaf level; for all levels n_h of the tree. */ for ( n_h = 0; n_h < MAX_HEIGHT && p_s_tb->insert_size[n_h]; n_h++ ) { if ( (n_ret_value = get_direct_parent(p_s_tb, n_h)) != CARRY_ON ) { return n_ret_value; } if ( (n_ret_value = check_balance (/*th,*/ n_op_mode, p_s_tb, n_h, n_item_num, n_pos_in_item, p_s_ins_ih)) != CARRY_ON ) { if ( n_ret_value == NO_BALANCING_NEEDED ) { /* No balancing for higher levels needed. */ if ( (n_ret_value = get_neighbors(p_s_tb, n_h)) != CARRY_ON ) { return n_ret_value; } if ( n_h != MAX_HEIGHT - 1 ) p_s_tb->insert_size[n_h + 1] = 0; /* ok, analysis and resource gathering are complete */ break; } return n_ret_value; } if ( (n_ret_value = get_neighbors(p_s_tb, n_h)) != CARRY_ON ) { return n_ret_value; } if ( (n_ret_value = get_empty_nodes(/*th,*/ p_s_tb, n_h)) != CARRY_ON ) { return n_ret_value; /* No disk space, or schedule occurred and analysis may be invalid and needs to be redone. */ } if ( ! PATH_H_PBUFFER(p_s_tb->tb_path, n_h) ) { /* We have a positive insert size but no nodes exist on this level, this means that we are creating a new root. */ #ifdef CONFIG_REISERFS_CHECK if ( p_s_tb->blknum[n_h] != 1 ) reiserfs_panic(p_s_tb->tb_sb,"PAP-8350: fix_nodes: creating new empty root"); #endif /* CONFIG_REISERFS_CHECK */ if ( n_h < MAX_HEIGHT - 1 ) p_s_tb->insert_size[n_h + 1] = 0; } else if ( ! PATH_H_PBUFFER(p_s_tb->tb_path, n_h + 1) ) { if ( p_s_tb->blknum[n_h] > 1 ) { /* The tree needs to be grown, so this node S[n_h] which is the root node is split into two nodes, and a new node (S[n_h+1]) will be created to become the root node. */ #ifdef CONFIG_REISERFS_CHECK if ( n_h == MAX_HEIGHT - 1 ) reiserfs_panic(p_s_tb->tb_sb, "PAP-8355: fix_nodes: attempt to create too high of a tree"); #endif /* CONFIG_REISERFS_CHECK */ p_s_tb->insert_size[n_h + 1] = (DC_SIZE + KEY_SIZE) * (p_s_tb->blknum[n_h] - 1) + DC_SIZE; } else if ( n_h < MAX_HEIGHT - 1 ) p_s_tb->insert_size[n_h + 1] = 0; } else p_s_tb->insert_size[n_h + 1] = (DC_SIZE + KEY_SIZE) * (p_s_tb->blknum[n_h] - 1); } return CARRY_ON; /* schedule did not occur */ } void unfix_nodes(/* struct reiserfs_transaction_handle *th,*/struct tree_balance * p_s_tb) { struct path * p_s_path = p_s_tb->tb_path; int n_counter; // int i, j; //struct buffer_head * bh; #ifdef CONFIG_REISERFS_CHECK if ( ! p_s_tb->vn_buf ) reiserfs_panic (p_s_tb->tb_sb, "PAP-16050: unfix_nodes: pointer to the virtual node is NULL"); #endif /* Release path buffers. */ pathrelse(p_s_path); for ( n_counter = 0; n_counter < MAX_HEIGHT; n_counter++ ) { /* Release fathers and neighbors. */ brelse(p_s_tb->L[n_counter]); brelse(p_s_tb->R[n_counter]); brelse(p_s_tb->FL[n_counter]); brelse(p_s_tb->FR[n_counter]); brelse(p_s_tb->CFL[n_counter]); brelse(p_s_tb->CFR[n_counter]); } /* Could be optimized. Will be done by PAP someday */ for ( n_counter = 0; n_counter < MAX_FEB_SIZE; n_counter++ ) { if ( p_s_tb->FEB[n_counter] ) { /* release what was not used */ reiserfs_free_block(p_s_tb->tb_sb, p_s_tb->FEB[n_counter]->b_blocknr); bforget(p_s_tb->FEB[n_counter]); /* tree balance bitmap of bitmaps has bit set already */ } /* release used as new nodes including a new root */ brelse (p_s_tb->used[n_counter]); } reiserfs_kfree (p_s_tb->vn_buf, p_s_tb->vn_buf_size, p_s_tb->tb_sb); } reiserfsprogs-3.x.0j/reiserfscore/hashes.c0000644000076400001440000001045207251671063014475 /* * Keyed 32-bit hash function using TEA in a Davis-Meyer function * H0 = Key * Hi = E Mi(Hi-1) + Hi-1 * * (see Applied Cryptography, 2nd edition, p448). * * Jeremy Fitzhardinge 1998 * * Jeremy has agreed to the contents of reiserfs/README. -Hans * Yura's function is added (04/07/2000) */ // // keyed_hash // yura_hash // r5 // #include #define DELTA 0x9E3779B9 #define FULLROUNDS 10 /* 32 is overkill, 16 is strong crypto */ #define PARTROUNDS 6 /* 6 gets complete mixing */ #ifndef __KERNEL__ typedef __u32 u32; #endif /* a, b, c, d - data; h0, h1 - accumulated hash */ #define TEACORE(rounds) \ do { \ u32 sum = 0; \ int n = rounds; \ u32 b0, b1; \ \ b0 = h0; \ b1 = h1; \ \ do \ { \ sum += DELTA; \ b0 += ((b1 << 4)+a) ^ (b1+sum) ^ ((b1 >> 5)+b); \ b1 += ((b0 << 4)+c) ^ (b0+sum) ^ ((b0 >> 5)+d); \ } while(--n); \ \ h0 += b0; \ h1 += b1; \ } while(0) u32 keyed_hash(const char *msg, int len) { u32 k[] = { 0x9464a485, 0x542e1a94, 0x3e846bff, 0xb75bcfc3}; u32 h0 = k[0], h1 = k[1]; u32 a, b, c, d; u32 pad; int i; // assert(len >= 0 && len < 256); pad = (u32)len | ((u32)len << 8); pad |= pad << 16; while(len >= 16) { a = (u32)msg[ 0] | (u32)msg[ 1] << 8 | (u32)msg[ 2] << 16| (u32)msg[ 3] << 24; b = (u32)msg[ 4] | (u32)msg[ 5] << 8 | (u32)msg[ 6] << 16| (u32)msg[ 7] << 24; c = (u32)msg[ 8] | (u32)msg[ 9] << 8 | (u32)msg[10] << 16| (u32)msg[11] << 24; d = (u32)msg[12] | (u32)msg[13] << 8 | (u32)msg[14] << 16| (u32)msg[15] << 24; TEACORE(PARTROUNDS); len -= 16; msg += 16; } if (len >= 12) { //assert(len < 16); if (len >= 16) *(int *)0 = 0; a = (u32)msg[ 0] | (u32)msg[ 1] << 8 | (u32)msg[ 2] << 16| (u32)msg[ 3] << 24; b = (u32)msg[ 4] | (u32)msg[ 5] << 8 | (u32)msg[ 6] << 16| (u32)msg[ 7] << 24; c = (u32)msg[ 8] | (u32)msg[ 9] << 8 | (u32)msg[10] << 16| (u32)msg[11] << 24; d = pad; for(i = 12; i < len; i++) { d <<= 8; d |= msg[i]; } } else if (len >= 8) { //assert(len < 12); if (len >= 12) *(int *)0 = 0; a = (u32)msg[ 0] | (u32)msg[ 1] << 8 | (u32)msg[ 2] << 16| (u32)msg[ 3] << 24; b = (u32)msg[ 4] | (u32)msg[ 5] << 8 | (u32)msg[ 6] << 16| (u32)msg[ 7] << 24; c = d = pad; for(i = 8; i < len; i++) { c <<= 8; c |= msg[i]; } } else if (len >= 4) { //assert(len < 8); if (len >= 8) *(int *)0 = 0; a = (u32)msg[ 0] | (u32)msg[ 1] << 8 | (u32)msg[ 2] << 16| (u32)msg[ 3] << 24; b = c = d = pad; for(i = 4; i < len; i++) { b <<= 8; b |= msg[i]; } } else { //assert(len < 4); if (len >= 4) *(int *)0 = 0; a = b = c = d = pad; for(i = 0; i < len; i++) { a <<= 8; a |= msg[i]; } } TEACORE(FULLROUNDS); /* return 0;*/ return h0^h1; } u32 yura_hash (const char *msg, int len) { int j, pow; u32 a, c; int i; for (pow=1,i=1; i < len; i++) pow = pow * 10; if (len == 1) a = msg[0]-48; else a = (msg[0] - 48) * pow; for (i=1; i < len; i++) { c = msg[i] - 48; for (pow=1,j=i; j < len-1; j++) pow = pow * 10; a = a + c * pow; } for (; i < 40; i++) { c = '0' - 48; for (pow=1,j=i; j < len-1; j++) pow = pow * 10; a = a + c * pow; } for (; i < 256; i++) { c = i; for (pow=1,j=i; j < len-1; j++) pow = pow * 10; a = a + c * pow; } a = a << 7; return a; } u32 r5_hash (const char *msg, int len) { u32 a=0; int i; for (i = 0; i < len; i ++) { a += msg[i] << 4; a += msg[i] >> 4; a *= 11; } return a; } #if 0 #include //#include int main (void) { char * name = 0; size_t n = 0; while (1) { getline (&name, &n, stdin); if (!strcmp (name, "\n")) break; name [strlen (name) - 1] = 0; printf ("tea %lu\n, r5 %lu\nyura %lu\n", keyed_hash (name, strlen (name)) & 0x7fffff80, r5_hash (name, strlen (name)) & 0x7fffff80, yura_hash (name, strlen (name)) & 0x7fffff80); free (name); name = 0; n = 0; } } #endif reiserfsprogs-3.x.0j/reiserfscore/ibalance.c0000644000076400001440000011077307254256172014772 /* * Copyright 1996, 1997, 1998 Hans Reiser, see reiserfs/README for licensing and copyright details */ #include "includes.h" /* this is one and only function that is used outside (do_balance.c) */ int balance_internal ( /*struct reiserfs_transaction_handle *th,*/ struct tree_balance * , int, int, struct item_head * , struct buffer_head ** ); /* modes of internal_shift_left, internal_shift_right and internal_insert_childs */ #define INTERNAL_SHIFT_FROM_S_TO_L 0 #define INTERNAL_SHIFT_FROM_R_TO_S 1 #define INTERNAL_SHIFT_FROM_L_TO_S 2 #define INTERNAL_SHIFT_FROM_S_TO_R 3 #define INTERNAL_INSERT_TO_S 4 #define INTERNAL_INSERT_TO_L 5 #define INTERNAL_INSERT_TO_R 6 static void internal_define_dest_src_infos ( int shift_mode, struct tree_balance * tb, int h, struct buffer_info * dest_bi, struct buffer_info * src_bi, int * d_key, struct buffer_head ** cf ) { #ifdef CONFIG_REISERFS_CHECK memset (dest_bi, 0, sizeof (struct buffer_info)); memset (src_bi, 0, sizeof (struct buffer_info)); #endif /* define dest, src, dest parent, dest position */ switch (shift_mode) { case INTERNAL_SHIFT_FROM_S_TO_L: /* used in internal_shift_left */ src_bi->bi_bh = PATH_H_PBUFFER (tb->tb_path, h); src_bi->bi_parent = PATH_H_PPARENT (tb->tb_path, h); src_bi->bi_position = PATH_H_POSITION (tb->tb_path, h + 1); dest_bi->bi_bh = tb->L[h]; dest_bi->bi_parent = tb->FL[h]; dest_bi->bi_position = get_left_neighbor_position (tb, h); *d_key = tb->lkey[h]; *cf = tb->CFL[h]; break; case INTERNAL_SHIFT_FROM_L_TO_S: src_bi->bi_bh = tb->L[h]; src_bi->bi_parent = tb->FL[h]; src_bi->bi_position = get_left_neighbor_position (tb, h); dest_bi->bi_bh = PATH_H_PBUFFER (tb->tb_path, h); dest_bi->bi_parent = PATH_H_PPARENT (tb->tb_path, h); dest_bi->bi_position = PATH_H_POSITION (tb->tb_path, h + 1); /* dest position is analog of dest->b_item_order */ *d_key = tb->lkey[h]; *cf = tb->CFL[h]; break; case INTERNAL_SHIFT_FROM_R_TO_S: /* used in internal_shift_left */ src_bi->bi_bh = tb->R[h]; src_bi->bi_parent = tb->FR[h]; src_bi->bi_position = get_right_neighbor_position (tb, h); dest_bi->bi_bh = PATH_H_PBUFFER (tb->tb_path, h); dest_bi->bi_parent = PATH_H_PPARENT (tb->tb_path, h); dest_bi->bi_position = PATH_H_POSITION (tb->tb_path, h + 1); *d_key = tb->rkey[h]; *cf = tb->CFR[h]; break; case INTERNAL_SHIFT_FROM_S_TO_R: src_bi->bi_bh = PATH_H_PBUFFER (tb->tb_path, h); src_bi->bi_parent = PATH_H_PPARENT (tb->tb_path, h); src_bi->bi_position = PATH_H_POSITION (tb->tb_path, h + 1); dest_bi->bi_bh = tb->R[h]; dest_bi->bi_parent = tb->FR[h]; dest_bi->bi_position = get_right_neighbor_position (tb, h); *d_key = tb->rkey[h]; *cf = tb->CFR[h]; break; case INTERNAL_INSERT_TO_L: dest_bi->bi_bh = tb->L[h]; dest_bi->bi_parent = tb->FL[h]; dest_bi->bi_position = get_left_neighbor_position (tb, h); break; case INTERNAL_INSERT_TO_S: dest_bi->bi_bh = PATH_H_PBUFFER (tb->tb_path, h); dest_bi->bi_parent = PATH_H_PPARENT (tb->tb_path, h); dest_bi->bi_position = PATH_H_POSITION (tb->tb_path, h + 1); break; case INTERNAL_INSERT_TO_R: dest_bi->bi_bh = tb->R[h]; dest_bi->bi_parent = tb->FR[h]; dest_bi->bi_position = get_right_neighbor_position (tb, h); break; default: reiserfs_panic ("internal_define_dest_src_infos", "shift type is unknown (%d)", shift_mode); } } /* Insert 'count' node pointers into buffer cur before position 'to' + 1. * Insert count items into buffer cur before position to. * Items and node pointers are specified by inserted and bh respectively. */ static void internal_insert_childs (reiserfs_filsys_t fs, struct buffer_info * cur_bi, int to, int count, struct item_head * inserted, struct buffer_head ** bh) { struct buffer_head * cur = cur_bi->bi_bh; int nr; struct key * key; struct disk_child new_dc[2]; struct disk_child * dc; int i; int from; if (count <= 0) return; nr = node_item_number (cur); #ifdef CONFIG_REISERFS_CHECK if (count > 2) reiserfs_panic (0, "internal_insert_childs", "too many children (%d) are to be inserted", count); if (node_free_space (cur) < count * (KEY_SIZE + DC_SIZE)) reiserfs_panic (0, "internal_insert_childs", "no enough free space (%d), needed %d bytes", node_free_space (cur), count * (KEY_SIZE + DC_SIZE)); #endif /* CONFIG_REISERFS_CHECK */ /* prepare space for count disk_child */ dc = B_N_CHILD (cur,to+1); memmove (dc + count, dc, (nr+1-(to+1)) * DC_SIZE); /* make disk child array for insertion */ for (i = 0; i < count; i ++) { new_dc[i].dc_size = cpu_to_le16 (MAX_CHILD_SIZE(bh[i]) - node_free_space (bh[i])); new_dc[i].dc_block_number = cpu_to_le32 (bh[i]->b_blocknr); } memcpy (dc, new_dc, DC_SIZE * count); /* prepare space for 'count' items */ from = ((to == -1) ? 0 : to); key = B_N_PDELIM_KEY (cur, from); memmove (key + count, key, (nr - from/*to*/) * KEY_SIZE + (nr + 1 + count) * DC_SIZE); /* copy keys */ memcpy (key, inserted, KEY_SIZE); if ( count > 1 ) memcpy (key + 1, inserted + 1, KEY_SIZE); /* sizes, item number */ set_node_item_number (cur, nr + count); set_node_free_space (cur, node_free_space (cur) - count * (DC_SIZE + KEY_SIZE)); mark_buffer_dirty (cur); if (cur_bi->bi_parent) { B_N_CHILD (cur_bi->bi_parent,cur_bi->bi_position)->dc_size += count * (DC_SIZE + KEY_SIZE); mark_buffer_dirty (cur_bi->bi_parent); } } /* Delete del_num items and node pointers from buffer cur starting from * * the first_i'th item and first_p'th pointers respectively. */ static void internal_delete_pointers_items (reiserfs_filsys_t fs, struct buffer_info * cur_bi, int first_p, int first_i, int del_num) { struct buffer_head * cur = cur_bi->bi_bh; int nr; struct block_head * blkh; struct key * key; struct disk_child * dc; #ifdef CONFIG_REISERFS_CHECK if (cur == NULL) reiserfs_panic (0, "internal_delete_pointers_items1: buffer is 0"); if (del_num < 0) reiserfs_panic (0, "internal_delete_pointers_items2", "negative number of items (%d) can not be deleted", del_num); if (first_p < 0 || first_p + del_num > B_NR_ITEMS (cur) + 1 || first_i < 0) reiserfs_panic (0, "internal_delete_pointers_items3", "first pointer order (%d) < 0 or " "no so many pointers (%d), only (%d) or " "first key order %d < 0", first_p, first_p + del_num, B_NR_ITEMS (cur) + 1, first_i); #endif /* CONFIG_REISERFS_CHECK */ if ( del_num == 0 ) return; nr = (blkh = B_BLK_HEAD(cur))->blk_nr_item; if ( first_p == 0 && del_num == nr + 1 ) { #ifdef CONFIG_REISERFS_CHECK if ( first_i != 0 ) reiserfs_panic (0, "internal_delete_pointers_items5", "first deleted key must have order 0, not %d", first_i); #endif /* CONFIG_REISERFS_CHECK */ make_empty_node (cur_bi); return; } #ifdef CONFIG_REISERFS_CHECK if (first_i + del_num > B_NR_ITEMS (cur)) { printk("first_i = %d del_num = %d\n",first_i,del_num); reiserfs_panic (0, "internal_delete_pointers_items4: :" "no so many keys (%d) in the node (%b)(%z)", first_i + del_num, cur, cur); } #endif /* CONFIG_REISERFS_CHECK */ /* deleting */ dc = B_N_CHILD (cur, first_p); memmove (dc, dc + del_num, (nr + 1 - first_p - del_num) * DC_SIZE); key = B_N_PDELIM_KEY (cur, first_i); memmove (key, key + del_num, (nr - first_i - del_num) * KEY_SIZE + (nr + 1 - del_num) * DC_SIZE); /* sizes, item number */ blkh->blk_nr_item -= del_num; blkh->blk_free_space += del_num * (KEY_SIZE + DC_SIZE); mark_buffer_dirty (cur); if (cur_bi->bi_parent) { B_N_CHILD (cur_bi->bi_parent, cur_bi->bi_position)->dc_size -= del_num * (KEY_SIZE + DC_SIZE); mark_buffer_dirty (cur_bi->bi_parent); } } /* delete n node pointers and items starting from given position */ static void internal_delete_childs (reiserfs_filsys_t fs, struct buffer_info * cur_bi, int from, int n) { int i_from; i_from = (from == 0) ? from : from - 1; /* delete n pointers starting from `from' position in CUR; delete n keys starting from 'i_from' position in CUR; */ internal_delete_pointers_items (fs, cur_bi, from, i_from, n); } /* copy cpy_num node pointers and cpy_num - 1 items from buffer src to buffer dest * last_first == FIRST_TO_LAST means, that we copy first items from src to tail of dest * last_first == LAST_TO_FIRST means, that we copy last items from src to head of dest */ static void internal_copy_pointers_items (reiserfs_filsys_t fs, struct buffer_info * dest_bi, struct buffer_head * src, int last_first, int cpy_num) { /* ATTENTION! Number of node pointers in DEST is equal to number of items in DEST * * as delimiting key have already inserted to buffer dest.*/ struct buffer_head * dest = dest_bi->bi_bh; int nr_dest, nr_src; int dest_order, src_order; struct block_head * blkh; struct key * key; struct disk_child * dc; nr_src = B_NR_ITEMS (src); #ifdef CONFIG_REISERFS_CHECK if ( dest == NULL || src == NULL ) reiserfs_panic (0, "internal_copy_pointers_items", "src (%p) or dest (%p) buffer is 0", src, dest); if (last_first != FIRST_TO_LAST && last_first != LAST_TO_FIRST) reiserfs_panic (0, "internal_copy_pointers_items", "invalid last_first parameter (%d)", last_first); if ( nr_src < cpy_num - 1 ) reiserfs_panic (0, "internal_copy_pointers_items", "no so many items (%d) in src (%d)", cpy_num, nr_src); if ( cpy_num < 0 ) reiserfs_panic (0, "internal_copy_pointers_items", "cpy_num less than 0 (%d)", cpy_num); if (cpy_num - 1 + B_NR_ITEMS(dest) > (int)MAX_NR_KEY(dest)) reiserfs_panic (0, "internal_copy_pointers_items", "cpy_num (%d) + item number in dest (%d) can not be more than MAX_NR_KEY(%d)", cpy_num, B_NR_ITEMS(dest), MAX_NR_KEY(dest)); #endif if ( cpy_num == 0 ) return; /* coping */ nr_dest = (blkh = B_BLK_HEAD(dest))->blk_nr_item; /*dest_order = (last_first == LAST_TO_FIRST) ? 0 : nr_dest;*/ /*src_order = (last_first == LAST_TO_FIRST) ? (nr_src - cpy_num + 1) : 0;*/ (last_first == LAST_TO_FIRST) ? (dest_order = 0, src_order = nr_src - cpy_num + 1) : (dest_order = nr_dest, src_order = 0); /* prepare space for cpy_num pointers */ dc = B_N_CHILD (dest, dest_order); memmove (dc + cpy_num, dc, (nr_dest - dest_order) * DC_SIZE); /* insert pointers */ memcpy (dc, B_N_CHILD (src, src_order), DC_SIZE * cpy_num); /* prepare space for cpy_num - 1 item headers */ key = B_N_PDELIM_KEY(dest, dest_order); memmove (key + cpy_num - 1, key, KEY_SIZE * (nr_dest - dest_order) + DC_SIZE * (nr_dest + cpy_num)); /* insert headers */ memcpy (key, B_N_PDELIM_KEY (src, src_order), KEY_SIZE * (cpy_num - 1)); /* sizes, item number */ blkh->blk_nr_item += cpy_num - 1; blkh->blk_free_space -= KEY_SIZE * (cpy_num - 1) + DC_SIZE * cpy_num; mark_buffer_dirty (dest); if (dest_bi->bi_parent) { B_N_CHILD(dest_bi->bi_parent,dest_bi->bi_position)->dc_size += KEY_SIZE * (cpy_num - 1) + DC_SIZE * cpy_num; mark_buffer_dirty (dest_bi->bi_parent); } } /* Copy cpy_num node pointers and cpy_num - 1 items from buffer src to buffer dest. * Delete cpy_num - del_par items and node pointers from buffer src. * last_first == FIRST_TO_LAST means, that we copy/delete first items from src. * last_first == LAST_TO_FIRST means, that we copy/delete last items from src. */ static void internal_move_pointers_items (reiserfs_filsys_t fs, struct buffer_info * dest_bi, struct buffer_info * src_bi, int last_first, int cpy_num, int del_par) { int first_pointer; int first_item; internal_copy_pointers_items (fs, dest_bi, src_bi->bi_bh, last_first, cpy_num); if (last_first == FIRST_TO_LAST) { /* shift_left occurs */ first_pointer = 0; first_item = 0; /* delete cpy_num - del_par pointers and keys starting for pointers with first_pointer, for key - with first_item */ internal_delete_pointers_items (fs, src_bi, first_pointer, first_item, cpy_num - del_par); } else { /* shift_right occurs */ int i, j; i = ( cpy_num - del_par == ( j = B_NR_ITEMS(src_bi->bi_bh)) + 1 ) ? 0 : j - cpy_num + del_par; internal_delete_pointers_items (fs, src_bi, j + 1 - cpy_num + del_par, i, cpy_num - del_par); } } /* Insert n_src'th key of buffer src before n_dest'th key of buffer dest. */ static void internal_insert_key (reiserfs_filsys_t fs, struct buffer_info * dest_bi, int dest_position_before, /* insert key before key with n_dest number */ struct buffer_head * src, int src_position ) { struct buffer_head * dest = dest_bi->bi_bh; int nr; struct block_head * blkh; struct key * key; #ifdef CONFIG_REISERFS_CHECK if (dest == NULL || src == NULL) reiserfs_panic (0, "internal_insert_key", "sourse(%p) or dest(%p) buffer is 0", src, dest); if (dest_position_before < 0 || src_position < 0) reiserfs_panic (0, "internal_insert_key", "source(%d) or dest(%d) key number less than 0", src_position, dest_position_before); if (dest_position_before > B_NR_ITEMS (dest) || src_position >= B_NR_ITEMS(src)) reiserfs_panic (0, "internal_insert_key", "invalid position in dest (%d (key number %d)) or in src (%d (key number %d))", dest_position_before, B_NR_ITEMS (dest), src_position, B_NR_ITEMS(src)); if (B_BLK_HEAD(dest)->blk_free_space < KEY_SIZE) reiserfs_panic (0, "internal_insert_key", "no enough free space (%d) in dest buffer", B_BLK_HEAD(dest)->blk_free_space); #endif nr = (blkh=B_BLK_HEAD(dest))->blk_nr_item; /* prepare space for inserting key */ key = B_N_PDELIM_KEY (dest, dest_position_before); memmove (key + 1, key, (nr - dest_position_before) * KEY_SIZE + (nr + 1) * DC_SIZE); /* insert key */ memcpy (key, B_N_PDELIM_KEY(src, src_position), KEY_SIZE); /* Change dirt, free space, item number fields. */ blkh->blk_nr_item ++; blkh->blk_free_space -= KEY_SIZE; mark_buffer_dirty (dest); if (dest_bi->bi_parent) { B_N_CHILD(dest_bi->bi_parent,dest_bi->bi_position)->dc_size += KEY_SIZE; mark_buffer_dirty (dest_bi->bi_parent); } } /* Insert d_key'th (delimiting) key from buffer cfl to tail of dest. * Copy pointer_amount node pointers and pointer_amount - 1 items from buffer src to buffer dest. * Replace d_key'th key in buffer cfl. * Delete pointer_amount items and node pointers from buffer src. */ /* this can be invoked both to shift from S to L and from R to S */ static void internal_shift_left (int mode, /* INTERNAL_FROM_S_TO_L | INTERNAL_FROM_R_TO_S */ struct tree_balance * tb, int h, int pointer_amount) { struct buffer_info dest_bi, src_bi; struct buffer_head * cf; int d_key_position; internal_define_dest_src_infos (mode, tb, h, &dest_bi, &src_bi, &d_key_position, &cf); /*printk("pointer_amount = %d\n",pointer_amount);*/ if (pointer_amount) { /* insert delimiting key from common father of dest and src to node dest into position B_NR_ITEM(dest) */ internal_insert_key (tb->tb_sb, &dest_bi, B_NR_ITEMS(dest_bi.bi_bh), cf, d_key_position); if (B_NR_ITEMS(src_bi.bi_bh) == pointer_amount - 1) { if (src_bi.bi_position/*src->b_item_order*/ == 0) replace_key (tb->tb_sb, cf, d_key_position, src_bi.bi_parent/*src->b_parent*/, 0); } else replace_key (tb->tb_sb, cf, d_key_position, src_bi.bi_bh, pointer_amount - 1); } /* last parameter is del_parameter */ internal_move_pointers_items (tb->tb_sb, &dest_bi, &src_bi, FIRST_TO_LAST, pointer_amount, 0); } /* Insert delimiting key to L[h]. * Copy n node pointers and n - 1 items from buffer S[h] to L[h]. * Delete n - 1 items and node pointers from buffer S[h]. */ /* it always shifts from S[h] to L[h] */ static void internal_shift1_left (struct tree_balance * tb, int h, int pointer_amount) { struct buffer_info dest_bi, src_bi; struct buffer_head * cf; int d_key_position; internal_define_dest_src_infos (INTERNAL_SHIFT_FROM_S_TO_L, tb, h, &dest_bi, &src_bi, &d_key_position, &cf); if ( pointer_amount > 0 ) /* insert lkey[h]-th key from CFL[h] to left neighbor L[h] */ internal_insert_key (tb->tb_sb, &dest_bi, B_NR_ITEMS(dest_bi.bi_bh), cf, d_key_position); /* last parameter is del_parameter */ internal_move_pointers_items (tb->tb_sb, &dest_bi, &src_bi, FIRST_TO_LAST, pointer_amount, 1); } /* Insert d_key'th (delimiting) key from buffer cfr to head of dest. * Copy n node pointers and n - 1 items from buffer src to buffer dest. * Replace d_key'th key in buffer cfr. * Delete n items and node pointers from buffer src. */ static void internal_shift_right (int mode, /* INTERNAL_FROM_S_TO_R | INTERNAL_FROM_L_TO_S */ struct tree_balance * tb, int h, int pointer_amount) { struct buffer_info dest_bi, src_bi; struct buffer_head * cf; int d_key_position; int nr; internal_define_dest_src_infos (mode, tb, h, &dest_bi, &src_bi, &d_key_position, &cf); nr = B_NR_ITEMS (src_bi.bi_bh); if (pointer_amount > 0) { /* insert delimiting key from common father of dest and src to dest node into position 0 */ internal_insert_key (tb->tb_sb, &dest_bi, 0, cf, d_key_position); if (nr == pointer_amount - 1) { #ifdef CONFIG_REISERFS_CHECK if ( src_bi.bi_bh != PATH_H_PBUFFER (tb->tb_path, h)/*tb->S[h]*/ || dest_bi.bi_bh != tb->R[h]) reiserfs_panic (tb->tb_sb, "internal_shift_right", "src (%p) must be == tb->S[h](%p) when it disappears", src_bi.bi_bh, PATH_H_PBUFFER (tb->tb_path, h)); #endif /* when S[h] disappers replace left delemiting key as well */ if (tb->CFL[h]) replace_key(tb->tb_sb, cf, d_key_position, tb->CFL[h], tb->lkey[h]); } else replace_key(tb->tb_sb, cf, d_key_position, src_bi.bi_bh, nr - pointer_amount); } /* last parameter is del_parameter */ internal_move_pointers_items (tb->tb_sb, &dest_bi, &src_bi, LAST_TO_FIRST, pointer_amount, 0); } /* Insert delimiting key to R[h]. * Copy n node pointers and n - 1 items from buffer S[h] to R[h]. * Delete n - 1 items and node pointers from buffer S[h]. */ /* it always shift from S[h] to R[h] */ static void internal_shift1_right (struct tree_balance * tb, int h, int pointer_amount) { struct buffer_info dest_bi, src_bi; struct buffer_head * cf; int d_key_position; internal_define_dest_src_infos (INTERNAL_SHIFT_FROM_S_TO_R, tb, h, &dest_bi, &src_bi, &d_key_position, &cf); if (pointer_amount > 0) /* insert rkey from CFR[h] to right neighbor R[h] */ internal_insert_key (tb->tb_sb, &dest_bi, 0, cf, d_key_position); /* last parameter is del_parameter */ internal_move_pointers_items (tb->tb_sb, &dest_bi, &src_bi, LAST_TO_FIRST, pointer_amount, 1); } /* Delete insert_num node pointers together with their left items * and balance current node.*/ static void balance_internal_when_delete (struct tree_balance * tb, int h, int child_pos) { int insert_num; int n; struct buffer_head * tbSh = PATH_H_PBUFFER (tb->tb_path, h); struct buffer_info bi; insert_num = tb->insert_size[h] / ((int)(DC_SIZE + KEY_SIZE)); /* delete child-node-pointer(s) together with their left item(s) */ bi.bi_bh = tbSh; bi.bi_parent = PATH_H_PPARENT (tb->tb_path, h); bi.bi_position = PATH_H_POSITION (tb->tb_path, h + 1); internal_delete_childs (tb->tb_sb, &bi, child_pos, -insert_num); #ifdef CONFIG_REISERFS_CHECK if ( tb->blknum[h] > 1 ) reiserfs_panic (tb->tb_sb, "balance_internal_when_delete", "tb->blknum[%d]=%d when insert_size < 0", h, tb->blknum[h]); #endif /* CONFIG_REISERFS_CHECK */ n = B_NR_ITEMS(tbSh); if ( tb->lnum[h] == 0 && tb->rnum[h] == 0 ) { if ( tb->blknum[h] == 0 ) { /* node S[h] (root of the tree) is empty now */ struct buffer_head *new_root; #ifdef CONFIG_REISERFS_CHECK if (n || B_BLK_HEAD (tbSh)->blk_free_space != MAX_CHILD_SIZE(tbSh) - DC_SIZE) reiserfs_panic (tb->tb_sb, "balance_internal_when_delete", "buffer must have only 0 keys (%d)", n); if (bi.bi_parent) reiserfs_panic (tb->tb_sb, "balance_internal_when_delete", "root has parent (%p)", bi.bi_parent); #endif /* CONFIG_REISERFS_CHECK */ /* choose a new root */ if ( ! tb->L[h-1] || ! B_NR_ITEMS(tb->L[h-1]) ) new_root = tb->R[h-1]; else new_root = tb->L[h-1]; /* update super block's tree height and pointer to a root block */ tb->tb_sb->s_rs->s_v1.s_root_block = cpu_to_le32 (new_root->b_blocknr); tb->tb_sb->s_rs->s_v1.s_tree_height = SB_TREE_HEIGHT (tb->tb_sb) - 1; mark_buffer_dirty (tb->tb_sb->s_sbh); tb->tb_sb->s_dirt = 1; /* mark buffer S[h] not uptodate and put it in free list */ reiserfs_invalidate_buffer(tb, tbSh, 1); return; } return; } if ( tb->L[h] && tb->lnum[h] == -B_NR_ITEMS(tb->L[h]) - 1 ) { /* join S[h] with L[h] */ #ifdef CONFIG_REISERFS_CHECK if ( tb->rnum[h] != 0 ) reiserfs_panic (tb->tb_sb, "balance_internal_when_delete", "invalid tb->rnum[%d]==%d when joining S[h] with L[h]", h, tb->rnum[h]); #endif /* CONFIG_REISERFS_CHECK */ internal_shift_left (INTERNAL_SHIFT_FROM_S_TO_L, tb, h, n + 1);/*tb->L[h], tb->CFL[h], tb->lkey[h], tb->S[h], n+1);*/ reiserfs_invalidate_buffer(tb, tbSh, 1); /* preserve not needed, internal, 1 mean free block */ return; } if ( tb->R[h] && tb->rnum[h] == -B_NR_ITEMS(tb->R[h]) - 1 ) { /* join S[h] with R[h] */ #ifdef CONFIG_REISERFS_CHECK if ( tb->lnum[h] != 0 ) reiserfs_panic (tb->tb_sb, "balance_internal_when_delete", "invalid tb->lnum[%d]==%d when joining S[h] with R[h]", h, tb->lnum[h]); #endif /* CONFIG_REISERFS_CHECK */ internal_shift_right (INTERNAL_SHIFT_FROM_S_TO_R, tb, h, n + 1); reiserfs_invalidate_buffer (tb, tbSh, 1); return; } if ( tb->lnum[h] < 0 ) { /* borrow from left neighbor L[h] */ #ifdef CONFIG_REISERFS_CHECK if ( tb->rnum[h] != 0 ) reiserfs_panic (tb->tb_sb, "balance_internal_when_delete", "invalid tb->rnum[%d]==%d when borrow from L[h]", h, tb->rnum[h]); #endif /* CONFIG_REISERFS_CHECK */ internal_shift_right (INTERNAL_SHIFT_FROM_L_TO_S, tb, h, -tb->lnum[h]); return; } if ( tb->rnum[h] < 0 ) { /* borrow from right neighbor R[h] */ #ifdef CONFIG_REISERFS_CHECK if ( tb->lnum[h] != 0 ) reiserfs_panic (tb->tb_sb, "balance_internal_when_delete", "invalid tb->lnum[%d]==%d when borrow from R[h]", h, tb->lnum[h]); #endif /* CONFIG_REISERFS_CHECK */ internal_shift_left (INTERNAL_SHIFT_FROM_R_TO_S, tb, h, -tb->rnum[h]);/*tb->S[h], tb->CFR[h], tb->rkey[h], tb->R[h], -tb->rnum[h]);*/ return; } if ( tb->lnum[h] > 0 ) { /* split S[h] into two parts and put them into neighbors */ #ifdef CONFIG_REISERFS_CHECK if ( tb->rnum[h] == 0 || tb->lnum[h] + tb->rnum[h] != n + 1 ) reiserfs_panic (tb->tb_sb, "balance_internal_when_delete", "invalid tb->lnum[%d]==%d or tb->rnum[%d]==%d when S[h](item number == %d) is split between them", h, tb->lnum[h], h, tb->rnum[h], n); #endif /* CONFIG_REISERFS_CHECK */ internal_shift_left (INTERNAL_SHIFT_FROM_S_TO_L, tb, h, tb->lnum[h]);/*tb->L[h], tb->CFL[h], tb->lkey[h], tb->S[h], tb->lnum[h]);*/ internal_shift_right (INTERNAL_SHIFT_FROM_S_TO_R, tb, h, tb->rnum[h]); reiserfs_invalidate_buffer (tb, tbSh, 1); return; } reiserfs_panic ("balance_internal_when_delete", "unexpected tb->lnum[%d]==%d or tb->rnum[%d]==%d", h, tb->lnum[h], h, tb->rnum[h]); } /* Replace delimiting key of buffers L[h] and S[h] by the given key.*/ void replace_lkey (struct tree_balance * tb, int h, struct item_head * key) { #ifdef CONFIG_REISERFS_CHECK if (tb->L[h] == NULL || tb->CFL[h] == NULL) reiserfs_panic (tb->tb_sb, "replace_lkey: 12255: " "L[h](%p) and CFL[h](%p) must exist in replace_lkey", tb->L[h], tb->CFL[h]); #endif if (B_NR_ITEMS(PATH_H_PBUFFER(tb->tb_path, h)) == 0) return; memcpy (B_N_PDELIM_KEY(tb->CFL[h],tb->lkey[h]), key, KEY_SIZE); mark_buffer_dirty (tb->CFL[h]); } /* Replace delimiting key of buffers S[h] and R[h] by the given key.*/ void replace_rkey (struct tree_balance * tb, int h, struct item_head * key) { #ifdef CONFIG_REISERFS_CHECK if (tb->R[h] == NULL || tb->CFR[h] == NULL) reiserfs_panic (tb->tb_sb, "replace_rkey: 12260: " "R[h](%p) and CFR[h](%p) must exist in replace_rkey", tb->R[h], tb->CFR[h]); if (B_NR_ITEMS(tb->R[h]) == 0) reiserfs_panic (tb->tb_sb, "replace_rkey: 12265: " "R[h] can not be empty if it exists (item number=%d)", B_NR_ITEMS(tb->R[h])); #endif memcpy (B_N_PDELIM_KEY(tb->CFR[h],tb->rkey[h]), key, KEY_SIZE); mark_buffer_dirty (tb->CFR[h]); } int balance_internal (struct tree_balance * tb, /* tree_balance structure */ int h, /* level of the tree */ int child_pos, struct item_head * insert_key, /* key for insertion on higher level */ struct buffer_head ** insert_ptr) /* node for insertion on higher level*/ /* if inserting/pasting { child_pos is the position of the node-pointer in S[h] that * pointed to S[h-1] before balancing of the h-1 level; * this means that new pointers and items must be inserted AFTER * child_pos } else { it is the position of the leftmost pointer that must be deleted (together with its corresponding key to the left of the pointer) as a result of the previous level's balancing. } */ { struct buffer_head * tbSh = PATH_H_PBUFFER (tb->tb_path, h); struct buffer_info bi; int order; /* we return this: it is 0 if there is no S[h], else it is tb->S[h]->b_item_order */ int insert_num, n, k; struct buffer_head * S_new; struct item_head new_insert_key; struct buffer_head * new_insert_ptr = NULL; struct item_head * new_insert_key_addr = insert_key; #ifdef CONFIG_REISERFS_CHECK if ( h < 1 ) reiserfs_panic (tb->tb_sb, "balance_internal", "h (%d) can not be < 1 on internal level", h); #endif /* CONFIG_REISERFS_CHECK */ order = ( tbSh ) ? PATH_H_POSITION (tb->tb_path, h + 1)/*tb->S[h]->b_item_order*/ : 0; /* Using insert_size[h] calculate the number insert_num of items that must be inserted to or deleted from S[h]. */ insert_num = tb->insert_size[h]/((int)(KEY_SIZE + DC_SIZE)); /* Check whether insert_num is proper **/ #ifdef CONFIG_REISERFS_CHECK if ( insert_num < -2 || insert_num > 2 ) reiserfs_panic (tb->tb_sb, "balance_internal", "incorrect number of items inserted to the internal node (%d)", insert_num); if ( h > 1 && (insert_num > 1 || insert_num < -1) ) reiserfs_panic (tb->tb_sb, "balance_internal", "incorrect number of items (%d) inserted to the internal node on a level (h=%d) higher than last internal level", insert_num, h); #endif /* CONFIG_REISERFS_CHECK */ /* Make balance in case insert_num < 0 */ if ( insert_num < 0 ) { balance_internal_when_delete (tb, h, child_pos); return order; } k = 0; if ( tb->lnum[h] > 0 ) { /* shift lnum[h] items from S[h] to the left neighbor L[h]. check how many of new items fall into L[h] or CFL[h] after shifting */ n = B_BLK_HEAD(tb->L[h])->blk_nr_item; /* number of items in L[h] */ if ( tb->lnum[h] <= child_pos ) { /* new items don't fall into L[h] or CFL[h] */ internal_shift_left (INTERNAL_SHIFT_FROM_S_TO_L, tb, h, tb->lnum[h]); child_pos -= tb->lnum[h]; } else if ( tb->lnum[h] > child_pos + insert_num ) { /* all new items fall into L[h] */ internal_shift_left (INTERNAL_SHIFT_FROM_S_TO_L, tb, h, tb->lnum[h] - insert_num); /* insert insert_num keys and node-pointers into L[h] */ bi.bi_bh = tb->L[h]; bi.bi_parent = tb->FL[h]; bi.bi_position = get_left_neighbor_position (tb, h); internal_insert_childs (tb->tb_sb, &bi,/*tb->L[h], tb->S[h-1]->b_next*/ n + child_pos + 1, insert_num,insert_key,insert_ptr); insert_num = 0; } else { struct disk_child * dc; /* some items fall into L[h] or CFL[h], but some don't fall */ internal_shift1_left (tb, h, child_pos + 1); /* calculate number of new items that fall into L[h] */ k = tb->lnum[h] - child_pos - 1; bi.bi_bh = tb->L[h]; bi.bi_parent = tb->FL[h]; bi.bi_position = get_left_neighbor_position (tb, h); internal_insert_childs (tb->tb_sb, &bi,/*tb->L[h], tb->S[h-1]->b_next,*/ n + child_pos + 1,k, insert_key,insert_ptr); replace_lkey(tb, h, insert_key + k); /* replace the first node-ptr in S[h] by node-ptr to insert_ptr[k] */ (dc = B_N_CHILD(tbSh, 0))->dc_size = MAX_CHILD_SIZE(insert_ptr[k]) - B_BLK_HEAD(insert_ptr[k])->blk_free_space; dc->dc_block_number = insert_ptr[k]->b_blocknr; mark_buffer_dirty (tbSh); k++; insert_key += k; insert_ptr += k; insert_num -= k; child_pos = 0; } } /* tb->lnum[h] > 0 */ if ( tb->rnum[h] > 0 ) { /*shift rnum[h] items from S[h] to the right neighbor R[h]*/ /* check how many of new items fall into R or CFR after shifting */ n = B_BLK_HEAD (tbSh)->blk_nr_item; /* number of items in S[h] */ if ( n - tb->rnum[h] >= child_pos ) /* new items fall into S[h] */ /*internal_shift_right(tb,h,tbSh,tb->CFR[h],tb->rkey[h],tb->R[h],tb->rnum[h]);*/ internal_shift_right (INTERNAL_SHIFT_FROM_S_TO_R, tb, h, tb->rnum[h]); else if ( n + insert_num - tb->rnum[h] < child_pos ) { /* all new items fall into R[h] */ internal_shift_right (INTERNAL_SHIFT_FROM_S_TO_R, tb, h, tb->rnum[h] - insert_num); /* insert insert_num keys and node-pointers into R[h] */ bi.bi_bh = tb->R[h]; bi.bi_parent = tb->FR[h]; bi.bi_position = get_right_neighbor_position (tb, h); internal_insert_childs (tb->tb_sb, &bi, /*tb->R[h],tb->S[h-1]->b_next*/ child_pos - n - insert_num + tb->rnum[h] - 1, insert_num,insert_key,insert_ptr); insert_num = 0; } else { struct disk_child * dc; /* one of the items falls into CFR[h] */ internal_shift1_right(tb, h, n - child_pos + 1); /* calculate number of new items that fall into R[h] */ k = tb->rnum[h] - n + child_pos - 1; bi.bi_bh = tb->R[h]; bi.bi_parent = tb->FR[h]; bi.bi_position = get_right_neighbor_position (tb, h); internal_insert_childs (tb->tb_sb, &bi, /*tb->R[h], tb->R[h]->b_child,*/ 0, k, insert_key + 1, insert_ptr + 1); replace_rkey(tb, h, insert_key + insert_num - k - 1); /* replace the first node-ptr in R[h] by node-ptr insert_ptr[insert_num-k-1]*/ (dc = B_N_CHILD(tb->R[h], 0))->dc_size = MAX_CHILD_SIZE(insert_ptr[insert_num-k-1]) - B_BLK_HEAD(insert_ptr[insert_num-k-1])->blk_free_space; dc->dc_block_number = insert_ptr[insert_num-k-1]->b_blocknr; mark_buffer_dirty (tb->R[h]); insert_num -= (k + 1); } } /** Fill new node that appears instead of S[h] **/ #ifdef CONFIG_REISERFS_CHECK if ( tb->blknum[h] > 2 ) reiserfs_panic(0, "balance_internal", "blknum can not be > 2 for internal level"); if ( tb->blknum[h] < 0 ) reiserfs_panic(0, "balance_internal", "blknum can not be < 0"); #endif /* CONFIG_REISERFS_CHECK */ if ( ! tb->blknum[h] ) { /* node S[h] is empty now */ #ifdef CONFIG_REISERFS_CHECK if ( ! tbSh ) reiserfs_panic(0,"balance_internal", "S[h] is equal NULL"); #endif /* CONFIG_REISERFS_CHECK */ /* Mark buffer as invalid and put it to head of free list. */ reiserfs_invalidate_buffer(tb, tbSh, 1);/* do not preserve, internal node*/ return order; } if ( ! tbSh ) { /* create new root */ struct disk_child * dc; struct buffer_head * tbSh_1 = PATH_H_PBUFFER (tb->tb_path, h - 1); if ( tb->blknum[h] != 1 ) reiserfs_panic(0, "balance_internal", "One new node required for creating the new root"); /* S[h] = empty buffer from the list FEB. */ tbSh = get_FEB (tb); B_BLK_HEAD(tbSh)->blk_level = h + 1; /* Put the unique node-pointer to S[h] that points to S[h-1]. */ (dc = B_N_CHILD(tbSh, 0))->dc_block_number = tbSh_1->b_blocknr; dc->dc_size = MAX_CHILD_SIZE (tbSh_1) - B_BLK_HEAD(tbSh_1)->blk_free_space; tb->insert_size[h] -= DC_SIZE; B_BLK_HEAD(tbSh)->blk_free_space -= DC_SIZE; mark_buffer_dirty (tbSh); /* put new root into path structure */ PATH_OFFSET_PBUFFER(tb->tb_path, ILLEGAL_PATH_ELEMENT_OFFSET) = tbSh; /* Change root in structure super block. */ tb->tb_sb->s_rs->s_v1.s_root_block = cpu_to_le32 (tbSh->b_blocknr); tb->tb_sb->s_rs->s_v1.s_tree_height = cpu_to_le16 (SB_TREE_HEIGHT (tb->tb_sb) + 1); mark_buffer_dirty (tb->tb_sb->s_sbh); tb->tb_sb->s_dirt = 1; } if ( tb->blknum[h] == 2 ) { int snum; struct buffer_info dest_bi, src_bi; /* S_new = free buffer from list FEB */ S_new = get_FEB(tb); B_BLK_HEAD(S_new)->blk_level = h + 1; dest_bi.bi_bh = S_new; dest_bi.bi_parent = 0; dest_bi.bi_position = 0; src_bi.bi_bh = tbSh; src_bi.bi_parent = PATH_H_PPARENT (tb->tb_path, h); src_bi.bi_position = PATH_H_POSITION (tb->tb_path, h + 1); n = B_BLK_HEAD(tbSh)->blk_nr_item; /* number of items in S[h] */ snum = (insert_num + n + 1)/2; if ( n - snum >= child_pos ) { /* new items don't fall into S_new */ /* store the delimiting key for the next level */ /* new_insert_key = (n - snum)'th key in S[h] */ memcpy (&new_insert_key,B_N_PDELIM_KEY(tbSh,n - snum), KEY_SIZE); /* last parameter is del_par */ internal_move_pointers_items (tb->tb_sb, &dest_bi, &src_bi, LAST_TO_FIRST, snum, 0); } else if ( n + insert_num - snum < child_pos ) { /* all new items fall into S_new */ /* store the delimiting key for the next level */ /* new_insert_key = (n + insert_item - snum)'th key in S[h] */ memcpy(&new_insert_key,B_N_PDELIM_KEY(tbSh,n + insert_num - snum), KEY_SIZE); /* last parameter is del_par */ internal_move_pointers_items (tb->tb_sb, &dest_bi, &src_bi, LAST_TO_FIRST, snum - insert_num, 0); /* internal_move_pointers_items(S_new,tbSh,1,snum - insert_num,0);*/ /* insert insert_num keys and node-pointers into S_new */ internal_insert_childs (tb->tb_sb, &dest_bi, /*S_new,tb->S[h-1]->b_next,*/child_pos - n - insert_num + snum - 1, insert_num,insert_key,insert_ptr); insert_num = 0; } else { struct disk_child * dc; /* some items fall into S_new, but some don't fall */ /* last parameter is del_par */ internal_move_pointers_items (tb->tb_sb, &dest_bi, &src_bi, LAST_TO_FIRST, n - child_pos + 1, 1); /* internal_move_pointers_items(S_new,tbSh,1,n - child_pos + 1,1);*/ /* calculate number of new items that fall into S_new */ k = snum - n + child_pos - 1; internal_insert_childs (tb->tb_sb, &dest_bi, /*S_new,*/ 0, k, insert_key + 1, insert_ptr+1); /* new_insert_key = insert_key[insert_num - k - 1] */ memcpy(&new_insert_key,insert_key + insert_num - k - 1, KEY_SIZE); /* replace first node-ptr in S_new by node-ptr to insert_ptr[insert_num-k-1] */ (dc = B_N_CHILD(S_new,0))->dc_size = MAX_CHILD_SIZE(insert_ptr[insert_num-k-1]) - B_BLK_HEAD(insert_ptr[insert_num-k-1])->blk_free_space; dc->dc_block_number = insert_ptr[insert_num-k-1]->b_blocknr; mark_buffer_dirty (S_new); insert_num -= (k + 1); } /* new_insert_ptr = node_pointer to S_new */ new_insert_ptr = S_new; #ifdef CONFIG_REISERFS_CHECK if ( buffer_locked(S_new) ) reiserfs_panic (tb->tb_sb, "balance_internal", "locked buffer S_new[]"); if (S_new->b_count != 1) if (!(buffer_journaled(S_new) && S_new->b_count == 2)) { printk ("REISERFS: balance_internal: S_new->b_count != 1 (%u)\n", S_new->b_count); } #endif /* CONFIG_REISERFS_CHECK */ /* S_new->b_count --; */ /*brelse(S_new);*/ } n = B_BLK_HEAD(tbSh)->blk_nr_item; /*number of items in S[h] */ #ifndef FU //REISERFS_FSCK if ( -1 <= child_pos && child_pos <= n && insert_num > 0 ) { #else if ( 0 <= child_pos && child_pos <= n && insert_num > 0 ) { #endif bi.bi_bh = tbSh; bi.bi_parent = PATH_H_PPARENT (tb->tb_path, h); bi.bi_position = PATH_H_POSITION (tb->tb_path, h + 1); #ifndef FU //REISERFS_FSCK if (child_pos == -1) { /* this is a little different from original do_balance: here we insert the minimal keys in the tree, that has never happened when file system works */ if (tb->CFL[h-1] || insert_num != 1 || h != 1) die ("balance_internal: invalid child_pos"); /* insert_child (tb->S[h], tb->S[h-1], child_pos, insert_num, B_N_ITEM_HEAD(tb->S[0],0), insert_ptr);*/ internal_insert_childs (tb->tb_sb, &bi, child_pos, insert_num, B_N_PITEM_HEAD (PATH_PLAST_BUFFER (tb->tb_path), 0), insert_ptr); } else #endif internal_insert_childs (tb->tb_sb, &bi, child_pos,insert_num,insert_key,insert_ptr); } memcpy (new_insert_key_addr,&new_insert_key,KEY_SIZE); insert_ptr[0] = new_insert_ptr; return order; } reiserfsprogs-3.x.0j/reiserfscore/lbalance.c0000644000076400001440000013701407255716344014775 /* * Copyright 1996, 1997, 1998 Hans Reiser, see reiserfs/README for licensing and copyright details */ #include "includes.h" /* these are used in do_balance.c */ /* leaf_move_items leaf_shift_left leaf_shift_right leaf_delete_items leaf_insert_into_buf leaf_paste_in_buffer leaf_cut_from_buffer leaf_paste_entries */ extern struct tree_balance init_tb; extern int init_item_pos; extern int init_pos_in_item; extern int init_mode; /* copy copy_count entries from source directory item to dest buffer (creating new item if needed) */ static void leaf_copy_dir_entries (reiserfs_filsys_t fs, struct buffer_info * dest_bi, struct buffer_head * source, int last_first, int item_num, int from, int copy_count) { struct buffer_head * dest = dest_bi->bi_bh; int item_num_in_dest; /* either the number of target item, or if we must create a new item, the number of the item we will create it next to */ struct item_head * ih; struct reiserfs_de_head * deh; int copy_records_len; /* length of all records in item to be copied */ char * records; ih = B_N_PITEM_HEAD (source, item_num); #ifdef CONFIG_REISERFS_CHECK if (!I_IS_DIRECTORY_ITEM (ih)) reiserfs_panic(0, "vs-10000: leaf_copy_dir_entries: item must be directory item"); #endif /* length of all record to be copied and first byte of the last of them */ deh = B_I_DEH (source, ih); if (copy_count) { copy_records_len = (from ? deh[from - 1].deh_location : ih->ih_item_len) - deh[from + copy_count - 1].deh_location; records = source->b_data + ih->ih_item_location + deh[from + copy_count - 1].deh_location; } else { copy_records_len = 0; records = 0; } /* when copy last to first, dest buffer can contain 0 items */ item_num_in_dest = (last_first == LAST_TO_FIRST) ? (( B_NR_ITEMS(dest) ) ? 0 : -1) : (B_NR_ITEMS(dest) - 1); /* if there are no items in dest or the first/last item in dest is not item of the same directory */ if ( (item_num_in_dest == - 1) || #ifndef FU //REISERFS_FSCK (last_first == FIRST_TO_LAST && are_items_mergeable (B_N_PITEM_HEAD (dest, item_num_in_dest), ih, dest->b_size) == 0) || (last_first == LAST_TO_FIRST && are_items_mergeable (ih, B_N_PITEM_HEAD (dest, item_num_in_dest), dest->b_size) == 0)) { #else (last_first == FIRST_TO_LAST && get_offset (&ih->ih_key) == DOT_OFFSET) || (last_first == LAST_TO_FIRST && not_of_one_file (&ih->ih_key, B_N_PKEY (dest, item_num_in_dest)))) { #endif /* create new item in dest */ struct item_head new_ih; /* form item header */ memcpy (&new_ih.ih_key, &ih->ih_key, KEY_SIZE); /* calculate item len */ new_ih.ih_item_len = cpu_to_le16 (DEH_SIZE * copy_count + copy_records_len); set_entry_count (&new_ih, 0); if (last_first == LAST_TO_FIRST) { /* form key by the following way */ if (from < ih_entry_count (ih)) { new_ih.ih_key.u.k_offset_v1.k_offset = deh[from].deh_offset; new_ih.ih_key.u.k_offset_v1.k_uniqueness = DIRENTRY_UNIQUENESS; /*memcpy (&new_ih.ih_key.k_offset, &deh[from].deh_offset, SHORT_KEY_SIZE);*/ } else { /* no entries will be copied to this item in this function */ new_ih.ih_key.u.k_offset_v1.k_offset = MAX_KEY1_OFFSET; /* this item is not yet valid, but we want I_IS_DIRECTORY_ITEM to return 1 for it, so we -1 */ new_ih.ih_key.u.k_offset_v1.k_uniqueness = DIRENTRY_UNIQUENESS/*TYPE_DIRECTORY_MAX*/; } } set_key_format (&new_ih, ih_key_format (ih)); new_ih.ih_format.fsck_need = ih->ih_format.fsck_need; /* insert item into dest buffer */ leaf_insert_into_buf (fs, dest_bi, (last_first == LAST_TO_FIRST) ? 0 : B_NR_ITEMS(dest), &new_ih, NULL, 0); } else { /* prepare space for entries */ leaf_paste_in_buffer (fs, dest_bi, (last_first==FIRST_TO_LAST) ? (B_NR_ITEMS(dest) - 1) : 0, USHRT_MAX, DEH_SIZE * copy_count + copy_records_len, records, 0); } item_num_in_dest = (last_first == FIRST_TO_LAST) ? (B_NR_ITEMS(dest)-1) : 0; leaf_paste_entries (dest_bi->bi_bh, item_num_in_dest, (last_first == FIRST_TO_LAST) ? ih_entry_count (B_N_PITEM_HEAD (dest, item_num_in_dest)) : 0, copy_count, deh + from, records, DEH_SIZE * copy_count + copy_records_len ); } /* Copy the first (if last_first == FIRST_TO_LAST) or last (last_first == LAST_TO_FIRST) item or part of it or nothing (see the return 0 below) from SOURCE to the end (if last_first) or beginning (!last_first) of the DEST */ /* returns 1 if anything was copied, else 0 */ static int leaf_copy_boundary_item (reiserfs_filsys_t fs, struct buffer_info * dest_bi, struct buffer_head * src, int last_first, int bytes_or_entries) { struct buffer_head * dest = dest_bi->bi_bh; int dest_nr_item, src_nr_item; /* number of items in the source and destination buffers */ struct item_head * ih; struct item_head * dih; dest_nr_item = B_NR_ITEMS(dest); if ( last_first == FIRST_TO_LAST ) { /* if ( DEST is empty or first item of SOURCE and last item of DEST are the items of different objects or of different types ) then there is no need to treat this item differently from the other items that we copy, so we return */ ih = B_N_PITEM_HEAD (src, 0); dih = B_N_PITEM_HEAD (dest, dest_nr_item - 1); #ifndef FU //REISERFS_FSCK if (!dest_nr_item || (are_items_mergeable (dih, ih, src->b_size) == 0)) #else if (!dest_nr_item || (!is_left_mergeable (ih, src->b_size))) #endif /* there is nothing to merge */ return 0; #ifdef CONFIG_REISERFS_CHECK if ( ! ih->ih_item_len ) reiserfs_panic (0, "vs-10010: leaf_copy_boundary_item: item can not have empty dynamic length"); #endif if ( I_IS_DIRECTORY_ITEM(ih) ) { if ( bytes_or_entries == -1 ) /* copy all entries to dest */ bytes_or_entries = ih_entry_count(ih); leaf_copy_dir_entries (fs, dest_bi, src, FIRST_TO_LAST, 0, 0, bytes_or_entries); return 1; } /* copy part of the body of the first item of SOURCE to the end of the body of the last item of the DEST part defined by 'bytes_or_entries'; if bytes_or_entries == -1 copy whole body; don't create new item header */ if ( bytes_or_entries == -1 ) bytes_or_entries = ih->ih_item_len; #ifdef CONFIG_REISERFS_CHECK else { if (bytes_or_entries == ih->ih_item_len && I_IS_INDIRECT_ITEM(ih)) if (ih_free_space (ih)) reiserfs_panic (0, "vs-10020: leaf_copy_boundary_item: " "last unformatted node must be filled entirely (free_space=%d)", ih_free_space (ih)); } #endif /* merge first item (or its part) of src buffer with the last item of dest buffer. Both are of the same file */ leaf_paste_in_buffer (fs, dest_bi, dest_nr_item - 1, dih->ih_item_len, bytes_or_entries, B_I_PITEM(src,ih), 0 ); if (I_IS_INDIRECT_ITEM(dih)) { #ifdef CONFIG_REISERFS_CHECK if (ih_free_space (dih)) reiserfs_panic (0, "vs-10030: leaf_copy_boundary_item: " "merge to left: last unformatted node of non-last indirect item must be filled entirely (free_space=%d)", ih_free_space (dih)); #endif if (bytes_or_entries == ih->ih_item_len) //dih->u.ih_free_space = ih->u.ih_free_space; set_free_space (dih, ih_free_space (ih)); } return 1; } /* copy boundary item to right (last_first == LAST_TO_FIRST) */ /* ( DEST is empty or last item of SOURCE and first item of DEST are the items of different object or of different types ) */ src_nr_item = B_NR_ITEMS (src); ih = B_N_PITEM_HEAD (src, src_nr_item - 1); dih = B_N_PITEM_HEAD (dest, 0); #ifndef FU //REISERFS_FSCK if (!dest_nr_item || are_items_mergeable (ih, dih, src->b_size) == 0) #else if (!dest_nr_item || !is_left_mergeable (dih, src->b_size)) #endif return 0; if ( I_IS_DIRECTORY_ITEM(ih)) { if ( bytes_or_entries == -1 ) /* bytes_or_entries = entries number in last item body of SOURCE */ bytes_or_entries = ih_entry_count(ih); leaf_copy_dir_entries (fs, dest_bi, src, LAST_TO_FIRST, src_nr_item - 1, ih_entry_count(ih) - bytes_or_entries, bytes_or_entries); return 1; } /* copy part of the body of the last item of SOURCE to the begin of the body of the first item of the DEST; part defined by 'bytes_or_entries'; if byte_or_entriess == -1 copy whole body; change first item key of the DEST; don't create new item header */ #ifdef CONFIG_REISERFS_CHECK if (I_IS_INDIRECT_ITEM(ih) && ih_free_space (ih)) reiserfs_panic (0, "vs-10040: leaf_copy_boundary_item: " "merge to right: last unformatted node of non-last indirect item must be filled entirely (free_space=%d)", ih_free_space (ih)); #endif if ( bytes_or_entries == -1 ) { /* bytes_or_entries = length of last item body of SOURCE */ bytes_or_entries = ih->ih_item_len; #ifdef CONFIG_REISERFS_CHECK if (get_offset (&dih->ih_key) != get_offset (&ih->ih_key) + get_bytes_number (ih, src->b_size))/*I_DNM_DATA_LEN(ih))*/ reiserfs_panic (0, "vs-10050: leaf_copy_boundary_item: right item offset (%lu) must not be (%lu),it must be %lu", get_offset (&dih->ih_key), get_offset (&ih->ih_key) + get_bytes_number (ih, src->b_size), get_offset (&dih->ih_key)); #endif /* change first item key of the DEST */ //dih->ih_key.k_offset = ih->ih_key.k_offset; set_offset (key_format (&dih->ih_key), &dih->ih_key, get_offset (&ih->ih_key)); /* item becomes non-mergeable */ /* or mergeable if left item was */ //dih->ih_key.k_uniqueness = ih->ih_key.k_uniqueness; set_type (key_format (&dih->ih_key), &dih->ih_key, get_type (&ih->ih_key)); } else { /* merge to right only part of item */ #ifdef CONFIG_REISERFS_CHECK if ( ih->ih_item_len <= bytes_or_entries ) reiserfs_panic (0, "vs-10060: leaf_copy_boundary_item: no so much bytes %lu (needed %lu)", ih->ih_item_len, bytes_or_entries); #endif /* change first item key of the DEST */ if ( I_IS_DIRECT_ITEM(dih) ) { #ifdef CONFIG_REISERFS_CHECK if (get_offset (&dih->ih_key) <= (unsigned long)bytes_or_entries) reiserfs_panic (0, "vs-10070: leaf_copy_boundary_item: dih->ih_key.k_offset(%d) <= bytes_or_entries(%d)", get_offset (&dih->ih_key), bytes_or_entries); #endif //dih->ih_key.k_offset -= bytes_or_entries; set_offset (key_format (&dih->ih_key), &dih->ih_key, get_offset (&dih->ih_key) - bytes_or_entries); } else { #ifdef CONFIG_REISERFS_CHECK if (get_offset (&dih->ih_key) <=(bytes_or_entries/UNFM_P_SIZE)*dest->b_size ) reiserfs_panic (0, "vs-10080: leaf_copy_boundary_item: dih->ih_key.k_offset(%d) <= bytes_or_entries(%d)", get_offset (&dih->ih_key), (bytes_or_entries/UNFM_P_SIZE)*dest->b_size); #endif //dih->ih_key.k_offset -= ((bytes_or_entries/UNFM_P_SIZE)*dest->b_size); set_offset (key_format (&dih->ih_key), &dih->ih_key, get_offset (&dih->ih_key) - ((bytes_or_entries/UNFM_P_SIZE)*dest->b_size)); } } leaf_paste_in_buffer (fs, dest_bi, 0, 0, bytes_or_entries, B_I_PITEM(src,ih) + ih->ih_item_len - bytes_or_entries, 0); return 1; } /* copy cpy_mun items from buffer src to buffer dest * last_first == FIRST_TO_LAST means, that we copy cpy_num items beginning from first-th item in src to tail of dest * last_first == LAST_TO_FIRST means, that we copy cpy_num items beginning from first-th item in src to head of dest */ static void leaf_copy_items_entirely (reiserfs_filsys_t fs, struct buffer_info * dest_bi, struct buffer_head * src, int last_first, int first, int cpy_num) { struct buffer_head * dest; int nr; int dest_before; int last_loc, last_inserted_loc, location; int i, j; struct block_head * blkh; struct item_head * ih; #ifdef CONFIG_REISERFS_CHECK if (last_first != LAST_TO_FIRST && last_first != FIRST_TO_LAST) reiserfs_panic (0, "vs-10090: leaf_copy_items_entirely: bad last_first parameter %d", last_first); if (B_NR_ITEMS (src) - first < cpy_num) reiserfs_panic (0, "vs-10100: leaf_copy_items_entirely: too few items in source %d, required %d from %d", B_NR_ITEMS(src), cpy_num, first); if (cpy_num < 0) reiserfs_panic (0, "vs-10110: leaf_copy_items_entirely: can not copy negative amount of items"); if ( ! dest_bi ) reiserfs_panic (0, "vs-10120: leaf_copy_items_entirely: can not copy negative amount of items"); #endif dest = dest_bi->bi_bh; #ifdef CONFIG_REISERFS_CHECK if ( ! dest ) reiserfs_panic (0, "vs-10130: leaf_copy_items_entirely: can not copy negative amount of items"); #endif if (cpy_num == 0) return; nr = (blkh = B_BLK_HEAD(dest))->blk_nr_item; /* we will insert items before 0-th or nr-th item in dest buffer. It depends of last_first parameter */ dest_before = (last_first == LAST_TO_FIRST) ? 0 : nr; /* location of head of first new item */ ih = B_N_PITEM_HEAD (dest, dest_before); #ifdef CONFIG_REISERFS_CHECK if (blkh->blk_free_space < cpy_num * IH_SIZE) { reiserfs_panic (0, "vs-10140: leaf_copy_items_entirely: not enough free space for headers %d (needed %d)", blkh->blk_free_space, cpy_num * IH_SIZE); } #endif /* prepare space for headers */ memmove (ih + cpy_num, ih, (nr-dest_before) * IH_SIZE); /* copy item headers */ memcpy (ih, B_N_PITEM_HEAD (src, first), cpy_num * IH_SIZE); blkh->blk_free_space -= IH_SIZE * cpy_num; /* location of unmovable item */ j = location = (dest_before == 0) ? dest->b_size : (ih-1)->ih_item_location; for (i = dest_before; i < nr + cpy_num; i ++) ih[i-dest_before].ih_item_location = (location -= ih[i-dest_before].ih_item_len); /* prepare space for items */ last_loc = ih[nr+cpy_num-1-dest_before].ih_item_location; last_inserted_loc = ih[cpy_num-1].ih_item_location; /* check free space */ #ifdef CONFIG_REISERFS_CHECK if (blkh->blk_free_space < j - last_inserted_loc) { reiserfs_panic (0, "vs-10150: leaf_copy_items_entirely: not enough free space for items %d (needed %d)", blkh->blk_free_space, j - last_inserted_loc); } #endif memmove (dest->b_data + last_loc, dest->b_data + last_loc + j - last_inserted_loc, last_inserted_loc - last_loc); /* copy items */ memcpy (dest->b_data + last_inserted_loc, B_N_PITEM(src,(first + cpy_num - 1)), j - last_inserted_loc); /* sizes, item number */ blkh->blk_nr_item += cpy_num; blkh->blk_free_space -= j - last_inserted_loc; mark_buffer_dirty (dest); if (dest_bi->bi_parent) { #ifdef CONFIG_REISERFS_CHECK if (B_N_CHILD (dest_bi->bi_parent, dest_bi->bi_position)->dc_block_number != dest->b_blocknr) { reiserfs_panic (0, "vs-10160: leaf_copy_items_entirely: " "block number in bh does not match to field in disk_child structure %lu and %lu", dest->b_blocknr, B_N_CHILD (dest_bi->bi_parent, dest_bi->bi_position)->dc_block_number); } #endif B_N_CHILD (dest_bi->bi_parent, dest_bi->bi_position)->dc_size += j - last_inserted_loc + IH_SIZE * cpy_num; mark_buffer_dirty(dest_bi->bi_parent); } } /* This function splits the (liquid) item into two items (useful when shifting part of an item into another node.) */ static void leaf_item_bottle (reiserfs_filsys_t fs, struct buffer_info * dest_bi, struct buffer_head * src, int last_first, int item_num, int cpy_bytes) { struct buffer_head * dest = dest_bi->bi_bh; struct item_head * ih; #ifdef CONFIG_REISERFS_CHECK if ( cpy_bytes == -1 ) reiserfs_panic (0, "vs-10170: leaf_item_bottle: bytes == - 1 means: do not split item"); #endif if ( last_first == FIRST_TO_LAST ) { /* if ( if item in position item_num in buffer SOURCE is directory item ) */ if (I_IS_DIRECTORY_ITEM(ih = B_N_PITEM_HEAD(src,item_num))) leaf_copy_dir_entries (fs, dest_bi, src, FIRST_TO_LAST, item_num, 0, cpy_bytes); else { struct item_head n_ih; /* copy part of the body of the item number 'item_num' of SOURCE to the end of the DEST part defined by 'cpy_bytes'; create new item header; change old item_header (????); n_ih = new item_header; */ memcpy (&n_ih, ih, IH_SIZE); n_ih.ih_item_len = cpy_bytes; if (I_IS_INDIRECT_ITEM(ih)) { #ifdef CONFIG_REISERFS_CHECK if (cpy_bytes == ih->ih_item_len && ih_free_space (ih)) reiserfs_panic (0, "vs-10180: leaf_item_bottle: " "when whole indirect item is bottle to left neighbor, it must have free_space==0 (not %lu)", ih_free_space (ih)); #endif //n_ih.u.ih_free_space = 0; set_free_space (&n_ih, 0);; } #ifdef CONFIG_REISERFS_CHECK if (is_left_mergeable (ih, src->b_size)) reiserfs_panic (0, "vs-10190: leaf_item_bottle: item %h should not be mergeable", ih); #endif //n_ih.ih_version = ih->ih_version; set_key_format (&n_ih, ih_key_format (ih)); n_ih.ih_format.fsck_need = ih->ih_format.fsck_need; leaf_insert_into_buf (fs, dest_bi, B_NR_ITEMS(dest), &n_ih, B_N_PITEM (src, item_num), 0); } } else { /* if ( if item in position item_num in buffer SOURCE is directory item ) */ if (I_IS_DIRECTORY_ITEM(ih = B_N_PITEM_HEAD (src, item_num))) leaf_copy_dir_entries (fs, dest_bi, src, LAST_TO_FIRST, item_num, ih_entry_count(ih) - cpy_bytes, cpy_bytes); else { struct item_head n_ih; /* copy part of the body of the item number 'item_num' of SOURCE to the begin of the DEST part defined by 'cpy_bytes'; create new item header; n_ih = new item_header; */ memcpy (&n_ih, ih, SHORT_KEY_SIZE); if (I_IS_DIRECT_ITEM(ih)) { //n_ih.ih_key.k_offset = ih->ih_key.k_offset + ih->ih_item_len - cpy_bytes; set_offset (key_format (&ih->ih_key), &n_ih.ih_key, get_offset (&ih->ih_key) + ih->ih_item_len - cpy_bytes); //n_ih.ih_key.k_uniqueness = TYPE_DIRECT; set_type (key_format (&ih->ih_key), &n_ih.ih_key, TYPE_DIRECT); //n_ih.u.ih_free_space = USHRT_MAX; set_free_space (&n_ih, USHRT_MAX); } else { /* indirect item */ #ifdef CONFIG_REISERFS_CHECK if (!cpy_bytes && ih_free_space (ih)) reiserfs_panic (0, "vs-10200: leaf_item_bottle: ih->ih_free_space must be 0 when indirect item will be appended"); #endif //n_ih.ih_key.k_offset = ih->ih_key.k_offset + (ih->ih_item_len - cpy_bytes) / UNFM_P_SIZE * dest->b_size; set_offset (key_format (&ih->ih_key), &n_ih.ih_key, get_offset (&ih->ih_key) + (ih->ih_item_len - cpy_bytes) / UNFM_P_SIZE * dest->b_size); //n_ih.ih_key.k_uniqueness = TYPE_INDIRECT; set_type (key_format (&ih->ih_key), &n_ih.ih_key, TYPE_INDIRECT); //n_ih.u.ih_free_space = ih->u.ih_free_space; set_free_space (&n_ih, ih_free_space (ih)); } /* set item length */ n_ih.ih_item_len = cpu_to_le16 (cpy_bytes); //n_ih.ih_version = ih->ih_version; set_key_format (&n_ih, ih_key_format (ih)); n_ih.ih_format.fsck_need = ih->ih_format.fsck_need; leaf_insert_into_buf (fs, dest_bi, 0, &n_ih, B_N_PITEM(src,item_num) + ih->ih_item_len - cpy_bytes, 0); } } } /* If cpy_bytes equals minus one than copy cpy_num whole items from SOURCE to DEST. If cpy_bytes not equal to minus one than copy cpy_num-1 whole items from SOURCE to DEST. From last item copy cpy_num bytes for regular item and cpy_num directory entries for directory item. */ static int leaf_copy_items (reiserfs_filsys_t fs, struct buffer_info * dest_bi, struct buffer_head * src, int last_first, int cpy_num, int cpy_bytes) { struct buffer_head * dest; int pos, i, src_nr_item, bytes; dest = dest_bi->bi_bh; #ifdef CONFIG_REISERFS_CHECK if (!dest || !src) reiserfs_panic (0, "vs-10210: leaf_copy_items: !dest || !src"); if ( last_first != FIRST_TO_LAST && last_first != LAST_TO_FIRST ) reiserfs_panic (0, "vs-10220: leaf_copy_items: last_first != FIRST_TO_LAST && last_first != LAST_TO_FIRST"); if ( B_NR_ITEMS(src) < cpy_num ) reiserfs_panic (0, "vs-10230: leaf_copy_items: No enough items: %d, required %d", B_NR_ITEMS(src), cpy_num); if ( cpy_num < 0 ) reiserfs_panic (0, "vs-10240: leaf_copy_items: cpy_num < 0 (%d)", cpy_num); #endif if ( cpy_num == 0 ) return 0; if ( last_first == FIRST_TO_LAST ) { /* copy items to left */ pos = 0; if ( cpy_num == 1 ) bytes = cpy_bytes; else bytes = -1; /* copy the first item or it part or nothing to the end of the DEST (i = leaf_copy_boundary_item(DEST,SOURCE,0,bytes)) */ i = leaf_copy_boundary_item (fs, dest_bi, src, FIRST_TO_LAST, bytes); cpy_num -= i; if ( cpy_num == 0 ) return i; pos += i; if ( cpy_bytes == -1 ) /* copy first cpy_num items starting from position 'pos' of SOURCE to end of DEST */ leaf_copy_items_entirely(fs, dest_bi, src, FIRST_TO_LAST, pos, cpy_num); else { /* copy first cpy_num-1 items starting from position 'pos-1' of the SOURCE to the end of the DEST */ leaf_copy_items_entirely(fs, dest_bi, src, FIRST_TO_LAST, pos, cpy_num-1); /* copy part of the item which number is cpy_num+pos-1 to the end of the DEST */ leaf_item_bottle (fs, dest_bi, src, FIRST_TO_LAST, cpy_num+pos-1, cpy_bytes); } } else { /* copy items to right */ src_nr_item = B_NR_ITEMS (src); if ( cpy_num == 1 ) bytes = cpy_bytes; else bytes = -1; /* copy the last item or it part or nothing to the begin of the DEST (i = leaf_copy_boundary_item(DEST,SOURCE,1,bytes)); */ i = leaf_copy_boundary_item (fs, dest_bi, src, LAST_TO_FIRST, bytes); cpy_num -= i; if ( cpy_num == 0 ) return i; pos = src_nr_item - cpy_num - i; if ( cpy_bytes == -1 ) { /* starting from position 'pos' copy last cpy_num items of SOURCE to begin of DEST */ leaf_copy_items_entirely(fs, dest_bi, src, LAST_TO_FIRST, pos, cpy_num); } else { /* copy last cpy_num-1 items starting from position 'pos+1' of the SOURCE to the begin of the DEST; */ leaf_copy_items_entirely(fs, dest_bi, src, LAST_TO_FIRST, pos+1, cpy_num-1); /* copy part of the item which number is pos to the begin of the DEST */ leaf_item_bottle (fs, dest_bi, src, LAST_TO_FIRST, pos, cpy_bytes); } } return i; } /* there are types of coping: from S[0] to L[0], from S[0] to R[0], from R[0] to L[0]. for each of these we have to define parent and positions of destination and source buffers */ static void leaf_define_dest_src_infos (int shift_mode, struct tree_balance * tb, struct buffer_info * dest_bi, struct buffer_info * src_bi, int * first_last, struct buffer_head * Snew) { #ifdef CONFIG_REISERFS_CHECK memset (dest_bi, 0, sizeof (struct buffer_info)); memset (src_bi, 0, sizeof (struct buffer_info)); #endif /* define dest, src, dest parent, dest position */ switch (shift_mode) { case LEAF_FROM_S_TO_L: /* it is used in leaf_shift_left */ src_bi->bi_bh = PATH_PLAST_BUFFER (tb->tb_path); src_bi->bi_parent = PATH_H_PPARENT (tb->tb_path, 0); src_bi->bi_position = PATH_H_B_ITEM_ORDER (tb->tb_path, 0); /* src->b_item_order */ dest_bi->bi_bh = tb->L[0]; dest_bi->bi_parent = tb->FL[0]; dest_bi->bi_position = get_left_neighbor_position (tb, 0); *first_last = FIRST_TO_LAST; break; case LEAF_FROM_S_TO_R: /* it is used in leaf_shift_right */ src_bi->bi_bh = PATH_PLAST_BUFFER (tb->tb_path); src_bi->bi_parent = PATH_H_PPARENT (tb->tb_path, 0); src_bi->bi_position = PATH_H_B_ITEM_ORDER (tb->tb_path, 0); dest_bi->bi_bh = tb->R[0]; dest_bi->bi_parent = tb->FR[0]; dest_bi->bi_position = get_right_neighbor_position (tb, 0); *first_last = LAST_TO_FIRST; break; case LEAF_FROM_R_TO_L: /* it is used in balance_leaf_when_delete */ src_bi->bi_bh = tb->R[0]; src_bi->bi_parent = tb->FR[0]; src_bi->bi_position = get_right_neighbor_position (tb, 0); dest_bi->bi_bh = tb->L[0]; dest_bi->bi_parent = tb->FL[0]; dest_bi->bi_position = get_left_neighbor_position (tb, 0); *first_last = FIRST_TO_LAST; break; case LEAF_FROM_L_TO_R: /* it is used in balance_leaf_when_delete */ src_bi->bi_bh = tb->L[0]; src_bi->bi_parent = tb->FL[0]; src_bi->bi_position = get_left_neighbor_position (tb, 0); dest_bi->bi_bh = tb->R[0]; dest_bi->bi_parent = tb->FR[0]; dest_bi->bi_position = get_right_neighbor_position (tb, 0); *first_last = LAST_TO_FIRST; break; case LEAF_FROM_S_TO_SNEW: src_bi->bi_bh = PATH_PLAST_BUFFER (tb->tb_path); src_bi->bi_parent = PATH_H_PPARENT (tb->tb_path, 0); src_bi->bi_position = PATH_H_B_ITEM_ORDER (tb->tb_path, 0); dest_bi->bi_bh = Snew; dest_bi->bi_parent = 0; dest_bi->bi_position = 0; *first_last = LAST_TO_FIRST; break; default: reiserfs_panic (0, "vs-10250: leaf_define_dest_src_infos: shift type is unknown (%d)", shift_mode); } #ifdef CONFIG_REISERFS_CHECK if (src_bi->bi_bh == 0 || dest_bi->bi_bh == 0) { reiserfs_panic (0, "vs-10260: leaf_define_dest_src_etc: mode==%d, source (%p) or dest (%p) buffer is initialized incorrectly", shift_mode, src_bi->bi_bh, dest_bi->bi_bh); } #endif } /* copy mov_num items and mov_bytes of the (mov_num-1)th item to neighbor. Delete them from source */ int leaf_move_items (int shift_mode, struct tree_balance * tb, int mov_num, int mov_bytes, struct buffer_head * Snew) { int ret_value; struct buffer_info dest_bi, src_bi; int first_last; leaf_define_dest_src_infos (shift_mode, tb, &dest_bi, &src_bi, &first_last, Snew); ret_value = leaf_copy_items (tb->tb_sb, &dest_bi, src_bi.bi_bh, first_last, mov_num, mov_bytes); leaf_delete_items (tb->tb_sb, &src_bi, first_last, (first_last == FIRST_TO_LAST) ? 0 : (B_NR_ITEMS(src_bi.bi_bh) - mov_num), mov_num, mov_bytes); return ret_value; } /* Shift shift_num items (and shift_bytes of last shifted item if shift_bytes != -1) from S[0] to L[0] and replace the delimiting key */ int leaf_shift_left (struct tree_balance * tb, int shift_num, int shift_bytes) { struct buffer_head * S0 = PATH_PLAST_BUFFER (tb->tb_path); int i; /* move shift_num (and shift_bytes bytes) items from S[0] to left neighbor L[0] */ i = leaf_move_items (LEAF_FROM_S_TO_L, tb, shift_num, shift_bytes, 0); if ( shift_num ) { if (B_NR_ITEMS (S0) == 0) { /* everything is moved from S[0] */ #ifdef CONFIG_REISERFS_CHECK if ( shift_bytes != -1 ) reiserfs_panic (tb->tb_sb, "vs-10270: leaf_shift_left: S0 is empty now, but shift_bytes != -1 (%d)", shift_bytes); if (init_mode == M_PASTE || init_mode == M_INSERT) { print_tb (init_mode, init_item_pos, init_pos_in_item, &init_tb, "vs-10275"); reiserfs_panic (tb->tb_sb, "vs-10275: leaf_shift_left: balance condition corrupted (%c)", init_mode); } #endif if (PATH_H_POSITION (tb->tb_path, 1) == 0) replace_key(tb->tb_sb, tb->CFL[0], tb->lkey[0], PATH_H_PPARENT (tb->tb_path, 0), 0); } else { /* replace lkey in CFL[0] by 0-th key from S[0]; */ replace_key(tb->tb_sb, tb->CFL[0], tb->lkey[0], S0, 0); #ifdef CONFIG_REISERFS_CHECK if (shift_bytes != -1 && !(I_IS_DIRECTORY_ITEM (B_N_PITEM_HEAD (S0, 0)) && !ih_entry_count (B_N_PITEM_HEAD (S0, 0)))) { if (!is_left_mergeable (B_N_PITEM_HEAD (S0, 0), S0->b_size)) { reiserfs_panic (tb->tb_sb, "vs-10280: leaf_shift_left: item must be mergeable"); } } #endif } } return i; } /* CLEANING STOPPED HERE */ /* Shift shift_num (shift_bytes) items from S[0] to the right neighbor, and replace the delimiting key */ int leaf_shift_right (struct tree_balance * tb, int shift_num, int shift_bytes) { int ret_value; /* move shift_num (and shift_bytes) items from S[0] to right neighbor R[0] */ ret_value = leaf_move_items (LEAF_FROM_S_TO_R, tb, shift_num, shift_bytes, 0); /* replace rkey in CFR[0] by the 0-th key from R[0] */ if (shift_num) { replace_key(tb->tb_sb, tb->CFR[0], tb->rkey[0], tb->R[0], 0); } return ret_value; } static void leaf_delete_items_entirely (struct super_block * sb, /*struct reiserfs_transaction_handle *th,*/ struct buffer_info * bi, int first, int del_num); /* If del_bytes == -1, starting from position 'first' delete del_num items in whole in buffer CUR. If not. If last_first == 0. Starting from position 'first' delete del_num-1 items in whole. Delete part of body of the first item. Part defined by del_bytes. Don't delete first item header If last_first == 1. Starting from position 'first+1' delete del_num-1 items in whole. Delete part of body of the last item . Part defined by del_bytes. Don't delete last item header. */ void leaf_delete_items (reiserfs_filsys_t fs, struct buffer_info * cur_bi, int last_first, int first, int del_num, int del_bytes) { struct buffer_head * bh; int item_amount = B_NR_ITEMS (bh = cur_bi->bi_bh); #ifdef CONFIG_REISERFS_CHECK if ( !bh ) reiserfs_panic (0, "leaf_delete_items: 10155: bh is not defined"); if ( del_num < 0 ) reiserfs_panic (0, "leaf_delete_items: 10160: del_num can not be < 0. del_num==%d", del_num); if ( first < 0 || first + del_num > item_amount ) reiserfs_panic (0, "leaf_delete_items: 10165: invalid number of first item to be deleted (%d) or " "no so much items (%d) to delete (only %d)", first, first + del_num, item_amount); #endif if ( del_num == 0 ) return; if ( first == 0 && del_num == item_amount && del_bytes == -1 ) { make_empty_node (cur_bi); mark_buffer_dirty (bh); return; } if ( del_bytes == -1 ) /* delete del_num items beginning from item in position first */ leaf_delete_items_entirely (fs, cur_bi, first, del_num); else { if ( last_first == FIRST_TO_LAST ) { /* delete del_num-1 items beginning from item in position first */ leaf_delete_items_entirely (fs, cur_bi, first, del_num-1); /* delete the part of the first item of the bh do not delete item header */ leaf_cut_from_buffer (fs, cur_bi, 0, 0, del_bytes); } else { struct item_head * ih; int len; /* delete del_num-1 items beginning from item in position first+1 */ leaf_delete_items_entirely (fs, cur_bi, first+1, del_num-1); if (I_IS_DIRECTORY_ITEM(ih = B_N_PITEM_HEAD(bh, B_NR_ITEMS(bh)-1))) /* the last item is directory */ /* len = numbers of directory entries in this item */ len = ih_entry_count(ih); else /* len = body len of item */ len = ih->ih_item_len; /* delete the part of the last item of the bh do not delete item header */ leaf_cut_from_buffer (fs, cur_bi, B_NR_ITEMS(bh) - 1, len - del_bytes, del_bytes); } } } /* insert item into the leaf node in position before */ void leaf_insert_into_buf (struct super_block * s, struct buffer_info * bi, int before, struct item_head * inserted_item_ih, const char * inserted_item_body, int zeros_number ) { struct buffer_head * bh = bi->bi_bh; int nr; struct block_head * blkh; struct item_head * ih; int i; int last_loc, unmoved_loc; char * to; nr = (blkh = B_BLK_HEAD (bh))->blk_nr_item; #ifdef CONFIG_REISERFS_CHECK /* check free space */ if (blkh->blk_free_space < inserted_item_ih->ih_item_len + IH_SIZE) reiserfs_panic (0, "leaf_insert_into_buf: 10170: not enough free space: needed %d, available %d", inserted_item_ih->ih_item_len + IH_SIZE, blkh->blk_free_space); if (zeros_number > inserted_item_ih->ih_item_len) reiserfs_panic (0, "vs-10172: leaf_insert_into_buf: zero number == %d, item length == %d", zeros_number, inserted_item_ih->ih_item_len); #endif /* CONFIG_REISERFS_CHECK */ /* get item new item must be inserted before */ ih = B_N_PITEM_HEAD (bh, before); /* prepare space for the body of new item */ last_loc = nr ? ih[nr - before - 1].ih_item_location : bh->b_size; unmoved_loc = before ? (ih-1)->ih_item_location : bh->b_size; memmove (bh->b_data + last_loc - inserted_item_ih->ih_item_len, bh->b_data + last_loc, unmoved_loc - last_loc); to = bh->b_data + unmoved_loc - inserted_item_ih->ih_item_len; memset (to, 0, zeros_number); to += zeros_number; /* copy body to prepared space */ if (inserted_item_body) //if (mem_mode == REISERFS_USER_MEM) // copy_from_user (to, inserted_item_body, inserted_item_ih->ih_item_len - zeros_number); //else { memmove (to, inserted_item_body, inserted_item_ih->ih_item_len - zeros_number); //} else memset(to, '\0', inserted_item_ih->ih_item_len - zeros_number); /* insert item header */ memmove (ih + 1, ih, IH_SIZE * (nr - before)); memmove (ih, inserted_item_ih, IH_SIZE); /* change locations */ for (i = before; i < nr + 1; i ++) ih[i-before].ih_item_location = (unmoved_loc -= ih[i-before].ih_item_len); /* sizes, free space, item number */ blkh->blk_nr_item ++; blkh->blk_free_space -= (IH_SIZE + inserted_item_ih->ih_item_len); mark_buffer_dirty(bh) ; if (bi->bi_parent) { B_N_CHILD (bi->bi_parent, bi->bi_position)->dc_size += (IH_SIZE + inserted_item_ih->ih_item_len); mark_buffer_dirty(bi->bi_parent) ; } if (who_is_this (bh->b_data, bh->b_size) != THE_LEAF) reiserfs_panic ("leaf_insert_into_buf: bad leaf %lu: %b", bh->b_blocknr, bh); } /* paste paste_size bytes to affected_item_num-th item. When item is a directory, this only prepare space for new entries */ void leaf_paste_in_buffer (reiserfs_filsys_t fs, struct buffer_info * bi, int affected_item_num, int pos_in_item, int paste_size, const char * body, int zeros_number) { struct buffer_head * bh = bi->bi_bh; int nr; struct block_head * blkh; struct item_head * ih; int i; int last_loc, unmoved_loc; nr = (blkh = B_BLK_HEAD(bh))->blk_nr_item; #ifdef CONFIG_REISERFS_CHECK /* check free space */ if (blkh->blk_free_space < paste_size) reiserfs_panic (th->t_super, "vs-10175: leaf_paste_in_buffer: " "not enough free space: needed %d, available %d", paste_size, blkh->blk_free_space); if (zeros_number > paste_size) { print_tb (init_mode, init_item_pos, init_pos_in_item, &init_tb, "10177"); reiserfs_panic (th->t_super, "vs-10177: leaf_paste_in_buffer: " "zero number == %d, paste_size == %d", zeros_number, paste_size); } #endif /* CONFIG_REISERFS_CHECK */ /* item to be appended */ ih = B_N_PITEM_HEAD(bh, affected_item_num); last_loc = ih[nr - affected_item_num - 1].ih_item_location; unmoved_loc = affected_item_num ? (ih-1)->ih_item_location : bh->b_size; /* prepare space */ memmove (bh->b_data + last_loc - paste_size, bh->b_data + last_loc, unmoved_loc - last_loc); /* change locations */ for (i = affected_item_num; i < nr; i ++) ih[i-affected_item_num].ih_item_location -= paste_size; if ( body ) { if (!I_IS_DIRECTORY_ITEM(ih)) { //if (mem_mode == REISERFS_USER_MEM) { //memset (bh->b_data + unmoved_loc - paste_size, 0, zeros_number); //copy_from_user (bh->b_data + unmoved_loc - paste_size + zeros_number, body, paste_size - zeros_number); //} else { if (!pos_in_item) { /* shift data to right */ memmove (bh->b_data + ih->ih_item_location + paste_size, bh->b_data + ih->ih_item_location, ih->ih_item_len); /* paste data in the head of item */ memset (bh->b_data + ih->ih_item_location, 0, zeros_number); memcpy (bh->b_data + ih->ih_item_location + zeros_number, body, paste_size - zeros_number); } else { memset (bh->b_data + unmoved_loc - paste_size, 0, zeros_number); memcpy (bh->b_data + unmoved_loc - paste_size + zeros_number, body, paste_size - zeros_number); } } } } else memset(bh->b_data + unmoved_loc - paste_size,'\0',paste_size); ih->ih_item_len += paste_size; /* change free space */ blkh->blk_free_space -= paste_size; mark_buffer_dirty(bh) ; if (bi->bi_parent) { B_N_CHILD (bi->bi_parent, bi->bi_position)->dc_size += paste_size; mark_buffer_dirty(bi->bi_parent); } if (who_is_this (bh->b_data, bh->b_size) != THE_LEAF) reiserfs_panic ("leaf_paste_in_buffer: bad leaf %lu: %b", bh->b_blocknr, bh); } /* cuts DEL_COUNT entries beginning from FROM-th entry. Directory item does not have free space, so it moves DEHs and remaining records as necessary. Return value is size of removed part of directory item in bytes. */ static int leaf_cut_entries (struct buffer_head * bh, struct item_head * ih, int from, int del_count) { char * item; struct reiserfs_de_head * deh; int prev_record_offset; /* offset of record, that is (from-1)th */ char * prev_record; /* */ int cut_records_len; /* length of all removed records */ int i; int entry_count; /* first byte of item */ item = bh->b_data + ih_location (ih); /* entry head array */ deh = B_I_DEH (bh, ih); entry_count = ih_entry_count (ih); if (del_count == 0) { int shift; int last_location; last_location = deh_location (deh + entry_count - 1); shift = last_location - DEH_SIZE * entry_count; memmove (deh + entry_count, item + last_location, ih_item_len (ih) - last_location); for (i = 0; i < entry_count; i ++) deh[i].deh_location = cpu_to_le16 (deh_location (deh + i) - shift); return shift; } /* first byte of remaining entries, those are BEFORE cut entries (prev_record) and length of all removed records (cut_records_len) */ prev_record_offset = (from ? deh[from - 1].deh_location : ih->ih_item_len); cut_records_len = prev_record_offset/*from_record*/ - deh[from + del_count - 1].deh_location; prev_record = item + prev_record_offset; /* adjust locations of remaining entries */ for (i = ih_entry_count (ih) - 1; i > from + del_count - 1; i --) deh[i].deh_location -= (DEH_SIZE * del_count); for (i = 0; i < from; i ++) deh[i].deh_location -= DEH_SIZE * del_count + cut_records_len; set_entry_count (ih, ih_entry_count (ih) - del_count); /* shift entry head array and entries those are AFTER removed entries */ memmove ((char *)(deh + from), deh + from + del_count, prev_record - cut_records_len - (char *)(deh + from + del_count)); /* shift records, those are BEFORE removed entries */ memmove (prev_record - cut_records_len - DEH_SIZE * del_count, prev_record, item + ih->ih_item_len - prev_record); return DEH_SIZE * del_count + cut_records_len; } /* when cut item is part of regular file pos_in_item - first byte that must be cut cut_size - number of bytes to be cut beginning from pos_in_item when cut item is part of directory pos_in_item - number of first deleted entry cut_size - count of deleted entries */ void leaf_cut_from_buffer (reiserfs_filsys_t fs, struct buffer_info * bi, int cut_item_num, int pos_in_item, int cut_size) { int nr; struct buffer_head * bh = bi->bi_bh; struct block_head * blkh; struct item_head * ih; int last_loc, unmoved_loc; int i; nr = (blkh = B_BLK_HEAD (bh))->blk_nr_item; /* item head of truncated item */ ih = B_N_PITEM_HEAD (bh, cut_item_num); if (I_IS_DIRECTORY_ITEM (ih)) { /* first cut entry ()*/ cut_size = leaf_cut_entries (bh, ih, pos_in_item, cut_size); if (pos_in_item == 0) { /* change key */ #ifdef CONFIG_REISERFS_CHECK if (cut_item_num) reiserfs_panic (th->t_super, "leaf_cut_from_buffer: 10190: " "when 0-th enrty of item is cut, that item must be first in the node, not %d-th", cut_item_num); #endif /* change item key by key of first entry in the item */ ih->ih_key.u.k_offset_v1.k_offset = B_I_DEH (bh, ih)->deh_offset; /*memcpy (&ih->ih_key.k_offset, &(B_I_DEH (bh, ih)->deh_offset), SHORT_KEY_SIZE);*/ } } else { /* item is direct or indirect */ #ifdef CONFIG_REISERFS_CHECK if (I_IS_STAT_DATA_ITEM (ih)) reiserfs_panic (th->t_super, "leaf_cut_from_buffer: 10195: item is stat data"); if (pos_in_item && pos_in_item + cut_size != ih->ih_item_len ) reiserfs_panic (th->t_super, "cut_from_buf: 10200: invalid offset (%lu) or trunc_size (%lu) or ih_item_len (%lu)", pos_in_item, cut_size, ih->ih_item_len); #endif /* shift item body to left if cut is from the head of item */ if (pos_in_item == 0) { memmove (bh->b_data + ih->ih_item_location, bh->b_data + ih->ih_item_location + cut_size, ih->ih_item_len - cut_size); /* change key of item */ if (I_IS_DIRECT_ITEM(ih)) { //ih->ih_key.k_offset += cut_size; set_offset (key_format (&ih->ih_key), &ih->ih_key, get_offset (&ih->ih_key) + cut_size); } else { //ih->ih_key.k_offset += (cut_size / UNFM_P_SIZE) * bh->b_size; set_offset (key_format (&ih->ih_key), &ih->ih_key, get_offset (&ih->ih_key) + (cut_size / UNFM_P_SIZE) * bh->b_size); #ifdef CONFIG_REISERFS_CHECK if ( ih->ih_item_len == cut_size && ih_free_space (ih) ) reiserfs_panic (th->t_super, "leaf_cut_from_buf: 10205: invalid ih_free_space (%lu)", ih_free_space (ih)); #endif } } } /* location of the last item */ last_loc = ih[nr - cut_item_num - 1].ih_item_location; /* location of the item, which is remaining at the same place */ unmoved_loc = cut_item_num ? (ih-1)->ih_item_location : bh->b_size; /* shift */ memmove (bh->b_data + last_loc + cut_size, bh->b_data + last_loc, unmoved_loc - last_loc - cut_size); /* change item length */ ih->ih_item_len -= cut_size; if (I_IS_INDIRECT_ITEM(ih)) { if (pos_in_item) //ih->u.ih_free_space = 0; set_free_space (ih, 0); } /* change locations */ for (i = cut_item_num; i < nr; i ++) ih[i-cut_item_num].ih_item_location += cut_size; /* size, free space */ blkh->blk_free_space += cut_size; mark_buffer_dirty(bh); if (bi->bi_parent) { B_N_CHILD (bi->bi_parent, bi->bi_position)->dc_size -= cut_size; mark_buffer_dirty(bi->bi_parent); } if (who_is_this (bh->b_data, bh->b_size) != THE_LEAF) reiserfs_panic ("leaf_cut_from_buffer: bad leaf %lu: %b", bh->b_blocknr, bh); } /* delete del_num items from buffer starting from the first'th item */ static void leaf_delete_items_entirely (reiserfs_filsys_t fs, struct buffer_info * bi, int first, int del_num) { struct buffer_head * bh = bi->bi_bh; int nr; int i, j; int last_loc, last_removed_loc; struct block_head * blkh; struct item_head * ih; #ifdef CONFIG_REISERFS_CHECK if (bh == NULL) reiserfs_panic (0, "leaf_delete_items_entirely: 10210: buffer is 0"); if (del_num < 0) reiserfs_panic (0, "leaf_delete_items_entirely: 10215: del_num less than 0 (%d)", del_num); #endif /* CONFIG_REISERFS_CHECK */ if (del_num == 0) return; nr = (blkh = B_BLK_HEAD(bh))->blk_nr_item; #ifdef CONFIG_REISERFS_CHECK if (first < 0 || first + del_num > nr) reiserfs_panic (0, "leaf_delete_items_entirely: 10220: first=%d, number=%d, there is %d items", first, del_num, nr); #endif /* CONFIG_REISERFS_CHECK */ if (first == 0 && del_num == nr) { /* this does not work */ make_empty_node (bi); mark_buffer_dirty(bh); return; } ih = B_N_PITEM_HEAD (bh, first); /* location of unmovable item */ j = (first == 0) ? bh->b_size : (ih-1)->ih_item_location; /* delete items */ last_loc = ih[nr-1-first].ih_item_location; last_removed_loc = ih[del_num-1].ih_item_location; memmove (bh->b_data + last_loc + j - last_removed_loc, bh->b_data + last_loc, last_removed_loc - last_loc); /* delete item headers */ memmove (ih, ih + del_num, (nr - first - del_num) * IH_SIZE); /* change item location */ for (i = first; i < nr - del_num; i ++) ih[i-first].ih_item_location += j - last_removed_loc; /* sizes, item number */ blkh->blk_nr_item -= del_num; blkh->blk_free_space += j - last_removed_loc + IH_SIZE * del_num; mark_buffer_dirty(bh); if (bi->bi_parent) { B_N_CHILD (bi->bi_parent, bi->bi_position)->dc_size -= j - last_removed_loc + IH_SIZE * del_num; mark_buffer_dirty(bi->bi_parent); } if (who_is_this (bh->b_data, bh->b_size) != THE_LEAF) reiserfs_panic ("leaf_delete_items_entirely: bad leaf %lu: %b", bh->b_blocknr, bh); } /* paste new_entry_count entries (new_dehs, records) into position before to item_num-th item */ void leaf_paste_entries (struct buffer_head * bh, int item_num, int before, int new_entry_count, struct reiserfs_de_head * new_dehs, const char * records, int paste_size) { struct item_head * ih; char * item; struct reiserfs_de_head * deh; char * insert_point; int i, old_entry_num; if (new_entry_count == 0) return; ih = B_N_PITEM_HEAD(bh, item_num); #ifdef CONFIG_REISERFS_CHECK /* make sure, that item is directory, and there are enough records in it */ if (!I_IS_DIRECTORY_ITEM (ih)) reiserfs_panic (0, "leaf_paste_entries: 10225: item is not directory item"); if (ih_entry_count (ih) < before) reiserfs_panic (0, "leaf_paste_entries: 10230: there are no entry we paste entries before. entry_count = %d, before = %d", ih_entry_count (ih), before); #endif /* first byte of dest item */ item = bh->b_data + ih->ih_item_location; /* entry head array */ deh = B_I_DEH (bh, ih); /* new records will be pasted at this point */ insert_point = item + (before ? deh[before - 1].deh_location : (ih->ih_item_len - paste_size)); /* adjust locations of records that will be AFTER new records */ for (i = ih_entry_count (ih) - 1; i >= before; i --) deh[i].deh_location += DEH_SIZE * new_entry_count; /* adjust locations of records that will be BEFORE new records */ for (i = 0; i < before; i ++) deh[i].deh_location += paste_size; old_entry_num = ih_entry_count (ih); //I_ENTRY_COUNT(ih) += new_entry_count; set_entry_count (ih, old_entry_num + new_entry_count); /* prepare space for pasted records */ memmove (insert_point + paste_size, insert_point, item + (ih->ih_item_len - paste_size) - insert_point); /* copy new records */ memcpy (insert_point + DEH_SIZE * new_entry_count, records, paste_size - DEH_SIZE * new_entry_count); /* prepare space for new entry heads */ deh += before; memmove ((char *)(deh + new_entry_count), deh, insert_point - (char *)deh); /* copy new entry heads */ deh = (struct reiserfs_de_head *)((char *)deh); memcpy (deh, new_dehs, DEH_SIZE * new_entry_count); /* set locations of new records */ for (i = 0; i < new_entry_count; i ++) deh[i].deh_location += (- new_dehs[new_entry_count - 1].deh_location + insert_point + DEH_SIZE * new_entry_count - item); /* change item key if neccessary (when we paste before 0-th entry */ if (!before) ih->ih_key.u.k_offset_v1.k_offset = new_dehs->deh_offset; #ifdef CONFIG_REISERFS_CHECK { int prev, next; /* check record locations */ deh = B_I_DEH (bh, ih); for (i = 0; i < ih_entry_count(ih); i ++) { next = (i < ih_entry_count(ih) - 1) ? deh[i + 1].deh_location : 0; prev = (i != 0) ? deh[i - 1].deh_location : 0; if (prev && prev <= deh[i].deh_location) reiserfs_warning ("vs-10240: leaf_paste_entries: directory item corrupted (%d %d)\n", prev, deh[i].deh_location); if (next && next >= deh[i].deh_location) reiserfs_warning ("vs-10250: leaf_paste_entries: directory item corrupted (%d %d)\n", prev, deh[i].deh_location); } } #endif } /* wrappers for operations on one separated node */ void delete_item (reiserfs_filsys_t fs, struct buffer_head * bh, int item_num) { struct buffer_info bi; bi.bi_bh = bh; bi.bi_parent = 0; bi.bi_position = 0; leaf_delete_items_entirely (fs, &bi, item_num, 1); } void cut_entry (reiserfs_filsys_t fs, struct buffer_head * bh, int item_num, int entry_num, int del_count) { struct buffer_info bi; bi.bi_bh = bh; bi.bi_parent = 0; bi.bi_position = 0; leaf_cut_from_buffer (fs, &bi, item_num, entry_num, del_count); } reiserfsprogs-3.x.0j/reiserfscore/prints.c0000644000076400001440000006412107261104002014524 /* * Copyright 1996, 1997, 1998 Hans Reiser, see reiserfs/README for licensing and copyright details */ #include "includes.h" #include #include #include static int _arginfo (const struct printf_info *info, size_t n, int *argtypes) { if (n > 0) argtypes[0] = PA_POINTER; return 1; } #if 0 static int _arginfo2 (const struct printf_info *info, size_t n, int *argtypes) { if (n > 0) argtypes[0] = PA_INT; return 1; } #endif #define FPRINTF \ if (len == -1) {\ return -1;\ }\ len = fprintf (stream, "%*s",\ info->left ? -info->width : info->width, buffer);\ free (buffer);\ return len;\ /* %z */ static int print_block_head (FILE * stream, const struct printf_info *info, const void *const *args) { const struct buffer_head * bh; char * buffer; int len; bh = *((const struct buffer_head **)(args[0])); len = asprintf (&buffer, "level=%d, nr_items=%d, free_space=%d rdkey", B_LEVEL (bh), B_NR_ITEMS (bh), node_free_space (bh)); FPRINTF; } /* %K */ static int print_short_key (FILE * stream, const struct printf_info *info, const void *const *args) { const struct key * key; char * buffer; int len; key = *((const struct key **)(args[0])); len = asprintf (&buffer, "%u %u", key->k_dir_id, key->k_objectid); FPRINTF; } /* %k */ static int print_key (FILE * stream, const struct printf_info *info, const void *const *args) { const struct key * key; char * buffer; int len; key = *((const struct key **)(args[0])); len = asprintf (&buffer, "%u %u 0x%Lx %s", key->k_dir_id, key->k_objectid, get_offset (key), key_of_what (key)); FPRINTF; } /* %H */ static int print_item_head (FILE * stream, const struct printf_info *info, const void *const *args) { const struct item_head * ih; char * buffer; int len; ih = *((const struct item_head **)(args[0])); len = asprintf (&buffer, "%u %u 0x%Lx %s, " "len %u, entry count %u, fsck need %u, format %s", ih->ih_key.k_dir_id, ih->ih_key.k_objectid, get_offset (&ih->ih_key), key_of_what (&ih->ih_key), ih->ih_item_len, ih_entry_count (ih), ih->ih_format.fsck_need, ih_key_format (ih) == KEY_FORMAT_2 ? "new" : ((ih_key_format (ih) == KEY_FORMAT_1) ? "old" : "BAD")); FPRINTF; } static int print_disk_child (FILE * stream, const struct printf_info *info, const void *const *args) { const struct disk_child * dc; char * buffer; int len; dc = *((const struct disk_child **)(args[0])); len = asprintf (&buffer, "[dc_number=%u, dc_size=%u]", le32_to_cpu (dc->dc_block_number), le16_to_cpu (dc->dc_size)); FPRINTF; } char ftypelet (mode_t mode) { if (S_ISBLK (mode)) return 'b'; if (S_ISCHR (mode)) return 'c'; if (S_ISDIR (mode)) return 'd'; if (S_ISREG (mode)) return '-'; if (S_ISFIFO (mode)) return 'p'; if (S_ISLNK (mode)) return 'l'; if (S_ISSOCK (mode)) return 's'; return '?'; } static int rwx (FILE * stream, mode_t mode) { return fprintf (stream, "%c%c%c", (mode & S_IRUSR) ? 'r' : '-', (mode & S_IWUSR) ? 'w' : '-', (mode & S_IXUSR) ? 'x' : '-'); } /* %M */ static int print_sd_mode (FILE * stream, const struct printf_info *info, const void *const *args) { int len = 0; mode_t mode; mode = *(mode_t *)args[0]; len = fprintf (stream, "%c", ftypelet (mode)); len += rwx (stream, (mode & 0700) << 0); len += rwx (stream, (mode & 0070) << 3); len += rwx (stream, (mode & 0007) << 6); return len; } void reiserfs_warning (FILE * fp, const char * fmt, ...) { static int registered = 0; va_list args; if (!registered) { registered = 1; register_printf_function ('K', print_short_key, _arginfo); register_printf_function ('k', print_key, _arginfo); register_printf_function ('H', print_item_head, _arginfo); register_printf_function ('b', print_block_head, _arginfo); register_printf_function ('y', print_disk_child, _arginfo); register_printf_function ('M', print_sd_mode, _arginfo); } va_start (args, fmt); vfprintf (fp, fmt, args); va_end (args); } static char * vi_type (struct virtual_item * vi) { static char *types[]={"directory", "direct", "indirect", "stat data"}; if (vi->vi_type & VI_TYPE_STAT_DATA) return types[3]; if (vi->vi_type & VI_TYPE_INDIRECT) return types[2]; if (vi->vi_type & VI_TYPE_DIRECT) return types[1]; if (vi->vi_type & VI_TYPE_DIRECTORY) return types[0]; reiserfs_panic ("vi_type: 6000: unknown type (0x%x)", vi->vi_type); return NULL; } void print_virtual_node (struct virtual_node * vn) { int i, j; printf ("VIRTUAL NODE CONTAINS %d items, has size %d,%s,%s, ITEM_POS=%d POS_IN_ITEM=%d MODE=\'%c\'\n", vn->vn_nr_item, vn->vn_size, (vn->vn_vi[0].vi_type & VI_TYPE_LEFT_MERGEABLE )? "left mergeable" : "", (vn->vn_vi[vn->vn_nr_item - 1].vi_type & VI_TYPE_RIGHT_MERGEABLE) ? "right mergeable" : "", vn->vn_affected_item_num, vn->vn_pos_in_item, vn->vn_mode); for (i = 0; i < vn->vn_nr_item; i ++) { printf ("%s %d %d", vi_type (&vn->vn_vi[i]), i, vn->vn_vi[i].vi_item_len); if (vn->vn_vi[i].vi_entry_sizes) { printf ("It is directory with %d entries: ", vn->vn_vi[i].vi_entry_count); for (j = 0; j < vn->vn_vi[i].vi_entry_count; j ++) printf ("%d ", vn->vn_vi[i].vi_entry_sizes[j]); } printf ("\n"); } } void print_path (struct tree_balance * tb, struct path * path) { int offset = path->path_length; struct buffer_head * bh; printf ("Offset Bh (b_blocknr, b_count) Position Nr_item\n"); while ( offset > ILLEGAL_PATH_ELEMENT_OFFSET ) { bh = PATH_OFFSET_PBUFFER (path, offset); printf ("%6d %10p (%9lu, %7d) %8d %7d\n", offset, bh, bh ? bh->b_blocknr : 0, bh ? bh->b_count : 0, PATH_OFFSET_POSITION (path, offset), bh ? B_NR_ITEMS (bh) : -1); offset --; } } #if 0 void print_de (struct reiserfs_dir_entry * de) { reiserfs_warning ("entry key: [%k], object_key: [%u %u], b_blocknr=%lu, item_num=%d, pos_in_item=%d\n", &de->de_entry_key, de->de_dir_id, de->de_objectid, de->de_bh->b_blocknr, de->de_item_num, de->de_entry_num); } static char * item_type (struct item_head * ih) { static char * types[] = { "SD", "DIR", "DRCT", "IND", "???" }; if (I_IS_STAT_DATA_ITEM(ih)) return types[0]; if (I_IS_DIRECTORY_ITEM(ih)) return types[1]; if (I_IS_DIRECT_ITEM(ih)) return types[2]; if (I_IS_INDIRECT_ITEM(ih)) return types[3]; return types[4]; } #endif void print_directory_item (FILE * fp, reiserfs_filsys_t fs, struct buffer_head * bh, struct item_head * ih) { int i; int namelen; struct reiserfs_de_head * deh; char * name; /* static char namebuf [80];*/ if (!I_IS_DIRECTORY_ITEM (ih)) return; //printk ("\n%2%-25s%-30s%-15s%-15s%-15s\n", " Name", "length", "Object key", "Hash", "Gen number", "Status"); reiserfs_warning (fp, "%3s: %-25s%s%-22s%-12s%s\n", "###", "Name", "length", " Object key", " Hash", "Gen number"); deh = B_I_DEH (bh, ih); for (i = 0; i < ih_entry_count (ih); i ++, deh ++) { if (dir_entry_bad_location (deh, ih, i == 0 ? 1 : 0)) { reiserfs_warning (fp, "%3d: wrong entry location %u, deh_offset %u\n", i, deh_location (deh), deh_offset (deh)); continue; } if (i && dir_entry_bad_location (deh - 1, ih, ((i - 1) == 0) ? 1 : 0)) /* previous entry has bad location so we can not calculate entry length */ namelen = 25; else namelen = name_length (ih, deh, i); name = name_in_entry (deh, i); reiserfs_warning (fp, "%3d: \"%-25.*s\"(%3d)%20K%12d%5d, loc %u, state %x %s\n", i, namelen, name, namelen, (struct key *)&(deh->deh_dir_id), GET_HASH_VALUE (deh->deh_offset), GET_GENERATION_NUMBER (deh->deh_offset), deh_location (deh), deh->deh_state, fs ? (is_properly_hashed (fs, name, namelen, deh_offset (deh)) ? "" : "(BROKEN)") : "??"); } } // // printing of indirect item // static void start_new_sequence (__u32 * start, int * len, __u32 new) { *start = new; *len = 1; } static int sequence_finished (__u32 start, int * len, __u32 new) { if (start == INT_MAX) return 1; if (start == 0 && new == 0) { (*len) ++; return 0; } if (start != 0 && (start + *len) == new) { (*len) ++; return 0; } return 1; } static void print_sequence (FILE * fp, __u32 start, int len) { if (start == INT_MAX) return; if (len == 1) reiserfs_warning (fp, " %d", start); else reiserfs_warning (fp, " %d(%d)", start, len); } void print_indirect_item (FILE * fp, struct buffer_head * bh, int item_num) { struct item_head * ih; int j; __u32 * unp, prev = INT_MAX; int num; ih = B_N_PITEM_HEAD (bh, item_num); unp = (__u32 *)B_I_PITEM (bh, ih); if (ih->ih_item_len % UNFM_P_SIZE) reiserfs_warning (fp, "print_indirect_item: invalid item len"); reiserfs_warning (fp, "%d pointers\n[ ", I_UNFM_NUM (ih)); for (j = 0; j < I_UNFM_NUM (ih); j ++) { if (sequence_finished (prev, &num, unp[j])) { print_sequence (fp, prev, num); start_new_sequence (&prev, &num, unp[j]); } } print_sequence (fp, prev, num); reiserfs_warning (fp, "]\n"); } char timebuf[256]; char * timestamp (time_t t) { strftime (timebuf, 256, "%m/%d/%Y %T", localtime (&t)); return timebuf; } static int print_stat_data (FILE * fp, struct buffer_head * bh, struct item_head * ih, int alltimes) { struct stat_data * sd = (struct stat_data *)B_I_PITEM (bh, ih); struct stat_data_v1 * sd_v1 = (struct stat_data_v1 *)B_I_PITEM (bh, ih); int retval; /* we can not figure out whether it is new stat data or old by key_format macro. Stat data's key looks identical in both formats */ if (ih_key_format (ih) == KEY_FORMAT_1) { reiserfs_warning (fp, "(OLD SD), mode %M, size %u, nlink %u, uid %d, FDB %d, mtime %s blocks %d", sd_v1->sd_mode, sd_v1->sd_size, sd_v1->sd_nlink, sd_v1->sd_uid, sd_v1->sd_first_direct_byte, timestamp (sd_v1->sd_mtime), sd_v1->u.sd_blocks); retval = (S_ISLNK (sd_v1->sd_mode)) ? 1 : 0; } else { reiserfs_warning (fp, "(NEW SD), mode %M, size %Lu, nlink %u, mtime %s blocks %d", sd->sd_mode, sd->sd_size, sd->sd_nlink, timestamp (sd->sd_mtime), sd->sd_blocks); retval = (S_ISLNK (sd->sd_mode)) ? 1 : 0; } if (alltimes) reiserfs_warning (fp, "%s %s\n", timestamp (sd->sd_ctime), timestamp (sd->sd_atime)); reiserfs_warning (fp, "\n"); return retval; } /* this prints internal nodes (4 keys/items in line) (dc_number, dc_size)[k_dirid, k_objectid, k_offset, k_uniqueness](dc_number, dc_size)...*/ static int print_internal (FILE * fp, struct buffer_head * bh, int first, int last) { struct key * key; struct disk_child * dc; int i; int from, to; if (!is_internal_node (bh)) return 1; if (first == -1) { from = 0; to = B_NR_ITEMS (bh); } else { from = first; to = last < B_NR_ITEMS (bh) ? last : B_NR_ITEMS (bh); } reiserfs_warning (fp, "INTERNAL NODE (%ld) contains %b\n", bh->b_blocknr, bh); dc = B_N_CHILD (bh, from); reiserfs_warning (fp, "PTR %d: %y ", from, dc); for (i = from, key = B_N_PDELIM_KEY (bh, from), dc ++; i < to; i ++, key ++, dc ++) { reiserfs_warning (fp, "KEY %d: %20k PTR %d: %20y ", i, key, i + 1, dc); if (i && i % 4 == 0) reiserfs_warning (fp, "\n"); } reiserfs_warning (fp, "\n"); return 0; } static int is_symlink = 0; static int print_leaf (FILE * fp, reiserfs_filsys_t fs, struct buffer_head * bh, int print_mode, int first, int last) { struct block_head * blkh; struct item_head * ih; int i; int from, to; if (!is_leaf_node (bh)) return 1; blkh = B_BLK_HEAD (bh); ih = B_N_PITEM_HEAD (bh,0); reiserfs_warning (fp, "\n===================================================================\n"); reiserfs_warning (fp, "LEAF NODE (%ld) contains %b\n", bh->b_blocknr, bh); if (!(print_mode & PRINT_LEAF_ITEMS)) { reiserfs_warning (fp, "FIRST ITEM_KEY: %k, LAST ITEM KEY: %k\n", &(ih->ih_key), &((ih + blkh->blk_nr_item - 1)->ih_key)); return 0; } if (first < 0 || first > blkh->blk_nr_item - 1) from = 0; else from = first; if (last < 0 || last > blkh->blk_nr_item) to = blkh->blk_nr_item; else to = last; reiserfs_warning (fp, "-------------------------------------------------------------------------------\n" "|###|type|ilen|f/sp| loc|fmt|fsck| key |\n" "| | | |e/cn| | |need| |\n"); for (i = from; i < to; i++) { reiserfs_warning (fp, "-------------------------------------------------------------------------------\n" "|%3d|%30H|\n", i, ih + i); if (I_IS_STAT_DATA_ITEM(ih+i) && print_mode & PRINT_ITEM_DETAILS) { is_symlink = print_stat_data (fp, bh, ih + i, 0/*all times*/); continue; } if (I_IS_DIRECTORY_ITEM(ih+i) && print_mode & PRINT_ITEM_DETAILS) { print_directory_item (fp, fs, bh, ih+i); continue; } if (I_IS_INDIRECT_ITEM(ih+i) && print_mode & PRINT_ITEM_DETAILS) { print_indirect_item (fp, bh, i); continue; } if (I_IS_DIRECT_ITEM(ih+i)) { int j = 0; if (is_symlink || print_mode & PRINT_DIRECT_ITEMS) { reiserfs_warning (fp, "\""); while (j < ih[i].ih_item_len) { if (B_I_PITEM(bh,ih+i)[j] == 10) reiserfs_warning (fp, "\\n"); else reiserfs_warning (fp, "%c", B_I_PITEM(bh,ih+i)[j]); j ++; } reiserfs_warning (fp, "\"\n"); } continue; } } reiserfs_warning (fp, "===================================================================\n"); return 0; } /* return 1 if this is not super block */ static int print_super_block (FILE * fp, struct buffer_head * bh) { struct reiserfs_super_block * rs = (struct reiserfs_super_block *)(bh->b_data); int skipped, data_blocks; if (is_reiser2fs_magic_string (rs)) reiserfs_warning (fp, "Super block of format 3.6 found on the 0x%x in block %ld\n", bh->b_dev, bh->b_blocknr); else if (is_reiserfs_magic_string (rs)) reiserfs_warning (fp, "Super block of format 3.5 found on the 0x%x in block %ld\n", bh->b_dev, bh->b_blocknr); else if (is_prejournaled_reiserfs (rs)) { reiserfs_warning (fp, "Prejournaled reiserfs super block found. Not supported here. Use proper tools instead\n"); return 1; } else // no reiserfs signature found in the block return 1; reiserfs_warning (fp, "Block count %u\n", rs_block_count (rs)); reiserfs_warning (fp, "Blocksize %d\n", rs_blocksize (rs)); reiserfs_warning (fp, "Free blocks %u\n", rs_free_blocks (rs)); skipped = bh->b_blocknr; // FIXME: this would be confusing if // someone stores reiserfs super block in reiserfs ;) data_blocks = rs_block_count (rs) - skipped - 1 - rs_bmap_nr (rs) - (rs_journal_size (rs) + 1) - rs_free_blocks (rs); reiserfs_warning (fp, "Busy blocks (skipped %d, bitmaps - %d, journal blocks - %d\n" "1 super blocks, %d data blocks\n", skipped, rs_bmap_nr (rs), (rs_journal_size (rs) + 1), data_blocks); reiserfs_warning (fp, "Root block %u\n", rs_root_block (rs)); reiserfs_warning (fp, "Journal block (first) %d\n", rs_journal_start (rs)); reiserfs_warning (fp, "Journal dev %d\n", rs->s_v1.s_journal_dev); reiserfs_warning (fp, "Journal orig size %d\n", rs_journal_size (rs)); reiserfs_warning (fp, "Filesystem state %s\n", (rs->s_v1.s_state == REISERFS_VALID_FS) ? "VALID" : "ERROR"); if (fsck_state (rs) == TREE_IS_BUILT) reiserfs_warning (fp, "fsck pass 2 completion code set\n"); #if 0 __u32 s_journal_trans_max ; /* max number of blocks in a transaction. */ __u32 s_journal_block_count ; /* total size of the journal. can change over time */ __u32 s_journal_max_batch ; /* max number of blocks to batch into a trans */ __u32 s_journal_max_commit_age ; /* in seconds, how old can an async commit be */ __u32 s_journal_max_trans_age ; /* in seconds, how old can a transaction be */ #endif reiserfs_warning (fp, "Tree height %d\n", rs_tree_height (rs)); reiserfs_warning (fp, "Hash function used to sort names: %s\n", code2name (rs_hash (rs))); reiserfs_warning (fp, "Objectid map size %d, max %d\n", rs_objectid_map_size (rs), rs_objectid_map_max_size (rs)); reiserfs_warning (fp, "Version %d\n", rs_version (rs)); return 0; } static int print_desc_block (FILE * fp, struct buffer_head * bh) { struct reiserfs_journal_desc * desc; desc = (struct reiserfs_journal_desc *)(bh->b_data); if (memcmp(desc->j_magic, JOURNAL_DESC_MAGIC, 8)) return 1; reiserfs_warning (fp, "Desc block %lu (j_trans_id %ld, j_mount_id %ld, j_len %ld)", bh->b_blocknr, desc->j_trans_id, desc->j_mount_id, desc->j_len); return 0; } void print_block (FILE * fp, reiserfs_filsys_t fs, struct buffer_head * bh, ...)//int print_mode, int first, int last) { va_list args; int mode, first, last; va_start (args, bh); if ( ! bh ) { reiserfs_warning (stderr, "print_block: buffer is NULL\n"); return; } mode = va_arg (args, int); first = va_arg (args, int); last = va_arg (args, int); if (print_desc_block (fp, bh)) if (print_super_block (fp, bh)) if (print_leaf (fp, fs, bh, mode, first, last)) if (print_internal (fp, bh, first, last)) reiserfs_warning (fp, "Block %ld contains unformatted data\n", bh->b_blocknr); } void print_tb (int mode, int item_pos, int pos_in_item, struct tree_balance * tb, char * mes) { int h = 0; int i; struct buffer_head * tbSh, * tbFh; if (!tb) return; printf ("\n********************** PRINT_TB for %s *******************\n", mes); printf ("MODE=%c, ITEM_POS=%d POS_IN_ITEM=%d\n", mode, item_pos, pos_in_item); printf ("*********************************************************************\n"); printf ("* h * S * L * R * F * FL * FR * CFL * CFR *\n"); /* 01234567890123456789012345678901234567890123456789012345678901234567890123456789 1 2 3 4 5 6 7 8 printk ("*********************************************************************\n"); */ for (h = 0; h < sizeof(tb->insert_size) / sizeof (tb->insert_size[0]); h ++) { if (PATH_H_PATH_OFFSET (tb->tb_path, h) <= tb->tb_path->path_length && PATH_H_PATH_OFFSET (tb->tb_path, h) > ILLEGAL_PATH_ELEMENT_OFFSET) { tbSh = PATH_H_PBUFFER (tb->tb_path, h); tbFh = PATH_H_PPARENT (tb->tb_path, h); } else { /* printk ("print_tb: h=%d, PATH_H_PATH_OFFSET=%d, path_length=%d\n", h, PATH_H_PATH_OFFSET (tb->tb_path, h), tb->tb_path->path_length);*/ tbSh = 0; tbFh = 0; } printf ("* %d * %3ld(%2d) * %3ld(%2d) * %3ld(%2d) * %5ld * %5ld * %5ld * %5ld * %5ld *\n", h, (tbSh) ? (tbSh->b_blocknr):(-1), (tbSh) ? tbSh->b_count : -1, (tb->L[h]) ? (tb->L[h]->b_blocknr):(-1), (tb->L[h]) ? tb->L[h]->b_count : -1, (tb->R[h]) ? (tb->R[h]->b_blocknr):(-1), (tb->R[h]) ? tb->R[h]->b_count : -1, (tbFh) ? (tbFh->b_blocknr):(-1), (tb->FL[h]) ? (tb->FL[h]->b_blocknr):(-1), (tb->FR[h]) ? (tb->FR[h]->b_blocknr):(-1), (tb->CFL[h]) ? (tb->CFL[h]->b_blocknr):(-1), (tb->CFR[h]) ? (tb->CFR[h]->b_blocknr):(-1)); } printf ("*********************************************************************\n"); /* print balance parameters for leaf level */ h = 0; printf ("* h * size * ln * lb * rn * rb * blkn * s0 * s1 * s1b * s2 * s2b * curb * lk * rk *\n"); printf ("* %d * %4d * %2d * %2d * %2d * %2d * %4d * %2d * %2d * %3d * %2d * %3d * %4d * %2d * %2d *\n", h, tb->insert_size[h], tb->lnum[h], tb->lbytes, tb->rnum[h],tb->rbytes, tb->blknum[h], tb->s0num, tb->s1num,tb->s1bytes, tb->s2num, tb->s2bytes, tb->cur_blknum, tb->lkey[h], tb->rkey[h]); /* this prints balance parameters for non-leaf levels */ do { h++; printf ("* %d * %4d * %2d * * %2d * * %2d *\n", h, tb->insert_size[h], tb->lnum[h], tb->rnum[h], tb->blknum[h]); } while (tb->insert_size[h]); printf ("*********************************************************************\n"); /* print FEB list (list of buffers in form (bh (b_blocknr, b_count), that will be used for new nodes) */ h = 0; for (i = 0; i < sizeof (tb->FEB) / sizeof (tb->FEB[0]); i ++) printf ("%s%p (%lu %d)", i == 0 ? "FEB list: " : ", ", tb->FEB[i], tb->FEB[i] ? tb->FEB[i]->b_blocknr : 0, tb->FEB[i] ? tb->FEB[i]->b_count : 0); printf ("\n"); printf ("********************** END OF PRINT_TB *******************\n\n"); } static void print_bmap_block (FILE * fp, int i, struct buffer_head * bmap, int blocks, int silent) { int j, k; int bits = bmap->b_size * 8; int zeros = 0, ones = 0; reiserfs_warning (fp, "#%d: block %lu: ", i, bmap->b_blocknr); if (test_bit (0, bmap->b_data)) { /* first block addressed by this bitmap block is used */ ones ++; if (!silent) reiserfs_warning (fp, "Busy (%d-", i * bits); for (j = 1; j < blocks; j ++) { while (test_bit (j, bmap->b_data)) { ones ++; if (j == blocks - 1) { if (!silent) reiserfs_warning (fp, "%d)\n", j + i * bits); goto end; } j++; } if (!silent) reiserfs_warning (fp, "%d) Free(%d-", j - 1 + i * bits, j + i * bits); while (!test_bit (j, bmap->b_data)) { zeros ++; if (j == blocks - 1) { if (!silent) reiserfs_warning (fp, "%d)\n", j + i * bits); goto end; } j++; } if (!silent) reiserfs_warning (fp, "%d) Busy(%d-", j - 1 + i * bits, j + i * bits); j --; end: } } else { /* first block addressed by this bitmap is free */ zeros ++; if (!silent) reiserfs_warning (fp, "Free (%d-", i * bits); for (j = 1; j < blocks; j ++) { k = 0; while (!test_bit (j, bmap->b_data)) { k ++; if (j == blocks - 1) { if (!silent) reiserfs_warning (fp, "%d)\n", j + i * bits); zeros += k; goto end2; } j++; } zeros += k; if (!silent) reiserfs_warning (fp, "%d) Busy(%d-", j - 1 + i * bits, j + i * bits); k = 0; while (test_bit (j, bmap->b_data)) { ones ++; if (j == blocks - 1) { if (!silent) reiserfs_warning (fp, "%d)\n", j + i * bits); ones += k; goto end2; } j++; } ones += k; if (!silent) reiserfs_warning (fp, "%d) Free(%d-", j - 1 + i * bits, j + i * bits); j --; end2: } } reiserfs_warning (fp, "used %d, free %d\n", ones, zeros); } /* if silent == 1, do not print details */ void print_bmap (FILE * fp, reiserfs_filsys_t s, int silent) { int bmapnr = SB_BMAP_NR (s); int i; int blocks = s->s_blocksize * 8; /* adressed by bitmap */ reiserfs_warning (fp, "Bitmap blocks are:\n"); for (i = 0; i < bmapnr; i ++) { if (i == bmapnr - 1) if (SB_BLOCK_COUNT (s) % (s->s_blocksize * 8)) blocks = SB_BLOCK_COUNT (s) % (s->s_blocksize * 8); print_bmap_block (fp, i, SB_AP_BITMAP(s)[i], blocks, silent); } /* check unused part of last bitmap */ { int bad_unused_bitmap = 0; int ones; ones = s->s_blocksize * 8 - SB_BLOCK_COUNT (s) % (s->s_blocksize * 8); if (ones == s->s_blocksize * 8) ones = 0; for (i = s->s_blocksize * 8; --i >= blocks; ) if (!test_bit (i, SB_AP_BITMAP (s)[bmapnr - 1]->b_data)) bad_unused_bitmap ++; if (bad_unused_bitmap) { reiserfs_warning (fp, "Unused part of bitmap is wrong: should be %d ones, found %d zeros\n", ones, bad_unused_bitmap); } } } void print_objectid_map (FILE * fp, reiserfs_filsys_t fs) { int i; struct reiserfs_super_block * rs; __u32 * omap; rs = fs->s_rs; if (fs->s_version == REISERFS_VERSION_2) omap = (__u32 *)(rs + 1); else if (fs->s_version == REISERFS_VERSION_1) omap = (__u32 *)((struct reiserfs_super_block_v1 *)rs + 1); else { reiserfs_warning (fp, "print_objectid_map: proper signature is not found\n"); return; } reiserfs_warning (fp, "Map of objectids (super block size %d)\n", (char *)omap - (char *)rs); for (i = 0; i < SB_OBJECTID_MAP_SIZE (fs); i ++) { if (i % 2 == 0) reiserfs_warning (fp, "busy(%u-%u) ", omap[i], omap[i+1] - 1); else reiserfs_warning (fp, "free(%u-%u) ", omap[i], ((i+1) == SB_OBJECTID_MAP_SIZE (fs)) ? -1 : omap[i+1] - 1); } reiserfs_warning (fp, "\nObject id array has size %d (max %d):", SB_OBJECTID_MAP_SIZE (fs), SB_OBJECTID_MAP_MAXSIZE (fs)); for (i = 0; i < SB_OBJECTID_MAP_SIZE (fs); i ++) reiserfs_warning (fp, "%s%u ", i % 2 ? "" : "*", omap[i]); reiserfs_warning (fp, "\n"); } #if 0 /* the below is from fileutils-4.0-66 (shortened) */ /* Look at read, write, and execute bits in BITS and set flags in CHARS accordingly. */ static void rwx (short unsigned int bits, char *chars) { chars[0] = (bits & S_IRUSR) ? 'r' : '-'; chars[1] = (bits & S_IWUSR) ? 'w' : '-'; chars[2] = (bits & S_IXUSR) ? 'x' : '-'; } /* snip */ /* Return a character indicating the type of file described by file mode BITS: 'd' for directories 'b' for block special files 'c' for character special files 'l' for symbolic links 's' for sockets 'p' for fifos '-' for regular files '?' for any other file type. */ static char ftypelet (long int bits) { #ifdef S_ISBLK if (S_ISBLK (bits)) return 'b'; #endif if (S_ISCHR (bits)) return 'c'; if (S_ISDIR (bits)) return 'd'; if (S_ISREG (bits)) return '-'; #ifdef S_ISFIFO if (S_ISFIFO (bits)) return 'p'; #endif #ifdef S_ISLNK if (S_ISLNK (bits)) return 'l'; #endif #ifdef S_ISSOCK if (S_ISSOCK (bits)) return 's'; #endif return '?'; } /* Like filemodestring, but only the relevant part of the `struct stat' is given as an argument. */ static void mode_string (short unsigned int mode, char *str) { str[0] = ftypelet ((long) mode); rwx ((mode & 0700) << 0, &str[1]); rwx ((mode & 0070) << 3, &str[4]); rwx ((mode & 0007) << 6, &str[7]); } char * st_mode2string (short unsigned int mode, char * buf) { mode_string (mode, buf); buf[10] = 0; return buf; } #endif reiserfsprogs-3.x.0j/reiserfscore/stree.c0000644000076400001440000004140507257461557014361 /* * Copyright 1996, 1997, 1998 Hans Reiser, see reiserfs/README for licensing and copyright details */ /* * Written by Anatoly P. Pinchuk pap@namesys.botik.ru * Programm System Institute * Pereslavl-Zalessky Russia */ /* * This file contains functions dealing with S+tree * * comp_keys * comp_short_keys * bin_search * get_lkey * get_rkey * key_in_buffer * decrement_bcount * decrement_counters_in_path * pathrelse * search_by_key * search_for_position_by_key * comp_items * prepare_for_delete_or_cut * calc_deleted_bytes_number * init_tb_struct * reiserfs_delete_item * indirect_to_direct * maybe_indirect_to_direct * reiserfs_cut_from_item * reiserfs_cut_dir_entry * reiserfs_paste_into_item * reiserfs_insert_item */ #include "includes.h" /* Does the buffer contain a disk block which is in the tree. */ inline int B_IS_IN_TREE (struct buffer_head * p_s_bh) { #ifdef CONFIG_REISERFS_CHECK if ( node_level (p_s_bh) > MAX_HEIGHT ) { reiserfs_panic(0, "PAP-1010: B_IS_IN_TREE: block (%b) has too big level (%z)", p_s_bh, p_s_bh); } #endif return ( node_level (p_s_bh) != FREE_LEVEL ); } /* Compare keys using REISERFS_SHORT_KEY_LEN fields. Returns: -1 if key1 < key2 0 if key1 = key2 1 if key1 > key2 */ int comp_short_keys (void * k1, void * k2) { __u32 * p_s_key1, * p_s_key2; int n_key_length = REISERFS_SHORT_KEY_LEN; p_s_key1 = (__u32 *)k1; p_s_key2 = (__u32 *)k2; for( ; n_key_length--; ++p_s_key1, ++p_s_key2 ) { if ( *p_s_key1 < *p_s_key2 ) return -1; if ( *p_s_key1 > *p_s_key2 ) return 1; } return 0; } /* Compare keys using all 4 key fields. Returns: -1 if key1 < key2 0 if key1 = key2 1 if key1 > key2 */ int comp_keys (void * p1, void * p2) { int retval; struct key * k1, * k2; k1 = p1; k2 = p2; retval = comp_short_keys (k1, k2); if (retval) return retval; if (get_offset (k1) < get_offset (k2)) return -1; if (get_offset (k1) > get_offset (k2)) return 1; /* this part is needed only when tail conversion is in progress */ if (get_type (k1) < get_type (k2)) return -1; if (get_type (k1) > get_type (k2)) return 1; return 0; } /************************************************************************** * Binary search toolkit function * * Search for an item in the array by the item key * * Returns: 1 if found, 0 if not found; * * *p_n_pos = number of the searched element if found, else the * * number of the first element that is larger than p_v_key. * **************************************************************************/ /* For those not familiar with binary search: n_lbound is the leftmost item that it could be, n_rbound the rightmost item that it could be. We examine the item halfway between n_lbound and n_rbound, and that tells us either that we can increase n_lbound, or decrease n_rbound, or that we have found it, or if n_lbound <= n_rbound that there are no possible items, and we have not found it. With each examination we cut the number of possible items it could be by one more than half rounded down, or we find it. */ inline int bin_search ( void * p_v_key, /* Key to search for. */ void * p_v_base, /* First item in the array. */ int p_n_num, /* Number of items in the array. */ int p_n_width, /* Item size in the array. searched. Lest the reader be confused, note that this is crafted as a general function, and when it is applied specifically to the array of item headers in a node, p_n_width is actually the item header size not the item size. */ int * p_n_pos /* Number of the searched for element. */ ) { int n_rbound, n_lbound, n_j; for ( n_j = ((n_rbound = p_n_num - 1) + (n_lbound = 0))/2; n_lbound <= n_rbound; n_j = (n_rbound + n_lbound)/2 ) switch( COMP_KEYS((struct key *)((char * )p_v_base + n_j * p_n_width), p_v_key) ) { case -1: n_lbound = n_j + 1; continue; case 1: n_rbound = n_j - 1; continue; case 0: *p_n_pos = n_j; return ITEM_FOUND; /* Key found in the array. */ } /* bin_search did not find given key, it returns position of key, that is minimal and greater than the given one. */ *p_n_pos = n_lbound; return ITEM_NOT_FOUND; } #ifdef CONFIG_REISERFS_CHECK extern struct tree_balance * cur_tb; extern struct tree_balance init_tb; extern int init_item_pos, init_pos_in_item, init_mode; #endif /* Minimal possible key. It is never in the tree. */ struct key MIN_KEY = {0, 0, {{0, 0},}}; /* Maximal possible key. It is never in the tree. */ struct key MAX_KEY = {0xffffffff, 0xffffffff, {{0xffffffff, 0xffffffff},}}; /* Get delimiting key of the buffer by looking for it in the buffers in the path, starting from the bottom of the path, and going upwards. We must check the path's validity at each step. If the key is not in the path, there is no delimiting key in the tree (buffer is first or last buffer in tree), and in this case we return a special key, either MIN_KEY or MAX_KEY. */ inline struct key * get_lkey ( struct path * p_s_chk_path, struct super_block * p_s_sb ) { int n_position, n_path_offset = p_s_chk_path->path_length; struct buffer_head * p_s_parent; #ifdef CONFIG_REISERFS_CHECK if ( n_path_offset < FIRST_PATH_ELEMENT_OFFSET ) reiserfs_panic(p_s_sb,"PAP-5010: get_lkey: illegal offset in the path"); #endif /* While not higher in path than first element. */ while ( n_path_offset-- > FIRST_PATH_ELEMENT_OFFSET ) { #ifdef CONFIG_REISERFS_CHECK if ( ! buffer_uptodate(PATH_OFFSET_PBUFFER(p_s_chk_path, n_path_offset)) ) reiserfs_panic(p_s_sb, "PAP-5020: get_lkey: parent is not uptodate"); #endif /* Parent at the path is not in the tree now. */ if ( ! B_IS_IN_TREE(p_s_parent = PATH_OFFSET_PBUFFER(p_s_chk_path, n_path_offset)) ) return &MAX_KEY; /* Check whether position in the parent is correct. */ if ( (n_position = PATH_OFFSET_POSITION(p_s_chk_path, n_path_offset)) > B_NR_ITEMS(p_s_parent) ) return &MAX_KEY; /* Check whether parent at the path really points to the child. */ if ( B_N_CHILD_NUM(p_s_parent, n_position) != PATH_OFFSET_PBUFFER(p_s_chk_path, n_path_offset + 1)->b_blocknr ) return &MAX_KEY; /* Return delimiting key if position in the parent is not equal to zero. */ if ( n_position ) return B_N_PDELIM_KEY(p_s_parent, n_position - 1); } /* Return MIN_KEY if we are in the root of the buffer tree. */ if ( PATH_OFFSET_PBUFFER(p_s_chk_path, FIRST_PATH_ELEMENT_OFFSET)->b_blocknr == SB_ROOT_BLOCK (p_s_sb) ) return &MIN_KEY; return &MAX_KEY; } /* Get delimiting key of the buffer at the path and its right neighbor. */ inline struct key * get_rkey ( struct path * p_s_chk_path, struct super_block * p_s_sb ) { int n_position, n_path_offset = p_s_chk_path->path_length; struct buffer_head * p_s_parent; #ifdef CONFIG_REISERFS_CHECK if ( n_path_offset < FIRST_PATH_ELEMENT_OFFSET ) reiserfs_panic(p_s_sb,"PAP-5030: get_rkey: illegal offset in the path"); #endif while ( n_path_offset-- > FIRST_PATH_ELEMENT_OFFSET ) { #ifdef CONFIG_REISERFS_CHECK if ( ! buffer_uptodate(PATH_OFFSET_PBUFFER(p_s_chk_path, n_path_offset)) ) reiserfs_panic(p_s_sb, "PAP-5040: get_rkey: parent is not uptodate"); #endif /* Parent at the path is not in the tree now. */ if ( ! B_IS_IN_TREE(p_s_parent = PATH_OFFSET_PBUFFER(p_s_chk_path, n_path_offset)) ) return &MIN_KEY; /* Check whether position in the parrent is correct. */ if ( (n_position = PATH_OFFSET_POSITION(p_s_chk_path, n_path_offset)) > B_NR_ITEMS(p_s_parent) ) return &MIN_KEY; /* Check whether parent at the path really points to the child. */ if ( B_N_CHILD_NUM(p_s_parent, n_position) != PATH_OFFSET_PBUFFER(p_s_chk_path, n_path_offset + 1)->b_blocknr ) return &MIN_KEY; /* Return delimiting key if position in the parent is not the last one. */ if ( n_position != B_NR_ITEMS(p_s_parent) ) return B_N_PDELIM_KEY(p_s_parent, n_position); } /* Return MAX_KEY if we are in the root of the buffer tree. */ if ( PATH_OFFSET_PBUFFER(p_s_chk_path, FIRST_PATH_ELEMENT_OFFSET)->b_blocknr == SB_ROOT_BLOCK (p_s_sb) ) return &MAX_KEY; return &MIN_KEY; } /* Check whether a key is contained in the tree rooted from a buffer at a path. This works by looking at the left and right delimiting keys for the buffer in the last path_element in the path. These delimiting keys are stored at least one level above that buffer in the tree. If the buffer is the first or last node in the tree order then one of the delimiting keys may be absent, and in this case get_lkey and get_rkey return a special key which is MIN_KEY or MAX_KEY. */ static inline int key_in_buffer ( struct path * p_s_chk_path, /* Path which should be checked. */ struct key * p_s_key, /* Key which should be checked. */ struct super_block * p_s_sb /* Super block pointer. */ ) { #ifdef CONFIG_REISERFS_CHECK if ( ! p_s_key || p_s_chk_path->path_length < FIRST_PATH_ELEMENT_OFFSET || p_s_chk_path->path_length > MAX_HEIGHT ) reiserfs_panic(p_s_sb, "PAP-5050: key_in_buffer: pointer to the key(%p) is NULL or illegal path length(%d)", p_s_key, p_s_chk_path->path_length); if ( PATH_PLAST_BUFFER(p_s_chk_path)->b_dev == NODEV ) reiserfs_panic(p_s_sb, "PAP-5060: key_in_buffer: device must not be NODEV"); #endif if ( COMP_KEYS(get_lkey(p_s_chk_path, p_s_sb), p_s_key) == 1 ) return 0; if ( COMP_KEYS(p_s_key, get_rkey(p_s_chk_path, p_s_sb)) != -1 ) return 0; return 1; } /* Release all buffers in the path. */ void pathrelse (struct path * p_s_search_path) { int n_path_offset = p_s_search_path->path_length; #ifdef CONFIG_REISERFS_CHECK if ( n_path_offset < ILLEGAL_PATH_ELEMENT_OFFSET ) reiserfs_panic(NULL, "PAP-5090: pathrelse: illegal path offset"); #endif while ( n_path_offset > ILLEGAL_PATH_ELEMENT_OFFSET ) brelse(PATH_OFFSET_PBUFFER(p_s_search_path, n_path_offset--)); p_s_search_path->path_length = ILLEGAL_PATH_ELEMENT_OFFSET; } /************************************************************************** * Algorithm SearchByKey * * look for item in the Disk S+Tree by its key * * Input: p_s_sb - super block * * p_s_key - pointer to the key to search * * Output: true value - 1 - found, 0 - not found * * p_s_search_path - path from the root to the needed leaf * **************************************************************************/ /* This function fills up the path from the root to the leaf as it descends the tree looking for the key. It uses reiserfs_bread to try to find buffers in the cache given their block number. If it does not find them in the cache it reads them from disk. For each node search_by_key finds using reiserfs_bread it then uses bin_search to look through that node. bin_search will find the position of the block_number of the next node if it is looking through an internal node. If it is looking through a leaf node bin_search will find the position of the item which has key either equal to given key, or which is the maximal key less than the given key. search_by_key returns a path that must be checked for the correctness of the top of the path but need not be checked for the correctness of the bottom of the path */ int search_by_key( struct super_block * p_s_sb, /* Super block. */ struct key * p_s_key, /* Key to search. */ struct path * p_s_search_path,/* This structure was allocated and initialized by the calling function. It is filled up by this function. */ int * p_n_repeat, /* Whether schedule occured. */ int n_stop_level /* How far down the tree to search.*/ ) { dev_t n_dev = p_s_sb->s_dev; int n_repeat, n_block_number = SB_ROOT_BLOCK (p_s_sb), expected_level = SB_TREE_HEIGHT (p_s_sb), n_block_size = p_s_sb->s_blocksize; struct buffer_head * p_s_bh; struct path_element * p_s_last_element; int n_retval; int right_neighbor_of_leaf_node; #ifdef CONFIG_REISERFS_CHECK int n_repeat_counter = 0; #endif /* As we add each node to a path we increase its count. This means that we must be careful to release all nodes in a path before we either discard the path struct or re-use the path struct, as we do here. */ pathrelse (p_s_search_path); *p_n_repeat = CARRY_ON; /* With each iteration of this loop we search through the items in the current node, and calculate the next current node(next path element) for the next iteration of this loop.. */ while ( 1 ) { #ifdef CONFIG_REISERFS_CHECK if ( !(++n_repeat_counter % 50000) ) printk ("PAP-5100: search_by_key(pid %u): there were %d searches from the tree_root lokking for key %p\n", current->pid, n_repeat_counter, p_s_key); #endif /* prep path to have another element added to it. */ p_s_last_element = PATH_OFFSET_PELEMENT(p_s_search_path, ++p_s_search_path->path_length); expected_level --; n_repeat = CARRY_ON; /* Read the next tree node, and set the last element in the path to have a pointer to it. */ if ( ! (p_s_bh = p_s_last_element->pe_buffer = reiserfs_bread(n_dev, n_block_number, n_block_size, &n_repeat)) ) { p_s_search_path->path_length --; pathrelse(p_s_search_path); *p_n_repeat |= n_repeat; return IO_ERROR; } *p_n_repeat |= n_repeat; /* It is possible that schedule occured. We must check whether the key to search is still in the tree rooted from the current buffer. If not then repeat search from the root. */ if ( n_repeat != CARRY_ON && (!B_IS_IN_TREE (p_s_bh) || (! key_in_buffer(p_s_search_path, p_s_key, p_s_sb))) ) { pathrelse (p_s_search_path); /* Get the root block number so that we can repeat the search starting from the root. */ n_block_number = SB_ROOT_BLOCK (p_s_sb); expected_level = SB_TREE_HEIGHT (p_s_sb); right_neighbor_of_leaf_node = 0; /* repeat search from the root */ continue; } #ifdef CONFIG_REISERFS_CHECK if ( ! key_in_buffer(p_s_search_path, p_s_key, p_s_sb) ) reiserfs_panic(p_s_sb, "PAP-5130: search_by_key: key is not in the buffer"); if ( cur_tb ) { /* print_tb (init_mode, init_item_pos, init_pos_in_item, &init_tb, "5140");*/ reiserfs_panic(p_s_sb, "PAP-5140: search_by_key: schedule occurred in do_balance!"); } #endif // make sure, that the node contents look like a nod of // certain level if (!is_tree_node (p_s_bh, expected_level)) { print_block (stderr, 0, p_s_bh, 3, -1, -1); reiserfs_panic ("vs-5150: search_by_key: expeced level %d", expected_level); pathrelse (p_s_search_path); return IO_ERROR; } /* ok, we have acquired next formatted node in the tree */ n_retval = bin_search (p_s_key, B_N_PITEM_HEAD(p_s_bh, 0), B_NR_ITEMS(p_s_bh), is_leaf_node (p_s_bh) ? IH_SIZE : KEY_SIZE, &(p_s_last_element->pe_position)); if (node_level (p_s_bh) == n_stop_level) return n_retval; /* we are not in the stop level */ if (n_retval == ITEM_FOUND) /* item has been found, so we choose the pointer which is to the right of the found one */ p_s_last_element->pe_position++; /* if item was not found we choose the position which is to the left of the found item. This requires no code, bin_search did it already.*/ /* So we have chosen a position in the current node which is an internal node. Now we calculate child block number by position in the node. */ n_block_number = B_N_CHILD_NUM(p_s_bh, p_s_last_element->pe_position); } } int bin_search_in_dir_item (struct item_head * ih, struct reiserfs_de_head * deh, struct key * key, int * pos_in_item) { int rbound, lbound, j; lbound = 0; rbound = ih_entry_count (ih) - 1; for (j = (rbound + lbound) / 2; lbound <= rbound; j = (rbound + lbound) / 2) { if (get_offset (key) < deh_offset (deh + j)) { rbound = j - 1; continue; } if (get_offset (key) > deh_offset (deh + j)) { lbound = j + 1; continue; } /* key found */ *pos_in_item = j; return POSITION_FOUND; } *pos_in_item = lbound; return POSITION_NOT_FOUND; } reiserfsprogs-3.x.0j/reiserfscore/node_formats.c0000644000076400001440000005441707261102557015711 /* * Copyrright 2000 by Hans Reiser, licensing governed by reiserfs/README */ #include "includes.h" /* this only checks that the node looks like a correct leaf. Item internals are not checked */ static int is_correct_leaf (char * buf, int blocksize) { struct block_head * blkh; struct item_head * ih; int used_space; int prev_location; int i; int nr; blkh = (struct block_head *)buf; if (!is_leaf_block_head (buf)) return 0; nr = le16_to_cpu (blkh->blk_nr_item); if (nr < 1 || nr > ((blocksize - BLKH_SIZE) / (IH_SIZE + MIN_ITEM_LEN))) /* item number is too big or too small */ return 0; ih = (struct item_head *)(buf + BLKH_SIZE) + nr - 1; used_space = BLKH_SIZE + IH_SIZE * nr + (blocksize - ih_location (ih)); if (used_space != blocksize - le16_to_cpu (blkh->blk_free_space)) /* free space does not match to calculated amount of use space */ return 0; // FIXME: it is_leaf will hit performance too much - we may have // return 1 here /* check tables of item heads */ ih = (struct item_head *)(buf + BLKH_SIZE); prev_location = blocksize; for (i = 0; i < nr; i ++, ih ++) { /* items of length are allowed - they may exist for short time during balancing */ if (ih_location (ih) > blocksize || ih_location (ih) < IH_SIZE * nr) return 0; if (/*ih_item_len (ih) < 1 ||*/ ih_item_len (ih) > MAX_ITEM_LEN (blocksize)) return 0; if (prev_location - ih_location (ih) != ih_item_len (ih)) return 0; prev_location = ih_location (ih); } // one may imagine much more checks return 1; } /* returns 1 if buf looks like an internal node, 0 otherwise */ static int is_correct_internal (char * buf, int blocksize) { struct block_head * blkh; int nr; int used_space; blkh = (struct block_head *)buf; if (!is_internal_block_head (buf)) return 0; nr = le16_to_cpu (blkh->blk_nr_item); if (nr > (blocksize - BLKH_SIZE - DC_SIZE) / (KEY_SIZE + DC_SIZE)) /* for internal which is not root we might check min number of keys */ return 0; used_space = BLKH_SIZE + KEY_SIZE * nr + DC_SIZE * (nr + 1); if (used_space != blocksize - le16_to_cpu (blkh->blk_free_space)) return 0; // one may imagine much more checks return 1; } // make sure that bh contains formatted node of reiserfs tree of // 'level'-th level int is_tree_node (struct buffer_head * bh, int level) { if (B_LEVEL (bh) != level) return 0; if (is_leaf_node (bh)) return is_correct_leaf (bh->b_data, bh->b_size); return is_correct_internal (bh->b_data, bh->b_size); } static int is_desc_block (struct reiserfs_journal_desc * desc) { if (!memcmp(desc->j_magic, JOURNAL_DESC_MAGIC, 8) && le32_to_cpu (desc->j_len) > 0) return 1; return 0; } int is_reiserfs_magic_string (struct reiserfs_super_block * rs) { return (!strncmp (rs->s_v1.s_magic, REISERFS_SUPER_MAGIC_STRING, strlen ( REISERFS_SUPER_MAGIC_STRING))); } int is_reiser2fs_magic_string (struct reiserfs_super_block * rs) { return (!strncmp (rs->s_v1.s_magic, REISER2FS_SUPER_MAGIC_STRING, strlen ( REISER2FS_SUPER_MAGIC_STRING))); } /* this one had signature in different place of the super_block structure */ int is_prejournaled_reiserfs (struct reiserfs_super_block * rs) { return (!strncmp((char*)rs + REISERFS_SUPER_MAGIC_STRING_OFFSET_NJ, REISERFS_SUPER_MAGIC_STRING, strlen(REISERFS_SUPER_MAGIC_STRING))); } /* compares description block with commit block. returns 1 if they differ, 0 if they are the same */ int does_desc_match_commit (struct reiserfs_journal_desc *desc, struct reiserfs_journal_commit *commit) { if (commit->j_trans_id != desc->j_trans_id || commit->j_len != desc->j_len || commit->j_len > JOURNAL_TRANS_MAX || commit->j_len <= 0) { return 1 ; } return 0 ; } /* returns code of reiserfs metadata block (leaf, internal, super block, journal descriptor), unformatted */ int who_is_this (char * buf, int blocksize) { if (is_correct_leaf (buf, blocksize)) /* block head and item head array seem matching (node level, free space, item number, item locations and length) */ return THE_LEAF; if (is_correct_internal (buf, blocksize)) return THE_INTERNAL; /* super block? */ if (is_reiser2fs_magic_string ((void *)buf) || is_reiserfs_magic_string ((void *)buf) || is_prejournaled_reiserfs ((void *)buf)) return THE_SUPER; /* journal descriptor block? */ if (is_desc_block ((void *)buf)) return THE_JDESC; /* contents of buf does not look like reiserfs metadata. Bitmaps are possible here */ return THE_UNKNOWN; } int block_of_journal (reiserfs_filsys_t fs, unsigned long block) { if (block >= SB_JOURNAL_BLOCK (fs) && block <= SB_JOURNAL_BLOCK (fs) + JOURNAL_BLOCK_COUNT) return 1; return 0; } int block_of_bitmap (reiserfs_filsys_t fs, unsigned long block) { if (spread_bitmaps (fs)) { if (!(block % (fs->s_blocksize * 8))) /* bitmap block */ return 1; return block == 17; } else { /* bitmap in */ if (block > 2 && block < 3 + SB_BMAP_NR (fs)) return 1; return 0; } #if 0 int i; int bmap_nr; bmap_nr = SB_BMAP_NR (fs); for (i = 0; i < bmap_nr; i ++) if (block == SB_AP_BITMAP (fs)[i]->b_blocknr) return 1; #endif return 0; } /* check whether 'block' can be pointed to by an indirect item */ int not_data_block (reiserfs_filsys_t fs, unsigned long block) { if (block_of_bitmap (fs, block)) /* it is one of bitmap blocks */ return 1; if (block > 32768) return 0; if (block_of_journal (fs, block)) /* block of journal area */ return 1; if (block <= fs->s_sbh->b_blocknr) /* either super block or a block from skipped area at the beginning of filesystem */ return 1; return 0; } /* check whether 'block' can be logged */ int not_journalable (reiserfs_filsys_t fs, unsigned long block) { /* we should not update SB with journal copy during fsck */ if (block < fs->s_sbh->b_blocknr) return 1; if (block_of_journal (fs, block)) return 1; if (block >= SB_BLOCK_COUNT (fs)) return 1; return 0; } // in reiserfs version 0 (undistributed bitmap) // FIXME: what if number of bitmaps is 15? int get_journal_old_start_must (struct reiserfs_super_block * rs) { return 3 + rs_bmap_nr (rs); } // in reiserfs version 1 (distributed bitmap) journal starts at 18-th // int get_journal_start_must (int blocksize) { return (REISERFS_DISK_OFFSET_IN_BYTES / blocksize) + 2; } int get_bmap_num (struct super_block * s) { return ((is_prejournaled_reiserfs (s->s_rs)) ? (((struct reiserfs_super_block_v0 *)s->s_rs)->s_bmap_nr) : SB_BMAP_NR (s)); } int get_block_count (struct super_block * s) { return ((is_prejournaled_reiserfs (s->s_rs)) ? (((struct reiserfs_super_block_v0 *)s->s_rs)->s_block_count) : SB_BLOCK_COUNT (s)); } int get_root_block (struct super_block * s) { return ((is_prejournaled_reiserfs (s->s_rs)) ? (((struct reiserfs_super_block_v0 *)s->s_rs)->s_root_block) : SB_ROOT_BLOCK (s)); } int journal_size (struct super_block * s) { return JOURNAL_BLOCK_COUNT; } int check_item_f (reiserfs_filsys_t fs, struct item_head * ih, char * item); /* make sure that key format written in item_head matches to key format defined looking at the key */ static int is_key_correct (struct item_head * ih) { if (is_stat_data_ih (ih)) { /* stat data key looks identical in both formats */ if (ih_item_len (ih) == SD_SIZE && ih_key_format (ih) == KEY_FORMAT_2) { /*printf ("new stat data\n");*/ return 1; } if (ih_item_len (ih) == SD_V1_SIZE && ih_key_format (ih) == KEY_FORMAT_1) { /*printf ("old stat data\n");*/ return 1; } return 0; } if (ih_key_format (ih) == key_format (&ih->ih_key)) return 1; return 0; } /* check stat data item length, ih_free_space, mode */ static int is_bad_sd (reiserfs_filsys_t fs, struct item_head * ih, char * item) { mode_t mode; if (ih_entry_count (ih) != 0xffff) return 1; if (ih_key_format (ih) == KEY_FORMAT_1) { struct stat_data_v1 * sd = (struct stat_data_v1 *)item; if (ih_item_len (ih) != SD_V1_SIZE) /* old stat data must be 32 bytes long */ return 1; mode = le16_to_cpu (sd->sd_mode); } else if (ih_key_format (ih) == KEY_FORMAT_2) { struct stat_data * sd = (struct stat_data *)item; if (ih_item_len (ih) != SD_SIZE) /* new stat data must be 44 bytes long */ return 1; mode = le16_to_cpu (sd->sd_mode); } else return 1; if (!S_ISDIR (mode) && !S_ISREG (mode) && !S_ISCHR (mode) && !S_ISBLK (mode) && !S_ISLNK (mode) && !S_ISFIFO (mode) && !S_ISSOCK (mode)) return 1; return 0; } /* symlinks created by 3.6.x have direct items with ih_free_space == 0 */ static int is_bad_direct (reiserfs_filsys_t fs, struct item_head * ih, char * item) { if (ih_entry_count (ih) != 0xffff && ih_entry_count (ih) != 0) return 1; return 0; } /* check item length, ih_free_space for pure 3.5 format, unformatted node pointers */ static int is_bad_indirect (reiserfs_filsys_t fs, struct item_head * ih, char * item, check_unfm_func_t check_unfm_func) { int i; __u32 * ind = (__u32 *)item; if (ih_item_len (ih) % UNFM_P_SIZE) return 1; for (i = 0; i < I_UNFM_NUM (ih); i ++) { if (!ind [i]) continue; if (check_unfm_func && check_unfm_func (fs, ind [i])) return 1; } if (fs->s_version == REISERFS_VERSION_1) { /* check ih_free_space for 3.5 format only */ if (ih_free_space (ih) > fs->s_blocksize - 1) return 1; } return 0; } static const struct { hashf_t func; char * name; } hashes[] = {{0, "not set"}, {keyed_hash, "\"tea\""}, {yura_hash, "\"rupasov\""}, {r5_hash, "\"r5\""}}; #define HASH_AMOUNT (sizeof (hashes) / sizeof (hashes [0])) int known_hashes (void) { return HASH_AMOUNT; } #define good_name(hashfn,name,namelen,deh_offset) \ (GET_HASH_VALUE ((hashfn) (name, namelen)) == GET_HASH_VALUE (deh_offset)) /* this also sets hash function */ int is_properly_hashed (reiserfs_filsys_t fs, char * name, int namelen, __u32 offset) { int i; if (namelen == 1 && name[0] == '.') { if (offset == DOT_OFFSET) return 1; return 0; } if (namelen == 2 && name[0] == '.' && name[1] == '.') { if (offset == DOT_DOT_OFFSET) return 1; return 0; } if (hash_func_is_unknown (fs)) { /* try to find what hash function the name is sorted with */ for (i = 1; i < HASH_AMOUNT; i ++) { if (good_name (hashes [i].func, name, namelen, offset)) { if (!hash_func_is_unknown (fs)) { /* two or more hash functions give the same value for this name */ fprintf (stderr, "Detecting hash code: could not detect hash with name \"%.*s\"\n", namelen, name); reiserfs_hash (fs) = 0; return 1; } /* set hash function */ reiserfs_hash(fs) = hashes [i].func; } } } if (good_name (reiserfs_hash(fs), name, namelen, offset)) return 1; #if 0 fprintf (stderr, "is_properly_hashed: namelen %d, name \"%s\", offset %u, hash %u\n", namelen, name_from_entry (name, namelen), GET_HASH_VALUE (offset), GET_HASH_VALUE (reiserfs_hash(fs) (name, namelen))); /* we could also check whether more than one hash function match on the name */ for (i = 1; i < sizeof (hashes) / sizeof (hashes [0]); i ++) { if (i == g_real_hash) continue; if (good_name (hashes[i], name, namelen, deh_offset)) { die ("bad_hash: at least two hashes got screwed up with this name: \"%s\"", bad_name (name, namelen)); } } #endif return 0; } int find_hash_in_use (char * name, int namelen, __u32 hash_value_masked, int code_to_try_first) { int i; if (code_to_try_first) { if (hash_value_masked == GET_HASH_VALUE (hashes [code_to_try_first].func (name, namelen))) return code_to_try_first; } for (i = 1; i < HASH_AMOUNT; i ++) { if (i == code_to_try_first) continue; if (hash_value_masked == GET_HASH_VALUE (hashes [i].func (name, namelen))) return i; } /* not matching hash found */ return UNSET_HASH; } char * code2name (int code) { if (code >= HASH_AMOUNT) code = 0; return hashes [code].name; } int func2code (hashf_t func) { int i; for (i = 0; i < HASH_AMOUNT; i ++) if (func == hashes [i].func) return i; reiserfs_panic ("func2code: no hashes matches this function\n"); return 0; } hashf_t code2func (int code) { if (code >= HASH_AMOUNT) { reiserfs_warning (stderr, "code2func: wrong hash code %d.\n" "Using default %s hash function\n", code, code2name (DEFAULT_HASH)); code = DEFAULT_HASH; } return hashes [code].func; } int dir_entry_bad_location (struct reiserfs_de_head * deh, struct item_head * ih, int first) { if (deh_location (deh) < DEH_SIZE * ih_entry_count (ih)) return 1; if (deh_location (deh) >= ih_item_len (ih)) return 1; if (!first && deh_location (deh) >= deh_location (deh - 1)) return 1; return 0; } /* the only corruption which is not considered fatal - is hash mismatching. If bad_dir is set - directory item having such names is considered bad */ static int is_bad_directory (reiserfs_filsys_t fs, struct item_head * ih, char * item, int bad_dir) { int i; int namelen; struct reiserfs_de_head * deh = (struct reiserfs_de_head *)item; __u32 prev_offset = 0; __u16 prev_location = ih_item_len (ih); for (i = 0; i < ih_entry_count (ih); i ++, deh ++) { if (deh_location (deh) >= prev_location) return 1; prev_location = deh_location (deh); namelen = name_length (ih, deh, i); if (namelen > REISERFS_MAX_NAME_LEN (fs->s_blocksize)) { return 1; } if (deh_offset (deh) <= prev_offset) return 1; prev_offset = deh_offset (deh); /* check hash value */ if (!is_properly_hashed (fs, item + prev_location, namelen, prev_offset)) { if (bad_dir) /* make is_bad_leaf to not insert whole leaf. Node will be marked not-insertable and put into tree item by item in pass 2 */ return 1; } } return 0; } /* used by debugreisrefs -p only yet */ #if 1 int is_it_bad_item (reiserfs_filsys_t fs, struct item_head * ih, char * item, check_unfm_func_t check_unfm, int bad_dir) { int retval; if (!is_key_correct (ih)) { reiserfs_warning (stderr, "is_key_correct %H\n", ih); return 1; } if (is_stat_data_ih (ih)) { retval = is_bad_sd (fs, ih, item); /* if (retval) reiserfs_warning (stderr, "is_bad_sd %H\n", ih);*/ return retval; } if (is_direntry_ih (ih)) { retval = is_bad_directory (fs, ih, item, bad_dir); /* if (retval) reiserfs_warning (stderr, "is_bad_directory %H\n", ih);*/ return retval; } if (is_indirect_ih (ih)) { retval = is_bad_indirect (fs, ih, item, check_unfm); /* if (retval) reiserfs_warning (stderr, "is_bad_indirect %H\n", ih);*/ return retval; } if (is_direct_ih (ih)) { retval = is_bad_direct (fs, ih, item); /* if (retval) reiserfs_warning (stderr, "is_bad_direct %H\n", ih);*/ return retval; } return 1; } #endif /* prepare new or old stat data for the new directory */ void make_dir_stat_data (int blocksize, int key_format, __u32 dirid, __u32 objectid, struct item_head * ih, void * sd) { memset (ih, 0, IH_SIZE); ih->ih_key.k_dir_id = cpu_to_le32 (dirid); ih->ih_key.k_objectid = cpu_to_le32 (objectid); set_offset (key_format, &ih->ih_key, SD_OFFSET); set_type (key_format, &ih->ih_key, TYPE_STAT_DATA); set_key_format (ih, key_format); set_free_space (ih, MAX_US_INT); if (key_format == KEY_FORMAT_2) { struct stat_data *sd_v2 = (struct stat_data *)sd; set_ih_item_len (ih, SD_SIZE); sd_v2->sd_mode = cpu_to_le16 (S_IFDIR + 0755); sd_v2->sd_nlink = cpu_to_le32 (2); sd_v2->sd_uid = 0; sd_v2->sd_gid = 0; sd_v2->sd_size = cpu_to_le64 (EMPTY_DIR_SIZE); sd_v2->sd_atime = sd_v2->sd_ctime = sd_v2->sd_mtime = cpu_to_le32 (time (NULL)); sd_v2->u.sd_rdev = 0; sd_v2->sd_blocks = cpu_to_le32 (dir_size2st_blocks (blocksize, EMPTY_DIR_SIZE)); }else{ struct stat_data_v1 *sd_v1 = (struct stat_data_v1 *)sd; set_ih_item_len (ih, SD_V1_SIZE); sd_v1->sd_mode = cpu_to_le16 (S_IFDIR + 0755); sd_v1->sd_nlink = cpu_to_le16 (2); sd_v1->sd_uid = 0; sd_v1->sd_gid = 0; sd_v1->sd_size = cpu_to_le32 (EMPTY_DIR_SIZE_V1); sd_v1->sd_atime = sd_v1->sd_ctime = sd_v1->sd_mtime = cpu_to_le32 (time (NULL)); sd_v1->u.sd_blocks = cpu_to_le32 (dir_size2st_blocks (blocksize, EMPTY_DIR_SIZE_V1)); sd_v1->sd_first_direct_byte = cpu_to_le32 (NO_BYTES_IN_DIRECT_ITEM); } } static void _empty_dir_item (int format, char * body, __u32 dirid, __u32 objid, __u32 par_dirid, __u32 par_objid) { struct reiserfs_de_head * deh; memset (body, 0, (format == KEY_FORMAT_2 ? EMPTY_DIR_SIZE : EMPTY_DIR_SIZE_V1)); deh = (struct reiserfs_de_head *)body; /* direntry header of "." */ deh[0].deh_offset = cpu_to_le32 (DOT_OFFSET); deh[0].deh_dir_id = cpu_to_le32 (dirid); deh[0].deh_objectid = cpu_to_le32 (objid); deh[0].deh_state = 0; set_bit (DEH_Visible, &(deh[0].deh_state)); /* direntry header of ".." */ deh[1].deh_offset = cpu_to_le32 (DOT_DOT_OFFSET); /* key of ".." for the root directory */ deh[1].deh_dir_id = cpu_to_le32 (par_dirid); deh[1].deh_objectid = cpu_to_le32 (par_objid); deh[1].deh_state = 0; set_bit (DEH_Visible, &(deh[1].deh_state)); if (format == KEY_FORMAT_2) { deh[0].deh_location = cpu_to_le16 (EMPTY_DIR_SIZE - ROUND_UP (strlen ("."))); deh[1].deh_location = cpu_to_le16 (deh_location (&deh[0]) - ROUND_UP (strlen (".."))); } else { deh[0].deh_location = cpu_to_le16 (EMPTY_DIR_SIZE_V1 - strlen (".")); deh[1].deh_location = cpu_to_le16 (deh_location (&deh[0]) - strlen ("..")); } /* copy ".." and "." */ memcpy (body + deh_location (&deh[0]), ".", 1); memcpy (body + deh_location (&deh[1]), "..", 2); } void make_empty_dir_item_v1 (char * body, __u32 dirid, __u32 objid, __u32 par_dirid, __u32 par_objid) { _empty_dir_item (KEY_FORMAT_1, body, dirid, objid, par_dirid, par_objid); } void make_empty_dir_item (char * body, __u32 dirid, __u32 objid, __u32 par_dirid, __u32 par_objid) { _empty_dir_item (KEY_FORMAT_2, body, dirid, objid, par_dirid, par_objid); } /* for every item call common action and an action corresponding to item type */ void for_every_item (struct buffer_head * bh, item_head_action_t action, item_action_t * actions) { int i; struct item_head * ih; item_action_t iaction; ih = B_N_PITEM_HEAD (bh, 0); for (i = 0; i < node_item_number (bh); i ++, ih ++) { if (action) action (ih); iaction = actions[get_type (&ih->ih_key)]; if (iaction) iaction (bh, ih); } } /* old keys (on i386) have k_offset_v2.k_type == 15 (direct and indirect) or == 0 (dir items and stat data) */ /* */ int key_format (const struct key * key) { int type; type = le16_to_cpu (key->u.k_offset_v2.k_type); if (type == 0 || type == 15) return KEY_FORMAT_1; return KEY_FORMAT_2; } loff_t get_offset (const struct key * key) { if (key_format (key) == KEY_FORMAT_1) return le32_to_cpu (key->u.k_offset_v1.k_offset); return le64_to_cpu (key->u.k_offset_v2.k_offset); } int uniqueness2type (__u32 uniqueness) { switch (uniqueness) { case V1_SD_UNIQUENESS: return TYPE_STAT_DATA; case V1_INDIRECT_UNIQUENESS: return TYPE_INDIRECT; case V1_DIRECT_UNIQUENESS: return TYPE_DIRECT; case V1_DIRENTRY_UNIQUENESS: return TYPE_DIRENTRY; } return TYPE_UNKNOWN; } __u32 type2uniqueness (int type) { switch (type) { case TYPE_STAT_DATA: return V1_SD_UNIQUENESS; case TYPE_INDIRECT: return V1_INDIRECT_UNIQUENESS; case TYPE_DIRECT: return V1_DIRECT_UNIQUENESS; case TYPE_DIRENTRY: return V1_DIRENTRY_UNIQUENESS; } return V1_UNKNOWN_UNIQUENESS; } int get_type (const struct key * key) { if (key_format (key) == KEY_FORMAT_1) return uniqueness2type (le32_to_cpu (key->u.k_offset_v1.k_uniqueness)); return le16_to_cpu (key->u.k_offset_v2.k_type); } char * key_of_what (const struct key * key) { switch (get_type (key)) { case TYPE_STAT_DATA: return "SD"; case TYPE_INDIRECT: return "IND"; case TYPE_DIRECT: return "DRCT"; case TYPE_DIRENTRY: return "DIR"; default: return "???"; } } int type_unknown (struct key * key) { int type = get_type (key); switch (type) { case TYPE_STAT_DATA: case TYPE_INDIRECT: case TYPE_DIRECT: case TYPE_DIRENTRY: return 0; default: break; } return 1; } // this sets key format as well as type of item key belongs to // void set_type (int format, struct key * key, int type) { if (format == KEY_FORMAT_1) key->u.k_offset_v1.k_uniqueness = cpu_to_le32 (type2uniqueness (type)); else key->u.k_offset_v2.k_type = cpu_to_le16 (type); } // void set_offset (int format, struct key * key, loff_t offset) { if (format == KEY_FORMAT_1) key->u.k_offset_v1.k_offset = cpu_to_le32 (offset); else key->u.k_offset_v2.k_offset = cpu_to_le64 (offset); } void set_type_and_offset (int format, struct key * key, loff_t offset, int type) { set_type (format, key, type); set_offset (format, key, offset); } /* length of the directory entry in directory item. This define calculates length of i-th directory entry using directory entry locations from dir entry head. When it calculates length of 0-th directory entry, it uses length of whole item in place of entry location of the non-existent following entry in the calculation. See picture above.*/ // NOTE: this is not name length. This is length of whole entry int entry_length (struct item_head * ih, struct reiserfs_de_head * deh, int pos_in_item) { if (pos_in_item) return (deh_location (deh - 1) - deh_location (deh)); return (ih_item_len (ih) - deh_location (deh)); } char * name_in_entry (struct reiserfs_de_head * deh, int pos_in_item) { return ((char *)(deh - pos_in_item) + deh_location(deh)); } int name_length (struct item_head * ih, struct reiserfs_de_head * deh, int pos_in_item) { int len; char * name; len = entry_length (ih, deh, pos_in_item); name = name_in_entry (deh, pos_in_item); // name might be padded with 0s while (!name [len - 1]) len --; return len; } reiserfsprogs-3.x.0j/reiserfscore/reiserfslib.c0000644000076400001440000004766507261210132015536 /* * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README */ #include "includes.h" /* fixme: this assumes that journal start and journal size are set correctly */ static void check_first_bitmap (reiserfs_filsys_t fs, char * bitmap) { int i; int bad; bad = 0; for (i = 0; i < rs_journal_start (fs->s_rs) + rs_journal_size (fs->s_rs) + 1; i ++) { if (!test_bit (i, bitmap)) { bad = 1; /*reiserfs_warning ("block %d is marked free in the first bitmap, fixed\n", i);*/ /*set_bit (i, bitmap);*/ } } if (bad) reiserfs_warning (stderr, "reiserfs_open: first bitmap looks corrupted\n"); } /* read bitmap blocks */ void reiserfs_read_bitmap_blocks (reiserfs_filsys_t fs) { struct reiserfs_super_block * rs = fs->s_rs; struct buffer_head * bh = SB_BUFFER_WITH_SB(fs); int fd = fs->s_dev; unsigned long block; int i; /* read bitmaps, and correct a bit if necessary */ SB_AP_BITMAP (fs) = getmem (sizeof (void *) * rs_bmap_nr (rs)); for (i = 0, block = bh->b_blocknr + 1; i < rs_bmap_nr (rs); i ++) { SB_AP_BITMAP (fs)[i] = bread (fd, block, fs->s_blocksize); if (!SB_AP_BITMAP (fs)[i]) { reiserfs_warning (stderr, "reiserfs_open: bread failed reading bitmap #%d (%lu)\n", i, block); SB_AP_BITMAP (fs)[i] = getblk (fd, block, fs->s_blocksize); memset (SB_AP_BITMAP (fs)[i]->b_data, 0xff, fs->s_blocksize); set_bit (BH_Uptodate, &SB_AP_BITMAP (fs)[i]->b_state); } /* all bitmaps have to have itself marked used on it */ if (bh->b_blocknr == 16) { if (!test_bit (block % (fs->s_blocksize * 8), SB_AP_BITMAP (fs)[i]->b_data)) { reiserfs_warning (stderr, "reiserfs_open: bitmap %d was marked free\n", i); /*set_bit (block % (fs->s_blocksize * 8), SB_AP_BITMAP (fs)[i]->b_data);*/ } } else { /* bitmap not spread over partition: fixme: does not work when number of bitmaps => 32768 */ if (!test_bit (block, SB_AP_BITMAP (fs)[0]->b_data)) { reiserfs_warning (stderr, "reiserfs_open: bitmap %d was marked free\n", i); /*set_bit (block, SB_AP_BITMAP (fs)[0]->b_data);*/ } } if (i == 0) { /* first bitmap has to have marked used super block and journal areas */ check_first_bitmap (fs, SB_AP_BITMAP (fs)[i]->b_data); } block = (bh->b_blocknr == 16 ? ((i + 1) * fs->s_blocksize * 8) : (block + 1)); } } void reiserfs_free_bitmap_blocks (reiserfs_filsys_t fs) { int i; /* release bitmaps if they were read */ if (SB_AP_BITMAP (fs)) { for (i = 0; i < SB_BMAP_NR (fs); i ++) brelse (SB_AP_BITMAP (fs) [i]); freemem (SB_AP_BITMAP (fs)); } } /* read super block and bitmaps. fixme: only 4k blocks, pre-journaled format is refused */ reiserfs_filsys_t reiserfs_open (char * filename, int flags, int *error, void * vp) { reiserfs_filsys_t fs; struct buffer_head * bh; struct reiserfs_super_block * rs; int fd, i; fd = open (filename, flags | O_LARGEFILE); if (fd == -1) { if (error) *error = errno; return 0; } fs = getmem (sizeof (*fs)); fs->s_dev = fd; fs->s_vp = vp; asprintf (&fs->file_name, "%s", filename); /* reiserfs super block is either in 16-th or in 2-nd 4k block of the device */ for (i = 16; i > 0; i -= 14) { bh = bread (fd, i, 4096); if (!bh) { reiserfs_warning (stderr, "reiserfs_open: bread failed reading block %d\n", i); } else { rs = (struct reiserfs_super_block *)bh->b_data; if (is_reiser2fs_magic_string (rs) || is_reiserfs_magic_string (rs)) goto found; /* reiserfs signature is not found at the i-th 4k block */ brelse (bh); } } reiserfs_warning (stderr, "reiserfs_open: neither new nor old reiserfs format " "found on %s\n", filename); if (error) *error = 0; return fs; found: /* fixme: we could make some check to make sure that super block looks correctly */ fs->s_version = is_reiser2fs_magic_string (rs) ? REISERFS_VERSION_2 : REISERFS_VERSION_1; fs->s_blocksize = rs_blocksize (rs); fs->s_hash_function = code2func (rs_hash (rs)); SB_BUFFER_WITH_SB (fs) = bh; fs->s_rs = rs; fs->s_flags = flags; /* O_RDONLY or O_RDWR */ fs->s_vp = vp; reiserfs_read_bitmap_blocks(fs); return fs; } int no_reiserfs_found (reiserfs_filsys_t fs) { return (fs->s_blocksize == 0) ? 1 : 0; } int new_format (reiserfs_filsys_t fs) { return fs->s_sbh->b_blocknr != 2; } int spread_bitmaps (reiserfs_filsys_t fs) { return fs->s_sbh->b_blocknr != 2; } void reiserfs_reopen (reiserfs_filsys_t fs, int flag) { close (fs->s_dev); fs->s_dev = open (fs->file_name, flag | O_LARGEFILE); if (fs->s_dev == -1) die ("reiserfs_reopen: could not reopen device: %m"); } int filesystem_dirty (reiserfs_filsys_t fs) { return fs->s_dirt; } void mark_filesystem_dirty (reiserfs_filsys_t fs) { fs->s_dirt = 1; } /* flush all changes made on a filesystem */ void reiserfs_flush (reiserfs_filsys_t fs) { flush_buffers (); } /* free all memory involved into manipulating with filesystem */ void reiserfs_free (reiserfs_filsys_t fs) { reiserfs_free_bitmap_blocks(fs); /* release super block and memory used by filesystem handler */ brelse (SB_BUFFER_WITH_SB (fs)); free_buffers (); free (fs->file_name); freemem (fs); } void reiserfs_close (reiserfs_filsys_t fs) { reiserfs_flush (fs); reiserfs_free (fs); } int reiserfs_new_blocknrs (reiserfs_filsys_t fs, unsigned long * free_blocknrs, unsigned long start, int amount_needed) { if (fs->block_allocator) return fs->block_allocator (fs, free_blocknrs, start, amount_needed); die ("block allocator is not defined\n"); return 0; } int reiserfs_free_block (reiserfs_filsys_t fs, unsigned long block) { if (fs->block_deallocator) return fs->block_deallocator (fs, block); die ("block allocator is not defined\n"); return 0; } typedef int (comp_function_t) (void * key1, void * key2); inline int _bin_search (void * key, void * base, int num, int width, __u32 *ppos, comp_function_t comp_func) { int rbound, lbound, j; if (num == 0) { /* objectid map may be 0 elements long */ *ppos = 0; return ITEM_NOT_FOUND; } lbound = 0; rbound = num - 1; for (j = (rbound + lbound) / 2; lbound <= rbound; j = (rbound + lbound) / 2) { switch (comp_func ((void *)((char *)base + j * width), key ) ) { case -1:/* second is greater */ lbound = j + 1; continue; case 1: /* first is greater */ if (j == 0) { *ppos = lbound; return ITEM_NOT_FOUND; } rbound = j - 1; continue; case 0: *ppos = j; return ITEM_FOUND; } } *ppos = lbound; return ITEM_NOT_FOUND; } #if 0 static inline int _bin_search (void * key, void * base, int num, int width, __u32 *ppos) { __u32 rbound, lbound, j; lbound = 0; rbound = num - 1; for (j = (rbound + lbound) / 2; lbound <= rbound; j = (rbound + lbound) / 2) { switch (comp_keys ((void *)((char *)base + j * width), key)) { case -1:/* second is greater */ lbound = j + 1; continue; case 1: /* first is greater */ if (j == 0) { *ppos = lbound; return ITEM_NOT_FOUND; } rbound = j - 1; continue; case 0: *ppos = j; return ITEM_FOUND; } } *ppos = lbound; return ITEM_NOT_FOUND; } #endif static int _search_by_key (reiserfs_filsys_t fs, struct key * key, struct path * path) { struct buffer_head * bh; unsigned long block = SB_ROOT_BLOCK (fs); struct path_element * curr; int retval; path->path_length = ILLEGAL_PATH_ELEMENT_OFFSET; while (1) { curr = PATH_OFFSET_PELEMENT (path, ++ path->path_length); bh = curr->pe_buffer = bread (fs->s_dev, block, fs->s_blocksize); if (bh == 0) { path->path_length --; pathrelse (path); return ITEM_NOT_FOUND; } retval = _bin_search (key, B_N_PKEY (bh, 0), B_NR_ITEMS (bh), is_leaf_node (bh) ? IH_SIZE : KEY_SIZE, &(curr->pe_position), comp_keys); if (retval == ITEM_FOUND) { /* key found, return if this is leaf level */ if (is_leaf_node (bh)) { path->pos_in_item = 0; return ITEM_FOUND; } curr->pe_position ++; } else { /* key not found in the node */ if (is_leaf_node (bh)) return ITEM_NOT_FOUND; } block = B_N_CHILD_NUM (bh, curr->pe_position); } printf ("search_by_key: you can not get here\n"); return ITEM_NOT_FOUND; } static int comp_dir_entries (void * p1, void * p2) { __u32 deh_offset; __u32 * off1, * off2; off1 = p1; off2 = p2; deh_offset = le32_to_cpu (*off1); if (deh_offset < *off2) return -1; if (deh_offset > *off2) return 1; return 0; } static struct key * _get_rkey (struct path * path) { int pos, offset = path->path_length; struct buffer_head * bh; if (offset < FIRST_PATH_ELEMENT_OFFSET) die ("_get_rkey: illegal offset in the path (%d)", offset); while (offset-- > FIRST_PATH_ELEMENT_OFFSET) { if (! buffer_uptodate (PATH_OFFSET_PBUFFER (path, offset))) die ("_get_rkey: parent is not uptodate"); /* Parent at the path is not in the tree now. */ if (! B_IS_IN_TREE (bh = PATH_OFFSET_PBUFFER (path, offset))) die ("_get_rkey: buffer on the path is not in tree"); /* Check whether position in the parrent is correct. */ if ((pos = PATH_OFFSET_POSITION (path, offset)) > B_NR_ITEMS (bh)) die ("_get_rkey: invalid position (%d) in the path", pos); /* Check whether parent at the path really points to the child. */ if (B_N_CHILD_NUM (bh, pos) != PATH_OFFSET_PBUFFER (path, offset + 1)->b_blocknr) die ("_get_rkey: invalid block number (%d). Must be %d", B_N_CHILD_NUM (bh, pos), PATH_OFFSET_PBUFFER (path, offset + 1)->b_blocknr); /* Return delimiting key if position in the parent is not the last one. */ if (pos != B_NR_ITEMS (bh)) return B_N_PDELIM_KEY (bh, pos); } /* there is no right delimiting key */ return 0; } /* NOTE: this only should be used to look for keys who exists */ int _search_by_entry_key (reiserfs_filsys_t fs, struct key * key, struct path * path) { struct buffer_head * bh; int item_pos; struct item_head * ih; struct key tmpkey; if (_search_by_key (fs, key, path) == ITEM_FOUND) { path->pos_in_item = 0; return POSITION_FOUND; } bh = get_bh (path); item_pos = get_item_pos (path); ih = get_ih (path); if (item_pos == 0) { /* key is less than the smallest key in the tree */ if (not_of_one_file (&(ih->ih_key), key)) /* there are no items of that directory */ return DIRECTORY_NOT_FOUND; if (!is_direntry_ih (ih)) reiserfs_panic ("_search_by_entry_key: found item is not of directory type %H", ih); /* key we looked for should be here */ path->pos_in_item = 0; return POSITION_NOT_FOUND; } /* take previous item */ item_pos --; ih --; PATH_LAST_POSITION (path) --; if (not_of_one_file (&(ih->ih_key), key) || !is_direntry_ih (ih)) { /* previous item belongs to another object or is stat data, check next item */ item_pos ++; PATH_LAST_POSITION (path) ++; if (item_pos < B_NR_ITEMS (bh)) { /* next item is in the same node */ ih ++; if (not_of_one_file (&(ih->ih_key), key)) { /* there are no items of that directory */ path->pos_in_item = 0; return DIRECTORY_NOT_FOUND; } if (!is_direntry_ih (ih)) reiserfs_panic ("_search_by_entry_key: %k is not a directory", key); } else { /* next item is in right neighboring node */ struct key * next_key = _get_rkey (path); if (next_key == 0 || not_of_one_file (next_key, key)) { /* there are no items of that directory */ path->pos_in_item = 0; return DIRECTORY_NOT_FOUND; } if (!is_direntry_key (next_key)) reiserfs_panic ("_search_by_entry_key: %k is not a directory", key); /* we got right delimiting key - search for it - the entry will be pasted in position 0 */ copy_key (&tmpkey, next_key); pathrelse (path); if (_search_by_key (fs, &tmpkey, path) != ITEM_FOUND || PATH_LAST_POSITION (path) != 0) reiserfs_panic ("_search_by_entry_key: item corresponding to delimiting key %k not found", &tmpkey); } /* next item is the part of this directory */ path->pos_in_item = 0; return POSITION_NOT_FOUND; } /* previous item is part of desired directory */ if (_bin_search (&(key->u.k_offset_v1.k_offset), B_I_DEH (bh, ih), ih_entry_count (ih), DEH_SIZE, &(path->pos_in_item), comp_dir_entries) == ITEM_FOUND) return POSITION_FOUND; return POSITION_NOT_FOUND; } static void _init_tb_struct (struct tree_balance * tb, reiserfs_filsys_t fs, struct path * path, int size) { memset (tb, '\0', sizeof(struct tree_balance)); tb->tb_sb = fs; tb->tb_path = path; PATH_OFFSET_PBUFFER(path, ILLEGAL_PATH_ELEMENT_OFFSET) = NULL; PATH_OFFSET_POSITION(path, ILLEGAL_PATH_ELEMENT_OFFSET) = 0; tb->insert_size[0] = size; } int reiserfs_remove_entry (reiserfs_filsys_t fs, struct key * key) { struct path path; struct tree_balance tb; struct item_head * ih; struct reiserfs_de_head * deh; if (_search_by_entry_key (fs, key, &path) != POSITION_FOUND) { pathrelse (&path); return 1; } ih = get_ih (&path); if (ih_entry_count (ih) == 1) { _init_tb_struct (&tb, fs, &path, -(IH_SIZE + ih_item_len (ih))); if (fix_nodes (M_DELETE, &tb, 0) != CARRY_ON) { unfix_nodes (&tb); return 1; } do_balance (&tb, 0, 0, M_DELETE, 0); return 0; } deh = B_I_DEH (get_bh (&path), ih) + path.pos_in_item; _init_tb_struct (&tb, fs, &path, -(DEH_SIZE + entry_length (ih, deh, path.pos_in_item))); if (fix_nodes (M_CUT, &tb, 0) != CARRY_ON) { unfix_nodes (&tb); return 1; } do_balance (&tb, 0, 0, M_CUT, 0); return 0; } void reiserfs_paste_into_item (reiserfs_filsys_t fs, struct path * path, const void * body, int size) { struct tree_balance tb; _init_tb_struct (&tb, fs, path, size); if (fix_nodes (M_PASTE, &tb, 0/*ih*/) != CARRY_ON) reiserfs_panic ("reiserfs_paste_into_item: fix_nodes failed"); do_balance (&tb, 0, body, M_PASTE, 0/*zero num*/); } void reiserfs_insert_item (reiserfs_filsys_t fs, struct path * path, struct item_head * ih, const void * body) { struct tree_balance tb; _init_tb_struct (&tb, fs, path, IH_SIZE + ih_item_len(ih)); if (fix_nodes (M_INSERT, &tb, ih) != CARRY_ON) die ("reiserfs_insert_item: fix_nodes failed"); do_balance (&tb, ih, body, M_INSERT, 0/*zero num*/); } /*===========================================================================*/ static __u32 hash_value (reiserfs_filsys_t fs, char * name) { __u32 res; if (!strcmp (name, ".")) return DOT_OFFSET; if (!strcmp (name, "..")) return DOT_DOT_OFFSET; res = reiserfs_hash (fs) (name, strlen (name)); res = GET_HASH_VALUE(res); if (res == 0) res = 128; return res; } /* returns 0 if name is not found in a directory and objectid of pointed object otherwise and returns minimal not used generation counter. dies if found object is not a directory. */ int reiserfs_find_entry (reiserfs_filsys_t fs, struct key * dir, char * name, int * min_gen_counter) { struct key entry_key; int retval; int i; INITIALIZE_PATH (path); struct item_head * ih; struct reiserfs_de_head * deh; struct key * rdkey; __u32 hash; entry_key.k_dir_id = dir->k_dir_id; entry_key.k_objectid = dir->k_objectid; hash = hash_value (fs, name); set_type_and_offset (KEY_FORMAT_1, &entry_key, hash, TYPE_DIRENTRY); *min_gen_counter = 0; if (_search_by_entry_key (fs, &entry_key, &path) == DIRECTORY_NOT_FOUND) { pathrelse (&path); return 0; } do { ih = get_ih (&path); deh = B_I_DEH (get_bh (&path), ih) + path.pos_in_item; for (i = path.pos_in_item; i < ih_entry_count (ih); i ++, deh ++) { if (GET_HASH_VALUE (deh_offset (deh)) != GET_HASH_VALUE (hash)) { /* all entries having the same hash were scanned */ pathrelse (&path); return 0; } if (GET_GENERATION_NUMBER (deh_offset (deh)) == *min_gen_counter) (*min_gen_counter) ++; if (!memcmp (name_in_entry (deh, i), name, strlen (name))) { pathrelse (&path); return deh_objectid (deh) ? deh_objectid (deh) : 1; } } rdkey = _get_rkey (&path); if (!rdkey || not_of_one_file (rdkey, dir)) { pathrelse (&path); return 0; } if (!is_direntry_key (rdkey)) reiserfs_panic ("reiserfs_find_entry: can not find name in broken directory yet"); /* next item is the item of the directory we are looking name in */ if (GET_HASH_VALUE (get_offset (rdkey)) != hash) { /* but there is no names with given hash */ pathrelse (&path); return 0; } /* first name of that item may be a name we are looking for */ entry_key = *rdkey; pathrelse (&path); retval = _search_by_entry_key (fs, &entry_key, &path); if (retval != POSITION_FOUND) reiserfs_panic ("reiserfs_find_entry: wrong delimiting key in the tree"); } while (1); return 0; } /* compose directory entry: dir entry head and name itself */ char * make_entry (char * entry, char * name, struct key * key, __u32 offset) { struct reiserfs_de_head * deh; if (!entry) entry = getmem (DEH_SIZE + ROUND_UP (strlen (name))); memset (entry, 0, DEH_SIZE + ROUND_UP (strlen (name))); deh = (struct reiserfs_de_head *)entry; deh->deh_location = 0; deh->deh_offset = cpu_to_le32 (offset); deh->deh_state = 0; mark_de_visible (deh); /* key of object entry will point to */ deh->deh_dir_id = cpu_to_le32 (key->k_dir_id); deh->deh_objectid = cpu_to_le32 (key->k_objectid); memcpy ((char *)(deh + 1), name, strlen (name)); return entry; } /* add new name into a directory. If it exists in a directory - do nothing */ int reiserfs_add_entry (reiserfs_filsys_t fs, struct key * dir, char * name, struct key * key, int fsck_need) { struct item_head entry_ih = {{0,}, }; char * entry; int retval; INITIALIZE_PATH(path); int gen_counter; int item_len; __u32 hash; if (reiserfs_find_entry (fs, dir, name, &gen_counter)) return 0; /* compose entry key to look for its place in the tree */ entry_ih.ih_key.k_dir_id = cpu_to_le32 (dir->k_dir_id); entry_ih.ih_key.k_objectid = cpu_to_le32 (dir->k_objectid); hash = hash_value (fs, name) + gen_counter; if (!strcmp (name, ".")) hash = DOT_OFFSET; if (!strcmp (name, "..")) hash = DOT_DOT_OFFSET; set_type_and_offset (KEY_FORMAT_1, &(entry_ih.ih_key), hash, TYPE_DIRENTRY); set_key_format (&entry_ih, KEY_FORMAT_1); set_entry_count (&entry_ih, 1); if (SB_VERSION (fs) == REISERFS_VERSION_2) item_len = DEH_SIZE + ROUND_UP (strlen (name)); else item_len = DEH_SIZE + strlen (name); set_ih_item_len (&entry_ih, item_len); /* fsck may need to insert item which was not reached yet */ entry_ih.ih_format.fsck_need = fsck_need; entry = make_entry (0, name, key, get_offset (&(entry_ih.ih_key))); retval = _search_by_entry_key (fs, &(entry_ih.ih_key), &path); switch (retval) { case POSITION_NOT_FOUND: reiserfs_paste_into_item (fs, &path, entry, item_len); break; case DIRECTORY_NOT_FOUND: ((struct reiserfs_de_head *)entry)->deh_location = cpu_to_le16 (DEH_SIZE); reiserfs_insert_item (fs, &path, &entry_ih, entry); break; default: reiserfs_panic ("reiserfs_add_entry: looking for %k (inserting name \"%s\") " "search_by_entry_key returned %d", &(entry_ih.ih_key), name, retval); } freemem (entry); return item_len; } void copy_key (void * to, void * from) { memcpy (to, from, KEY_SIZE); } void copy_short_key (void * to, void * from) { memcpy (to, from, SHORT_KEY_SIZE); } void copy_item_head(void * p_v_to, void * p_v_from) { memcpy (p_v_to, p_v_from, IH_SIZE); } reiserfsprogs-3.x.0j/reiserfscore/bitmap.c0000644000076400001440000002434507254142676014512 /* * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README */ /* * 2000/10/26 - Initial version. */ #include #include "includes.h" /* create clean bitmap */ reiserfs_bitmap_t reiserfs_create_bitmap (unsigned int bit_count) { reiserfs_bitmap_t bm; bm = getmem (sizeof (*bm)); if (!bm) return 0; bm->bm_bit_size = bit_count; bm->bm_byte_size = (bit_count + 7) / 8; bm->bm_set_bits = 0; bm->bm_map = getmem (bm->bm_byte_size); if (!bm->bm_map) { freemem (bm); return 0; } return bm; } /* Expand existing bitmap. Return non-zero if can't. FIXME: it is assumed that bit_count is new number of blocks to be addressed */ int reiserfs_expand_bitmap (reiserfs_bitmap_t bm, unsigned int bit_count) { unsigned int byte_count = ((bit_count + 7) / 8); char * new_map; new_map = expandmem (bm->bm_map, bm->bm_byte_size, byte_count - bm->bm_byte_size); if (!new_map) { return 1; } bm->bm_map = new_map; bm->bm_byte_size = byte_count; bm->bm_bit_size = bit_count; return 0; } /* bitmap destructor */ void reiserfs_delete_bitmap (reiserfs_bitmap_t bm) { freemem(bm->bm_map); bm->bm_map = NULL; /* to not reuse bitmap handle */ bm->bm_bit_size = 0; bm->bm_byte_size = 0; freemem(bm); } void reiserfs_bitmap_copy (reiserfs_bitmap_t to, reiserfs_bitmap_t from) { assert (to->bm_byte_size == from->bm_byte_size); memcpy (to->bm_map, from->bm_map, from->bm_byte_size); to->bm_bit_size = from->bm_bit_size; to->bm_set_bits = from->bm_set_bits; } int reiserfs_bitmap_compare (reiserfs_bitmap_t bm1, reiserfs_bitmap_t bm2) { int bytes, bits; int i, diff; assert (bm1->bm_byte_size == bm2->bm_byte_size && bm1->bm_bit_size == bm2->bm_bit_size); diff = 0; /* compare full bytes */ bytes = bm1->bm_bit_size / 8; if (memcmp (bm1->bm_map, bm2->bm_map, bytes)) { for (i = 0; i < bytes; i ++) if (bm1->bm_map [i] != bm2->bm_map[i]) { printf ("byte %d: bm1: %x bm2 %x\n", i, bm1->bm_map[i], bm2->bm_map[i]); diff ++; } } /* compare last byte of bitmap which can be used partially */ bits = bm1->bm_bit_size % 8; if (bits) { int mask; mask = 255 >> (8 - bits); if ((bm1->bm_map [bytes] & mask) != (bm2->bm_map [bytes] & mask)) { printf ("last byte %d: bm1: %x bm2 %x\n", bytes, bm1->bm_map[bytes], bm2->bm_map[bytes]); diff ++; } } return diff; } void reiserfs_bitmap_set_bit (reiserfs_bitmap_t bm, unsigned int bit_number) { assert(bit_number < bm->bm_bit_size); if (test_bit (bit_number, bm->bm_map)) return; set_bit(bit_number, bm->bm_map); bm->bm_set_bits ++; } void reiserfs_bitmap_clear_bit (reiserfs_bitmap_t bm, unsigned int bit_number) { assert(bit_number < bm->bm_bit_size); if (!test_bit (bit_number, bm->bm_map)) return; clear_bit (bit_number, bm->bm_map); bm->bm_set_bits --; } int reiserfs_bitmap_test_bit (reiserfs_bitmap_t bm, unsigned int bit_number) { if (bit_number >= bm->bm_bit_size) printf ("bit %u, bitsize %lu\n", bit_number, bm->bm_bit_size); assert(bit_number < bm->bm_bit_size); return test_bit(bit_number, bm->bm_map); } int reiserfs_bitmap_zeros (reiserfs_bitmap_t bm) { return bm->bm_bit_size - bm->bm_set_bits; } int reiserfs_bitmap_ones (reiserfs_bitmap_t bm) { return bm->bm_set_bits; } int reiserfs_bitmap_find_zero_bit (reiserfs_bitmap_t bm, unsigned long * start) { unsigned int bit_nr = *start; assert(*start < bm->bm_bit_size); bit_nr = find_next_zero_bit(bm->bm_map, bm->bm_bit_size, *start); if (bit_nr >= bm->bm_bit_size) { /* search failed */ return 1; } *start = bit_nr; return 0; } /* copy reiserfs filesystem bitmap into memory bitmap */ int reiserfs_fetch_disk_bitmap (reiserfs_bitmap_t bm, reiserfs_filsys_t fs) { int i; int bytes; char * p; int unused_bits; reiserfs_warning (stderr, "Fetching on-disk bitmap.."); assert (bm->bm_bit_size == SB_BLOCK_COUNT (fs)); bytes = fs->s_blocksize; p = bm->bm_map; for (i = 0; i < SB_BMAP_NR (fs); i ++) { if ((i == (SB_BMAP_NR (fs) - 1)) && bm->bm_byte_size % fs->s_blocksize) bytes = bm->bm_byte_size % fs->s_blocksize; memcpy (p, SB_AP_BITMAP (fs)[i]->b_data, bytes); p += bytes; } /* on disk bitmap has bits out of SB_BLOCK_COUNT set to 1, where as reiserfs_bitmap_t has those bits set to 0 */ unused_bits = bm->bm_byte_size * 8 - bm->bm_bit_size; for (i = 0; i < unused_bits; i ++) clear_bit (bm->bm_bit_size + i, bm->bm_map); bm->bm_set_bits = 0; /* FIXME: optimize that */ for (i = 0; i < bm->bm_bit_size; i ++) if (reiserfs_bitmap_test_bit (bm, i)) bm->bm_set_bits ++; /* unused part of last bitmap block is filled with 0s */ if (bm->bm_bit_size % (fs->s_blocksize * 8)) for (i = SB_BLOCK_COUNT (fs) % (fs->s_blocksize * 8); i < fs->s_blocksize * 8; i ++) if (!test_bit (i, SB_AP_BITMAP (fs)[SB_BMAP_NR (fs) - 1]->b_data)) { reiserfs_warning (stderr, "fetch_bitmap: on-disk bitmap is not padded properly\n"); break; } reiserfs_warning (stderr, "done\n"); return 0; } /* copy bitmap to buffers which hold on-disk bitmap */ int reiserfs_flush_bitmap (reiserfs_bitmap_t bm, reiserfs_filsys_t fs) { int i; int bytes; char * p; bytes = fs->s_blocksize; p = bm->bm_map; for (i = 0; i < SB_BMAP_NR (fs); i ++) { if ((i == (SB_BMAP_NR (fs) - 1)) && (bm->bm_byte_size % fs->s_blocksize)) bytes = bm->bm_byte_size % fs->s_blocksize; memcpy (SB_AP_BITMAP (fs)[i]->b_data, p, bytes); mark_buffer_dirty (SB_AP_BITMAP (fs)[i]); p += bytes; } /* unused part of last bitmap block is filled with 0s */ if (bm->bm_bit_size % (fs->s_blocksize * 8)) for (i = bm->bm_bit_size % (fs->s_blocksize * 8); i < fs->s_blocksize * 8; i ++) set_bit (i, SB_AP_BITMAP (fs)[SB_BMAP_NR (fs) - 1]->b_data); return 0; } void reiserfs_bitmap_zero (reiserfs_bitmap_t bm) { memset (bm->bm_map, 0, bm->bm_byte_size); bm->bm_set_bits = 0; } void reiserfs_bitmap_fill (reiserfs_bitmap_t bm) { memset (bm->bm_map, 0xff, bm->bm_byte_size); bm->bm_set_bits = bm->bm_bit_size; } /* format of bitmap saved in a file: magic number (32 bits) bm_bit_size (32 bits) number of ranges of used and free blocks (32 bits) number of contiguously used block, .. of free blocks, used, free, etc magic number (32 bits) */ #define BITMAP_START_MAGIC 374031 #define BITMAP_END_MAGIC 7786472 void reiserfs_bitmap_save (char * filename, reiserfs_bitmap_t bm) { FILE * fp; __u32 v; int zeros; int count; int i; int extents; fp = fopen (filename, "w+"); if (!fp) { reiserfs_warning (stderr, "reiserfs_bitmap_save: could not save bitmap in %s: %m", filename); return; } reiserfs_warning (stderr, "Saving bitmap in \"%s\" .. ", filename); fflush (stderr); v = BITMAP_START_MAGIC; fwrite (&v, 4, 1, fp); v = bm->bm_bit_size; fwrite (&v, 4, 1, fp); /*printf ("SAVE: bit_size - %d\n", v);*/ if (fseek (fp, 4, SEEK_CUR)) { reiserfs_warning (stderr, "reiserfs_bitmap_save: fseek failed: %m\n"); fclose (fp); return; } zeros = 0; count = 0; extents = 0; for (i = 0; i < v; i ++) { if (reiserfs_bitmap_test_bit (bm, i)) { if (zeros) { /* previous bit was not set, write amount of not set bits, switch to count set bits */ fwrite (&count, 4, 1, fp); /*printf ("SAVE: Free %d\n", count);*/ extents ++; count = 1; zeros = 0; } else { /* one more zero bit appeared */ count ++; } } else { /* zero bit found */ if (zeros) { count ++; } else { /* previous bit was set, write amount of set bits, switch to count not set bits */ fwrite (&count, 4, 1, fp); /*printf ("SAVE: Used %d\n", count);*/ extents ++; count = 1; zeros = 1; } } } fwrite (&count, 4, 1, fp); extents ++; /* if (zeros) printf ("SAVE: Free %d\n", count); else printf ("SAVE: Used %d\n", count); */ v = BITMAP_END_MAGIC; fwrite (&v, 4, 1, fp); if (fseek (fp, 8, SEEK_SET)) { reiserfs_warning (stderr, "reiserfs_bitmap_save: fseek failed: %m"); fclose (fp); return; } fwrite (&extents, 4, 1, fp); /*printf ("SAVE: extents %d\n", extents);*/ fclose (fp); reiserfs_warning (stderr, "done\n"); fflush (stderr); } reiserfs_bitmap_t reiserfs_bitmap_load (char * filename) { FILE * fp; __u32 v; int count; int i, j; int extents; int bit; reiserfs_bitmap_t bm; fp = fopen (filename, "r"); if (!fp) { reiserfs_warning (stderr, "reiserfs_bitmap_load: fseek failed: %m\n"); return 0; } fread (&v, 4, 1, fp); if (v != BITMAP_START_MAGIC) { reiserfs_warning (stderr, "reiserfs_bitmap_load: " "no bitmap start magic found"); fclose (fp); return 0; } /* read bit size of bitmap */ fread (&v, 4, 1, fp); bm = reiserfs_create_bitmap (v); if (!bm) { reiserfs_warning (stderr, "reiserfs_bitmap_load: creation failed"); fclose (fp); return 0; } reiserfs_warning (stderr, "Loading bitmap from %s .. ", filename); fflush (stderr); /*printf ("LOAD: bit_size - %d\n", v);*/ fread (&extents, 4, 1, fp); /*printf ("LOAD: extents - %d\n", extents);*/ bit = 0; for (i = 0; i < extents; i ++) { fread (&count, 4, 1, fp); /* if (i % 2) printf ("LOAD: Free %d\n", count); else printf ("LOAD: Used %d\n", count); */ for (j = 0; j < count; j ++, bit ++) if (i % 2 == 0) { reiserfs_bitmap_set_bit (bm, bit); } } fread (&v, 4, 1, fp); /*printf ("LOAD: Endmagic %d\n", v);*/ fclose (fp); if (v != BITMAP_END_MAGIC) { reiserfs_warning (stderr, "reiserfs_bitmap_load: " "no bitmap end magic found"); return 0; } reiserfs_warning (stderr, "%d bits set - done\n", reiserfs_bitmap_ones (bm)); fflush (stderr); return bm; } void reiserfs_bitmap_invert (reiserfs_bitmap_t bm) { int i; reiserfs_warning (stderr, "Bitmap inverting..");fflush (stderr); for (i = 0; i < bm->bm_bit_size; i ++) { if (reiserfs_bitmap_test_bit (bm, i)) reiserfs_bitmap_clear_bit (bm, i); else reiserfs_bitmap_set_bit (bm, i); } reiserfs_warning (stderr, "done\n"); } reiserfsprogs-3.x.0j/reiserfscore/includes.h0000644000076400001440000000057707231645160015041 /* * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include "io.h" #include "misc.h" #include "reiserfs_lib.h" reiserfsprogs-3.x.0j/mkreiserfs/0000777000076400001440000000000007261220337012612 5reiserfsprogs-3.x.0j/mkreiserfs/Makefile.in0000644000076400001440000002124607261220337014600 # Makefile.in generated automatically by automake 1.4 from Makefile.am # Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. # This Makefile.in 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. SHELL = @SHELL@ srcdir = @srcdir@ top_srcdir = @top_srcdir@ VPATH = @srcdir@ prefix = @prefix@ exec_prefix = @exec_prefix@ bindir = @bindir@ sbindir = @sbindir@ libexecdir = @libexecdir@ datadir = @datadir@ sysconfdir = @sysconfdir@ sharedstatedir = @sharedstatedir@ localstatedir = @localstatedir@ libdir = @libdir@ infodir = @infodir@ mandir = @mandir@ includedir = @includedir@ oldincludedir = /usr/include DESTDIR = pkgdatadir = $(datadir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ top_builddir = .. ACLOCAL = @ACLOCAL@ AUTOCONF = @AUTOCONF@ AUTOMAKE = @AUTOMAKE@ AUTOHEADER = @AUTOHEADER@ INSTALL = @INSTALL@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS) INSTALL_DATA = @INSTALL_DATA@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ transform = @program_transform_name@ NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : CC = @CC@ MAKEINFO = @MAKEINFO@ PACKAGE = @PACKAGE@ RANLIB = @RANLIB@ VERSION = @VERSION@ sbin_PROGRAMS = mkreiserfs mkreiserfs_SOURCES = mkreiserfs.c man_MANS = mkreiserfs.8 EXTRA_DIST = $(man_MANS) LDADD = ../lib/libmisc.a ../reiserfscore/libcore.a INCLUDES = -I../include mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs CONFIG_CLEAN_FILES = PROGRAMS = $(sbin_PROGRAMS) DEFS = @DEFS@ -I. -I$(srcdir) CPPFLAGS = @CPPFLAGS@ LDFLAGS = @LDFLAGS@ LIBS = @LIBS@ mkreiserfs_OBJECTS = mkreiserfs.o mkreiserfs_LDADD = $(LDADD) mkreiserfs_DEPENDENCIES = ../lib/libmisc.a ../reiserfscore/libcore.a mkreiserfs_LDFLAGS = CFLAGS = @CFLAGS@ COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ man8dir = $(mandir)/man8 MANS = $(man_MANS) NROFF = nroff DIST_COMMON = Makefile.am Makefile.in DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) TAR = tar GZIP_ENV = --best SOURCES = $(mkreiserfs_SOURCES) OBJECTS = $(mkreiserfs_OBJECTS) all: all-redirect .SUFFIXES: .SUFFIXES: .S .c .o .s $(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps mkreiserfs/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status cd $(top_builddir) \ && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status mostlyclean-sbinPROGRAMS: clean-sbinPROGRAMS: -test -z "$(sbin_PROGRAMS)" || rm -f $(sbin_PROGRAMS) distclean-sbinPROGRAMS: maintainer-clean-sbinPROGRAMS: install-sbinPROGRAMS: $(sbin_PROGRAMS) @$(NORMAL_INSTALL) $(mkinstalldirs) $(DESTDIR)$(sbindir) @list='$(sbin_PROGRAMS)'; for p in $$list; do \ if test -f $$p; then \ echo " $(INSTALL_PROGRAM) $$p $(DESTDIR)$(sbindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`"; \ $(INSTALL_PROGRAM) $$p $(DESTDIR)$(sbindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \ else :; fi; \ done uninstall-sbinPROGRAMS: @$(NORMAL_UNINSTALL) list='$(sbin_PROGRAMS)'; for p in $$list; do \ rm -f $(DESTDIR)$(sbindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \ done .c.o: $(COMPILE) -c $< .s.o: $(COMPILE) -c $< .S.o: $(COMPILE) -c $< mostlyclean-compile: -rm -f *.o core *.core clean-compile: distclean-compile: -rm -f *.tab.c maintainer-clean-compile: mkreiserfs: $(mkreiserfs_OBJECTS) $(mkreiserfs_DEPENDENCIES) @rm -f mkreiserfs $(LINK) $(mkreiserfs_LDFLAGS) $(mkreiserfs_OBJECTS) $(mkreiserfs_LDADD) $(LIBS) install-man8: $(mkinstalldirs) $(DESTDIR)$(man8dir) @list='$(man8_MANS)'; \ l2='$(man_MANS)'; for i in $$l2; do \ case "$$i" in \ *.8*) list="$$list $$i" ;; \ esac; \ done; \ for i in $$list; do \ if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ else file=$$i; fi; \ ext=`echo $$i | sed -e 's/^.*\\.//'`; \ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ inst=`echo $$inst | sed '$(transform)'`.$$ext; \ echo " $(INSTALL_DATA) $$file $(DESTDIR)$(man8dir)/$$inst"; \ $(INSTALL_DATA) $$file $(DESTDIR)$(man8dir)/$$inst; \ done uninstall-man8: @list='$(man8_MANS)'; \ l2='$(man_MANS)'; for i in $$l2; do \ case "$$i" in \ *.8*) list="$$list $$i" ;; \ esac; \ done; \ for i in $$list; do \ ext=`echo $$i | sed -e 's/^.*\\.//'`; \ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ inst=`echo $$inst | sed '$(transform)'`.$$ext; \ echo " rm -f $(DESTDIR)$(man8dir)/$$inst"; \ rm -f $(DESTDIR)$(man8dir)/$$inst; \ done install-man: $(MANS) @$(NORMAL_INSTALL) $(MAKE) $(AM_MAKEFLAGS) install-man8 uninstall-man: @$(NORMAL_UNINSTALL) $(MAKE) $(AM_MAKEFLAGS) uninstall-man8 tags: TAGS ID: $(HEADERS) $(SOURCES) $(LISP) list='$(SOURCES) $(HEADERS)'; \ unique=`for i in $$list; do echo $$i; done | \ awk ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ here=`pwd` && cd $(srcdir) \ && mkid -f$$here/ID $$unique $(LISP) TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) tags=; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS)'; \ unique=`for i in $$list; do echo $$i; done | \ awk ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) mostlyclean-tags: clean-tags: distclean-tags: -rm -f TAGS ID maintainer-clean-tags: distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) subdir = mkreiserfs distdir: $(DISTFILES) @for file in $(DISTFILES); do \ d=$(srcdir); \ if test -d $$d/$$file; then \ cp -pr $$/$$file $(distdir)/$$file; \ else \ test -f $(distdir)/$$file \ || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ || cp -p $$d/$$file $(distdir)/$$file || :; \ fi; \ done mkreiserfs.o: mkreiserfs.c ../include/io.h ../include/misc.h \ ../include/reiserfs_lib.h ../include/reiserfs_fs.h ../version.h info-am: info: info-am dvi-am: dvi: dvi-am check-am: all-am check: check-am installcheck-am: installcheck: installcheck-am install-exec-am: install-sbinPROGRAMS install-exec: install-exec-am install-data-am: install-man install-data: install-data-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am install: install-am uninstall-am: uninstall-sbinPROGRAMS uninstall-man uninstall: uninstall-am all-am: Makefile $(PROGRAMS) $(MANS) all-redirect: all-am install-strip: $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install installdirs: $(mkinstalldirs) $(DESTDIR)$(sbindir) $(DESTDIR)$(mandir)/man8 mostlyclean-generic: clean-generic: distclean-generic: -rm -f Makefile $(CONFIG_CLEAN_FILES) -rm -f config.cache config.log stamp-h stamp-h[0-9]* maintainer-clean-generic: mostlyclean-am: mostlyclean-sbinPROGRAMS mostlyclean-compile \ mostlyclean-tags mostlyclean-generic mostlyclean: mostlyclean-am clean-am: clean-sbinPROGRAMS clean-compile clean-tags clean-generic \ mostlyclean-am clean: clean-am distclean-am: distclean-sbinPROGRAMS distclean-compile distclean-tags \ distclean-generic clean-am distclean: distclean-am maintainer-clean-am: maintainer-clean-sbinPROGRAMS \ maintainer-clean-compile maintainer-clean-tags \ maintainer-clean-generic distclean-am @echo "This command is intended for maintainers to use;" @echo "it deletes files that may require special tools to rebuild." maintainer-clean: maintainer-clean-am .PHONY: mostlyclean-sbinPROGRAMS distclean-sbinPROGRAMS \ clean-sbinPROGRAMS maintainer-clean-sbinPROGRAMS uninstall-sbinPROGRAMS \ install-sbinPROGRAMS mostlyclean-compile distclean-compile \ clean-compile maintainer-clean-compile install-man8 uninstall-man8 \ install-man uninstall-man tags mostlyclean-tags distclean-tags \ clean-tags maintainer-clean-tags distdir info-am info dvi-am dvi check \ check-am installcheck-am installcheck install-exec-am install-exec \ install-data-am install-data install-am install uninstall-am uninstall \ all-redirect all-am all installdirs mostlyclean-generic \ distclean-generic clean-generic maintainer-clean-generic clean \ mostlyclean distclean maintainer-clean # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: reiserfsprogs-3.x.0j/mkreiserfs/Makefile.am0000644000076400001440000000027407251155756014600 sbin_PROGRAMS = mkreiserfs mkreiserfs_SOURCES = mkreiserfs.c man_MANS = mkreiserfs.8 EXTRA_DIST = $(man_MANS) LDADD = ../lib/libmisc.a ../reiserfscore/libcore.a INCLUDES = -I../include reiserfsprogs-3.x.0j/mkreiserfs/mkreiserfs.c0000644000076400001440000003576407257135310015064 /* * Copyright 1996, 1997, 1998, 1999 Hans Reiser */ /* mkreiserfs is very simple. It supports only 4 and 8K blocks. It skips first 64k of device, and then writes the super block, the needed amount of bitmap blocks (this amount is calculated based on file system size), and root block. Bitmap policy is primitive: it assumes, that device does not have unreadable blocks, and it occupies first blocks for super, bitmap and root blocks. bitmap blocks are interleaved across the disk, mainly to make resizing faster. */ // // FIXME: not 'not-i386' safe // #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "io.h" #include "misc.h" #include "reiserfs_lib.h" #include "../version.h" #define print_usage_and_exit() die ("Usage: %s [ -f ] [ -h tea | rupasov | r5 ]"\ " [ -v 1 | 2] [ -q ] device [block-count]\n\n", argv[0]) #define DEFAULT_BLOCKSIZE 4096 struct buffer_head * g_sb_bh; struct buffer_head * g_bitmap_bh; struct buffer_head * g_rb_bh; struct buffer_head * g_journal_bh ; int g_block_size = DEFAULT_BLOCKSIZE; unsigned long int g_block_number; int g_hash = DEFAULT_HASH; int g_3_6_format = 1; /* new format is default */ int quiet = 0; /* reiserfs needs at least: enough blocks for journal, 64 k at the beginning, one block for super block, bitmap block and root block */ static unsigned long min_block_amount (int block_size, unsigned long journal_size) { unsigned long blocks; blocks = REISERFS_DISK_OFFSET_IN_BYTES / block_size + 1 + 1 + 1 + journal_size; if (blocks > block_size * 8) die ("mkreiserfs: journal size specified incorrectly"); return blocks; } /* form super block (old one) */ static void make_super_block (int dev) { struct reiserfs_super_block * rs; int sb_size = g_3_6_format ? SB_SIZE : SB_SIZE_V1; __u32 * oids; if (SB_SIZE > g_block_size) die ("mkreiserfs: blocksize (%d) too small", g_block_size); /* get buffer for super block */ g_sb_bh = getblk (dev, REISERFS_DISK_OFFSET_IN_BYTES / g_block_size, g_block_size); rs = (struct reiserfs_super_block *)g_sb_bh->b_data; set_blocksize (rs, g_block_size); set_block_count (rs, g_block_number); set_state (rs, REISERFS_VALID_FS); set_tree_height (rs, 2); set_bmap_nr (rs, (g_block_number + (g_block_size * 8 - 1)) / (g_block_size * 8)); set_version (rs, g_3_6_format ? REISERFS_VERSION_2 : REISERFS_VERSION_1); set_hash (rs, g_hash); // journal things rs->s_v1.s_journal_dev = cpu_to_le32 (0) ; rs->s_v1.s_orig_journal_size = cpu_to_le32 (JOURNAL_BLOCK_COUNT) ; rs->s_v1.s_journal_trans_max = cpu_to_le32 (0) ; rs->s_v1.s_journal_block_count = cpu_to_le32 (0) ; rs->s_v1.s_journal_max_batch = cpu_to_le32 (0) ; rs->s_v1.s_journal_max_commit_age = cpu_to_le32 (0) ; rs->s_v1.s_journal_max_trans_age = cpu_to_le32 (0) ; // the differences between sb V1 and sb V2 are: magic string memcpy (rs->s_v1.s_magic, g_3_6_format ? REISER2FS_SUPER_MAGIC_STRING : REISERFS_SUPER_MAGIC_STRING, strlen (g_3_6_format ? REISER2FS_SUPER_MAGIC_STRING : REISERFS_SUPER_MAGIC_STRING)); // start of objectid map oids = (__u32 *)((char *)rs + sb_size); // max size of objectid map rs->s_v1.s_oid_maxsize = cpu_to_le16 ((g_block_size - sb_size) / sizeof(__u32) / 2 * 2); oids[0] = cpu_to_le32 (1); oids[1] = cpu_to_le32 (REISERFS_ROOT_OBJECTID + 1); set_objectid_map_size (rs, 2); mark_buffer_dirty (g_sb_bh); mark_buffer_uptodate (g_sb_bh, 1); return; } void zero_journal_blocks(int dev, int start, int len) { int i ; struct buffer_head *bh ; unsigned long done = 0; printf ("Initializing journal - "); fflush (stdout); for (i = 0 ; i < len ; i++) { print_how_far (&done, len, 1, quiet); bh = getblk (dev, start + i, g_block_size) ; memset(bh->b_data, 0, g_block_size) ; mark_buffer_dirty(bh) ; mark_buffer_uptodate(bh,0) ; bwrite (bh); brelse(bh) ; } printf ("\n"); fflush (stdout); } /* this only sets few first bits in bitmap block. Fills not initialized fields of super block (root block and bitmap block numbers) */ static void make_bitmap (void) { struct reiserfs_super_block * rs = (struct reiserfs_super_block *)g_sb_bh->b_data; int i, j; /* get buffer for bitmap block */ g_bitmap_bh = getblk (g_sb_bh->b_dev, g_sb_bh->b_blocknr + 1, g_sb_bh->b_size); /* mark, that first 8K of device is busy */ for (i = 0; i < REISERFS_DISK_OFFSET_IN_BYTES / g_block_size; i ++) set_bit (i, g_bitmap_bh->b_data); /* mark that super block is busy */ set_bit (i++, g_bitmap_bh->b_data); /* mark first bitmap block as busy */ set_bit (i ++, g_bitmap_bh->b_data); /* sb->s_journal_block = g_block_number - JOURNAL_BLOCK_COUNT ; */ /* journal goes at end of disk */ set_journal_start (rs, i); /* mark journal blocks as busy BUG! we need to check to make sure journal will fit in the first bitmap block */ for (j = 0 ; j < (JOURNAL_BLOCK_COUNT + 1); j++) /* the descriptor block goes after the journal */ set_bit (i ++, g_bitmap_bh->b_data); /* and tree root is busy */ set_bit (i, g_bitmap_bh->b_data); set_root_block (rs, i); set_free_blocks (rs, rs_block_count (rs) - i - 1); /* count bitmap blocks not resides in first s_blocksize blocks - ?? */ set_free_blocks (rs, rs_free_blocks (rs) - (rs_bmap_nr (rs) - 1)); mark_buffer_dirty (g_bitmap_bh); mark_buffer_uptodate (g_bitmap_bh, 0); mark_buffer_dirty (g_sb_bh); return; } /* form the root block of the tree (the block head, the item head, the root directory) */ static void make_root_block (void) { struct reiserfs_super_block * rs = (struct reiserfs_super_block *)g_sb_bh->b_data; char * rb; struct item_head * ih; /* get memory for root block */ g_rb_bh = getblk (g_sb_bh->b_dev, rs_root_block (rs), rs_blocksize (rs)); rb = g_rb_bh->b_data; /* block head */ set_leaf_node_level (g_rb_bh); set_node_item_number (g_rb_bh, 0); set_node_free_space (g_rb_bh, rs_blocksize (rs) - BLKH_SIZE); /* first item is stat data item of root directory */ ih = (struct item_head *)(g_rb_bh->b_data + BLKH_SIZE); make_dir_stat_data (g_block_size, g_3_6_format ? KEY_FORMAT_2 : KEY_FORMAT_1, REISERFS_ROOT_PARENT_OBJECTID, REISERFS_ROOT_OBJECTID, ih, g_rb_bh->b_data + g_block_size - (g_3_6_format ? SD_SIZE : SD_V1_SIZE)); set_ih_location (ih, g_block_size - ih_item_len (ih)); // adjust block head set_node_item_number (g_rb_bh, node_item_number (g_rb_bh) + 1); set_node_free_space (g_rb_bh, node_free_space (g_rb_bh) - (IH_SIZE + ih_item_len (ih))); /* second item is root directory item, containing "." and ".." */ ih ++; ih->ih_key.k_dir_id = cpu_to_le32 (REISERFS_ROOT_PARENT_OBJECTID); ih->ih_key.k_objectid = cpu_to_le32 (REISERFS_ROOT_OBJECTID); ih->ih_key.u.k_offset_v1.k_offset = cpu_to_le32 (DOT_OFFSET); ih->ih_key.u.k_offset_v1.k_uniqueness = cpu_to_le32 (DIRENTRY_UNIQUENESS); ih->ih_item_len = cpu_to_le16 (g_3_6_format ? EMPTY_DIR_SIZE : EMPTY_DIR_SIZE_V1); ih->ih_item_location = cpu_to_le16 (ih_location (ih-1) - ih_item_len (ih)); ih->u.ih_entry_count = cpu_to_le16 (2); set_key_format (ih, KEY_FORMAT_1); if (g_3_6_format) make_empty_dir_item (g_rb_bh->b_data + ih_location (ih), REISERFS_ROOT_PARENT_OBJECTID, REISERFS_ROOT_OBJECTID, 0, REISERFS_ROOT_PARENT_OBJECTID); else make_empty_dir_item_v1 (g_rb_bh->b_data + ih_location (ih), REISERFS_ROOT_PARENT_OBJECTID, REISERFS_ROOT_OBJECTID, 0, REISERFS_ROOT_PARENT_OBJECTID); // adjust block head set_node_item_number (g_rb_bh, node_item_number (g_rb_bh) + 1); set_node_free_space (g_rb_bh, node_free_space (g_rb_bh) - (IH_SIZE + ih_item_len (ih))); print_block (stdout, 0, g_rb_bh, 3, -1, -1); mark_buffer_dirty (g_rb_bh); mark_buffer_uptodate (g_rb_bh, 0); return; } /* * write the super block, the bitmap blocks and the root of the tree */ static void write_super_and_root_blocks (void) { struct reiserfs_super_block * rs = (struct reiserfs_super_block *)g_sb_bh->b_data; int i; zero_journal_blocks(g_sb_bh->b_dev, rs_journal_start (rs), JOURNAL_BLOCK_COUNT + 1) ; /* super block */ bwrite (g_sb_bh); /* bitmap blocks */ for (i = 0; i < rs_bmap_nr (rs); i ++) { if (i != 0) { g_bitmap_bh->b_blocknr = i * rs_blocksize (rs) * 8; memset (g_bitmap_bh->b_data, 0, g_bitmap_bh->b_size); set_bit (0, g_bitmap_bh->b_data); } if (i == rs_bmap_nr (rs) - 1) { int j; /* fill unused part of last bitmap block with 1s */ if (rs_block_count (rs) % (rs_blocksize (rs) * 8)) for (j = rs_block_count (rs) % (rs_blocksize (rs) * 8); j < rs_blocksize (rs) * 8; j ++) { set_bit (j, g_bitmap_bh->b_data); } } /* write bitmap */ mark_buffer_dirty (g_bitmap_bh); bwrite (g_bitmap_bh); } /* root block */ bwrite (g_rb_bh); brelse (g_rb_bh); brelse (g_bitmap_bh); brelse (g_sb_bh); } static void report (char * devname) { struct reiserfs_super_block * rs = (struct reiserfs_super_block *)g_sb_bh->b_data; unsigned int i; printf ("Creating reiserfs of %s format\n", g_3_6_format ? "3.6" : "3.5"); printf ("Block size %d bytes\n", rs_blocksize (rs)); printf ("Block count %d\n", rs_block_count (rs)); printf ("Used blocks %d\n", rs_block_count (rs) - rs_free_blocks (rs)); printf ("Free blocks count %d\n", rs_free_blocks (rs)); printf ("First %ld blocks skipped\n", g_sb_bh->b_blocknr); printf ("Super block is in %ld\n", g_sb_bh->b_blocknr); printf ("Bitmap blocks (%d) are : \n\t%ld", rs_bmap_nr (rs), g_bitmap_bh->b_blocknr); for (i = 1; i < rs_bmap_nr (rs); i ++) { printf (", %d", i * rs_blocksize (rs) * 8); } printf ("\nJournal size %d (blocks %d-%d of file %s)\n", JOURNAL_BLOCK_COUNT, rs_journal_start (rs), rs_journal_start (rs) + JOURNAL_BLOCK_COUNT, devname); printf ("Root block %u\n", rs_root_block (rs)); printf ("Hash function \"%s\"\n", g_hash == TEA_HASH ? "tea" : ((g_hash == YURA_HASH) ? "rupasov" : "r5")); fflush (stdout); } /* wipe out first 2 k of a device and both possible reiserfs super block */ static void invalidate_other_formats (int dev) { struct buffer_head * bh; bh = getblk (dev, 0, 2048); mark_buffer_uptodate (bh, 1); mark_buffer_dirty (bh); bwrite (bh); brelse (bh); bh = getblk(dev, REISERFS_OLD_DISK_OFFSET_IN_BYTES / 1024, 1024) ; mark_buffer_uptodate (bh, 1); mark_buffer_dirty (bh); bwrite (bh); brelse (bh); bh = getblk(dev, REISERFS_DISK_OFFSET_IN_BYTES / 1024, 1024) ; mark_buffer_uptodate (bh, 1); mark_buffer_dirty (bh); bwrite (bh); brelse (bh); } static void set_hash_function (char * str) { if (!strcmp (str, "tea")) g_hash = TEA_HASH; else if (!strcmp (str, "rupasov")) g_hash = YURA_HASH; else if (!strcmp (str, "r5")) g_hash = R5_HASH; else printf ("mkreiserfs: wrong hash type specified. Using default\n"); } static void set_reiserfs_version (char * str) { if (!strcmp (str, "1")) g_3_6_format = 0; else if (!strcmp (str, "2")) g_3_6_format = 1; else printf ("mkreiserfs: wrong reiserfs version specified. Using default 3.5 format\n"); } int main (int argc, char **argv) { char *tmp; int dev; int force = 0; struct stat st; char * device_name; char c; print_banner ("mkreiserfs"); if (argc < 2) print_usage_and_exit (); while ( ( c = getopt( argc, argv, "fh:v:q" ) ) != EOF ) switch( c ) { case 'f' : /* force if file is not a block device or fs is mounted. Confirm still required */ force = 1; break; case 'h': set_hash_function (optarg); break; case 'v': set_reiserfs_version (optarg); break; case 'q': quiet = 1; break; default : print_usage_and_exit (); } device_name = argv [optind]; /* get block number for file system */ if (optind == argc - 2) { g_block_number = strtol (argv[optind + 1], &tmp, 0); if (*tmp == 0) { /* The string is integer */ if (g_block_number > count_blocks (device_name, g_block_size, -1)) die ("mkreiserfs: specified block number (%d) is too high", g_block_number); } else { die ("mkreiserfs: bad block count : %s\n", argv[optind + 1]); } } else if (optind == argc - 1) { /* number of blocks is not specified */ g_block_number = count_blocks (device_name, g_block_size, -1); tmp = ""; } else print_usage_and_exit (); /*g_block_number = g_block_number / 8 * 8;*/ if (g_block_number < min_block_amount (g_block_size, JOURNAL_BLOCK_COUNT + 1)) die ("mkreiserfs: can not create filesystem on that small device (%lu blocks).\n" "It should have at least %lu blocks", g_block_number, min_block_amount (g_block_size, JOURNAL_BLOCK_COUNT + 1)); if (is_mounted (device_name)) { printf ("mkreiserfs: '%s' contains a mounted file system\n", device_name); if (!force) exit (1); if (!user_confirmed ("Forced to continue, but please confirm (y/n)", "y")) exit (1); } dev = open (device_name, O_RDWR); if (dev == -1) die ("mkreiserfs: can not open '%s': %s", device_name, strerror (errno)); if (fstat (dev, &st) < 0) die ("mkreiserfs: unable to stat %s", device_name); if (!S_ISBLK (st.st_mode)) { printf ("mkreiserfs: %s is not a block special device.\n", device_name); if (!force) { exit (1); } if (!user_confirmed ("Forced to continue, but please confirm (y/n)", "y")) exit (1); } else { // from e2progs-1.18/misc/mke2fs.c if ((MAJOR (st.st_rdev) == HD_MAJOR && MINOR (st.st_rdev)%64 == 0) || (SCSI_BLK_MAJOR (MAJOR(st.st_rdev)) && MINOR (st.st_rdev) % 16 == 0)) { printf ("mkreiserfs: %s is entire device, not just one partition! Continue? (y/n) ", device_name); if (!user_confirmed ("Continue (y/n)", "y")) exit (1); } } /* these fill buffers (super block, first bitmap, root block) with reiserfs structures */ make_super_block (dev); make_bitmap (); make_root_block (); report (device_name); printf ("ATTENTION: YOU SHOULD REBOOT AFTER FDISK!\n\t ALL DATA WILL BE LOST ON '%s'! ", device_name); if (!user_confirmed ("(y/n)", "y\n")) die ("mkreiserfs: Disk was not formatted"); invalidate_other_formats (dev); write_super_and_root_blocks (); check_and_free_buffer_mem (); printf ("Syncing.."); fflush (stdout); close(dev) ; sync (); printf ("\n\nReiserFS core development sponsored by SuSE Labs (suse.com)\n\n" "Journaling sponsored by MP3.com.\n\n" //"Item handlers sponsored by Ecila.com\n\n "To learn about the programmers and ReiserFS, please go to\n" "http://www.devlinux.com/namesys\n\nHave fun.\n\n"); fflush (stdout); return 0; } reiserfsprogs-3.x.0j/mkreiserfs/mkreiserfs.80000644000076400001440000000244407260374604015003 .\" -*- nroff -*- .\" Copyright 1996-2001 Hans Reiser. .\" .TH MKREISERFS 8 "March 2001" "Reiserfsprogs-3.x.0j" .SH NAME mkreiserfs \- create a Linux Reiserfs file system .SH SYNOPSIS .B mkreiserfs [ .B -h .I r5 | .I tea | .I rupasov ] [ .B \-v .I 1 | .I 2 ] [ .B -q ] .I device [ .I size-in-blocks ] .SH DESCRIPTION It creates a Linux Reiserfs file system on a device (usually a disk partition). .TP .I device is the special file corresponding to the device (e.g /dev/hdXX for IDE disk partition or /dev/sdXX for SCSI disk partition). .TP .I block-count is the number of blocks on the device. If omitted, it will be determined by .B mkreiserfs automatically. .SH OPTIONS .TP \fB\-h \fIr5\fR |\fI tea\fR |\fI rupasov This specifies the name of hash function file names in directories will be sorted with. Choose one of the above. 'r5' is default. .TP \fB\-v \fI1\fR |\fI 2 This specifies format new filsystem has to be of. .TP \fB\-q\fR This makes the progress bar much less verbose. Useful when logged in via a slow link (e.g. serial console). .SH AUTHOR This version of .B mkreiserfs has been written by Hans Reiser . .SH BUGS No other blocksizes but 4k are available. Please, report about other bugs to Hans Reiser . .SH SEE ALSO .BR reiserfsck (8), .BR debugreiserfs (8) reiserfsprogs-3.x.0j/fsck/0000777000076400001440000000000007261220341011361 5reiserfsprogs-3.x.0j/fsck/Makefile.in0000644000076400001440000002517107261220341013350 # Makefile.in generated automatically by automake 1.4 from Makefile.am # Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. # This Makefile.in 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. SHELL = @SHELL@ srcdir = @srcdir@ top_srcdir = @top_srcdir@ VPATH = @srcdir@ prefix = @prefix@ exec_prefix = @exec_prefix@ bindir = @bindir@ sbindir = @sbindir@ libexecdir = @libexecdir@ datadir = @datadir@ sysconfdir = @sysconfdir@ sharedstatedir = @sharedstatedir@ localstatedir = @localstatedir@ libdir = @libdir@ infodir = @infodir@ mandir = @mandir@ includedir = @includedir@ oldincludedir = /usr/include DESTDIR = pkgdatadir = $(datadir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ top_builddir = .. ACLOCAL = @ACLOCAL@ AUTOCONF = @AUTOCONF@ AUTOMAKE = @AUTOMAKE@ AUTOHEADER = @AUTOHEADER@ INSTALL = @INSTALL@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS) INSTALL_DATA = @INSTALL_DATA@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ transform = @program_transform_name@ NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : CC = @CC@ MAKEINFO = @MAKEINFO@ PACKAGE = @PACKAGE@ RANLIB = @RANLIB@ VERSION = @VERSION@ sbin_PROGRAMS = reiserfsck reiserfsck_SOURCES = main.c pass0.c pass1.c pass2.c semantic.c pass4.c lost+found.c ubitmap.c uobjectid.c ustree.c ufile.c check.c check_tree.c journal.c info.c segments.c fsck.h man_MANS = reiserfsck.8 EXTRA_DIST = $(man_MANS) LDADD = ../lib/libmisc.a ../reiserfscore/libcore.a INCLUDES = -I../include -I. mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs CONFIG_CLEAN_FILES = PROGRAMS = $(sbin_PROGRAMS) DEFS = @DEFS@ -I. -I$(srcdir) CPPFLAGS = @CPPFLAGS@ LDFLAGS = @LDFLAGS@ LIBS = @LIBS@ reiserfsck_OBJECTS = main.o pass0.o pass1.o pass2.o semantic.o pass4.o \ lost+found.o ubitmap.o uobjectid.o ustree.o ufile.o check.o \ check_tree.o journal.o info.o segments.o reiserfsck_LDADD = $(LDADD) reiserfsck_DEPENDENCIES = ../lib/libmisc.a ../reiserfscore/libcore.a reiserfsck_LDFLAGS = CFLAGS = @CFLAGS@ COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ man8dir = $(mandir)/man8 MANS = $(man_MANS) NROFF = nroff DIST_COMMON = Makefile.am Makefile.in DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) TAR = tar GZIP_ENV = --best SOURCES = $(reiserfsck_SOURCES) OBJECTS = $(reiserfsck_OBJECTS) all: all-redirect .SUFFIXES: .SUFFIXES: .S .c .o .s $(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps fsck/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status cd $(top_builddir) \ && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status mostlyclean-sbinPROGRAMS: clean-sbinPROGRAMS: -test -z "$(sbin_PROGRAMS)" || rm -f $(sbin_PROGRAMS) distclean-sbinPROGRAMS: maintainer-clean-sbinPROGRAMS: install-sbinPROGRAMS: $(sbin_PROGRAMS) @$(NORMAL_INSTALL) $(mkinstalldirs) $(DESTDIR)$(sbindir) @list='$(sbin_PROGRAMS)'; for p in $$list; do \ if test -f $$p; then \ echo " $(INSTALL_PROGRAM) $$p $(DESTDIR)$(sbindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`"; \ $(INSTALL_PROGRAM) $$p $(DESTDIR)$(sbindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \ else :; fi; \ done uninstall-sbinPROGRAMS: @$(NORMAL_UNINSTALL) list='$(sbin_PROGRAMS)'; for p in $$list; do \ rm -f $(DESTDIR)$(sbindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \ done .c.o: $(COMPILE) -c $< .s.o: $(COMPILE) -c $< .S.o: $(COMPILE) -c $< mostlyclean-compile: -rm -f *.o core *.core clean-compile: distclean-compile: -rm -f *.tab.c maintainer-clean-compile: reiserfsck: $(reiserfsck_OBJECTS) $(reiserfsck_DEPENDENCIES) @rm -f reiserfsck $(LINK) $(reiserfsck_LDFLAGS) $(reiserfsck_OBJECTS) $(reiserfsck_LDADD) $(LIBS) install-man8: $(mkinstalldirs) $(DESTDIR)$(man8dir) @list='$(man8_MANS)'; \ l2='$(man_MANS)'; for i in $$l2; do \ case "$$i" in \ *.8*) list="$$list $$i" ;; \ esac; \ done; \ for i in $$list; do \ if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ else file=$$i; fi; \ ext=`echo $$i | sed -e 's/^.*\\.//'`; \ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ inst=`echo $$inst | sed '$(transform)'`.$$ext; \ echo " $(INSTALL_DATA) $$file $(DESTDIR)$(man8dir)/$$inst"; \ $(INSTALL_DATA) $$file $(DESTDIR)$(man8dir)/$$inst; \ done uninstall-man8: @list='$(man8_MANS)'; \ l2='$(man_MANS)'; for i in $$l2; do \ case "$$i" in \ *.8*) list="$$list $$i" ;; \ esac; \ done; \ for i in $$list; do \ ext=`echo $$i | sed -e 's/^.*\\.//'`; \ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ inst=`echo $$inst | sed '$(transform)'`.$$ext; \ echo " rm -f $(DESTDIR)$(man8dir)/$$inst"; \ rm -f $(DESTDIR)$(man8dir)/$$inst; \ done install-man: $(MANS) @$(NORMAL_INSTALL) $(MAKE) $(AM_MAKEFLAGS) install-man8 uninstall-man: @$(NORMAL_UNINSTALL) $(MAKE) $(AM_MAKEFLAGS) uninstall-man8 tags: TAGS ID: $(HEADERS) $(SOURCES) $(LISP) list='$(SOURCES) $(HEADERS)'; \ unique=`for i in $$list; do echo $$i; done | \ awk ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ here=`pwd` && cd $(srcdir) \ && mkid -f$$here/ID $$unique $(LISP) TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) tags=; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS)'; \ unique=`for i in $$list; do echo $$i; done | \ awk ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) mostlyclean-tags: clean-tags: distclean-tags: -rm -f TAGS ID maintainer-clean-tags: distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) subdir = fsck distdir: $(DISTFILES) @for file in $(DISTFILES); do \ d=$(srcdir); \ if test -d $$d/$$file; then \ cp -pr $$/$$file $(distdir)/$$file; \ else \ test -f $(distdir)/$$file \ || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ || cp -p $$d/$$file $(distdir)/$$file || :; \ fi; \ done check.o: check.c fsck.h ../include/io.h ../include/misc.h \ ../include/reiserfs_lib.h ../include/reiserfs_fs.h check_tree.o: check_tree.c fsck.h ../include/io.h ../include/misc.h \ ../include/reiserfs_lib.h ../include/reiserfs_fs.h info.o: info.c fsck.h ../include/io.h ../include/misc.h \ ../include/reiserfs_lib.h ../include/reiserfs_fs.h journal.o: journal.c fsck.h ../include/io.h ../include/misc.h \ ../include/reiserfs_lib.h ../include/reiserfs_fs.h lost+found.o: lost+found.c fsck.h ../include/io.h ../include/misc.h \ ../include/reiserfs_lib.h ../include/reiserfs_fs.h main.o: main.c fsck.h ../include/io.h ../include/misc.h \ ../include/reiserfs_lib.h ../include/reiserfs_fs.h ../version.h pass0.o: pass0.c fsck.h ../include/io.h ../include/misc.h \ ../include/reiserfs_lib.h ../include/reiserfs_fs.h pass1.o: pass1.c fsck.h ../include/io.h ../include/misc.h \ ../include/reiserfs_lib.h ../include/reiserfs_fs.h pass2.o: pass2.c fsck.h ../include/io.h ../include/misc.h \ ../include/reiserfs_lib.h ../include/reiserfs_fs.h pass4.o: pass4.c fsck.h ../include/io.h ../include/misc.h \ ../include/reiserfs_lib.h ../include/reiserfs_fs.h segments.o: segments.c fsck.h ../include/io.h ../include/misc.h \ ../include/reiserfs_lib.h ../include/reiserfs_fs.h semantic.o: semantic.c fsck.h ../include/io.h ../include/misc.h \ ../include/reiserfs_lib.h ../include/reiserfs_fs.h ubitmap.o: ubitmap.c fsck.h ../include/io.h ../include/misc.h \ ../include/reiserfs_lib.h ../include/reiserfs_fs.h ufile.o: ufile.c fsck.h ../include/io.h ../include/misc.h \ ../include/reiserfs_lib.h ../include/reiserfs_fs.h uobjectid.o: uobjectid.c fsck.h ../include/io.h ../include/misc.h \ ../include/reiserfs_lib.h ../include/reiserfs_fs.h ustree.o: ustree.c fsck.h ../include/io.h ../include/misc.h \ ../include/reiserfs_lib.h ../include/reiserfs_fs.h info-am: info: info-am dvi-am: dvi: dvi-am check-am: all-am check: check-am installcheck-am: installcheck: installcheck-am install-exec-am: install-sbinPROGRAMS install-exec: install-exec-am install-data-am: install-man install-data: install-data-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am install: install-am uninstall-am: uninstall-sbinPROGRAMS uninstall-man uninstall: uninstall-am all-am: Makefile $(PROGRAMS) $(MANS) all-redirect: all-am install-strip: $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install installdirs: $(mkinstalldirs) $(DESTDIR)$(sbindir) $(DESTDIR)$(mandir)/man8 mostlyclean-generic: clean-generic: distclean-generic: -rm -f Makefile $(CONFIG_CLEAN_FILES) -rm -f config.cache config.log stamp-h stamp-h[0-9]* maintainer-clean-generic: mostlyclean-am: mostlyclean-sbinPROGRAMS mostlyclean-compile \ mostlyclean-tags mostlyclean-generic mostlyclean: mostlyclean-am clean-am: clean-sbinPROGRAMS clean-compile clean-tags clean-generic \ mostlyclean-am clean: clean-am distclean-am: distclean-sbinPROGRAMS distclean-compile distclean-tags \ distclean-generic clean-am distclean: distclean-am maintainer-clean-am: maintainer-clean-sbinPROGRAMS \ maintainer-clean-compile maintainer-clean-tags \ maintainer-clean-generic distclean-am @echo "This command is intended for maintainers to use;" @echo "it deletes files that may require special tools to rebuild." maintainer-clean: maintainer-clean-am .PHONY: mostlyclean-sbinPROGRAMS distclean-sbinPROGRAMS \ clean-sbinPROGRAMS maintainer-clean-sbinPROGRAMS uninstall-sbinPROGRAMS \ install-sbinPROGRAMS mostlyclean-compile distclean-compile \ clean-compile maintainer-clean-compile install-man8 uninstall-man8 \ install-man uninstall-man tags mostlyclean-tags distclean-tags \ clean-tags maintainer-clean-tags distdir info-am info dvi-am dvi check \ check-am installcheck-am installcheck install-exec-am install-exec \ install-data-am install-data install-am install uninstall-am uninstall \ all-redirect all-am all installdirs mostlyclean-generic \ distclean-generic clean-generic maintainer-clean-generic clean \ mostlyclean distclean maintainer-clean # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: reiserfsprogs-3.x.0j/fsck/Makefile.am0000644000076400001440000000052407231645160013341 sbin_PROGRAMS = reiserfsck reiserfsck_SOURCES = main.c pass0.c pass1.c pass2.c semantic.c pass4.c lost+found.c \ ubitmap.c uobjectid.c ustree.c ufile.c check.c check_tree.c journal.c info.c segments.c\ fsck.h man_MANS = reiserfsck.8 EXTRA_DIST = $(man_MANS) LDADD = ../lib/libmisc.a ../reiserfscore/libcore.a INCLUDES = -I../include -I. reiserfsprogs-3.x.0j/fsck/main.c0000644000076400001440000004606107261146722012406 /* * Copyright 1996-2000 Hans Reiser */ #include "fsck.h" #include #include "../version.h" #define print_usage_and_exit() die ("Usage: %s [options] "\ " device\n"\ "\n"\ "Options:\n\n"\ " --check\t\tconsistency checking (default)\n"\ " --rebuild-sb\t\tsuper block checking and rebuilding if needed\n"\ " --rebuild-tree\tforce fsck to rebuild filesystem from scratch\n"\ " \t\t\t(takes a long time)\n"\ " --interactive, -i\tmake fsck to stop after every stage\n"\ " -l | --logfile logfile\n"\ " \t\t\tmake fsck to complain to specifed file\n"\ " -b | --scan-marked-in-bitmap file\n"\ " \t\t\tbuild tree of blocks marked in the bitmapfile\n"\ " -c | --create-bitmap-file\n"\ " \t\t\tsave bitmap of found leaves\n"\ " -x | --fix-fixable\tfix corruptions which can be fixed w/o --rebuild-tree\n"\ " -o | --fix-non-critical\n"\ " \t\t\tfix strange modes, file sizes to real size and\n"\ " \t\t\trelocate files using busy objectids\n"\ " -q | --quiet\t\tno speed info\n"\ " -n | --nolog\t\t suppresses all logs\n"\ " -V\t\t\tprints version and exits\n"\ " -a\t\t\tmakes fsck to do nothing\n"\ " -p\t\t\tdo nothing, exist for compatibility with fsck(8)\n"\ " -r\n", argv[0]); /* fsck is called with one non-optional argument - file name of device containing reiserfs. This function parses other options, sets flags based on parsing and returns non-optional argument */ static char * parse_options (struct fsck_data * data, int argc, char * argv []) { int c; static int mode = FSCK_CHECK; data->scan_area = USED_BLOCKS; while (1) { static struct option options[] = { /* modes */ {"check", no_argument, &mode, FSCK_CHECK}, {"rebuild-sb", no_argument, &mode, FSCK_SB}, {"rebuild-tree", no_argument, &mode, FSCK_REBUILD}, /* {"fast-rebuild", no_argument, &opt_fsck_mode, FSCK_FAST_REBUILD}, */ /* options */ {"logfile", required_argument, 0, 'l'}, {"interactive", no_argument, 0, 'i'}, {"fix-fixable", no_argument, 0, 'x'}, {"fix-non-critical", no_argument, 0, 'o'}, {"quiet", no_argument, 0, 'q'}, {"nolog", no_argument, 0, 'n'}, /* if file exists ad reiserfs can be load of it - only blocks marked used in that bitmap will be read */ {"scan-marked-in-bitmap", required_argument, 0, 'b'}, /* */ {"create-leaf-bitmap", required_argument, 0, 'c'}, /* all blocks will be read */ {"scan-whole-partition", no_argument, 0, 'S'}, /* special option: will mark free blocks used, zero all unformatted node pointers and mark them free */ {"zero-files", no_argument, &mode, FSCK_ZERO_FILES}, {0, 0, 0, 0} }; int option_index; c = getopt_long (argc, argv, "iql:b:Sc:xoVaprt:n", options, &option_index); if (c == -1) break; switch (c) { case 0: /* long option specifying fsck mode is found */ break; case 'i': /* --interactive */ data->options |= OPT_INTERACTIVE; break; case 'q': /* --quiet */ data->options |= OPT_QUIET; break; case 'l': /* --logfile */ asprintf (&data->log_file_name, "%s", optarg); data->log = fopen (optarg, "w"); if (!data->log) fprintf (stderr, "reiserfsck: could not open \'%s\': %m", optarg); break; case 'b': /* --scan-marked-in-bitmap */ /* will try to load a bitmap from a file and read only blocks marked in it. That bitmap could be created by previous run of reiserfsck with -c */ asprintf (&data->bitmap_file_name, "%s", optarg); data->scan_area = EXTERN_BITMAP; break; case 'S': /* --scan-whole-partition */ data->scan_area = ALL_BLOCKS; break; case 'c': /* --create-leaf-bitmap */ asprintf (&data->new_bitmap_file_name, "%s", optarg); data->options |= OPT_SAVE_EXTERN_BITMAP; break; case 'x': /* --fix-fixable */ data->options |= OPT_FIX_FIXABLE; break; case 'o': /* --fix-non-critical */ data->options |= OPT_FIX_NON_CRITICAL; break; case 'n': /* --nolog */ data->options |= OPT_SILENT; break; case 'V': case 'p': /* these say reiserfsck to do nothing */ case 'r': case 'a': mode = DO_NOTHING; break; case 't': mode = DO_TEST; data->test = atoi (optarg); break; default: print_usage_and_exit(); } } if (optind != argc - 1 && mode != DO_NOTHING) /* only one non-option argument is permitted */ print_usage_and_exit(); data->mode = mode; if (!data->log) data->log = stderr; return argv[optind]; } reiserfs_filsys_t fs; static void reset_super_block (reiserfs_filsys_t fs) { set_free_blocks (fs->s_rs, SB_BLOCK_COUNT (fs)); set_root_block (fs->s_rs, ~0); set_tree_height (fs->s_rs, ~0); /* make file system invalid unless fsck done () */ set_state (fs->s_rs, REISERFS_ERROR_FS); if (is_reiser2fs_magic_string (fs->s_rs)) { set_version (fs->s_rs, REISERFS_VERSION_2); } if (is_reiserfs_magic_string (fs->s_rs)) { set_version (fs->s_rs, REISERFS_VERSION_1); } /* can be not set yet. If so, hash function will be set when first dir entry will be found */ fs->s_hash_function = code2func (rs_hash (fs->s_rs)); /* objectid map is not touched */ mark_buffer_dirty (fs->s_sbh); bwrite (fs->s_sbh); } reiserfs_bitmap_t uninsertable_leaf_bitmap; int g_blocks_to_read; /* on-disk bitmap is read, fetch it. create new bitmap, mark used blocks which are always used (skipped, super block, journal area, bitmaps), create other auxiliary bitmaps */ static void init_bitmaps (reiserfs_filsys_t fs) { unsigned long i; unsigned long block_count; unsigned long tmp; block_count = SB_BLOCK_COUNT (fs); switch (stats (fs)->scan_area) { case ALL_BLOCKS: fsck_disk_bitmap (fs) = reiserfs_create_bitmap (block_count); reiserfs_bitmap_fill (fsck_disk_bitmap (fs)); fsck_progress ("Whole device (%d blocks) is to be scanned\n", reiserfs_bitmap_ones (fsck_disk_bitmap (fs))); break; case USED_BLOCKS: fsck_progress ("Loading on-disk bitmap .. "); fsck_disk_bitmap (fs) = reiserfs_create_bitmap (block_count); reiserfs_fetch_disk_bitmap (fsck_disk_bitmap (fs), fs); fsck_progress ("%d bits set - done\n", reiserfs_bitmap_ones (fsck_disk_bitmap (fs))); break; case EXTERN_BITMAP: fsck_disk_bitmap (fs) = reiserfs_bitmap_load (stats (fs)->bitmap_file_name); if (!fsck_disk_bitmap (fs)) reiserfs_panic ("could not load fitmap from \"%s\"", stats (fs)->bitmap_file_name); break; default: reiserfs_panic ("No area to scan specified"); } /* pass 0 will skip super block and journal areas and bitmap blocks, find how many blocks have to be read */ tmp = 0; for (i = 0; i <= fs->s_sbh->b_blocknr; i ++) { if (!reiserfs_bitmap_test_bit (fsck_disk_bitmap (fs), i)) continue; reiserfs_bitmap_clear_bit (fsck_disk_bitmap (fs), i); tmp ++; } /* unmark bitmaps */ for (i = 0; i < rs_bmap_nr (fs->s_rs); i ++) { unsigned long block; block = SB_AP_BITMAP (fs)[i]->b_blocknr; if (!reiserfs_bitmap_test_bit (fsck_disk_bitmap (fs), block)) continue; reiserfs_bitmap_clear_bit (fsck_disk_bitmap (fs), block); tmp ++; } /* unmark journal area */ for (i = rs_journal_start (fs->s_rs); i <= rs_journal_start (fs->s_rs) + rs_journal_size (fs->s_rs); i ++) { if (!reiserfs_bitmap_test_bit (fsck_disk_bitmap (fs), i)) continue; reiserfs_bitmap_clear_bit (fsck_disk_bitmap (fs), i); tmp ++; } reiserfs_warning (stderr, "Skipping %d blocks (super block, journal, " "bitmaps) %d blocks will be read\n", tmp, reiserfs_bitmap_ones (fsck_disk_bitmap (fs))); #if 0 { int tmp = 0; int tmp2 = 0; int tmp3 = 0; int j; for (i = 0; i < block_count; i += 32) { if (i + 32 < block_count && !*(int *)&(fsck_disk_bitmap (fs)->bm_map[i/8])) { tmp2 ++; continue; } tmp3 ++; for (j = 0; j < 32 && ((i + j) < block_count); j ++) { if (!reiserfs_bitmap_test_bit (fsck_disk_bitmap (fs), i + j)) continue; if (not_data_block (fs, i + j)) { reiserfs_bitmap_clear_bit (fsck_disk_bitmap (fs), i + j); tmp ++; continue; } } } /* for (i = 0; i < block_count; i ++) { if (!fsck_disk_bitmap (fs)->bm_map[i / 8]) continue; if (!reiserfs_bitmap_test_bit (fsck_disk_bitmap (fs), i)) continue; if (not_data_block (fs, i)) { if (reiserfs_bitmap_test_bit (fsck_disk_bitmap (fs), i)) tmp ++; reiserfs_bitmap_clear_bit (fsck_disk_bitmap (fs), i); continue; } } */ reiserfs_warning (stderr, "%d not data blocks cleared (skipped %d checked %d)\n", tmp, tmp2, tmp3); } #endif fsck_new_bitmap (fs) = reiserfs_create_bitmap (SB_BLOCK_COUNT (fs)); /* mark_block_used skips 0, ste the bit explicitly */ reiserfs_bitmap_set_bit (fsck_new_bitmap (fs), 0); /* mark other skipped blocks and super block used */ for (i = 1; i <= SB_BUFFER_WITH_SB (fs)->b_blocknr; i ++) mark_block_used (i); /* mark bitmap blocks as used */ for (i = 0; i < SB_BMAP_NR (fs); i ++) mark_block_used (SB_AP_BITMAP (fs)[i]->b_blocknr); /* mark journal area as used */ for (i = 0; i < JOURNAL_BLOCK_COUNT + 1; i ++) mark_block_used (i + SB_JOURNAL_BLOCK (fs)); uninsertable_leaf_bitmap = reiserfs_create_bitmap (SB_BLOCK_COUNT (fs)); reiserfs_bitmap_fill (uninsertable_leaf_bitmap); fsck_allocable_bitmap (fs) = reiserfs_create_bitmap (SB_BLOCK_COUNT (fs)); reiserfs_bitmap_fill (fsck_allocable_bitmap (fs)); } #define REBUILD_WARNING \ "\nThis is an experimental version of reiserfsck, MAKE A BACKUP FIRST!\n\ Don't run this program unless something is broken. \n\ Some types of random FS damage can be recovered\n\ from by this program, which basically throws away the internal nodes\n\ of the tree and then reconstructs them. This program is for use only\n\ by the desperate, and is of only beta quality. Email\n\ reiserfs@devlinux.com with bug reports. \nWill rebuild the filesystem tree\n" /* warning #2 you seem to be running this automatically. you are almost certainly doing it by mistake as a result of some script that doesn't know what it does. doing nothing, rerun without -p if you really intend to do this. */ void warn_what_will_be_done (struct fsck_data * data) { fsck_progress ("\n"); /* warn about fsck mode */ switch (data->mode) { case FSCK_CHECK: fsck_progress ("Will read-only check consistency of the partition\n"); if (data->options & OPT_FIX_FIXABLE) fsck_progress ("\tWill fix what can be fixed w/o --rebuild-tree\n"); break; case FSCK_SB: fsck_progress ("Will check SB and rebuild if it is needed\n"); break; case FSCK_REBUILD: { fsck_progress (REBUILD_WARNING); if (data->options & OPT_INTERACTIVE) fsck_progress ("\tWill stop after every stage and ask for " "confirmation before continuing\n"); if (data->options & OPT_SAVE_EXTERN_BITMAP) fsck_progress ("Will save list of found leaves in '%s'\n", data->new_bitmap_file_name); if (data->bitmap_file_name) fsck_progress ("\tWill try to load bitmap of leaves from file '%s'\n", data->bitmap_file_name); if (data->options & OPT_FIX_NON_CRITICAL) fsck_progress ("\tWill fix following non-critical things:\n" "\t\tunknown file modes will be set to regular files\n" "\t\tfile sizes will be set to real file size\n" "\t\tfiles sharing busy inode number will be relocated\n"); break; } case FSCK_ZERO_FILES: fsck_progress ("Will zero existing files and mark free blocks as used\n"); } fsck_progress ("Will put log info to '%s'\n", (data->log != stderr) ? data->log_file_name : "stderr"); if (!user_confirmed ("Do you want to run this program?[N/Yes] (note need to type Yes):", "Yes\n")) exit (0); } static void start_rebuild (reiserfs_filsys_t fs) { reset_super_block (fs); init_bitmaps (fs); proper_id_map (fs) = init_id_map (); semantic_id_map (fs) = init_id_map (); } /* called before semantic pass starts */ static void end_rebuilding (reiserfs_filsys_t fs) { reiserfs_flush_bitmap (fsck_new_bitmap (fs), fs); flush_objectid_map (proper_id_map (fs), fs); set_fsck_state (fs->s_rs, TREE_IS_BUILT); set_free_blocks (fs->s_rs, reiserfs_bitmap_zeros (fsck_new_bitmap (fs))); mark_buffer_dirty (SB_BUFFER_WITH_SB (fs)); /* write all dirty blocks */ fsck_progress ("Syncing.."); fflush (stdout); reiserfs_flush (fs); fsck_progress ("done\n"); fflush (stdout); /* release what will not be needed */ reiserfs_delete_bitmap (fsck_disk_bitmap (fs)); reiserfs_delete_bitmap (fsck_allocable_bitmap (fs)); /* FIXME: could be not a bitmap */ reiserfs_delete_bitmap (uninsertable_leaf_bitmap); if (fsck_user_confirmed (fs, "Tree building completed. " "You can stop now and restart from this point later " "(this is probably not what you need). Do you want to stop? ", "Yes\n", 0/*default*/)) { reiserfs_close (fs); exit (4); } } static int skip_rebuilding (reiserfs_filsys_t fs) { if (fsck_state (fs->s_rs) == TREE_IS_BUILT) { if (fsck_user_confirmed (fs, "S+ tree of filesystem looks built. Skip rebuilding? ", "Yes\n", 0/*default*/)) { fsck_new_bitmap (fs) = reiserfs_create_bitmap (SB_BLOCK_COUNT (fs)); reiserfs_fetch_disk_bitmap (fsck_new_bitmap (fs), fs); proper_id_map (fs) = init_id_map (); fetch_objectid_map (proper_id_map (fs), fs); semantic_id_map (fs) = init_id_map (); return 1; } } return 0; } static void start_continuing (reiserfs_filsys_t fs) { fsck_allocable_bitmap (fs) = reiserfs_create_bitmap (SB_BLOCK_COUNT (fs)); reiserfs_bitmap_copy (fsck_allocable_bitmap (fs), fsck_new_bitmap (fs)); } static void the_end (reiserfs_filsys_t fs) { reiserfs_flush_bitmap (fsck_new_bitmap (fs), fs); flush_objectid_map (proper_id_map (fs), fs); set_fsck_state (fs->s_rs, 0); set_free_blocks (fs->s_rs, reiserfs_bitmap_zeros (fsck_new_bitmap (fs))); set_state (fs->s_rs, REISERFS_VALID_FS); mark_buffer_dirty (SB_BUFFER_WITH_SB (fs)); /* write all dirty blocks */ fsck_progress ("Syncing.."); fflush (stderr); reiserfs_flush (fs); sync (); fsck_progress ("done\n"); fflush (stderr); reiserfs_delete_bitmap (fsck_new_bitmap (fs)); free_id_map (&proper_id_map(fs)); if (semantic_id_map(fs)) free_id_map (&semantic_id_map(fs)); reiserfs_close (fs); fsck_progress ("Done\n"); fflush (stderr); } static void rebuild_tree (reiserfs_filsys_t fs) { if (is_mounted (fs->file_name)) { fsck_progress ("rebuild_tree: can not rebuild tree of mounted filesystem\n"); return; } reiserfs_reopen (fs, O_RDWR); /* FIXME: for regular file take care of of file size */ /* rebuild starts with journal replaying */ reiserfs_replay_journal (fs); if (!skip_rebuilding (fs)) { fsck_progress ("Rebuilding..\n"); start_rebuild (fs); pass_0 (fs); /* passes 1 and 2. building of the tree */ pass_1_pass_2_build_the_tree (); end_rebuilding (fs); } /* re-building of filesystem tree is now separated of sematic pass of the fsck */ start_continuing (fs); /* 3. semantic pass */ pass_3_semantic (); /* if --lost+found is set - link unaccessed directories to lost+found directory */ pass_3a_look_for_lost (fs); /* 4. look for unaccessed items in the leaves */ pass_4_check_unaccessed_items (); the_end (fs); } static void zero_files (reiserfs_filsys_t fs) { init_bitmaps (fs); reiserfs_reopen (fs, O_RDWR); pass_0 (fs); } /* check umounted or read-only mounted filesystems only */ static void check_fs (reiserfs_filsys_t fs) { if (!is_mounted (fs->file_name)) { /* filesystem is not mounted, replay journal before checking */ reiserfs_reopen (fs, O_RDWR); reiserfs_replay_journal (fs); reiserfs_reopen (fs, O_RDONLY); } else { /* filesystem seems mounted. we do not check filesystems mounted with r/w permissions */ if (!is_mounted_read_only (fs->file_name)) { fsck_progress ("Device %s is mounted w/ write permissions, can not check it\n", fs->file_name); reiserfs_close (fs); exit (0); } fsck_progress ("Filesystem seems mounted read-only. Skipping journal replay..\n"); if (fsck_fix_fixable (fs)) { fsck_progress ("--fix-fixable ignored\n"); stats(fs)->options &= ~OPT_FIX_FIXABLE; } } fsck_disk_bitmap (fs) = reiserfs_create_bitmap (SB_BLOCK_COUNT (fs)); reiserfs_fetch_disk_bitmap (fsck_disk_bitmap (fs), fs); if (fsck_fix_fixable (fs)) reiserfs_reopen (fs, O_RDWR); /*proper_id_map (fs) = init_id_map ();*/ semantic_id_map (fs) = init_id_map (); check_fs_tree (fs); semantic_check (); reiserfs_delete_bitmap (fsck_disk_bitmap (fs)); /*free_id_map (proper_id_map (fs));*/ free_id_map (&semantic_id_map (fs)); reiserfs_close (fs); } #include int main (int argc, char * argv []) { char * file_name; struct fsck_data * data; struct rlimit rlim = {0xffffffff, 0xffffffff}; print_banner ("reiserfsck"); /* this is only needed (and works) when running under 2.4 on regural files */ if (setrlimit (RLIMIT_FSIZE, &rlim) == -1) { reiserfs_warning (stderr, "could not setrlimit: %m"); } data = getmem (sizeof (struct fsck_data)); file_name = parse_options (data, argc, argv); if (data->mode == DO_NOTHING) { freemem (data); return 0; } warn_what_will_be_done (data); /* and ask confirmation Yes */ fs = reiserfs_open (file_name, O_RDONLY, 0, data); if (!fs) die ("reiserfsck: could not open filesystem on \"%s\"", file_name); if (fsck_mode (fs) == FSCK_SB) { reiserfs_reopen (fs, O_RDWR); rebuild_sb (fs); reiserfs_close (fs); return 0; } if (no_reiserfs_found (fs)) { fsck_progress ("reiserfsck: --rebuild-sb may restore reiserfs super block\n"); reiserfs_close (fs); return 0; } fs->block_allocator = reiserfsck_reiserfs_new_blocknrs; fs->block_deallocator = reiserfsck_reiserfs_free_block; if (fsck_mode (fs) == FSCK_CHECK) { check_fs (fs); return 0; } #ifdef FAST_REBUILD_READY /* and tested */ if (opt_fsck_mode == FSCK_FAST_REBUILD) { __u32 root_block = SB_ROOT_BLOCK(fs); reopen_read_write (file_name); printf ("Replaying log.."); reiserfs_replay_journal (fs); printf ("done\n"); if (opt_fsck == 1) printf ("ReiserFS : checking %s\n",file_name); else printf ("Rebuilding..\n"); reset_super_block (fs); SB_DISK_SUPER_BLOCK(fs)->s_root_block = cpu_to_le32 (root_block); init_bitmaps (fs); /* 1,2. building of the tree */ recover_internal_tree(fs); /* 3. semantic pass */ pass3_semantic (); /* if --lost+found is set - link unaccessed directories to lost+found directory */ look_for_lost (fs); /* 4. look for unaccessed items in the leaves */ pass4_check_unaccessed_items (); end_fsck (); } #endif /* FAST REBUILD READY */ if (fsck_mode (fs) == FSCK_ZERO_FILES) zero_files (fs); if (fsck_mode (fs) != FSCK_REBUILD && fsck_mode (fs) != DO_TEST) return 0; /* the --rebuild-tree is here */ rebuild_tree (fs); return 0; } reiserfsprogs-3.x.0j/fsck/pass0.c0000644000076400001440000012062107261175557012513 /* * Copyright 1996-2001 Hans Reiser */ #include "fsck.h" static unsigned long tmp_zeroed; /* pass 0 scans the partition (used part). It creates two maps which will be used on the pass 1. These are a map of nodes looking like leaves and a map of "bad" unformatted nodes. */ /* leaves */ reiserfs_bitmap_t leaves_bitmap; #define pass0_is_leaf(block) __is_marked (leaves, block) #define pass0_mark_leaf(block) __mark (leaves, block) /* nodes which are referred to from only one indirect item */ reiserfs_bitmap_t good_unfm_bitmap; #define pass0_is_good_unfm(block) __is_marked (good_unfm, block) #define pass0_mark_good_unfm(block) __mark (good_unfm, block) #define pass0_unmark_good_unfm(block) __unmark (good_unfm, block) /* nodes which are referred to from more than one indirect item */ reiserfs_bitmap_t bad_unfm_bitmap; #define pass0_is_bad_unfm(block) __is_marked (bad_unfm, block) #define pass0_mark_bad_unfm(block) __mark (bad_unfm, block) #define pass0_unmark_bad_unfm(block) __unmark (bad_unfm, block) /* there are three way to say of which blocks the tree should be built off: default - */ static void make_aux_bitmaps (reiserfs_filsys_t fs) { /* bitmap of leaves found on the device. It will be saved if -c specified */ leaves_bitmap = reiserfs_create_bitmap (SB_BLOCK_COUNT (fs)); good_unfm_bitmap = reiserfs_create_bitmap (SB_BLOCK_COUNT (fs)); bad_unfm_bitmap = reiserfs_create_bitmap (SB_BLOCK_COUNT (fs)); } /* register block some indirect item points to */ static void register_unfm (unsigned long block) { if (!pass0_is_good_unfm (block) && !pass0_is_bad_unfm (block)) { /* this block was not pointed by other indirect items yet */ pass0_mark_good_unfm (block); return; } if (pass0_is_good_unfm (block)) { /* block was pointed once already, unmark it in bitmap of good unformatted nodes and mark in bitmap of bad pointers */ pass0_unmark_good_unfm (block); pass0_mark_bad_unfm (block); return; } assert (pass0_is_bad_unfm (block)); } /* 'upper' item is correct if 'upper + 2' exists and its key is greater than key of 'upper' */ static int upper_correct (struct buffer_head * bh, struct item_head * upper, int upper_item_num) { if (upper_item_num + 2 < B_NR_ITEMS (bh)) { if (comp_keys (&upper->ih_key, &(upper + 2)->ih_key) != -1) /* item-num's item is out of order of order */ return 0; return 1; } /* there is no item above the "bad pair" */ return 2; } /* 'lower' item is correct if 'lower - 2' exists and its key is smaller than key of 'lower' */ static int lower_correct (struct buffer_head * bh, struct item_head * lower, int lower_item_num) { if (lower_item_num - 2 >= 0) { if (comp_keys (&(lower - 2)->ih_key, &lower->ih_key) != -1) return 0; return 1; } return 2; } /* return 1 if something was changed */ static int correct_key_format (struct item_head * ih) { int dirty = 0; if (is_stat_data_ih (ih)) { /* for stat data we have no way to check whether key format in item head matches to the key format found from the key directly */ if (ih_item_len (ih) == SD_V1_SIZE) { if (ih_key_format (ih) != KEY_FORMAT_1) { fsck_log ("correct_key_format: ih_key_format of (%H) is set to format 1\n", ih); set_key_format (ih, KEY_FORMAT_1); return 1; } return 0; } if (ih_item_len (ih) == SD_SIZE) { if (ih_key_format (ih) != KEY_FORMAT_2) { fsck_log ("correct_key_format: ih_key_format of (%H) is set to format 2\n", ih); set_key_format (ih, KEY_FORMAT_2); return 1; } return 0; } die ("stat data of wrong length"); } if (key_format (&ih->ih_key) != ih_key_format (ih)) { fsck_log ("correct_key_format: ih_key_format of (%H) is set to format found in the key\n", ih); set_key_format (ih, key_format (&ih->ih_key)); dirty = 1; } if (type_unknown (&ih->ih_key)) { /* FIXME: */ set_type (key_format (&ih->ih_key), &ih->ih_key, TYPE_DIRECT); dirty = 1; } return dirty; } #if 0 /* fixme: we might try all available hashes */ static int prob_name (reiserfs_filsys_t fs, char ** name, int max_len, __u32 deh_offset) { int start; /* */ int len; for (start = 0; start < max_len; start ++) { for (len = 0; len < max_len - start; len ++) { if (is_properly_hashed (fs, *name + start, len + 1, deh_offset)) { *name = *name + start; return len + 1; } } } return 0; } #endif static void hash_hits_init (reiserfs_filsys_t fs) { stats (fs)->hash_amount = known_hashes (); stats (fs)->hash_hits = getmem (sizeof (unsigned long) * stats (fs)->hash_amount); return; } static void add_hash_hit (reiserfs_filsys_t fs, int hash_code) { stats (fs)->hash_hits [hash_code] ++; } /* deh_location look reasonable, try to find name length. return 0 if we failed */ static int try_to_get_name_length (struct item_head * ih, struct reiserfs_de_head * deh, int i) { int len; len = name_length (ih, deh, i); if (i == 0 || !de_bad_location (deh - 1)) return (len > 0) ? len : 0; /* previous entry had bad location so we had no way to find name length */ return 0; } /* define this if you are using -t to debug recovering of corrupted directory item */ #define DEBUG_VERIFY_DENTRY #undef DEBUG_VERIFY_DENTRY /* check directory item and try to recover something */ static int verify_directory_item (reiserfs_filsys_t fs, struct buffer_head * bh, int item_num) { struct item_head * ih; struct item_head tmp; char * item; struct reiserfs_de_head * deh; char * name; int name_len; int bad; int i, j; #if 0 int bad_entries; /* how many bad neighboring entries */ int total_entry_len; char * entries, * end; #endif int dirty; int entry_count; int hash_code; int bad_locations; #ifdef DEBUG_VERIFY_DENTRY char * direntries; #endif ih = B_N_PITEM_HEAD (bh, item_num); item = B_I_PITEM (bh,ih); deh = (struct reiserfs_de_head *)item; dirty = 0; bad_locations = 0; entry_count = ih_entry_count (ih); /* check deh_location */ for (i = 0; i < ih_entry_count (ih); i ++) { /* silently fix deh_state */ if (deh [i].deh_state != (1 << DEH_Visible)) { deh [i].deh_state = cpu_to_le16 (1 << DEH_Visible); mark_buffer_dirty (bh); } if (dir_entry_bad_location (deh + i, ih, !i)) mark_de_bad_location (deh + i); } #ifdef DEBUG_VERIFY_DENTRY direntries = getmem (ih_entry_count (ih) * sizeof (int)); printf ("entries with bad locations: "); for (i = 0; i < ih_entry_count (ih); i ++) { if (de_bad_location (deh + i)) printf ("%d ", i); } printf ("\n"); #endif /* DEBUG_VERIFY_DENTRY */ /* find entries names in which have mismatching deh_offset */ for (i = ih_entry_count (ih) - 1; i >= 0; i --) { if (de_bad (deh + i)) /* bad location */ continue; if (i) { if (deh_location (deh + i - 1) < deh_location (deh + i)) mark_de_bad_location (deh + i - 1); } name = name_in_entry (deh + i, i); /* we found a name, but we not always we can get its length as it depends on deh_location of previous entry */ name_len = try_to_get_name_length (ih, deh + i, i); #ifdef DEBUG_VERIFY_DENTRY if (name_len == 0) printf ("trying to find name length for %d-th entry\n", i); #endif /* DEBUG_VERIFY_DENTRY */ if (is_dot (name, name_len)) { if (i != 0) fsck_log ("block %lu: item %d: \".\" is %d-th entry\n", bh->b_blocknr, item_num, i); /* check and fix "." */ if (deh_offset (deh + i) != DOT_OFFSET) { deh[i].deh_offset = cpu_to_le32 (DOT_OFFSET); mark_buffer_dirty (bh); } /* "." must point to the directory it is in */ if (not_of_one_file (&(deh[i].deh_dir_id), &(ih->ih_key))) { fsck_log ("verify_direntry: block %lu, item %H has entry \".\" " "pointing to (%K) instead of (%K)\n", bh->b_blocknr, ih, &(deh[i].deh_dir_id), &(ih->ih_key)); deh[i].deh_dir_id = key_dir_id (&ih->ih_key); deh[i].deh_objectid = key_objectid (&ih->ih_key); mark_buffer_dirty (bh); } } else if (is_dot_dot (name, name_len)) { if (i != 1) fsck_log ("block %lu: item %d: \"..\" is %d-th entry\n", bh->b_blocknr, item_num, i); /* check and fix ".." */ if (deh_offset (deh + i) != DOT_DOT_OFFSET) deh[i].deh_offset = cpu_to_le32 (DOT_DOT_OFFSET); } else { int min_length, max_length; /* check other name */ if (name_len == 0) { /* we do not know the length of name - we will try to find it */ min_length = 1; max_length = item + ih_item_len (ih) - name; } else /* we kow name length, so we will try only one name length */ min_length = max_length = name_len; for (j = min_length; j <= max_length; j ++) { hash_code = find_hash_in_use (name, j, GET_HASH_VALUE (deh_offset (deh + i)), rs_hash (fs->s_rs)); add_hash_hit (fs, hash_code); if (code2func (hash_code) != 0) { /* deh_offset matches to some hash of the name */ if (!name_len) { fsck_log ("pass0: block %lu, item %H: entry %d. found a name \"%.*s\" " "matching to deh_offset %u. FIXME: should set deh_location " "of previous entry (not ready)\n", bh->b_blocknr, ih, i, j, name, deh_offset (deh + i)); /* FIXME: if next byte is 0 we think that the name is aligned to 8 byte boundary */ if (i) { deh[i - 1].deh_location = cpu_to_le16 (deh_location (deh + i) + ((name[j] || SB_VERSION (fs) == REISERFS_VERSION_1) ? j : ROUND_UP (j))); mark_de_good_location (deh + i - 1); mark_buffer_dirty (bh); } } break; } } if (j == max_length + 1) { /* deh_offset does not match to anything. it will be deleted for now, but maybe we could just fix a deh_offset if it is in ordeer */ mark_de_bad_offset (deh + i); } } } /* for */ #if 0 /* find entries names in which have mismatching deh_offset */ for (i = 0; i < ih_entry_count (ih); i ++) { if (de_bad (deh + i)) /* bad location */ continue; name = name_in_entry (deh + i, i); /* we found a name, but we not always we can get its length as it depends on deh_location of previous entry */ name_len = try_to_get_name_length (ih, deh + i, i); if (i == 0 && is_dot (name, name_len)) { /* check and fix "." */ if (deh_offset (deh + i) != DOT_OFFSET) { deh[i].deh_offset = cpu_to_le32 (DOT_OFFSET); mark_buffer_dirty (bh); } /* "." must point to the directory it is in */ if (not_of_one_file (&(deh[i].deh_dir_id), &(ih->ih_key))) { fsck_log ("verify_direntry: block %lu, item %H has entry \".\" " "pointing to (%K) instead of (%K)\n", bh->b_blocknr, ih, &(deh[i].deh_dir_id), &(ih->ih_key)); deh[i].deh_dir_id = key_dir_id (&ih->ih_key); deh[i].deh_objectid = key_objectid (&ih->ih_key); mark_buffer_dirty (bh); } } else if (i == 1 && is_dot_dot (name, name_len)) { /* check and fix ".." */ if (deh_offset (deh + i) != DOT_DOT_OFFSET) deh[i].deh_offset = cpu_to_le32 (DOT_DOT_OFFSET); } else { int min_length, max_length; /* check other name */ if (name_len == 0) { /* we do not know the length of name - we will try to find it */ min_length = 1; max_length = item + ih_item_len (ih) - name; } else /* we kow name length, so we will try only one name length */ min_length = max_length = name_len; for (j = min_length; j <= max_length; j ++) { hash_code = find_hash_in_use (name, j, GET_HASH_VALUE (deh_offset (deh + i)), rs_hash (fs->s_rs)); add_hash_hit (fs, hash_code); if (code2func (hash_code) != 0) { /* deh_offset matches to some hash of the name */ if (!name_len) { fsck_log ("pass0: block %lu, item %H: entry %d. found a name \"%.*s\" " "matching to deh_offset %u. FIXME: should set deh_location " "of previous entry (not ready)\n", bh->b_blocknr, ih, i, j, name, deh_offset (deh + i)); /* FIXME: if next byte is 0 we think that the name is aligned to 8 byte boundary */ deh[i - 1].deh_location = cpu_to_le16 (deh_location (deh + i) + ((name[j] || SB_VERSION (fs) == REISERFS_VERSION_1) ? j : ROUND_UP (j))); } break; } } if (j == max_length + 1) { /* deh_offset does not match to anything. it will be deleted for now, but maybe we could just fix a deh_offset if it is in ordeer */ mark_de_bad_offset (deh + i); } } } #endif #ifdef DEBUG_VERIFY_DENTRY printf ("entries with mismatching deh_offsets: "); for (i = 0; i < ih_entry_count (ih); i ++) { if (de_bad_offset (deh + i)) printf ("%d ", i); } printf ("\n"); #endif /* DEBUG_VERIFY_DENTRY */ /* correct deh_locations such that code cutting entries will not get screwed up */ { int prev_loc; int loc_fixed; prev_loc = ih_item_len (ih); for (i = 0; i < ih_entry_count (ih); i ++) { loc_fixed = 0; if (de_bad_location (deh + i)) { deh[i].deh_location = cpu_to_le16 (prev_loc/* - 1*/); mark_buffer_dirty (bh); loc_fixed = 1; } else { if (deh_location (deh + i) >= prev_loc) { deh[i].deh_location = cpu_to_le16 (prev_loc/* - 1*/); mark_buffer_dirty (bh); loc_fixed = 1; } } prev_loc = deh_location (deh + i); if (i == ih_entry_count (ih) - 1) { /* last entry starts right after an array of dir entry headers */ if (!de_bad (deh + i) && deh_location (deh + i) != (DEH_SIZE * ih_entry_count (ih))) { /* free space in the directory item */ fsck_log ("verify_direntry: block %lu, item %H has free space\n", bh->b_blocknr, ih); cut_entry (fs, bh, item_num, ih_entry_count (ih), 0); } if (deh_location (deh + i) != (DEH_SIZE * ih_entry_count (ih))) { deh[i].deh_location = cpu_to_le16 (DEH_SIZE * ih_entry_count (ih)); loc_fixed = 1; mark_buffer_dirty (bh); } } #ifdef DEBUG_VERIFY_DENTRY if (loc_fixed) direntries [i] = 1; #endif } /* for */ #ifdef DEBUG_VERIFY_DENTRY printf ("entries with fixed deh_locations: "); for (i = 0; i < ih_entry_count (ih); i ++) { if (direntries [i]) printf ("%d ", i); } printf ("\n"); #endif /* DEBUG_VERIFY_DENTRY */ } #ifdef DEBUG_VERIFY_DENTRY printf (" N location name\n"); for (i = 0; i < ih_entry_count (ih); i ++) { if (de_bad (deh + i) || (i && de_bad (deh + i - 1)) || /* previous entry marked bad */ (i < ih_entry_count (ih) - 1 && de_bad (deh + i + 1))) { /* next entry is marked bad */ /* print only entries to be deleted and their nearest neighbors */ printf ("%3d: %8d ", i, deh_location (deh + i)); if (de_bad (deh + i)) printf ("will be deleted\n"); else printf ("\"%.*s\"\n", name_length (ih, deh + i, i), name_in_entry (deh + i, i)); } } #endif bad = 0; tmp = *ih; /* delete entries which are marked bad */ for (i = 0; i < ih_entry_count (ih); i ++) { deh = B_I_DEH (bh, ih) + i; if (de_bad (deh)) { bad ++; if (ih_entry_count (ih) == 1) { delete_item (fs, bh, item_num); break; } else { cut_entry (fs, bh, item_num, i, 1); } i --; } } if (bad == ih_entry_count (&tmp)) { fsck_log ("pass0: block %lu, item %H - all entries were deleted\n", bh->b_blocknr, &tmp); return 0; } deh = B_I_DEH (bh, ih); if (get_offset (&ih->ih_key) != deh_offset (deh)) { fsck_log ("verify_direntry: block %lu, item %H: k_offset and deh_offset %u mismatched\n", bh->b_blocknr, ih, deh_offset (deh)); set_offset (KEY_FORMAT_1, &ih->ih_key, deh_offset (deh)); mark_buffer_dirty (bh); } if (bad) fsck_log ("pass0: block %lu, item %H: %d entries were deleted of \n", bh->b_blocknr, &tmp, bad); return 0; #if 0 /* FIXME: temporary */ if (bad_locations > ih_entry_count (ih) / 2) { fsck_log ("pass0: block %u: item %d (%H) had too bad directory - deleted\n", bh->b_blocknr, item_num, ih); delete_item (fs, bh, item_num); return 0; } if (!dirty) return 0; /* something is broken */ fsck_log ("pass0: block %lu: %d-th item (%H) has %d bad entries..", bh->b_blocknr, item_num, ih, dirty); if (get_offset (&ih->ih_key) == DOT_OFFSET) { /* first item of directory - make sure that "." and ".." are in place */ if (deh_offset (deh) != DOT_OFFSET || name_in_entry (deh, 0)[0] != '.') { deh->deh_offset = cpu_to_le32 (DOT_OFFSET); name_in_entry (deh, 0)[0] = '.'; } if (deh_offset (deh + 1) != DOT_DOT_OFFSET || name_in_entry (deh + 1, 1)[0] != '.' || name_in_entry (deh + 1, 1)[1] != '.') { (deh + 1)->deh_offset = cpu_to_le32 (DOT_DOT_OFFSET); name_in_entry (deh + 1, 1)[0] = '.'; name_in_entry (deh + 1, 1)[1] = '.'; } } end = item + ih_item_len (ih); deh += ih_entry_count (ih); entries = (char *)deh; total_entry_len = ih_item_len (ih) - DEH_SIZE * ih_entry_count (ih); i = ih_entry_count (ih); bad_entries = 0; do { i --; deh --; name_len = prob_name (fs, &entries, total_entry_len, deh_offset (deh)); if (!name_len) { if (!bad_entries) { deh->deh_location = cpu_to_le16 (entries - item); } else { deh->deh_location = cpu_to_le16 (deh_location (deh + 1) + 1); } bad_entries ++; /*fsck_log ("verify_directory_item: entry %d: in string \'%s\' there is no substring matching hash %ld\n", i, bad_name (entries, total_entry_len), masked_offset);*/ mark_de_bad (deh); continue; } bad_entries = 0; /*fsck_log ("verify_directory_item: entry %d: found \"%s\" name matching hash %ld\n", i, bad_name (entries, name_len), masked_offset);*/ /* 'entries' points now to the name which match given offset - so, set deh_location */ deh->deh_location = cpu_to_le16 (entries - item); deh->deh_state = 0; mark_de_visible (deh); entries += name_len; total_entry_len = end - entries; /* skip padding zeros */ while (!*entries) { entries ++; total_entry_len --; } /* 'entries' points now at the place where next (previous) entry should start */ } while ((char *)deh != item); /* fixme: this will not work if all entries are to be deleted */ for (i = 0; i < ih_entry_count (ih); i ++, deh ++) { deh = (struct reiserfs_de_head *)B_I_PITEM (bh, ih) + i; if (de_bad (deh)) { if (ih_entry_count (ih) == 1) { delete_item (fs, bh, i); break; } else { cut_entry (fs, bh, item_num, i); } i --; } /* fsck_log ("verify_directory_item: %d-th entry is to be deleted: " "\"%s\" does not match to hash %lu\n", i, bad_name (name_in_entry (deh, i), name_length (ih, deh, i)), deh_offset (deh)); */ } fsck_log ("%d entries were deleted\n", entry_count - ih_entry_count (ih)); mark_buffer_dirty (bh); return 0; #endif } /* do this on pass 0 with every leaf marked used */ /* FIXME: we can improve fixing of broken keys: we can ssfe direct items which go after stat data and have broken keys */ static void pass0_correct_leaf (reiserfs_filsys_t fs, struct buffer_head * bh) { int i, j; struct item_head * ih; __u32 * ind_item; unsigned long unfm_ptr; int dirty = 0; start_again: ih = B_N_PITEM_HEAD (bh, 0); for (i = 0; i < node_item_number (bh); i ++, ih ++) { if (ih->ih_key.k_dir_id == 0 || ih->ih_key.k_objectid == 0) { /* sometimes stat datas get k_objectid==0 or k_dir_id==0 */ if (i == (node_item_number (bh) - 1)) { /* */ if (i == 0) { fsck_log ("block %lu: item %d: (%H) is alone in the block\n", bh->b_blocknr, i, ih); return; } /* delete last item */ delete_item (fs, bh, i - 1); return; } /* there is next item: if it is not stat data - take its k_dir_id and k_objectid. if key order will be still wrong - the changed item will be deleted */ if (!is_stat_data_ih (ih + 1)) { fsck_log ("block %lu: item %d: (%H) fixed to ", bh->b_blocknr, i, ih); ih->ih_key.k_dir_id = (ih + 1)->ih_key.k_dir_id; ih->ih_key.k_objectid = (ih + 1)->ih_key.k_objectid; set_offset (KEY_FORMAT_1, &ih->ih_key, 0); set_type (KEY_FORMAT_1, &ih->ih_key, TYPE_STAT_DATA); fsck_log ("(%H)\n", ih); dirty = 1; } else if (i == 0) { delete_item (fs, bh, i); goto start_again; } } /* this recovers corruptions like the below: 1774 1732 0 0 116262638 1732 1 3 1774 1736 0 0 */ if (i && is_stat_data_ih (ih - 1) && !is_stat_data_ih (ih)) { if (ih->ih_key.k_objectid != (ih - 1)->ih_key.k_objectid || ih->ih_key.k_dir_id != (ih - 1)->ih_key.k_dir_id || get_offset (&ih->ih_key) != 1) { if (is_direntry_ih (ih)) { fsck_log ("block %lu: item %d: no \".\" entry found in " "the first item of a directory\n", bh->b_blocknr, i); } else { fsck_log ("block %lu: item %d: (%H) fixed to ", bh->b_blocknr, i, ih); ih->ih_key.k_dir_id = (ih - 1)->ih_key.k_dir_id; ih->ih_key.k_objectid = (ih - 1)->ih_key.k_objectid; if (ih_item_len (ih - 1) == SD_SIZE) { /* stat data is new, therefore this item is new too */ set_offset (KEY_FORMAT_2, &(ih->ih_key), 1); if (ih_entry_count (ih) != 0xffff) set_type (KEY_FORMAT_2, &(ih->ih_key), TYPE_INDIRECT); else set_type (KEY_FORMAT_2, &(ih->ih_key), TYPE_DIRECT); set_key_format (ih, KEY_FORMAT_2); } else { /* stat data is old, therefore this item is old too */ set_offset (KEY_FORMAT_1, &(ih->ih_key), 1); if (ih_entry_count (ih) != 0xffff) set_type (KEY_FORMAT_1, &(ih->ih_key), TYPE_INDIRECT); else set_type (KEY_FORMAT_1, &(ih->ih_key), TYPE_DIRECT); set_key_format (ih, KEY_FORMAT_1); } fsck_log ("%H\n", ih); dirty = 1; } } } /* FIXME: corruptions like: 56702 66802 1 2 56702 65536 0 0 56702 66803 1 2 do not get recovered (both last items will be deleted) */ /* delete item if it is not in correct order of object items */ if (i && not_of_one_file (&ih->ih_key, &(ih - 1)->ih_key) && !is_stat_data_ih (ih)) { fsck_log ("block %lu: item %d: %H follows non stat item %H - deleted\n", bh->b_blocknr, i, ih, ih - 1); delete_item (fs, bh, i); goto start_again; } if (i && comp_keys (&(ih - 1)->ih_key, &ih->ih_key) != -1) { /* previous item has key not smaller than the key of currect item */ if (is_stat_data_ih (ih - 1) && !is_stat_data_ih (ih)) { /* fix key of stat data such as if it was stat data of that item */ fsck_log ("pass0: block %lu: %d-th item %k is out of order, made a stat data of %d-th (%k)\n", bh->b_blocknr, i - 1, &(ih - 1)->ih_key, i, &ih->ih_key); (ih - 1)->ih_key.k_dir_id = ih->ih_key.k_dir_id; (ih - 1)->ih_key.k_objectid = ih->ih_key.k_objectid; set_offset (KEY_FORMAT_1, &(ih - 1)->ih_key, 0); set_type (KEY_FORMAT_1, &(ih - 1)->ih_key, TYPE_STAT_DATA); dirty = 1; } else { /* ok, we have to delete one of these two - decide which one */ int retval; /* something will be deleted */ dirty = 1; retval = upper_correct (bh, ih - 1, i - 1); switch (retval) { case 0: /* delete upper item */ fsck_log ("pass0: block %lu: %d-th (upper) item (%k) is out of order, deleted\n", bh->b_blocknr, i - 1, &(ih - 1)->ih_key); delete_item (fs, bh, i - 1); goto start_again; case 1: /* delete lower item */ fsck_log ("pass0: block %lu: %d-th (lower) item (%k) is out of order, deleted\n", bh->b_blocknr, i, &ih->ih_key); delete_item (fs, bh, i); goto start_again; default: /* upper item was the first item of a node */ } retval = lower_correct (bh, ih, i); switch (retval) { case 0: /* delete lower item */ fsck_log ("pass0: block %lu: %d-th (lower) item (%k) is out of order, deleted\n", bh->b_blocknr, i, &ih->ih_key); delete_item (fs, bh, i); goto start_again; case 1: /* delete upper item */ fsck_log ("pass0: block %lu: %d-th (upper) item (%k) is out of order, deleted\n", bh->b_blocknr, i - 1, &(ih - 1)->ih_key); delete_item (fs, bh, i - 1); goto start_again; default: /* there wer only two items in a node, so we could not decide what to delete, go and ask user */ } fsck_log ("pass0: which of these items looks better (other will be deleted)?\n" "%H\n%H\n", ih - 1, ih); if (fsck_user_confirmed (fs, "1 or 2?", "1\n", 1)) delete_item (fs, bh, i - 1); else delete_item (fs, bh, i); goto start_again; } } if (is_stat_data_ih (ih) && (ih_item_len (ih) != SD_SIZE && ih_item_len (ih) != SD_V1_SIZE)) { fsck_log ("pass0: block %lu, stat data of wrong length %H - deleted\n", bh, ih); delete_item (fs, bh, i); goto start_again; } dirty += correct_key_format (ih); if (is_stat_data_ih (ih)) { ;/*correct_stat_data (fs, bh, i);*/ } if (is_direntry_ih (ih)) { verify_directory_item (fs, bh, i); continue; } if (!is_indirect_ih (ih)) continue; ind_item = (__u32 *)B_I_PITEM (bh, ih); for (j = 0; j < I_UNFM_NUM (ih); j ++) { unfm_ptr = le32_to_cpu (ind_item [j]); if (!unfm_ptr) continue; if (fsck_mode (fs) == FSCK_ZERO_FILES) { /* FIXME: this is temporary mode of fsck */ ind_item [j] = 0; reiserfs_bitmap_clear_bit (fsck_new_bitmap(fs), unfm_ptr); tmp_zeroed ++; dirty = 1; continue; } if (not_data_block (fs, unfm_ptr) || /* journal area or bitmap or super block */ unfm_ptr >= SB_BLOCK_COUNT (fs)) {/* garbage in pointer */ stats (fs)->wrong_pointers ++; /* fsck_log ("pass0: %d-th pointer (%lu) in item %k (leaf block %lu) is wrong\n", j, unfm_ptr, &ih->ih_key, bh->b_blocknr); */ ind_item [j] = 0; dirty = 1; continue; } #if 0 if (!was_block_used (unfm_ptr)) { /* this will get to a pool of allocable blocks */ ind_item [j] = 0; dirty = 1; stat_wrong_pointer_found (fs); continue; } #endif /* mark block in bitmaps of unformatted nodes */ register_unfm (unfm_ptr); } } /* mark all objectids in use */ ih = B_N_PITEM_HEAD (bh, 0); for (i = 0; i < node_item_number (bh); i ++, ih ++) { mark_objectid_really_used (proper_id_map (fs), le32_to_cpu (ih->ih_key.k_dir_id)); mark_objectid_really_used (proper_id_map (fs), le32_to_cpu (ih->ih_key.k_objectid)); } if (node_item_number (bh) < 1) { /* pass 1 will skip this */ stats(fs)->all_contents_removed ++; fsck_log ("pass0: block %lu got all items deleted\n", bh->b_blocknr); } else { /* pass1 will use this bitmap */ pass0_mark_leaf (bh->b_blocknr); } if (dirty) { stats(fs)->leaves_corrected ++; mark_buffer_dirty (bh); } } static int is_bad_sd (struct item_head * ih, char * item) { struct stat_data * sd = (struct stat_data *)item; if (ih->ih_key.u.k_offset_v1.k_offset || ih->ih_key.u.k_offset_v1.k_uniqueness) { reiserfs_warning (stderr, "Bad SD? %H\n", ih); return 1; } if (ih_item_len (ih) == SD_V1_SIZE) { /* looks like old stat data */ if (ih_key_format (ih) != KEY_FORMAT_1) fsck_log ("item %H has wrong format\n", ih); return 0; } if (!S_ISDIR (sd->sd_mode) && !S_ISREG(sd->sd_mode) && !S_ISCHR (sd->sd_mode) && !S_ISBLK(sd->sd_mode) && !S_ISLNK (sd->sd_mode) && !S_ISFIFO(sd->sd_mode) && !S_ISSOCK(sd->sd_mode)) { /*fsck_log ("file %k unexpected mode encountered 0%o\n", &ih->ih_key, sd->sd_mode)*/; } return 0; } int is_bad_directory (struct item_head * ih, char * item, int dev, int blocksize) { int i; char * name; int namelen, entrylen; struct reiserfs_de_head * deh = (struct reiserfs_de_head *)item; __u32 prev_offset = 0; __u16 prev_location = ih_item_len (ih); int min_entry_size = 1;/* we have no way to understand whether the filesystem were created in 3.6 format or converted to it. So, we assume that minimal name length is 1 */ if (ih_item_len (ih) / (DEH_SIZE + min_entry_size) < ih_entry_count (ih)) /* entry count is too big */ return 1; for (i = 0; i < ih_entry_count (ih); i ++, deh ++) { entrylen = entry_length(ih, deh, i); if (entrylen > REISERFS_MAX_NAME_LEN (blocksize)) { return 1; } if (deh_offset (deh) <= prev_offset) { return 1; } prev_offset = deh_offset (deh); if (deh_location(deh) + entrylen != prev_location) { return 1; } prev_location = deh_location (deh); namelen = name_length (ih, deh, i); name = name_in_entry (deh, i); if (!is_properly_hashed (fs, name, namelen, deh_offset (deh))) { return 1; } } return 0; } /* change incorrect block adresses by 0. Do not consider such item as incorrect */ static int is_bad_indirect (struct item_head * ih, char * item, int dev, int blocksize) { int i; int bad = 0; int blocks; if (ih_item_len(ih) % UNFM_P_SIZE) { fsck_log ("is_bad_indirect: indirect item of %H of invalid length\n", ih); return 1; } blocks = SB_BLOCK_COUNT (fs); for (i = 0; i < I_UNFM_NUM (ih); i ++) { __u32 * ind = (__u32 *)item; if (le32_to_cpu (ind[i]) >= blocks) { bad ++; fsck_log ("is_bad_indirect: %d-th pointer of item %H looks bad (%lu)\n", i, ih, le32_to_cpu (ind [i])); continue; } } return bad; } /* this is used by pass1.c:save_item and check.c:is_leaf_bad */ int is_bad_item (struct buffer_head * bh, struct item_head * ih, char * item) { int blocksize, dev; blocksize = bh->b_size; dev = bh->b_dev; // FIXME: refuse transparently bad items if (ih->ih_key.k_dir_id == ih->ih_key.k_objectid) return 1; if (!ih->ih_key.k_dir_id || !ih->ih_key.k_objectid) return 1; if (is_stat_data_ih(ih)) return is_bad_sd (ih, item); if (is_direntry_ih (ih)) return is_bad_directory (ih, item, dev, blocksize); if (is_indirect_ih (ih)) return is_bad_indirect (ih, item, dev, blocksize); if (is_direct_ih (ih)) return 0; return 1; } int is_leaf_bad (struct buffer_head * bh) { int i; struct item_head * ih; int bad = 0; assert (is_leaf_node (bh)); for (i = 0, ih = B_N_PITEM_HEAD (bh, 0); i < B_NR_ITEMS (bh); i ++, ih ++) { if (is_bad_item (bh, ih, B_I_PITEM (bh, ih))) { fsck_log ("is_leaf_bad: block %lu: %d-th item (%H) is bad\n", bh->b_blocknr, i, ih); bad = 1; continue; } if (i && bad_pair (fs, bh, i)) { fsck_log ("is_leaf_bad: block %luL %d-th item (%H) and " "the next one (%H) are in wrong order\n", bh->b_blocknr, i - 1, ih - 1, ih); bad = 1; } } return bad; } static void go_through (reiserfs_filsys_t fs) { struct buffer_head * bh; int i; int what_node; unsigned long done = 0, total; if (fsck_mode (fs) == DO_TEST) { /* just to test pass0_correct_leaf */ bh = bread (fs->s_dev, stats(fs)->test, fs->s_blocksize); /* if (is_leaf_bad (bh)) { fsck_progress ("############### bad #################\n"); } */ pass0_correct_leaf (fs, bh); print_block (stdout, fs, bh, 3, -1, -1); if (is_leaf_bad (bh)) { fsck_progress ("############### still bad #################\n"); } brelse (bh); reiserfs_free (fs); exit(4); } total = reiserfs_bitmap_ones (fsck_disk_bitmap (fs)); fsck_progress ("\nPass 0 (%lu (of %lu) blocks will be read):\n", total, SB_BLOCK_COUNT (fs)); for (i = 0; i < SB_BLOCK_COUNT (fs); i ++) { if (!is_to_be_read (fs, i)) continue; print_how_far (&done, total, 1, fsck_quiet (fs)); bh = bread (fs->s_dev, i, fs->s_blocksize); if (!bh) { /* we were reading one block at time, and failed, so mark block bad */ fsck_progress ("pass0: reading block %lu failed\n", i); continue; } if (not_data_block (fs, i)) reiserfs_panic ("not data block found"); stats (fs)->analyzed ++; what_node = who_is_this (bh->b_data, fs->s_blocksize); if ( what_node != THE_LEAF ) { brelse (bh); continue; } pass0_correct_leaf (fs, bh); brelse (bh); } #if 0 for (i = 0; i < SB_BLOCK_COUNT (fs); i += nr_to_read) { to_scan = how_many_to_scan (fs, i, nr_to_read); if (to_scan) { print_how_far (&done, total, to_scan, fsck_quiet (fs)); /* at least one of nr_to_read blocks is to be checked */ bbh = bread (fs->s_dev, i / nr_to_read, fs->s_blocksize * nr_to_read); if (bbh) { for (j = 0; j < nr_to_read; j ++) { if (!is_to_be_read (fs, i + j)) continue; if (not_data_block (fs, i + j)) reiserfs_panic ("not data block found"); stats (fs)->analyzed ++; data = bbh->b_data + j * fs->s_blocksize; what_node = who_is_this (data, fs->s_blocksize); if ( what_node != THE_LEAF ) { continue; } /* the node looks like a leaf, but it still can be not perfect */ bh = make_buffer (fs->s_dev, i + j, fs->s_blocksize, data); /*printf ("block %lu .. ", bh->b_blocknr);fflush(stdout);*/ pass0_correct_leaf (fs, bh); /*printf ("ok\n");fflush(stdout);*/ brelse (bh); } if (buffer_dirty (bbh)) bwrite (bbh); bforget (bbh); } else { done -= to_scan; /* bread failed */ if (nr_to_read != 1) { /* we tryied to read bunch of blocks. Try to read them by one */ nr_to_read = 1; i --; continue; } else { /* we were reading one block at time, and failed, so mark block bad */ fsck_progress ("pass0: block %lu is bad, marked used\n", i); } } } if (nr_to_read == 1 && ((i + 1) % NR_TO_READ) == 0) { /* we have read NR_TO_READ blocks one at time, switch back to reading NR_TO_READ blocks at time */ i -= (NR_TO_READ - 1); nr_to_read = NR_TO_READ; } } #endif /* just in case */ mark_objectid_really_used (proper_id_map (fs), REISERFS_ROOT_OBJECTID); fsck_progress ("\n"); if (fsck_save_leaf_bitmap (fs)) { reiserfs_bitmap_save (stats (fs)->new_bitmap_file_name, leaves_bitmap); } } /* this makes a map of blocks which can be allocated when fsck will continue: */ static void find_allocable_blocks (reiserfs_filsys_t fs) { int i; fsck_progress ("Looking for allocable blocks .. "); stats (fs)->all_blocks = SB_BLOCK_COUNT (fs); /* find how many leaves are not pointed by any indirect items */ for (i = 0; i < SB_BLOCK_COUNT (fs); i ++) { if (not_data_block (fs, i)) continue; #if 0 if (!was_block_used (i)) { /* marked free in the on-disk bitmap - so it is allocable */ make_allocable (i); stat_allocable_found (fs); continue; } #endif if (pass0_is_leaf (i)) { /* block looks like a reiserfs leaf */ stats(fs)->leaves ++; if (pass0_is_good_unfm (i) || pass0_is_bad_unfm (i)) /* leaf to which one or more indirect items point to */ stats(fs)->pointed_leaves ++; } if (pass0_is_good_unfm (i) && pass0_is_bad_unfm (i)) die ("find_allocable_blocks: bad and good unformatted"); if (pass0_is_good_unfm (i)) { /* blocks which were pointed only once */ stats(fs)->pointed ++; stats(fs)->pointed_once ++; continue; } if (pass0_is_bad_unfm (i)) { /* blocks pointed more than once */ stats(fs)->pointed ++; stats(fs)->pointed_more_than_once ++; continue; } /* blocks which marked used but are not leaves and are not pointed (internals in short) get into bitmap of allocable blocks */ if (!pass0_is_leaf (i)) { make_allocable (i); stats(fs)->allocable ++; } } fsck_progress ("ok\n"); } #if 0 int are_there_used_leaves (unsigned long from, int count) { int i; int used; used = 0; for (i = 0; i < count; i ++) { if ((SB_BLOCK_COUNT (fs) > from + i) && pass0_is_leaf (from + i)) used ++; } return used; } #endif int is_used_leaf (unsigned long block) { return pass0_is_leaf (block); } int how_many_leaves_were_there (void) { return stats (fs)->leaves; } /* these are used to correct uformatted node pointers */ int is_bad_unformatted (unsigned long block) { return pass0_is_bad_unfm (block); } /* this is for check only. With this we make sure that all pointers we put into tree on pass 1 do not point to leaves (FIXME), do not point to journal, bitmap, etc, do not point out of fs boundary and are marked used in on-disk bitmap */ int still_bad_unfm_ptr_1 (unsigned long block) { if (!block) return 0; if (pass0_is_leaf (block)) return 1; if (pass0_is_bad_unfm (block) && !is_bad_unfm_in_tree_once (block)) return 1; if (not_data_block (fs, block)) return 1; /* if (!was_block_used (block)) return 1; */ if (block >= stats (fs)->all_blocks) return 1; return 0; } /* pointers to data block which get into tree are checked with this */ int still_bad_unfm_ptr_2 (unsigned long block) { if (!block) return 0; if (is_block_used (block)) return 1; if (block >= stats (fs)->all_blocks) return 1; return 0; } /* these are used to allocate blocks for tree building */ int are_there_allocable_blocks (int amout_needed) { if (reiserfs_bitmap_zeros (fsck_allocable_bitmap (fs)) < amout_needed) { int zeros = 0, i; fsck_progress ("Hmm, there are not enough allocable blocks, checking bitmap...");fflush (stdout); for (i = 0; i < fsck_allocable_bitmap (fs)->bm_bit_size; i ++) if (!reiserfs_bitmap_test_bit (fsck_allocable_bitmap (fs), i)) zeros ++; fsck_progress ("there are %d zeros, btw\n", zeros); return 0; } return 1; } unsigned long alloc_block (void) { unsigned long block = 0; /* FIXME: start point could be used */ if (reiserfs_bitmap_find_zero_bit (fsck_allocable_bitmap (fs), &block)) { die ("alloc_block: allocable blocks counter is wrong"); return 0; } reiserfs_bitmap_set_bit (fsck_allocable_bitmap (fs), block); return block; } void make_allocable (unsigned long block) { reiserfs_bitmap_clear_bit (fsck_allocable_bitmap (fs), block); } unsigned long how_many_uninsertables_were_there (void) { return stats (fs)->uninsertable_leaves; } unsigned long how_many_items_were_saved (void) { return stats (fs)->saved_on_pass1; } static void choose_hash_function (reiserfs_filsys_t fs) { unsigned long max; int hash_code; int i; max = 0; hash_code = func2code (0); for (i = 0; i < stats (fs)->hash_amount; i ++) { /* remember hash whihc got more hits */ if (stats (fs)->hash_hits [i] > max) { hash_code = i; max = stats (fs)->hash_hits [i]; } if (stats (fs)->hash_hits [i]) fsck_log ("%s got %lu hits\n", code2name (i), stats (fs)->hash_hits [i]); } if (max == 0) { /* no names were found. take either super block value or default */ reiserfs_hash (fs) = code2func (rs_hash (fs->s_rs)); if (!reiserfs_hash (fs)) reiserfs_hash (fs) = code2func (DEFAULT_HASH); return; } /* compare the most appropriate hash with the hash set in super block */ if (hash_code != rs_hash (fs->s_rs)) { fsck_progress ("Selected hash (%s) does not match to one set in super block (%s).\n", code2name (hash_code), code2name (rs_hash (fs->s_rs))); /* if (!fsck_user_confirmed (fs, "Overwrite?(Yes)", "Yes", 1)) { fsck_progress ("Not confirmed\n"); exit (4); } */ set_hash (fs->s_rs, hash_code); } else { fsck_progress ("\t%s hash is selected\n", code2name (hash_code)); } reiserfs_hash (fs) = code2func (hash_code); } int pass_0 (reiserfs_filsys_t fs) { if (fsck_log_file (fs) != stderr) /* this is just to separate warnings in the log file */ fsck_log ("####### Pass 0 #######\n"); if (fsck_mode (fs) == FSCK_ZERO_FILES) { reiserfs_bitmap_fill (fsck_new_bitmap (fs)); fsck_progress ("Zeroing existing files - all blocks marked used\n"); } make_aux_bitmaps (fs); /* pass0 gathers statistics about hash hits */ hash_hits_init (fs); /* scan the partition */ go_through (fs); /* find blocks which can be allocated */ find_allocable_blocks (fs); if (fsck_mode (fs) == FSCK_ZERO_FILES) { /* flush bitmaps and exit */ fsck_progress ("Zeroing existing files - zeroed %lu blocks\n", tmp_zeroed); reiserfs_flush_bitmap (fsck_new_bitmap (fs), fs); reiserfs_close (fs); exit (0); } choose_hash_function (fs); stage_report (0, fs); return 0; } #if 0 /* node looks like a leaf (block head and ih_item_length & ih_location of item_head array are correct. This function recovers (tries to) node's key table and directory items. */ static void recover_leaf (reiserfs_filsys_t fs, struct buffer_head * bh) { int i; struct item_head * ih; /* mark transparently corrupted items - bad */ ih = B_N_PITEM_HEAD (bh, 0); for (i = 0; i < node_item_number (bh); i ++, ih ++) { if (type_unknown (&ih->ih_key) || ih->ih_key.k_dir_id == 0 || ih->ih_key.k_objectid) { mark_ih_bad (ih); continue; } } } #endif reiserfsprogs-3.x.0j/fsck/pass1.c0000644000076400001440000005565107260734357012524 /* * Copyright 1996-1999 Hans Reiser */ #include "fsck.h" #include reiserfs_bitmap_t bad_unfm_in_tree_once_bitmap; //int step = 0; // 0 - find stat_data or any item ; 1 - find item ; 2 - already found /* allocates buffer head and copy buffer content */ struct buffer_head * make_buffer (int dev, int blocknr, int size, char * data) { struct buffer_head * bh; bh = getblk (dev, blocknr, size); if (buffer_uptodate (bh)) return bh; // die ("make_buffer: uptodate buffer found"); memcpy (bh->b_data, data, size); set_bit (BH_Uptodate, (char *)&bh->b_state); return bh; } int find_not_of_one_file(struct key * to_find, struct key * key) { if ((to_find->k_objectid != -1) && (to_find->k_objectid != key->k_objectid)) return 1; if ((to_find->k_dir_id != -1) && (to_find->k_dir_id != key->k_dir_id)) return 1; return 0; } int is_item_reachable (struct item_head * ih) { return ih_reachable (ih) ? 1 : 0; } void mark_item_unreachable (struct item_head * ih) { mark_ih_unreachable (ih); if (is_indirect_ih (ih)) set_free_space (ih, 0); } void mark_item_reachable (struct item_head * ih, struct buffer_head * bh) { mark_ih_ok (ih); mark_buffer_dirty (bh); } static void stat_data_in_tree (struct buffer_head *bh, struct item_head * ih) { #if 0 __u32 objectid; objectid = le32_to_cpu (ih->ih_key.k_objectid); if (mark_objectid_really_used (proper_id_map (fs), objectid)) { stat_shared_objectid_found (fs); mark_objectid_really_used (shared_id_map (fs), objectid); } #endif zero_nlink (ih, B_I_PITEM (bh, ih)); } /* this just marks blocks pointed by an indirect item as used in the new bitmap */ static void indirect_in_tree (struct buffer_head * bh, struct item_head * ih) { int i; __u32 * unp; unsigned long unfm_ptr; unp = (__u32 *)B_I_PITEM (bh, ih); for (i = 0; i < I_UNFM_NUM (ih); i ++) { unfm_ptr = le32_to_cpu (unp[i]); if (unfm_ptr == 0) continue; if (still_bad_unfm_ptr_1 (unfm_ptr)) reiserfs_panic ("mark_unformatted_used: (%lu: %k) " "still has bad pointer %lu", bh->b_blocknr, &ih->ih_key, unfm_ptr); mark_block_used (unfm_ptr); } } static void leaf_is_in_tree_now (struct buffer_head * bh) { item_action_t actions[] = {stat_data_in_tree, indirect_in_tree, 0, 0}; mark_block_used ((bh)->b_blocknr); for_every_item (bh, mark_item_unreachable, actions); stats(fs)->inserted_leaves ++; mark_buffer_dirty (bh); } static void insert_pointer (struct buffer_head * bh, struct path * path) { struct item_head * ih; char * body; int zeros_number; int retval; struct tree_balance tb; init_tb_struct (&tb, fs, path, 0x7fff); /* fix_nodes & do_balance must work for internal nodes only */ ih = 0; retval = fix_nodes (/*tb.transaction_handle,*/ M_INTERNAL, &tb, ih); if (retval != CARRY_ON) die ("insert_pointer: fix_nodes failed with retval == %d", retval); /* child_pos: we insert after position child_pos: this feature of the insert_child */ /* there is special case: we insert pointer after (-1)-st key (before 0-th key) in the parent */ if (PATH_LAST_POSITION (path) == 0 && path->pos_in_item == 0) PATH_H_B_ITEM_ORDER (path, 0) = -1; else { if (PATH_H_PPARENT (path, 0) == 0) PATH_H_B_ITEM_ORDER (path, 0) = 0; /* PATH_H_B_ITEM_ORDER (path, 0) = PATH_H_PPARENT (path, 0) ? PATH_H_B_ITEM_ORDER (path, 0) : 0;*/ } ih = 0; body = (char *)bh; //memmode = 0; zeros_number = 0; do_balance (&tb, ih, body, M_INTERNAL, zeros_number); leaf_is_in_tree_now (bh); } /* return 1 if left and right can be joined. 0 otherwise */ int balance_condition_fails (struct buffer_head * left, struct buffer_head * right) { if (B_FREE_SPACE (left) >= B_CHILD_SIZE (right) - (are_items_mergeable (B_N_PITEM_HEAD (left, B_NR_ITEMS (left) - 1), B_N_PITEM_HEAD (right, 0), left->b_size) ? IH_SIZE : 0)) return 1; return 0; } /* return 1 if new can be joined with last node on the path or with its right neighbor, 0 otherwise */ int balance_condition_2_fails (struct buffer_head * new, struct path * path) { struct buffer_head * bh; struct key * right_dkey; int pos, used_space; bh = PATH_PLAST_BUFFER (path); if (balance_condition_fails (bh, new)) /* new node can be joined with last buffer on the path */ return 1; /* new node can not be joined with its left neighbor */ right_dkey = uget_rkey (path); if (right_dkey == 0) /* there is no right neighbor */ return 0; pos = PATH_H_POSITION (path, 1); if (pos == B_NR_ITEMS (bh = PATH_H_PBUFFER (path, 1))) { /* we have to read parent of right neighbor. For simplicity we call search_by_key, which will read right neighbor as well */ INITIALIZE_PATH(path_to_right_neighbor); if (usearch_by_key (fs, right_dkey, &path_to_right_neighbor) != ITEM_FOUND) die ("get_right_neighbor_free_space: invalid right delimiting key"); used_space = B_CHILD_SIZE (PATH_PLAST_BUFFER (&path_to_right_neighbor)); pathrelse (&path_to_right_neighbor); } else used_space = B_N_CHILD (bh, pos + 1)->dc_size; if (B_FREE_SPACE (new) >= used_space - (are_items_mergeable (B_N_PITEM_HEAD (new, B_NR_ITEMS (new) - 1), (struct item_head *)right_dkey, new->b_size) ? IH_SIZE : 0)) return 1; return 0; } static void get_max_buffer_key (struct buffer_head * bh, struct key * key) { struct item_head * ih; ih = B_N_PITEM_HEAD (bh, B_NR_ITEMS (bh) - 1); copy_key (key, &(ih->ih_key)); if (is_direntry_key (key)) { /* copy 3-rd and 4-th key components of the last entry */ //set_le_key_k_offset (ih_version(ih), key, B_I_DEH (bh, ih)[I_ENTRY_COUNT (ih) - 1].deh_offset); //set_le_key_k_type (ih_version(ih), key, TYPE_DIRENTRY); set_offset (KEY_FORMAT_1, key, le32_to_cpu (B_I_DEH (bh, ih)[ih_entry_count (ih) - 1].deh_offset)); } else if (!is_stat_data_key (key)) /* get key of the last byte, which is contained in the item */ set_offset (key_format (key), key, get_offset (key) + get_bytes_number (ih, bh->b_size) - 1); //set_le_key_k_offset(ih_version(ih), key, // le_key_k_offset(ih_version(ih), key) + get_bytes_number (bh, ih, 0, CHECK_FREE_BYTES) - 1 ); } static int tree_is_empty (void) { return (SB_ROOT_BLOCK (fs) == ~0) ? 1 : 0; } static void make_single_leaf_tree (struct buffer_head * bh) { /* tree is empty, make tree root */ set_root_block (fs->s_rs, bh->b_blocknr); set_tree_height (fs->s_rs, 2); mark_buffer_dirty (fs->s_sbh); leaf_is_in_tree_now (bh); } /* inserts pointer to leaf into tree if possible. If not, marks node as uninsertable in special bitmap */ static void try_to_insert_pointer_to_leaf (struct buffer_head * new_bh) { INITIALIZE_PATH (path); struct buffer_head * bh; /* last path buffer */ struct key * first_bh_key, last_bh_key; /* first and last keys of new buffer */ struct key last_path_buffer_last_key, * right_dkey; int ret_value; if (tree_is_empty () == 1) { make_single_leaf_tree (new_bh); return; } first_bh_key = B_N_PKEY (new_bh, 0); /* try to find place in the tree for the first key of the coming node */ ret_value = usearch_by_key (fs, first_bh_key, &path); if (ret_value == ITEM_FOUND) goto cannot_insert; /* get max key in the new node */ get_max_buffer_key (new_bh, &last_bh_key); bh = PATH_PLAST_BUFFER (&path); if (comp_keys (B_N_PKEY (bh, 0), &last_bh_key) == 1/* first is greater*/) { /* new buffer falls before the leftmost leaf */ if (balance_condition_fails (new_bh, bh)) goto cannot_insert; if (uget_lkey (&path) != 0 || PATH_LAST_POSITION (&path) != 0) die ("try_to_insert_pointer_to_leaf: bad search result"); path.pos_in_item = 0; goto insert; } /* get max key of buffer, that is in tree */ get_max_buffer_key (bh, &last_path_buffer_last_key); if (comp_keys (&last_path_buffer_last_key, first_bh_key) != -1/* second is greater */) /* first key of new buffer falls in the middle of node that is in tree */ goto cannot_insert; right_dkey = uget_rkey (&path); if (right_dkey && comp_keys (right_dkey, &last_bh_key) != 1 /* first is greater */) goto cannot_insert; if (balance_condition_2_fails (new_bh, &path)) goto cannot_insert; insert: insert_pointer (new_bh, &path); goto out; cannot_insert: /* statistic */ stats (fs)->uninsertable_leaves ++; mark_block_uninsertable (new_bh->b_blocknr); out: pathrelse (&path); return; } /* everything should be correct already in the leaf but contents of indirect items. So we only 1. zero slots pointing to a leaf 2. zero pointers to blocks which are pointed already 3. what we should do with directory entries hashed by another hash? they are deleted for now */ static void pass1_correct_leaf (reiserfs_filsys_t s, struct buffer_head * bh) { int i, j; struct item_head * ih; __u32 * ind_item; unsigned long unfm_ptr; int dirty = 0; ih = B_N_PITEM_HEAD (bh, 0); for (i = 0; i < B_NR_ITEMS (bh); i ++, ih ++) { if (is_direntry_ih (ih)) { struct reiserfs_de_head * deh; char * name; int name_len; int hash_code; deh = B_I_DEH (bh, ih); for (j = 0; j < ih_entry_count (ih); j ++) { name = name_in_entry (deh + j, j); name_len = name_length (ih, deh + j, j); if ((j == 0 && is_dot (name, name_len)) || (j == 1 && is_dot_dot (name, name_len))) { continue; } hash_code = find_hash_in_use (name, name_len, GET_HASH_VALUE (deh_offset (deh + j)), rs_hash (fs->s_rs)); if (hash_code != rs_hash (fs->s_rs)) { fsck_log ("pass1: block %lu, %H, entry \"%.*s\" " "hashed with %s whereas proper hash is %s\n", bh->b_blocknr, ih, name_len, name, code2name (hash_code), code2name (rs_hash (fs->s_rs))); if (ih_entry_count (ih) == 1) { delete_item (fs, bh, i); i --; ih --; break; } else { cut_entry (fs, bh, i, j, 1); j --; deh = B_I_DEH (bh, ih); } } } continue; } if (!is_indirect_ih (ih)) continue; /* correct indirect items */ ind_item = (__u32 *)B_I_PITEM (bh, ih); for (j = 0; j < I_UNFM_NUM (ih); j ++, ind_item ++) { unfm_ptr = le32_to_cpu (*ind_item); if (!unfm_ptr) continue; /* this corruption of indirect item had to be fixed in pass0 */ if (not_data_block (s, unfm_ptr) || unfm_ptr >= SB_BLOCK_COUNT (s)) /*!was_block_used (unfm_ptr))*/ reiserfs_panic ("pass1_correct_leaf: (%lu: %k), %d-th slot is not fixed", bh->b_blocknr, &ih->ih_key, j); /* 1. zero slots pointing to a leaf */ if (is_used_leaf (unfm_ptr)) { dirty ++; *ind_item = 0; stats(fs)->wrong_pointers ++; continue; } /* 2. zero pointers to blocks which are pointed already */ if (is_bad_unformatted (unfm_ptr)) { /* this unformatted pointed more than once. Did we see it already? */ if (!is_bad_unfm_in_tree_once (unfm_ptr)) /* keep first reference to it and mark about that in special bitmap */ mark_bad_unfm_in_tree_once (unfm_ptr); else { /* Yes, we have seen this pointer already, zero other pointers to it */ dirty ++; *ind_item = 0; stats(fs)->wrong_pointers ++; continue; } } } } if (dirty) mark_buffer_dirty (bh); } /*######### has to die ##########*/ /* append item to end of list. Set head if it is 0. For indirect item set wrong unformatted node pointers to 0 */ void save_item (struct si ** head, struct buffer_head * bh, struct item_head * ih, char * item) { struct si * si, * cur; if (is_bad_item (bh, ih, item/*, fs->s_blocksize, fs->s_dev*/)) { return; } if (is_indirect_ih (ih)) { fsck_progress ("save_item: %H (should not happen)\n", ih); } stats(fs)->saved_on_pass1 ++; si = getmem (sizeof (*si)); si->si_dnm_data = getmem (ih_item_len(ih)); /*si->si_blocknr = blocknr;*/ memcpy (&(si->si_ih), ih, IH_SIZE); memcpy (si->si_dnm_data, item, ih_item_len(ih)); // changed by XB si->last_known = NULL; if (*head == 0) *head = si; else { cur = *head; // changed by XB // while (cur->si_next) // cur = cur->si_next; { int count = 0; int speedcount = 0; while (cur->si_next) { if (cur->last_known!=NULL) { cur = cur->last_known; // speed up to the end if the chain speedcount++; } else { cur = cur->si_next; count++; } } if ((*head)!=cur) // no self referencing loop please (*head)->last_known = cur; } cur->si_next = si; } return; } static void save_items (struct si ** head, struct buffer_head * bh) { int i; struct item_head * ih; ih = B_N_PITEM_HEAD (bh, 0); for (i = 0; i < B_NR_ITEMS (bh); i ++, ih ++) { save_item (head, bh, ih, B_I_PITEM (bh, ih)); } } struct si * remove_saved_item (struct si * si) { struct si * tmp = si->si_next; freemem (si->si_dnm_data); freemem (si); return tmp; } /* insert_item_separately */ static void put_saved_items_into_tree_1 (struct si * si) { while (si) { insert_item_separately (&(si->si_ih), si->si_dnm_data, 0/*was not in tree*/); si = remove_saved_item (si); } } /* reads the device by set of 8 blocks, takes leaves and tries to insert them into tree */ void pass_1_pass_2_build_the_tree (void) { struct buffer_head * bh; int i; int what_node; unsigned long done = 0, total; struct si * saved_items = 0; if (fsck_log_file (fs) != stderr) fsck_log ("####### Pass 1 #######\n"); bad_unfm_in_tree_once_bitmap = reiserfs_create_bitmap (SB_BLOCK_COUNT (fs)); /* on pass0 we have found that amount of leaves */ total = how_many_leaves_were_there (); fsck_progress ("\nPass1:\n"); /* read all leaves found on the pass 0 */ for (i = 0; i < SB_BLOCK_COUNT (fs); i ++) { if (!is_used_leaf (i)) continue; print_how_far (&done, total, 1, fsck_quiet (fs)); /* at least one of nr_to_read blocks is to be checked */ bh = bread (fs->s_dev, i, fs->s_blocksize); if (!bh) { /* we were reading one block at time, and failed, so mark block bad */ fsck_progress ("pass1: reading block %lu failed\n", i); continue; } what_node = who_is_this (bh->b_data, fs->s_blocksize); if ( what_node != THE_LEAF ) { fsck_progress ("build_the_tree: nothing but leaves are expected. " "Block %lu - %s\n", i, (what_node == THE_INTERNAL) ? "internal" : "??"); brelse (bh); continue; } if (is_block_used (i)) /* block is in new tree already */ die ("build_the_tree: leaf (%lu) is in tree already\n", i); /* fprintf (block_list, "leaf %d\n", i + j);*/ stats(fs)->analyzed ++; /* the leaf may still contain indirect items with wrong slots. Fix that */ pass1_correct_leaf (fs, bh); if (node_item_number (bh) == 0) { /* all items were deleted on pass 0 or pass 1 */ mark_buffer_clean (bh); brelse (bh); continue; } if (is_leaf_bad (bh)) { /* FIXME: will die */ fsck_log ("pass1: (is_leaf_bad) bad leaf (%lu)\n", bh->b_blocknr); /* Save good items only to put them into tree at the end of this pass */ save_items (&saved_items, bh); brelse (bh); continue; } try_to_insert_pointer_to_leaf (bh); brelse (bh); } #if 0 /* read all leaves found on the pass 0 */ for (i = 0; i < SB_BLOCK_COUNT (fs); i += nr_to_read) { to_scan = how_many_to_scan (fs, i, nr_to_read); if (to_scan) { print_how_far (&done, total, to_scan, fsck_quiet (fs)); /* at least one of nr_to_read blocks is to be checked */ bbh = bread (fs->s_dev, i / nr_to_read, fs->s_blocksize * nr_to_read); if (bbh) { for (j = 0; j < nr_to_read; j ++) { if (!is_used_leaf (i + j)) continue; data = bbh->b_data + j * fs->s_blocksize; what_node = who_is_this (data, fs->s_blocksize); if ( what_node != THE_LEAF ) { fsck_progress ("build_the_tree: nothing but leaves are expected. " "Block %lu - %s\n", i + j, (what_node == THE_INTERNAL) ? "internal" : "??"); continue; } if (is_block_used (i + j)) /* block is in new tree already */ die ("build_the_tree: leaf (%lu) is in tree already\n", i + j); /* fprintf (block_list, "leaf %d\n", i + j);*/ bh = make_buffer (fs->s_dev, i + j, fs->s_blocksize, data); stats(fs)->analyzed ++; /* the leaf may still contain indirect items with wrong slots. Fix that */ pass1_correct_leaf (fs, bh); if (node_item_number (bh) == 0) { /* all items were deleted on pass 0 or pass 1 */ mark_buffer_clean (bh); brelse (bh); continue; } if (is_leaf_bad (bh)) { /* FIXME: will die */ fsck_log ("pass1: (is_leaf_bad) bad leaf (%lu)\n", bh->b_blocknr); /* Save good items only to put them into tree at the end of this pass */ save_items (&saved_items, bh); brelse (bh); continue; } try_to_insert_pointer_to_leaf (bh); brelse (bh); } bforget (bbh); } else { done -= to_scan; /* bread failed */ if (nr_to_read != 1) { /* we tryied to read bunch of blocks. Try to read them by one */ nr_to_read = 1; i --; continue; } else { /* we were reading one block at time, and failed, so mark block bad */ fsck_progress ("pass0: block %lu is bad, marked used\n", i); } } } if (nr_to_read == 1 && ((i + 1) % NR_TO_READ) == 0) { /* we have read NR_TO_READ blocks one at time, switch back to reading NR_TO_READ blocks at time */ i -= (NR_TO_READ - 1); nr_to_read = NR_TO_READ; } } #endif fsck_progress ("\n"); /* Pass 1a (this should die) */ /* put saved items into tree. These items were in leaves, those could not be inserted into tree because some indirect items point to those leaves. Rather than lookup for corresponding unfm pointers in the tree, we save items of those leaves and put them into tree separately */ if (how_many_items_were_saved ()) { fsck_progress ("There were %lu saved items\nPass 1a - ", how_many_items_were_saved ()); fflush (stdout); put_saved_items_into_tree_1 (saved_items); } stage_report (1, fs); /* end of pass 1 */ if (SB_ROOT_BLOCK(fs) == -1) die ("\n\nNo reiserfs metadata found"); /* pass 2 */ pass_2_take_bad_blocks_put_into_tree (); flush_buffers (); stage_report (2, fs); fsck_progress ("Tree is built. Checking it - "); fflush (stdout); reiserfsck_check_pass1 (); fsck_progress ("done\n"); fflush (stdout); reiserfs_delete_bitmap (bad_unfm_in_tree_once_bitmap); } #if 0 /* pass the S+ tree of filesystem */ void recover_internal_tree (struct super_block * s) { check_internal_structure(s); build_the_tree(); } #endif void rebuild_sb (reiserfs_filsys_t fs) { int version; struct buffer_head * bh; struct reiserfs_super_block * rs; __u32 blocks; if (no_reiserfs_found (fs)) { char * answer = 0; size_t n = 0; printf("\nwhat is version of ReiserFS you use[1-4]\n" "\t(1) 3.6.x\n" "\t(2) >=3.5.9\n" "\t(3) < 3.5.9 converted to new format\n" "\t(4) < 3.5.9\n" "\t(X) exit\n"); getline (&answer, &n, stdin); version = atoi (answer); if (version < 1 || version > 4) die ("rebuild_sb: wrong version"); fs->s_blocksize = 4096; switch(version){ case 1: case 2: bh = getblk (fs->s_dev, (REISERFS_DISK_OFFSET_IN_BYTES / fs->s_blocksize), fs->s_blocksize); break; case 3: case 4: bh = getblk (fs->s_dev, (2), fs->s_blocksize); break; default: exit(0); } if (!bh) die ("rebuild_sb: can't bread"); rs = (struct reiserfs_super_block *)bh->b_data; fs->s_rs = rs; } else { /* reiserfs super block is found */ version = check_sb(fs); if (!user_confirmed ("\nDo you want to remake your super block\n" "(say no if you use resizer)[Yes/no]: ", "Yes\n")) return; rs = fs->s_rs; bh = fs->s_sbh; } // set block number on the device and number of bitmap blocks needed to // address all blocks blocks = (count_blocks ("", fs->s_blocksize, fs->s_dev) / 8) * 8; set_block_count (rs, blocks); //rs->s_block_count = cpu_to_le32(blocks); set_bmap_nr (rs, (blocks + (fs->s_blocksize * 8 - 1)) / (fs->s_blocksize * 8)); set_journal_size(rs, JOURNAL_BLOCK_COUNT); //rs->s_bmap_nr = cpu_to_le16( blocks / (g_sb.s_blocksize * 8) + // ((blocks % (g_sb.s_blocksize * 8)) ? 1 : 0) ); switch (version){ case 1: // super block v2 at 64k offset set_blocksize (rs, fs->s_blocksize); strncpy (rs->s_v1.s_magic, REISER2FS_SUPER_MAGIC_STRING, strlen(REISER2FS_SUPER_MAGIC_STRING)); set_journal_start (rs, get_journal_start_must (fs->s_blocksize)); set_version (rs, REISERFS_VERSION_2); set_objectid_map_max_size (rs, (fs->s_blocksize - SB_SIZE) / sizeof(__u32) / 2 * 2); break; case 2: // super block v1 at 64k offset set_blocksize (rs, fs->s_blocksize); strncpy (rs->s_v1.s_magic, REISERFS_SUPER_MAGIC_STRING, strlen(REISERFS_SUPER_MAGIC_STRING)); set_journal_start (rs, get_journal_start_must (fs->s_blocksize)); set_version (rs, REISERFS_VERSION_1); set_objectid_map_max_size (rs, (fs->s_blocksize - SB_SIZE_V1) / sizeof(__u32) / 2 * 2); break; case 3: // super block v2 at 8k offset set_blocksize (rs, fs->s_blocksize); strncpy (rs->s_v1.s_magic, REISER2FS_SUPER_MAGIC_STRING, strlen(REISER2FS_SUPER_MAGIC_STRING)); set_journal_start (rs, get_journal_old_start_must (rs)); set_version (rs, REISERFS_VERSION_2); set_objectid_map_max_size (rs, (fs->s_blocksize - SB_SIZE) / sizeof(__u32) / 2 * 2); break; case 4: // super block v1 at 8k offset set_blocksize (rs, fs->s_blocksize); strncpy (rs->s_v1.s_magic, REISERFS_SUPER_MAGIC_STRING, strlen(REISERFS_SUPER_MAGIC_STRING)); set_journal_start (rs, get_journal_old_start_must (rs)); set_version (rs, REISERFS_VERSION_1); set_objectid_map_max_size (rs, (fs->s_blocksize - SB_SIZE_V1) / sizeof(__u32) / 2 * 2); break; } print_block (stderr, fs, bh); if (user_confirmed ("Is this ok ? [N/Yes]: ", "Yes\n")) { mark_buffer_uptodate (bh, 1); mark_buffer_dirty (bh); bwrite (bh); fsck_progress ("\nDo not forget to run reiserfsck --rebuild-tree\n\n"); } else fsck_progress ("Super block was not written\n"); brelse (bh); } /* check_sb and rebuild-sb don't touch these fields: __u32 s_journal_dev; __u32 s_journal_trans_max ; __u32 s_journal_block_count ; __u32 s_journal_max_batch ; __u32 s_journal_max_commit_age ; __u32 s_journal_max_trans_age ; others are checked and set in either rebuild_sb or rebuild-tree */ reiserfsprogs-3.x.0j/fsck/pass2.c0000644000076400001440000003340107260630426012502 /* * Copyright 1996-2001 Hans Reiser */ #include "fsck.h" /* on pass2 we take leaves which could not be inserted into tree during pass1 and insert each item separately. It is possible that items of different objects with the same key can be found. We treat that in the following way: we put it into tree with new key and link it into /lost+found directory with name made of dir,oid. When coming item is a directory - we delete object from the tree, put it back with different key, link it to /lost+found directory and insert directory as it is */ /* relocation rules: we have an item (it is taken from "non-insertable" leaf). It has original key yet. We check to see if object with this key is remapped. Object can be only remapped if it is not a piece of directory */ /* in list of this structures we store what has been relocated. */ struct relocated { unsigned long old_dir_id; unsigned long old_objectid; unsigned long new_objectid; /*mode_t mode;*/ struct relocated * next; }; /* all relocated files will be linked into lost+found directory at the beginning of semantic pass */ struct relocated * relocated_list; /* return objectid the object has to be remapped with */ __u32 objectid_for_relocation (struct key * key) { struct relocated * cur; cur = relocated_list; while (cur) { if (cur->old_dir_id == key->k_dir_id && cur->old_objectid == key->k_objectid) /* object is relocated already */ return cur->new_objectid; cur = cur->next; } cur = getmem (sizeof (struct relocated)); cur->old_dir_id = key->k_dir_id; cur->old_objectid = key->k_objectid; cur->new_objectid = get_unused_objectid (fs); cur->next = relocated_list; relocated_list = cur; fsck_log ("relocation: (%K) is relocated to (%lu, %lu)\n", key, key->k_dir_id, cur->new_objectid); return cur->new_objectid; } /* this item is in tree. All unformatted pointer are correct. Do not check them */ static void save_item_2 (struct si ** head, struct item_head * ih, char * item, __u32 blocknr) { struct si * si, * cur; si = getmem (sizeof (*si)); si->si_dnm_data = getmem (ih_item_len(ih)); /*si->si_blocknr = blocknr;*/ memcpy (&(si->si_ih), ih, IH_SIZE); memcpy (si->si_dnm_data, item, ih_item_len(ih)); if (*head == 0) *head = si; else { cur = *head; while (cur->si_next) cur = cur->si_next; cur->si_next = si; } return; } struct si * save_and_delete_file_item (struct si * si, struct path * path) { struct buffer_head * bh = PATH_PLAST_BUFFER (path); struct item_head * ih = PATH_PITEM_HEAD (path); save_item_2 (&si, ih, B_I_PITEM (bh, ih), bh->b_blocknr); /* delete item temporary - do not free unformatted nodes */ reiserfsck_delete_item (path, 1/*temporary*/); return si; } /* check whether there are any directory items with this key */ static int should_relocate (struct item_head * ih) { struct key key; struct key * rkey; struct path path; struct item_head * path_ih; /* starting with the leftmost item with this key */ key = ih->ih_key; set_type_and_offset (KEY_FORMAT_1, &key, SD_OFFSET, TYPE_STAT_DATA); while (1) { usearch_by_key (fs, &key, &path); if (get_item_pos (&path) == B_NR_ITEMS (get_bh (&path))) { rkey = uget_rkey (&path); if (rkey && !not_of_one_file (&key, rkey)) { /* file continues in the right neighbor */ key = *rkey; pathrelse (&path); continue; } /* there is no more items with this key */ pathrelse (&path); break; } path_ih = get_ih (&path); if (not_of_one_file (&key, &(path_ih->ih_key))) { /* there are no more item with this key */ pathrelse (&path); break; } /* ok, item found, but make sure that it is not a directory one */ if ((is_stat_data_ih (path_ih) && !not_a_directory (get_item (&path))) || (is_direntry_ih (path_ih))) { /* item of directory found. so, we have to relocate the file */ pathrelse (&path); return 1; } key = path_ih->ih_key; set_offset (KEY_FORMAT_1, &key, get_offset (&key) + 1); pathrelse (&path); } return 0; } /* delete all items (but directory ones) with the same key 'ih' has (including stat data of not a directory) and put them back at the other place */ void relocate_file (struct item_head * ih, int change_ih) { struct key key; struct key * rkey; struct path path; struct item_head * path_ih; struct si * si; __u32 new_objectid; /* starting with the leftmost one - look for all items of file, store them and delete */ key = ih->ih_key; set_type_and_offset (KEY_FORMAT_1, &key, SD_OFFSET, TYPE_STAT_DATA); si = 0; while (1) { usearch_by_key (fs, &key, &path); if (get_item_pos (&path) == B_NR_ITEMS (get_bh (&path))) { rkey = uget_rkey (&path); if (rkey && !not_of_one_file (&key, rkey)) { /* file continues in the right neighbor */ key = *rkey; pathrelse (&path); continue; } /* there is no more items with this key */ pathrelse (&path); break; } path_ih = get_ih (&path); if (not_of_one_file (&key, &(path_ih->ih_key))) { /* there are no more item with this key */ pathrelse (&path); break; } /* ok, item found, but make sure that it is not a directory one */ if ((is_stat_data_ih (path_ih) && !not_a_directory (get_item (&path))) || (is_direntry_ih (path_ih))) { /* item of directory found. Leave it in the tree */ key = path_ih->ih_key; set_offset (KEY_FORMAT_1, &key, get_offset (&key) + 1); pathrelse (&path); continue; } si = save_and_delete_file_item (si, &path); } if (si || change_ih) { int moved_items; struct key old, new; /* get new objectid for relocation or get objectid with which file was relocated already */ new_objectid = objectid_for_relocation (&ih->ih_key); if (change_ih) ih->ih_key.k_objectid = new_objectid; moved_items = 0; /* put all items removed back into tree */ while (si) { /*fsck_log ("relocate_file: move %H to ", &si->si_ih);*/ old = si->si_ih.ih_key; si->si_ih.ih_key.k_objectid = new_objectid; new = si->si_ih.ih_key; /*fsck_log ("%H\n", &si->si_ih);*/ insert_item_separately (&(si->si_ih), si->si_dnm_data, 1/*was in tree*/); si = remove_saved_item (si); moved_items ++; } if (moved_items) fsck_log ("relocate_file: %d items of file %K moved to %K\n", moved_items, &old, &new); } } /* this works for both new and old stat data */ #define st_mode(sd) le16_to_cpu(((struct stat_data *)(sd))->sd_mode) #define st_mtime_v1(sd) le32_to_cpu(((struct stat_data_v1 *)(sd))->sd_mtime) #define st_mtime_v2(sd) le32_to_cpu(((struct stat_data *)(sd))->sd_mtime) static void overwrite_stat_data (struct item_head * new_ih, void * new_item, struct path * path) { if (stat_data_v1 (new_ih)) { if (st_mtime_v1 (new_item) > st_mtime_v1 (get_item (path))) { memcpy (get_item (path), new_item, SD_V1_SIZE); mark_buffer_dirty (get_bh (path)); } } else { if (st_mtime_v2 (new_item) > st_mtime_v2 (get_item (path))) { memcpy (get_item (path), new_item, SD_SIZE); mark_buffer_dirty (get_bh (path)); } } return; } /* insert sd item if it does not exist, overwrite it otherwise */ static void put_sd_into_tree (struct item_head * new_ih, char * new_item) { struct path path; if (!not_a_directory (new_item)) { /* new item is a stat data of a directory. So we have to relocate all items which have the same short key and are of not a directory */ relocate_file (new_ih, 0/*do not change new_ih*/); } else { /* new item is a stat data of something else but directory. If there are items of directory - we have to relocate the file */ if (should_relocate (new_ih)) relocate_file (new_ih, 1/*change new_ih*/); } /* if we will have to insert item into tree - it is ready */ zero_nlink (new_ih, new_item); mark_item_unreachable (new_ih); /* we are sure now that if we are inserting stat data of a directory - there are no items with the same key which are not items of a directory, and that if we are inserting stat data is of not a directory - it either has new key already or there are no items with this key which are items of a directory */ if (usearch_by_key (fs, &(new_ih->ih_key), &path) == ITEM_FOUND) { /* this stat data is found */ if (ih_key_format (get_ih(&path)) != ih_key_format (new_ih)) { /* in tree stat data and a new one are of different formats */ fsck_log ("put_sd_into_tree: inserting stat data %K (%M)..", &(new_ih->ih_key), st_mode (new_item)); if (stat_data_v1 (new_ih)) { /* sd to be inserted is of V1, where as sd in the tree is of V2 */ fsck_log ("found newer in the tree (%M), skip inserting\n", st_mode (get_item (&path))); } else { /* the stat data in the tree is sd_v1 */ fsck_log ("older sd (%M) is replaced with it\n", st_mode (get_item (&path))); reiserfsck_delete_item (&path, 0/*not temporary*/); usearch_by_key (fs, &new_ih->ih_key, &path); reiserfsck_insert_item (&path, new_ih, new_item); } } else { /* both stat data are of the same version */ overwrite_stat_data (new_ih, new_item, &path); pathrelse (&path); } return; } /* item not found, insert a new one */ reiserfsck_insert_item (&path, new_ih, new_item); } /* this tries to put each item entry to the tree, if there is no items of the directory, insert item containing 1 entry */ static void put_directory_item_into_tree (struct item_head * comingih, char * item) { struct reiserfs_de_head * deh; int i; char * buf; char * name; int namelen; /* if there are anything ith this key but a directory - move it somewhere else */ relocate_file (comingih, 0/* do not change ih */); deh = (struct reiserfs_de_head *)item; for (i = 0; i < ih_entry_count (comingih); i ++, deh ++) { name = name_in_entry (deh, i); namelen = name_length (comingih, deh, i); if (!is_properly_hashed (fs, name, namelen, deh_offset (deh))) reiserfs_panic ("put_directory_item_into_tree: should be hashed properly ()"); asprintf (&buf, "%.*s", namelen, name); /* 1 for fsck is important: if there is no any items of this directory in the tree yet - new item will be inserted marked not reached */ reiserfs_add_entry (fs, &(comingih->ih_key), buf, (struct key *)&(deh->deh_dir_id), 1/*fsck_need*/); free (buf); } /* make a directory */ } /* relocated files get added into lost+found with slightly different names */ static void link_one (struct relocated * file) { char * name; struct key obj_key; asprintf (&name, "%lu,%lu", file->old_dir_id, file->new_objectid); obj_key.k_dir_id = file->old_dir_id; obj_key.k_objectid = file->new_objectid; /* 0 for fsck_need does not mean too much - it would make effect if there were no this directory yet. But /lost_found is there already */ reiserfs_add_entry (fs, &lost_found_dir_key, name, &obj_key, 0/*fsck_need*/); stats(fs)->relocated ++; free (name); } void link_relocated_files (void) { struct relocated * tmp; int count; count = 0; while (relocated_list) { link_one (relocated_list); tmp = relocated_list; relocated_list = relocated_list->next; freemem (tmp); count ++; } } void insert_item_separately (struct item_head * ih, char * item, int was_in_tree) { if (ih->ih_key.k_dir_id == ih->ih_key.k_objectid) reiserfs_panic ("insert_item_separately: can not insert bad item %H", ih); if (is_stat_data_ih (ih)) { put_sd_into_tree (ih, item); } else if (is_direntry_ih (ih)) { put_directory_item_into_tree (ih, item); } else { if (should_relocate (ih)) relocate_file (ih, 1/*change new_ih*/); reiserfsck_file_write (ih, item, was_in_tree); } } static void put_items (struct buffer_head * bh) { int i; struct item_head * ih; ih = B_N_PITEM_HEAD (bh, 0); for (i = 0; i < B_NR_ITEMS (bh); i ++, ih ++) { if (i && bad_pair (fs, bh, i)) { /* skip item if it is in wrong order */ continue; } insert_item_separately (ih, B_I_PITEM (bh, ih), 0/*was in tree*/); } } /* uninsertable blocks are marked by 0s in uninsertable_leaf_bitmap during the pass 1. They must be not in the tree */ void pass_2_take_bad_blocks_put_into_tree (void) { struct buffer_head * bh; unsigned long j; unsigned long bb_counter = 0; int what_node; if (!stats(fs)->uninsertable_leaves) return; if (fsck_log_file (fs) != stderr) fsck_log ("####### Pass 2 #######\n"); fsck_progress ("\nPass2:\n"); j = 0; while (reiserfs_bitmap_find_zero_bit (uninsertable_leaf_bitmap, &j) == 0) { bh = bread (fs->s_dev, j, fs->s_blocksize); if (bh == 0) { fsck_log ("pass_2_take_bad_blocks_put_into_tree: " "unable to read %lu block on device 0x%x\n", j, fs->s_dev); goto next; } if (is_block_used (bh->b_blocknr)) { fsck_log ("pass_2_take_bad_blocks_put_into_tree: " "block %d can not be in tree\n", bh->b_blocknr); goto next; } /* this must be leaf */ what_node = who_is_this (bh->b_data, fs->s_blocksize); if (what_node != THE_LEAF) { // || B_IS_KEYS_LEVEL(bh)) { fsck_log ("take_bad_blocks_put_into_tree: buffer (%b %z) must contain leaf\n", bh, bh); goto next; } /*fsck_log ("block %lu is being inserted\n", bh->b_blocknr);*/ put_items (bh); print_how_far (&bb_counter, stats(fs)->uninsertable_leaves, 1, fsck_quiet (fs)); next: brelse (bh); j ++; } fsck_progress ("\n"); if (bb_counter != stats(fs)->uninsertable_leaves) die ("take_bad_blocks_put_into_tree: found bad block %d, must be %d", bb_counter, stats(fs)->uninsertable_leaves); } reiserfsprogs-3.x.0j/fsck/semantic.c0000644000076400001440000011045007261146625013261 /* * Copyright 1996-1999 Hans Reiser */ #include "fsck.h" struct key root_dir_key = {REISERFS_ROOT_PARENT_OBJECTID, REISERFS_ROOT_OBJECTID, {{0, 0},}}; struct key parent_root_dir_key = {0, REISERFS_ROOT_PARENT_OBJECTID, {{0, 0},}}; struct key lost_found_dir_key = {REISERFS_ROOT_OBJECTID, 0, {{0, 0}, }}; struct path_key { struct short_key { __u32 k_dir_id; __u32 k_objectid; } key; struct path_key * next, * prev; }; struct path_key * head_key = NULL; struct path_key * tail_key = NULL; void check_path_key(struct key * key) { struct path_key * cur = head_key; while(cur != NULL) { if (!comp_short_keys(&cur->key, key)) die("\nsemantic check: loop found %k", key); cur = cur->next; } } void add_path_key(struct key * key) { check_path_key(key); if (tail_key == NULL) { tail_key = getmem(sizeof(struct path_key)); head_key = tail_key; tail_key->prev = NULL; }else{ tail_key->next = getmem(sizeof(struct path_key)); tail_key->next->prev = tail_key; tail_key = tail_key->next; } copy_short_key (&tail_key->key, key); tail_key->next = NULL; } void del_path_key() { if (tail_key == NULL) die("wrong path_key structure"); if (tail_key->prev == NULL) { freemem(tail_key); tail_key = head_key = NULL; }else{ tail_key = tail_key->prev; freemem(tail_key->next); tail_key->next = NULL; } } /* semantic pass progress */ static void print_name (char * dir_name, int len) { int i; if (fsck_quiet (fs)) return; printf("/"); for (i = 0; isd_mode = cpu_to_le16 (*(__u16 *)value); else *(__u16 *)value = le16_to_cpu (sd_v1->sd_mode); break; case GET_SD_SIZE: /* value must point to 64 bit int */ if (set) sd_v1->sd_size = cpu_to_le32 (*(__u64 *)value); else *(__u64 *)value = le32_to_cpu (sd_v1->sd_size); break; case GET_SD_BLOCKS: if (set) sd_v1->u.sd_blocks = cpu_to_le32 (*(__u32 *)value); else *(__u32 *)value = le32_to_cpu (sd_v1->u.sd_blocks); break; case GET_SD_NLINK: /* value must point to 32 bit int */ if (set) sd_v1->sd_nlink = cpu_to_le16 (*(__u32 *)value); else *(__u32 *)value = le16_to_cpu (sd_v1->sd_nlink); break; case GET_SD_FIRST_DIRECT_BYTE: if (set) sd_v1->sd_first_direct_byte = cpu_to_le32 (*(__u32 *)value); else *(__u32 *)value = le32_to_cpu (sd_v1->sd_first_direct_byte); break; default: reiserfs_panic ("get_set_sd_field: unknown field of old stat data"); } } else { struct stat_data * sd_v2 = sd; switch (field) { case GET_SD_MODE: if (set) sd_v2->sd_mode = cpu_to_le16 (*(__u16 *)value); else *(__u16 *)value = le16_to_cpu (sd_v2->sd_mode); break; case GET_SD_SIZE: if (set) sd_v2->sd_size = cpu_to_le64 (*(__u64 *)value); else *(__u64 *)value = le64_to_cpu (sd_v2->sd_size); break; case GET_SD_BLOCKS: if (set) sd_v2->sd_blocks = cpu_to_le32 (*(__u32 *)value); else *(__u32 *)value = le32_to_cpu (sd_v2->sd_blocks); break; case GET_SD_NLINK: if (set) sd_v2->sd_nlink = cpu_to_le32 (*(__u32 *)value); else *(__u32 *)value = le32_to_cpu (sd_v2->sd_nlink); break; case GET_SD_FIRST_DIRECT_BYTE: default: reiserfs_panic ("get_set_sd_field: unknown field of new stat data"); } } } /* *size is "real" file size, sd_size - size from stat data */ static int wrong_st_size (struct key * key, loff_t max_file_size, int blocksize, __u64 * size, __u64 sd_size, int is_dir) { if (sd_size <= max_file_size) { if (sd_size == *size) return 0; if (is_dir) { /* directory size must match to the sum of length of its entries */ fsck_log ("dir %K has wrong sd_size %Ld, has to be %Ld\n", key, sd_size, *size); return 1; } if (sd_size > *size) { /* size in stat data can be bigger than size calculated by items */ if (fsck_fix_non_critical (fs)) { /* but it -o is given - fix that */ fsck_log ("file %K has too big file size sd_size %Ld - fixed to %Ld\n", key, sd_size, *size); stats(fs)->fixed_sizes ++; return 1; } *size = sd_size; return 0; } if (!(*size % blocksize)) { /* last item is indirect */ if (((sd_size & ~(blocksize - 1)) == (*size - blocksize)) && sd_size % blocksize) { /* size in stat data is correct */ *size = sd_size; return 0; } } else { /* last item is a direct one */ if (!(*size % 8)) { if (((sd_size & ~7) == (*size - 8)) && sd_size % 8) { /* size in stat data is correct */ *size = sd_size; return 0; } } } } fsck_log ("file %K has wrong sd_size %Ld, has to be %Ld\n", key, sd_size, *size); stats(fs)->fixed_sizes ++; return 1; } /* sd_blocks is 32 bit only */ static int wrong_st_blocks (struct key * key, __u32 blocks, __u32 sd_blocks, int is_dir) { if (blocks == sd_blocks) return 0; if (!is_dir || blocks != _ROUND_UP (sd_blocks, fs->s_blocksize / 512)) { /*fsck_log ("%s %K has wrong sd_blocks %d, has to be %d\n", is_dir ? "dir" : "file", key, sd_blocks, blocks);*/ return 1; } else return 0; } /* only regular files and symlinks may have items but stat data. Symlink shold have body */ static int wrong_mode (struct key * key, mode_t * mode, __u64 real_size) { if (!fsck_fix_non_critical (fs)) return 0; if (ftypelet (*mode) != '?') { /* mode looks reasonable */ if (S_ISREG (*mode) || S_ISLNK (*mode)) return 0; /* device, pipe, socket have no items */ if (!real_size) return 0 ; } /* there are items, so change file mode to regular file. Otherwise - file bodies do not get deleted */ fsck_log ("file %K (%M) has body, mode fixed to %M\n", key, *mode, (S_IFREG | 0600)); *mode = (S_IFREG | 0600); return 1; } /* key is a key of last file item */ static int wrong_first_direct_byte (struct key * key, int blocksize, __u32 * first_direct_byte, __u32 sd_first_direct_byte, __u32 size) { if (!size || is_indirect_key (key)) { /* there is no direct item */ *first_direct_byte = NO_BYTES_IN_DIRECT_ITEM; if (sd_first_direct_byte != NO_BYTES_IN_DIRECT_ITEM) { return 1; } return 0; } /* there is direct item */ *first_direct_byte = (get_offset (key) & ~(blocksize - 1)) + 1; if (*first_direct_byte != sd_first_direct_byte) { fsck_log ("file %k has wrong first direct byte %d, has to be %d\n", key, sd_first_direct_byte, *first_direct_byte); return 1; } return 0; } /* return values for check_regular_file and check_semantic_tree */ #define OK 0 #define STAT_DATA_NOT_FOUND -1 #define DIRECTORY_HAS_NO_ITEMS -2 #define RELOCATED -3 /* delete all items (but directory ones) with the same key 'ih' has (including stat data of not a directory) and put them back at the other place */ void relocate_dir (struct item_head * ih, int change_ih) { struct key key; struct key * rkey; struct path path; struct item_head * path_ih; struct si * si; __u32 new_objectid; /* starting with the leftmost one - look for all items of file, store them and delete */ key = ih->ih_key; set_type_and_offset (KEY_FORMAT_1, &key, SD_OFFSET, TYPE_STAT_DATA); si = 0; while (1) { usearch_by_key (fs, &key, &path); if (get_item_pos (&path) == B_NR_ITEMS (get_bh (&path))) { rkey = uget_rkey (&path); if (rkey && !not_of_one_file (&key, rkey)) { /* file continues in the right neighbor */ key = *rkey; pathrelse (&path); continue; } /* there is no more items of a directory */ pathrelse (&path); break; } path_ih = get_ih (&path); if (not_of_one_file (&key, &(path_ih->ih_key))) { /* there are no more item with this key */ pathrelse (&path); break; } /* ok, item found, but make sure that it is not a directory one */ if ((is_stat_data_ih (path_ih) && not_a_directory (get_item (&path))) || is_direct_ih (path_ih) || is_indirect_ih (path_ih)) { /* item of not a directory found. Leave it in the tree. FIXME: should not happen */ key = path_ih->ih_key; set_offset (KEY_FORMAT_1, &key, get_offset (&key) + 1); pathrelse (&path); continue; } /* directory stat data ro directory item */ si = save_and_delete_file_item (si, &path); } if (!si) { fsck_progress ("relocate_dir: no directory %K items found\n", &key); return; } /* get new objectid for relocation or get objectid with which file was relocated already */ new_objectid = objectid_for_relocation (&ih->ih_key); ih->ih_key.k_objectid = new_objectid; /* put all items removed back into tree */ while (si) { fsck_log ("relocate_dir: move %H to ", &si->si_ih); si->si_ih.ih_key.k_objectid = new_objectid; fsck_log ("%H\n", &si->si_ih); if (get_offset (&(si->si_ih.ih_key)) == DOT_OFFSET) { /* fix "." entry to point to a directtory properly */ struct reiserfs_de_head * deh; deh = (struct reiserfs_de_head *)si->si_dnm_data; deh->deh_objectid = new_objectid; } insert_item_separately (&(si->si_ih), si->si_dnm_data, 1/*was in tree*/); si = remove_saved_item (si); } } /* path is path to stat data. If file will be relocated - new_ih will contain a key file was relocated with */ int rebuild_check_regular_file (struct path * path, void * sd, struct item_head * new_ih) { int is_new_file; struct key key, sd_key; mode_t mode; __u32 nlink; __u64 real_size, saved_size; __u32 blocks, saved_blocks; /* proper values and value in stat data */ __u32 first_direct_byte, saved_first_direct_byte; struct buffer_head * bh; struct item_head * ih; int fix_sd; int symlnk = 0; int retval; retval = OK; /* stat data of a file */ ih = get_ih (path); bh = get_bh (path); if (new_ih) { /* this objectid is used already */ *new_ih = *ih; pathrelse (path); relocate_file (new_ih, 1); stats(fs)->oid_sharing_files_relocated ++; retval = RELOCATED; if (usearch_by_key (fs, &(new_ih->ih_key), path) == ITEM_NOT_FOUND) reiserfs_panic ("rebuild_check_regular_file: could not find stat data of relocated file"); /* stat data is marked unreachable again due to relocation, fix that */ ih = get_ih (path); bh = get_bh (path); mark_item_reachable (ih, bh); sd = get_item (path); } /* check and set nlink first */ get_sd_nlink (ih, sd, &nlink); nlink ++; set_sd_nlink (ih, sd, &nlink); mark_buffer_dirty (bh); if (nlink > 1) return OK; /* firts name of a file found */ if (ih_item_len (ih) == SD_SIZE) is_new_file = 1; else is_new_file = 0; get_sd_mode (ih, sd, &mode); get_sd_size (ih, sd, &saved_size); get_sd_blocks (ih, sd, &saved_blocks); if (!is_new_file) get_sd_first_direct_byte (ih, sd, &saved_first_direct_byte); /* we met this file first time */ if (S_ISREG (mode)) { stats(fs)->regular_files ++; } else if (S_ISLNK (mode)) { symlnk = 1; stats(fs)->symlinks ++; } else { stats(fs)->others ++; } key = ih->ih_key; /*??*/ sd_key = key; /*??*/ pathrelse (path); if (are_file_items_correct (&key, is_new_file ? KEY_FORMAT_2 : KEY_FORMAT_1, &real_size, &blocks, 1/*mark items reachable*/, symlnk, saved_size) != 1) { /* unpassed items will be deleted in pass 4 as they left unaccessed */ stats(fs)->broken_files ++; } fix_sd = 0; fix_sd += wrong_mode (&sd_key, &mode, real_size); if (!is_new_file) fix_sd += wrong_first_direct_byte (&key, fs->s_blocksize, &first_direct_byte, saved_first_direct_byte, real_size); fix_sd += wrong_st_size (&sd_key, is_new_file ? MAX_FILE_SIZE_V2 : MAX_FILE_SIZE_V1, fs->s_blocksize, &real_size, saved_size, 0/*not dir*/); if (!is_new_file && (S_ISREG (mode) || S_ISLNK (mode))) /* old stat data shares sd_block and sd_dev. We do not want to wipe put sd_dev for device files */ fix_sd += wrong_st_blocks (&sd_key, blocks, saved_blocks, 0/*not dir*/); if (fix_sd) { /* find stat data and correct it */ if (usearch_by_key (fs, &sd_key, path) != ITEM_FOUND) die ("check_regular_file: stat data not found"); bh = get_bh (path); ih = get_ih (path); sd = get_item (path); set_sd_size (ih, sd, &real_size); set_sd_blocks (ih, sd, &blocks); set_sd_mode (ih, sd, &mode); if (!is_new_file) set_sd_first_direct_byte (ih, sd, &first_direct_byte); mark_buffer_dirty (bh); } return retval; } static int is_rootdir_key (struct key * key) { if (comp_keys (key, &root_dir_key)) return 0; return 1; } /* returns buffer, containing found directory item.*/ static char * get_next_directory_item (struct key * key, /* on return this will contain key of next item in the tree */ struct key * parent, struct item_head * ih,/*not in tree*/ int * pos_in_item) { INITIALIZE_PATH (path); char * dir_item; struct key * rdkey; struct buffer_head * bh; struct reiserfs_de_head * deh; int i; int retval; if ((retval = usearch_by_entry_key (fs, key, &path)) != POSITION_FOUND) { die ("get_next_directory_item: %k is not found", key); } #if 0 if (get_offset (key) != DOT_OFFSET) /* we always search for existing key, but "." */ die ("get_next_directory_item: %k is not found", key); pathrelse (&path); if (fsck_mode (fs) == FSCK_CHECK) { fsck_log ("get_next_directory_item: directory has no \".\" entry %k\n", key); pathrelse (&path); return 0; } fsck_log ("making \".\" and/or \"..\" for %K\n", key); reiserfs_add_entry (fs, key, ".", key, 1 << IH_Unreachable); reiserfs_add_entry (fs, key, "..", parent, 1 << IH_Unreachable); /* we have fixed a directory, search its first item again */ usearch_by_entry_key (fs, key, &path); } #endif /* leaf containing directory item */ bh = PATH_PLAST_BUFFER (&path); *pos_in_item = path.pos_in_item; *ih = *get_ih (&path); deh = B_I_DEH (bh, ih); /* make sure, that ".." exists as well */ if (get_offset (key) == DOT_OFFSET) { if (ih_entry_count (ih) < 2) { fsck_progress ("1. Does this ever happen?\n"); pathrelse (&path); return 0; } if (name_length (ih, deh + 1, 1) != 2 || strncmp (name_in_entry (deh + 1, 1), "..", 2)) { fsck_progress ("2. Does this ever happen?\n"); fsck_log ("get_next_directory_item: \"..\" not found in %H\n", ih); pathrelse (&path); return 0; } } /* mark hidden entries as visible, set "." and ".." correctly */ deh += *pos_in_item; for (i = *pos_in_item; i < ih_entry_count (ih); i ++, deh ++) { int namelen; char * name; name = name_in_entry (deh, i); namelen = name_length (ih, deh, i); if (de_hidden (deh)) reiserfs_panic ("get_next_directory_item: item %k: hidden entry %d \'%.*s\'\n", key, i, namelen, name); if (deh->deh_offset == DOT_OFFSET) { if (not_of_one_file (&(deh->deh_dir_id), key)) //deh->deh_objectid != REISERFS_ROOT_PARENT_OBJECTID)/*????*/ { reiserfs_panic ("get_next_directory_item: wrong \".\" found %k\n", key); } if (deh->deh_offset == DOT_DOT_OFFSET) { /* set ".." so that it points to the correct parent directory */ if (comp_short_keys (&(deh->deh_dir_id), parent) && deh->deh_objectid != REISERFS_ROOT_PARENT_OBJECTID)/*???*/ { /* FIXME */ fsck_log ("get_next_directory_item: %k: \"..\" pointes to [%K], " "should point to [%K]", key, (struct key *)(&(deh->deh_dir_id)), parent); if (fsck_mode (fs) == FSCK_REBUILD) { deh->deh_dir_id = parent->k_dir_id; deh->deh_objectid = parent->k_objectid; mark_buffer_dirty (bh); fsck_log (" - fixed\n"); } else fsck_log ("\n"); } } } /* copy directory item to the temporary buffer */ dir_item = getmem (ih_item_len (ih)); memcpy (dir_item, B_I_PITEM (bh, ih), ih_item_len (ih)); /* next item key */ if (PATH_LAST_POSITION (&path) == (B_NR_ITEMS (bh) - 1) && (rdkey = uget_rkey (&path))) copy_key (key, rdkey); else { key->k_dir_id = 0; key->k_objectid = 0; } if (fsck_mode (fs) != FSCK_CHECK) mark_item_reachable (get_ih (&path), bh); pathrelse (&path); return dir_item; } // get key of an object pointed by direntry and the key of the entry itself static void get_object_key (struct reiserfs_de_head * deh, struct key * key, struct key * entry_key, struct item_head * ih) { key->k_dir_id = deh->deh_dir_id; key->k_objectid = deh->deh_objectid; key->u.k_offset_v1.k_offset = SD_OFFSET; key->u.k_offset_v1.k_uniqueness = V1_SD_UNIQUENESS; entry_key->k_dir_id = ih->ih_key.k_dir_id; entry_key->k_objectid = ih->ih_key.k_objectid; entry_key->u.k_offset_v1.k_offset = deh->deh_offset; entry_key->u.k_offset_v1.k_uniqueness = DIRENTRY_UNIQUENESS; } /* check recursively the semantic tree. Returns OK if entry points to good object, STAT_DATA_NOT_FOUND if stat data was not found or RELOCATED when file was relocated because its objectid was already marked as used by another file */ int rebuild_semantic_pass (struct key * key, struct key * parent, int dot_dot, struct item_head * new_ih) { struct path path; void * sd; int is_new_dir; __u32 nlink; struct buffer_head * bh; struct item_head * ih; int retval, retval1; char * dir_item; int pos_in_item; struct item_head tmp_ih; struct key item_key, entry_key, object_key; __u64 dir_size; __u32 blocks; __u64 saved_size; __u32 saved_blocks; int fix_sd; int relocate; retval = OK; start_again: /* when directory was relocated */ if (!KEY_IS_STAT_DATA_KEY (key)) reiserfs_panic ("rebuild_semantic_pass: key %k must be key of a stat data", key); /* look for stat data of an object */ if (usearch_by_key (fs, key, &path) == ITEM_NOT_FOUND) { pathrelse (&path); if (is_rootdir_key (key)) /* root directory has to exist at this point */ reiserfs_panic ("rebuild_semantic_pass: root directory not found"); return STAT_DATA_NOT_FOUND; } /* stat data has been found */ bh = get_bh (&path); ih = get_ih (&path); sd = get_item(&path); /* */ get_sd_nlink (ih, sd, &nlink); relocate = 0; if (!nlink) { /* we reached the stat data for the first time */ if (is_objectid_really_used (semantic_id_map (fs), ih->ih_key.k_objectid, &pos_in_item)) { /* calculate number of found files/dirs who are using objectid which is used by another file */ stats(fs)->oid_sharing ++; if (fsck_fix_non_critical (fs)) /* this works for files only */ relocate = 1; } else mark_objectid_really_used (semantic_id_map (fs), ih->ih_key.k_objectid); mark_item_reachable (ih, bh); } if (not_a_directory (sd)) { retval = rebuild_check_regular_file (&path, sd, relocate ? new_ih : 0); pathrelse (&path); return retval; } if (relocate) { if (!new_ih) reiserfs_panic ("rebuild_semantic_pass: can not relocate %K", &ih->ih_key); *new_ih = *ih; pathrelse (&path); stats(fs)->oid_sharing_dirs_relocated ++; relocate_dir (new_ih, 1); *key = new_ih->ih_key; retval = RELOCATED; goto start_again; } /* stat data of a directory found */ if (nlink) { /* we saw this directory already */ if (!dot_dot) { /* this name is not ".." - and hard links are not allowed on directories */ pathrelse (&path); return STAT_DATA_NOT_FOUND; } else { /* ".." found */ nlink ++; set_sd_nlink (ih, sd, &nlink); mark_buffer_dirty (bh); pathrelse (&path); return OK; } } /* we see the directory first time */ stats(fs)->directories ++; nlink = 2; if (key->k_objectid == REISERFS_ROOT_OBJECTID) nlink ++; set_sd_nlink (ih, sd, &nlink); mark_buffer_dirty (bh); if (ih_item_len (ih) == SD_SIZE) is_new_dir = 1; else is_new_dir = 0; /* release path pointing to stat data */ pathrelse (&path); /* make sure that "." and ".." exist */ reiserfs_add_entry (fs, key, ".", key, 1 << IH_Unreachable); reiserfs_add_entry (fs, key, "..", parent, 1 << IH_Unreachable); item_key = *key; item_key.u.k_offset_v1.k_offset = DOT_OFFSET; item_key.u.k_offset_v1.k_uniqueness = DIRENTRY_UNIQUENESS; /* save stat data's size and st_blocks */ get_sd_size (ih, sd, &saved_size); get_sd_blocks (ih, sd, &saved_blocks); dir_size = 0; while ((dir_item = get_next_directory_item (&item_key, parent, &tmp_ih, &pos_in_item)) != 0) { /* dir_item is copy of the item in separately allocated memory, item_key is a key of next item in the tree */ int i; struct reiserfs_de_head * deh = (struct reiserfs_de_head *)dir_item + pos_in_item; for (i = pos_in_item; i < ih_entry_count (&tmp_ih); i ++, deh ++) { char * name; int namelen; struct item_head relocated_ih; name = name_in_entry (deh, i); namelen = name_length (&tmp_ih, deh, i); if (is_dot (name, namelen)) { dir_size += DEH_SIZE + entry_length (&tmp_ih, deh, i); continue; } print_name (name, namelen); if (!is_properly_hashed (fs, name, namelen, deh_offset (deh))) reiserfs_panic ("rebuild_semantic_pass: name has to be hashed properly"); get_object_key (deh, &object_key, &entry_key, &tmp_ih); retval1 = rebuild_semantic_pass (&object_key, key, is_dot_dot (name, namelen), &relocated_ih); erase_name (namelen); switch (retval1) { case OK: dir_size += DEH_SIZE + entry_length (&tmp_ih, deh, i); break; case STAT_DATA_NOT_FOUND: case DIRECTORY_HAS_NO_ITEMS: if (get_offset (&entry_key) == DOT_DOT_OFFSET && object_key.k_objectid == REISERFS_ROOT_PARENT_OBJECTID) { /* ".." of root directory can not be found */ dir_size += DEH_SIZE + entry_length (&tmp_ih, deh, i); continue; } fsck_log ("name \"%.*s\" in directory %K points to nowhere %K - removed\n", namelen, name, &tmp_ih.ih_key, (struct key *)&(deh->deh_dir_id)); reiserfs_remove_entry (fs, &entry_key); stats(fs)->deleted_entries ++; break; case RELOCATED: /* file was relocated, update key in corresponding directory entry */ if (_search_by_entry_key (fs, &entry_key, &path) != POSITION_FOUND) { fsck_progress ("could not find name of relocated file\n"); } else { /* update key dir entry points to */ struct reiserfs_de_head * tmp_deh; tmp_deh = B_I_DEH (get_bh (&path), get_ih (&path)) + path.pos_in_item; fsck_log ("name \"%.*s\" of dir %K pointing to %K updated to point to ", namelen, name, &tmp_ih.ih_key, &tmp_deh->deh_dir_id); tmp_deh->deh_dir_id = cpu_to_le32 (relocated_ih.ih_key.k_dir_id); tmp_deh->deh_objectid = cpu_to_le32 (relocated_ih.ih_key.k_objectid); fsck_log ("%K\n", &tmp_deh->deh_dir_id); mark_buffer_dirty (get_bh (&path)); } dir_size += DEH_SIZE + entry_length (&tmp_ih, deh, i); pathrelse (&path); break; } } /* for */ freemem (dir_item); if (not_of_one_file (&item_key, key)) /* next key is not of this directory */ break; } /* while (dir_item) */ if (dir_size == 0) /* FIXME: is it possible? */ return DIRECTORY_HAS_NO_ITEMS; /* calc correct value of sd_blocks field of stat data */ blocks = dir_size2st_blocks (fs->s_blocksize, dir_size); fix_sd = 0; fix_sd += wrong_st_blocks (key, blocks, saved_blocks, 1/*dir*/); fix_sd += wrong_st_size (key, is_new_dir ? MAX_FILE_SIZE_V2 : MAX_FILE_SIZE_V1, fs->s_blocksize, &dir_size, saved_size, 1/*dir*/); if (fix_sd) { /* we have to fix either sd_size or sd_blocks, so look for stat data again */ if (usearch_by_key (fs, key, &path) != ITEM_FOUND) die ("rebuild_semantic_pass: stat data not found"); bh = get_bh (&path); ih = get_ih (&path); sd = get_item (&path); set_sd_size (ih, sd, &dir_size); set_sd_blocks (ih, sd, &blocks); mark_buffer_dirty (bh); pathrelse (&path); } return retval; } int is_dot (char * name, int namelen) { return (namelen == 1 && name[0] == '.') ? 1 : 0; } int is_dot_dot (char * name, int namelen) { return (namelen == 2 && name[0] == '.' && name[1] == '.') ? 1 : 0; } int not_a_directory (void * sd) { /* mode is at the same place and of the same size in both stat datas (v1 and v2) */ struct stat_data_v1 * sd_v1 = sd; return !(S_ISDIR (le16_to_cpu (sd_v1->sd_mode))); } void zero_nlink (struct item_head * ih, void * sd) { int zero = 0; if (ih_item_len (ih) == SD_V1_SIZE && ih_key_format (ih) != KEY_FORMAT_1) { fsck_log ("zero_nlink: %H had wrong keys format %d, fixed to %d", ih, ih_key_format (ih), KEY_FORMAT_1); set_key_format (ih, KEY_FORMAT_1); } if (ih_item_len (ih) == SD_SIZE && ih_key_format (ih) != KEY_FORMAT_2) { fsck_log ("zero_nlink: %H had wrong keys format %d, fixed to %d", ih, ih_key_format (ih), KEY_FORMAT_2); set_key_format (ih, KEY_FORMAT_2); } set_sd_nlink (ih, sd, &zero); } /* inserts new or old stat data of a directory (unreachable, nlinks == 0) */ void create_dir_sd (reiserfs_filsys_t fs, struct path * path, struct key * key) { struct item_head ih; struct stat_data sd; int key_format; if (SB_VERSION(fs) == REISERFS_VERSION_2) key_format = KEY_FORMAT_2; else key_format = KEY_FORMAT_1; make_dir_stat_data (fs->s_blocksize, key_format, key->k_dir_id, key->k_objectid, &ih, &sd); /* set nlink count to 0 and make the item unreachable */ zero_nlink (&ih, &sd); mark_item_unreachable (&ih); reiserfs_insert_item (fs, path, &ih, &sd); } static void make_sure_root_dir_exists (reiserfs_filsys_t fs) { INITIALIZE_PATH (path); /* is there root's stat data */ if (usearch_by_key (fs, &root_dir_key, &path) == ITEM_NOT_FOUND) { create_dir_sd (fs, &path, &root_dir_key); mark_objectid_really_used (proper_id_map (fs), REISERFS_ROOT_OBJECTID); } else pathrelse (&path); /* add "." and ".." if any of them do not exist. Last two parameters say: 0 - entry is not added on lost_found pass and 1 - mark item unreachable */ reiserfs_add_entry (fs, &root_dir_key, ".", &root_dir_key, 1 << IH_Unreachable); reiserfs_add_entry (fs, &root_dir_key, "..", &parent_root_dir_key, 1 << IH_Unreachable); } /* mkreiserfs should have created this */ static void make_sure_lost_found_exists (reiserfs_filsys_t fs) { int retval; INITIALIZE_PATH (path); int gen_counter; /* look for "lost+found" in the root directory */ lost_found_dir_key.k_objectid = reiserfs_find_entry (fs, &root_dir_key, "lost+found", &gen_counter); if (!lost_found_dir_key.k_objectid) { lost_found_dir_key.k_objectid = get_unused_objectid (fs); if (!lost_found_dir_key.k_objectid) { fsck_progress ("make_sure_lost_found_exists: could not get objectid" " for \"/lost+found\", will not link lost files\n"); return; } } /* look for stat data of "lost+found" */ retval = usearch_by_key (fs, &lost_found_dir_key, &path); if (retval == ITEM_NOT_FOUND) create_dir_sd (fs, &path, &lost_found_dir_key); else { if (not_a_directory (get_item (&path))) { fsck_progress ("make_sure_lost_found_exists: \"/lost+found\" is " "not a directory, will not link lost files\n"); lost_found_dir_key.k_objectid = 0; pathrelse (&path); return; } pathrelse (&path); } /* add "." and ".." if any of them do not exist */ reiserfs_add_entry (fs, &lost_found_dir_key, ".", &lost_found_dir_key, 1 << IH_Unreachable); reiserfs_add_entry (fs, &lost_found_dir_key, "..", &root_dir_key, 1 << IH_Unreachable); reiserfs_add_entry (fs, &root_dir_key, "lost+found", &lost_found_dir_key, 1 << IH_Unreachable); return; } /* this is part of rebuild tree */ void pass_3_semantic (void) { fsck_progress ("Pass 3 (semantic):\n"); /* when warnings go not to stderr - separate then in the log */ if (fsck_log_file (fs) != stderr) fsck_log ("####### Pass 3 #########\n"); if (!fs->s_hash_function) reiserfs_panic ("Hash function should be selected already"); make_sure_root_dir_exists (fs); make_sure_lost_found_exists (fs); /* link all relocated files into root directory */ link_relocated_files (); rebuild_semantic_pass (&root_dir_key, &parent_root_dir_key, 0/*!dot_dot*/, 0/*reloc_ih*/); stage_report (3, fs); } /* path is path to stat data. If file will be relocated - new_ih will contain a key file was relocated with */ static int check_check_regular_file (struct path * path, void * sd) { int is_new_file; struct key key, sd_key; mode_t mode; __u32 nlink; __u64 real_size, saved_size; __u32 blocks, saved_blocks; /* proper values and value in stat data */ __u32 first_direct_byte, saved_first_direct_byte; struct buffer_head * bh; struct item_head * ih; int fix_sd; int symlnk = 0; ih = get_ih (path); bh = get_bh (path); if (ih_item_len (ih) == SD_SIZE) is_new_file = 1; else is_new_file = 0; get_sd_nlink (ih, sd, &nlink); get_sd_mode (ih, sd, &mode); get_sd_size (ih, sd, &saved_size); get_sd_blocks (ih, sd, &saved_blocks); if (!is_new_file) get_sd_first_direct_byte (ih, sd, &saved_first_direct_byte); if (S_ISREG (mode)) { /* fixme: this could be wrong due to hard links */ stats(fs)->regular_files ++; } else if (S_ISLNK (mode)) { symlnk = 1; stats(fs)->symlinks ++; } else { stats(fs)->others ++; } key = ih->ih_key; /*??*/ sd_key = key; /*??*/ pathrelse (path); if (are_file_items_correct (&key, is_new_file ? KEY_FORMAT_2 : KEY_FORMAT_1, &real_size, &blocks, 0/*do not mark items reachable*/, symlnk, saved_size) != 1) { fsck_log ("check_regular_file: broken file found %K\n", key); } else { fix_sd = 0; fix_sd += wrong_mode (&sd_key, &mode, real_size); if (!is_new_file) fix_sd += wrong_first_direct_byte (&key, fs->s_blocksize, &first_direct_byte, saved_first_direct_byte, real_size); fix_sd += wrong_st_size (&sd_key, is_new_file ? MAX_FILE_SIZE_V2 : MAX_FILE_SIZE_V1, fs->s_blocksize, &real_size, saved_size, 0/*not dir*/); if (!is_new_file && (S_ISREG (mode) || S_ISLNK (mode))) /* old stat data shares sd_block and sd_dev. We do not want to wipe put sd_dev for device files */ fix_sd += wrong_st_blocks (&sd_key, blocks, saved_blocks, 0/*not dir*/); if (fix_sd && fsck_fix_fixable (fs)) { /* find stat data and correct it */ if (usearch_by_key (fs, &sd_key, path) != ITEM_FOUND) die ("check_regular_file: stat data not found"); bh = get_bh (path); ih = get_ih (path); sd = get_item (path); set_sd_size (ih, sd, &real_size); set_sd_blocks (ih, sd, &blocks); set_sd_mode (ih, sd, &mode); if (!is_new_file) set_sd_first_direct_byte (ih, sd, &first_direct_byte); mark_buffer_dirty (bh); } } return OK; } /* semantic pass of --check */ static int check_semantic_pass (struct key * key, struct key * parent) { struct path path; void * sd; int is_new_dir; struct buffer_head * bh; struct item_head * ih; int retval; char * dir_item; int pos_in_item; struct item_head tmp_ih; struct key next_item_key, entry_key, object_key; __u64 dir_size = 0; __u32 blocks; __u64 saved_size; __u32 saved_blocks; int fix_sd; if (!KEY_IS_STAT_DATA_KEY (key)) die ("check_semantic_pass: key must be key of a stat data"); /* look for stat data of an object */ if (usearch_by_key (fs, key, &path) == ITEM_NOT_FOUND) { pathrelse (&path); return STAT_DATA_NOT_FOUND; } /* stat data has been found */ sd = get_item(&path); if (not_a_directory (sd)) { retval = check_check_regular_file (&path, sd); pathrelse (&path); return retval; } ih = get_ih (&path); /* directory stat data found */ if (ih_item_len (ih) == SD_SIZE) is_new_dir = 1; else is_new_dir = 0; /* save stat data's size and st_blocks */ get_sd_size (ih, sd, &saved_size); get_sd_blocks (ih, sd, &saved_blocks); /* release path pointing to stat data */ pathrelse (&path); stats(fs)->directories ++; next_item_key = *key; next_item_key.u.k_offset_v1.k_offset = DOT_OFFSET; next_item_key.u.k_offset_v1.k_uniqueness = DIRENTRY_UNIQUENESS; dir_size = 0; while ((dir_item = get_next_directory_item (&next_item_key, parent, &tmp_ih, &pos_in_item)) != 0) { /* dir_item is copy of the item in separately allocated memory, item_key is a key of next item in the tree */ int i; struct reiserfs_de_head * deh = (struct reiserfs_de_head *)dir_item + pos_in_item; for (i = pos_in_item; i < ih_entry_count (&tmp_ih); i ++, deh ++) { char * name; int namelen; name = name_in_entry (deh, i); namelen = name_length (&tmp_ih, deh, i); print_name (name, namelen); if (!is_properly_hashed (fs, name, namelen, deh_offset (deh))) { fsck_log ("check_semantic_pass: hash mismatch detected (%.*s)\n", namelen, name); } get_object_key (deh, &object_key, &entry_key, &tmp_ih); if (is_dot (name, namelen) || is_dot_dot (name, namelen)) { /* do not go through "." and ".." */ retval = OK; } else { add_path_key (&object_key); retval = check_semantic_pass (&object_key, key); del_path_key (); } erase_name (namelen); /* check what check_semantic_tree returned */ switch (retval) { case OK: dir_size += DEH_SIZE + entry_length (&tmp_ih, deh, i); break; case STAT_DATA_NOT_FOUND: fsck_log ("check_semantic_pass: name \"%.*s\" in directory %K points to nowhere", namelen, name, &tmp_ih.ih_key); if (fsck_fix_fixable (fs)) { reiserfs_remove_entry (fs, &entry_key); stats(fs)->deleted_entries ++; fsck_log (" - removed"); } fsck_log ("\n"); break; case DIRECTORY_HAS_NO_ITEMS: fsck_log ("check_semantic_pass: name \"%.*s\" in directory %K points dir without body\n", namelen, name, &tmp_ih.ih_key); /* fixme: stat data should be deleted as well */ /* if (fsck_fix_fixable (fs)) { reiserfs_remove_entry (fs, &entry_key); stats(fs)->deleted_entries ++; fsck_log (" - removed"); } fsck_log ("\n");*/ break; case RELOCATED: /* fixme: we could also relocate file */ reiserfs_panic ("check_semantic_pass: relocation in check mode is not ready"); } } /* for */ freemem (dir_item); if (not_of_one_file (&next_item_key, key)) /* next key is not of this directory */ break; } /* while (dir_item) */ if (dir_size == 0) /* FIXME: is it possible? */ return DIRECTORY_HAS_NO_ITEMS; /* calc correct value of sd_blocks field of stat data */ blocks = dir_size2st_blocks (fs->s_blocksize, dir_size); fix_sd = 0; fix_sd += wrong_st_blocks (key, blocks, saved_blocks, 1/*dir*/); fix_sd += wrong_st_size (key, is_new_dir ? MAX_FILE_SIZE_V2 : MAX_FILE_SIZE_V1, fs->s_blocksize, &dir_size, saved_size, 1/*dir*/); if (fix_sd && fsck_fix_fixable (fs)) { /* we have to fix either sd_size or sd_blocks, so look for stat data again */ if (usearch_by_key (fs, key, &path) != ITEM_FOUND) die ("check_semantic_tree: stat data not found"); bh = get_bh (&path); ih = get_ih (&path); sd = get_item (&path); set_sd_size (ih, sd, &dir_size); set_sd_blocks (ih, sd, &blocks); mark_buffer_dirty (bh); pathrelse (&path); } return OK; } /* called when --check is given */ void semantic_check (void) { fsck_progress ("Checking Semantic tree..."); if (check_semantic_pass (&root_dir_key, &parent_root_dir_key) != OK) die ("check_semantic_tree: no root directory found"); fsck_progress ("ok\n"); } reiserfsprogs-3.x.0j/fsck/pass4.c0000644000076400001440000000277407254517755012531 /* * Copyright 1996, 1997, 1998 Hans Reiser */ #include "fsck.h" void get_next_key (struct path * path, int i, struct key * key) { struct buffer_head * bh = PATH_PLAST_BUFFER (path); struct key * rkey; if (i < B_NR_ITEMS (bh) - 1) { /* next item is in this block */ copy_key (key, B_N_PKEY (bh, i + 1)); return; } rkey = uget_rkey (path); if (rkey) { /* got next item key from right delimiting key */ copy_key (key, rkey); } else { /* there is no next item */ memset (key, 0xff, KEY_SIZE); } } int pass_4_check_unaccessed_items (void) { struct key key; struct path path; int i; struct buffer_head * bh; struct item_head * ih; unsigned long items; path.path_length = ILLEGAL_PATH_ELEMENT_OFFSET; key = root_dir_key; fsck_progress ("Pass 4 - "); items = 0; while (usearch_by_key (fs, &key, &path) == ITEM_FOUND) { bh = PATH_PLAST_BUFFER (&path); /* print ~ how many leaves were scanned and how fast it was */ if (!fsck_quiet (fs)) print_how_fast (0, items++, 50); for (i = get_item_pos (&path), ih = get_ih (&path); i < B_NR_ITEMS (bh); i ++, ih ++) { if (!is_item_reachable (ih)) { get_next_key (&path, i, &key); stats(fs)->deleted_items ++; PATH_LAST_POSITION (&path) = i; reiserfsck_delete_item (&path, 0); goto cont; } } get_next_key (&path, i - 1, &key); pathrelse (&path); cont: } pathrelse (&path); fsck_progress ("done\n"); stage_report (4, fs); return 0; } reiserfsprogs-3.x.0j/fsck/lost+found.c0000644000076400001440000001663307261175466013563 /* * Copyright 2000-2001 Hans Reiser */ #include "fsck.h" /* fixme: search_by_key is not needed after any add_entry */ static __u64 _look_for_lost (reiserfs_filsys_t fs, int link_lost_dirs) { struct key key, prev_key, * rdkey; INITIALIZE_PATH (path); int item_pos; struct buffer_head * bh; struct item_head * ih; unsigned long leaves; int is_it_dir; static int lost_files = 0; /* looking for lost dirs we calculate amount of lost files, so that when we will look for lost files we will be able to stop when there are no lost files anymore */ int retval; __u64 size; key = root_dir_key; if (!link_lost_dirs && !lost_files) { /* we have to look for lost files but we know already that there are no any */ return 0; } fsck_progress ("Looking for lost %s:\n", link_lost_dirs ? "directories" : "files"); leaves = 0; /* total size of added entries */ size = 0; while (1) { retval = usearch_by_key (fs, &key, &path); /* fixme: we assume path ends up with a leaf */ bh = get_bh (&path); item_pos = get_item_pos (&path); if (retval != ITEM_FOUND) { if (item_pos == node_item_number (bh)) { rdkey = uget_rkey (&path); if (!rdkey) { pathrelse (&path); break; } key = *rdkey; pathrelse (&path); continue; } /* we are on the item in the buffer */ } /* print ~ how many leaves were scanned and how fast it was */ if (!fsck_quiet (fs)) print_how_fast (0, leaves++, 50); for (ih = get_ih (&path); item_pos < node_item_number (bh); item_pos ++, ih ++) { if (is_item_reachable (ih)) continue; /* found item which can not be reached */ if (!is_direntry_ih (ih) && !is_stat_data_ih (ih)) { continue; } if (is_direntry_ih (ih)) { /* if this directory has no stat data - try to recover it */ struct key sd; struct path tmp; sd = ih->ih_key; set_type_and_offset (KEY_FORMAT_1, &sd, SD_OFFSET, TYPE_STAT_DATA); if (usearch_by_key (fs, &sd, &tmp) == ITEM_FOUND) { /* should not happen - because if there were a stat data - we would have done with the whole directory */ pathrelse (&tmp); continue; } stats(fs)->dir_recovered ++; create_dir_sd (fs, &tmp, &sd); key = sd; pathrelse (&path); goto cont; } /* stat data marked "not having name" found */ is_it_dir = ((not_a_directory (B_I_PITEM (bh,ih))) ? 0 : 1); if (is_it_dir) { struct key tmp_key; INITIALIZE_PATH (tmp_path); struct item_head * tmp_ih; /* there is no need to link empty lost directories into /lost+found */ tmp_key = ih->ih_key; set_type_and_offset (KEY_FORMAT_1, &tmp_key, 0xffffffff, TYPE_DIRENTRY); usearch_by_key (fs, &tmp_key, &tmp_path); tmp_ih = get_ih (&tmp_path); tmp_ih --; if (not_of_one_file (&tmp_key, tmp_ih)) reiserfs_panic ("not directory found"); if (!is_direntry_ih (tmp_ih) || (deh_offset (B_I_DEH (get_bh (&tmp_path), ih) + ih_entry_count (tmp_ih) - 1) == DOT_DOT_OFFSET)) { /* last directory item is either stat data or empty directory item - do not link this dir into lost+found */ stats(fs)->empty_lost_dirs ++; pathrelse (&tmp_path); continue; } pathrelse (&tmp_path); } if (link_lost_dirs && !is_it_dir) { /* we are looking for directories and it is not a dir */ lost_files ++; continue; } stats(fs)->lost_found ++; { struct key obj_key = {0, 0, {{0, 0},}}; char * lost_name; struct item_head tmp_ih; int pos_in_map; /* key to continue */ key = ih->ih_key; key.k_objectid ++; tmp_ih = *ih; if (is_objectid_really_used (semantic_id_map (fs), ih->ih_key.k_objectid, &pos_in_map)) { /* objectid is used, relocate an object */ stats(fs)->oid_sharing ++; if (fsck_fix_non_critical (fs)) { if (is_it_dir) { relocate_dir (&tmp_ih, 1); stats(fs)->oid_sharing_dirs_relocated ++; } else { relocate_file (&tmp_ih, 1); stats(fs)->oid_sharing_files_relocated ++; } } } else { if (!is_it_dir) mark_objectid_really_used (semantic_id_map (fs), ih->ih_key.k_objectid); } asprintf (&lost_name, "%u_%u", le32_to_cpu (tmp_ih.ih_key.k_dir_id), le32_to_cpu (tmp_ih.ih_key.k_objectid)); /* entry in lost+found directory will point to this key */ obj_key.k_dir_id = tmp_ih.ih_key.k_dir_id; obj_key.k_objectid = tmp_ih.ih_key.k_objectid; pathrelse (&path); /* 0 does not mean anyting - item w/ "." and ".." already exists and reached, so only name will be added */ size += reiserfs_add_entry (fs, &lost_found_dir_key, lost_name, &obj_key, 0/*fsck_need*/); if (is_it_dir) { /* fixme: we hope that if we will try to pull all the directory right now - then there will be less lost_found things */ fsck_progress ("\tChecking lost dir \"%s\":", lost_name); rebuild_semantic_pass (&obj_key, &lost_found_dir_key, /*dot_dot*/0, /*reloc_ih*/0); fsck_progress ("ok\n"); stats(fs)->lost_found_dirs ++; } else { if (usearch_by_key (fs, &obj_key, &path) != ITEM_FOUND) reiserfs_panic ("look_for_lost: lost file stat data %K not found", &obj_key); /* check_regular_file does not mark stat data reachable */ mark_item_reachable (get_ih (&path), get_bh (&path)); mark_buffer_dirty (get_bh (&path)); rebuild_check_regular_file (&path, get_item (&path), 0/*reloc_ih*/); pathrelse (&path); stats(fs)->lost_found_files ++; lost_files --; } free (lost_name); goto cont; } } /* for */ prev_key = key; get_next_key (&path, item_pos - 1, &key); if (comp_keys (&prev_key, &key) != -1) reiserfs_panic ("pass_3a: key must grow 2: prev=%k next=%k", &prev_key, &key); pathrelse (&path); cont: if (!link_lost_dirs && !lost_files) { break; } } pathrelse (&path); #if 0 /* check names added we just have added to/lost+found. Those names are marked DEH_Lost_found flag */ fsck_progress ("Checking lost+found directory.."); fflush (stdout); check_semantic_tree (&lost_found_dir_key, &root_dir_key, 0, 1/* lost+found*/); fsck_progress ("ok\n"); #endif if (!link_lost_dirs && lost_files) fsck_log ("look_for_lost: %d files seem to left not linked to lost+found\n", lost_files); return size; } void pass_3a_look_for_lost (reiserfs_filsys_t fs) { INITIALIZE_PATH (path); struct item_head * ih; void * sd; __u64 size, sd_size; __u32 blocks; fsck_progress ("Pass 3a (looking for lost files):\n"); /* when warnings go not to stderr - separate then in the log */ if (fsck_log_file (fs) != stderr) fsck_log ("####### Pass 3a (lost+found pass) #########\n"); /* look for lost dirs first */ size = _look_for_lost (fs, 1); /* link files which are still lost */ size += _look_for_lost (fs, 0); /* update /lost+found sd_size and sd_blocks (nlink is correct already) */ if (usearch_by_key (fs, &lost_found_dir_key, &path) != ITEM_FOUND) reiserfs_panic ("look_for_lost: /lost+found stat data %K not found", &lost_found_dir_key); ih = get_ih (&path); sd = get_item (&path); get_sd_size (ih, sd, &sd_size); size += sd_size; blocks = dir_size2st_blocks (fs->s_blocksize, size); set_sd_size (ih, sd, &size); set_sd_blocks (ih, sd, &blocks); mark_buffer_dirty (get_bh (&path)); pathrelse (&path); stage_report (0x3a, fs); } reiserfsprogs-3.x.0j/fsck/ubitmap.c0000644000076400001440000000765707254512602013127 /* * Copyright 1996-1999 Hans Reiser */ #include "fsck.h" /* g_disk_bitmap initially contains copy of disk bitmaps (cautious version of it); g_new_bitmap initially has marked only super block, bitmap blocks and bits after the end of bitmap in pass 1 we go through g_disk_bitmap. If block does not look like formatted node, we skip it. If block contains internal node, put 0 in g_disk_bitmap if block is not used in new tree yet. If block contains leaf and is used already (by an indirect item handled already to this time) save all items. They will be inserted into tree after pass 1. If block looking like leaf is not used in the new tree, try to insert in into tree. If it is not possible, mark block in g_uninsertable_leaf_bitmap. Blocks marked in this bitmap will be inserted into tree in pass 2. They can not be This means, that in pass 1 when we have found block containing the internal nodes we mark it in g_disk_bitmap as free (reiserfs_free_internal_block). When block gets into new tree it is marked in g_new_bitmap (mark_block_used) When collecting resources for do_balance, we mark new blocks with mark_block_used. After do_balance we unmark unused new blocks in g_new_bitmap (bitmap.c:/reiserfs_free_block) Allocating of new blocks: look for 0 bit in g_disk_bitmap (find_zero_bit_in_bitmap), make sure, that g_new_bitmap contains 0 at the corresponding bit (is_block_used). */ int is_to_be_read (reiserfs_filsys_t fs, unsigned long block) { return reiserfs_bitmap_test_bit (fsck_disk_bitmap (fs), block); } /* is blocks used (marked by 1 in new bitmap) in the tree which is being built (as leaf, internal, bitmap, or unformatted node) */ int is_block_used (unsigned long block) { return reiserfs_bitmap_test_bit (fsck_new_bitmap (fs), block); } void mark_block_used (unsigned long block) { if (!block) return; if (is_block_used (block)) die ("mark_block_used: (%lu) used already", block); reiserfs_bitmap_set_bit (fsck_new_bitmap (fs), block); } void mark_block_free (unsigned long block) { if (!is_block_used (block)) die ("mark_block_used: (%lu) is free", block); reiserfs_bitmap_clear_bit (fsck_new_bitmap (fs), block); } int is_block_uninsertable (unsigned long block) { return !reiserfs_bitmap_test_bit (uninsertable_leaf_bitmap, block); } /* uninsertable block is marked by bit clearing */ void mark_block_uninsertable (unsigned long block) { if (is_block_uninsertable (block)) die ("mark_block_uninsertable: (%lu) is uninsertable already", block); reiserfs_bitmap_clear_bit (uninsertable_leaf_bitmap, block); } int reiserfsck_reiserfs_new_blocknrs (reiserfs_filsys_t fs, unsigned long * free_blocknrs, unsigned long start, int amount_needed) { int i; if (!are_there_allocable_blocks (amount_needed)) die ("out of disk space"); for (i = 0; i < amount_needed; i ++) { free_blocknrs[i] = alloc_block (); if (!free_blocknrs[i]) die ("reiserfs_new_blocknrs: 0 is allocated"); mark_block_used (free_blocknrs[i]); } return CARRY_ON; } // FIXME: do you check readability of a block? If f_read fails - you // free block in bitmap or if you mark bad blocks used to avoid their // allocation in future you should have bad block counter in a super // block. Another minor issue: users of _get_new_buffer expect buffer // to be filled with 0s struct buffer_head * reiserfsck_get_new_buffer (unsigned long start) { unsigned long blocknr = 0; struct buffer_head * bh = NULL; reiserfs_new_blocknrs (fs, &blocknr, start, 1); bh = getblk (fs->s_dev, blocknr, fs->s_blocksize); return bh; } /* free block in new bitmap */ int reiserfsck_reiserfs_free_block (reiserfs_filsys_t fs, unsigned long block) { mark_block_free (block); /* put it back to pool of blocks for allocation */ make_allocable (block); return 0; } reiserfsprogs-3.x.0j/fsck/uobjectid.c0000644000076400001440000002461307260404605013425 /* * Copyright 1996-2001 Hans Reiser */ #include "fsck.h" /* when --check fsck builds a map of objectids of files it finds in the tree when --rebuild-tree - fsck builds map of objectids it inserts into tree FIXME: objectid gets into map when stat data item */ /* is it marked used in super block's objectid map */ int is_objectid_used (reiserfs_filsys_t s, __u32 objectid) { __u32 * objectid_map; int i = 0; objectid_map = (__u32 *)((char *)(s->s_rs) + (sb_size(s))); while (i < SB_OBJECTID_MAP_SIZE (s)) { if (objectid == objectid_map[i]) { return 1; /* objectid is used */ } if (objectid > objectid_map[i] && objectid < objectid_map[i+1]) { return 1; /* objectid is used */ } if (objectid < objectid_map[i]) break; i += 2; } /* objectid is free */ return 0; } /* true objectid map */ /* size of 1 piece of map */ #define MAP_SIZE 4096 /* must be n * 2 * sizeof(__u32) */ #define MAX_MAP_SIZE 1 /* % of available memory? */ /* increase area by MAP_SIZE bytes */ static void grow_id_map (struct id_map * map) { if (map->m_page_count && ((map->m_page_count % 5) == 0)) { fsck_log ("grow_id_map: objectid map expanded: used %lu, %d blocks\n", map->m_used_slots_count, map->m_page_count); } map->m_begin = expandmem (map->m_begin, map->m_page_count * MAP_SIZE, MAP_SIZE); map->m_page_count ++; } static void try_to_shrink_id_map (struct id_map * map) { if (map->m_used_slots_count * sizeof(__u32) <= (map->m_page_count - 1) * MAP_SIZE) { if (map->m_page_count && ((map->m_page_count % 5) == 0)) fsck_log ("shrink_id_map: objectid map shrinked: used %lu, %d blocks\n", map->m_used_slots_count, map->m_page_count); map->m_begin = expandmem (map->m_begin, map->m_page_count * MAP_SIZE, -MAP_SIZE); map->m_page_count--; } } /* ubin_search_id is used to find id in the map (or proper place to insert the new id). if smth goes wrong or ubin_search_id stops working properly check_id_search_result should help to find raised problems */ static void check_id_search_result(struct id_map * map, int res, __u32 pos, __u32 id) { if (res != ITEM_FOUND && res != ITEM_NOT_FOUND) die("check_id_search_result: get wrong result from ubin_search (%d)", res); if (res == 1 && *(map->m_begin + pos) != id) die("check_id_search_result: wrong id found %u %u", id, *(map->m_begin + pos)); if (res == 1) { if (pos > map->m_used_slots_count) die("check_id_search_result: get bad position (%u), used %u", pos, map->m_used_slots_count); if (pos >= 0 && pos <= map->m_used_slots_count && *(map->m_begin + pos - 1) >= id) die("check_id_search_result: previous id (%u) not less than (%u)", *(map->m_begin + pos - 1), id); if (pos >= 0 && pos < map->m_used_slots_count && *(map->m_begin + pos) < id) die("check_id_search_result: found id (%u) not much than (%u)", *(map->m_begin + pos), id); } } static int comp_ids (void * p1, void * p2) { __u32 * id1, * id2; id1 = p1; id2 = p2; if ( *id1 < *id2 ) return -1; if ( *id1 > *id2 ) return 1; return 0; } /* */ struct id_map * init_id_map (void) { struct id_map * map; map = getmem (sizeof (struct id_map)); map->m_begin = NULL; map->m_used_slots_count = 0; map->m_page_count = 0; mark_objectid_really_used (map, 1); return map; } /* free whole map */ void free_id_map (struct id_map ** map) { freemem ((*map)->m_begin); freemem (*map); *map = 0; } /* return 1 if id is marked used, 0 otherwise */ int is_objectid_really_used (struct id_map * map, __u32 id, int * ppos) { int res; *ppos = 0; if (map->m_begin == NULL) return 0; /* smth exists in the map, find proper place to insert or this id */ res = ubin_search (&id, map->m_begin, map->m_used_slots_count, sizeof (__u32), ppos, comp_ids); #if 1 check_id_search_result (map, res, *ppos, id); #endif /* *ppos is position in objectid map of the element which is equal id or position of an element which is smallest and greater than id */ if (res == ITEM_NOT_FOUND) /* id is not found in the map. if returned position is odd - id is marked used */ return (*ppos % 2); /* if returned position is odd - id is marked free */ return !(*ppos % 2); } static void check_objectid_map (struct id_map * map) { int i; for (i = 1; i < map->m_used_slots_count; i ++) if (map->m_begin [i - 1] >= map->m_begin [i]) die ("check_objectid_map: map corrupted"); } /* returns 1 objectid is marked used already, 0 otherwise */ int mark_objectid_really_used (struct id_map * map, __u32 id) { int pos; /* check whether id is used and get place if used or place to insert if not */ if (is_objectid_really_used (map, id, &pos) == 1) return 1; map->objectids_marked ++; if (pos % 2 == 0){ /* id not found in the map. why? is_id_used() knows */ if (map->m_begin == NULL) /* map is empty */ grow_id_map (map); /* id + 1 is used, change id + 1 to id and exit */ if ( id + 1 == le32_to_cpu (map->m_begin[pos]) ) { /* we can mark id as used w/o expanding of id map */ map->m_begin[pos] = cpu_to_le32 (id); check_objectid_map (map); return 0; } if (map->m_page_count * MAP_SIZE == map->m_used_slots_count * sizeof(__u32)) /* fixme: do not grow too much */ grow_id_map (map); if (map->m_used_slots_count - pos > 0) memmove (map->m_begin + pos + 2, map->m_begin + pos, (map->m_used_slots_count - pos) * sizeof (__u32)); map->m_used_slots_count += 2; map->m_begin[pos] = cpu_to_le32 (id); map->m_begin[pos+1] = cpu_to_le32 (id + 1); check_objectid_map (map); return 0; } /* id found in the map. pos is odd position () */ map->m_begin[pos] = cpu_to_le32 (id + 1); /* if end id of current interval == start id of next interval we eliminated a sequence of unused objectids */ if (pos + 1 < map->m_used_slots_count && map->m_begin[pos + 1] == map->m_begin[pos]) { memmove (map->m_begin + pos, map->m_begin + pos + 2, (map->m_used_slots_count - pos - 2) * sizeof (__u32)); map->m_used_slots_count -= 2; try_to_shrink_id_map (map); } check_objectid_map (map); return 0; } static __u32 get_free_id (reiserfs_filsys_t fs) { struct id_map * map; map = proper_id_map (fs); /* If map is not NULL return the second element (first position in the map). This allocates the first unused objectid. That is to say, the first entry on the objectid map is the first unused objectid. */ if (map->m_begin == NULL) { fprintf (stderr, "get_free_id: hmm, 1 is allocated as objectid\n"); return 1; } return (le32_to_cpu (map->m_begin[1])); } __u32 get_unused_objectid (reiserfs_filsys_t fs) { __u32 objectid; objectid = get_free_id (fs); if (mark_objectid_really_used (proper_id_map (fs), objectid)) die ("get_unused_objectid: could not mark %lu used", objectid); return objectid; } #define objectid_map(fs) ((char *)((char *)((fs)->s_rs) + sb_size (fs))) #if 0 /* returns 0 if on-disk objectid map matches to the correct one, 1 otherwise */ int compare_id_maps (reiserfs_filsys_t fs) { struct id_map * map; int disk_size; map = proper_id_map (fs); disk_size = rs_objectid_map_size (fs->s_rs); if (disk_size != map->m_used_slots_count || memcmp ((char *)((char *)((fs)->s_rs) + sb_size (fs)), map->m_begin, sizeof(__u32) * disk_size)) { fprintf (stderr, "Objectid maps mismatch\n"); return 1; } return 0; } /* copy objectid map into buffer containing super block */ void correct_objectid_map (reiserfs_filsys_t fs) { struct id_map * map; int size, disk_max; map = proper_id_map (fs); size = map->m_used_slots_count; disk_max = rs_objectid_map_max_size (fs->s_rs); if (disk_max < size) { size = disk_max; } else { memset (fu_objectid_map (fs) + size, 0, (disk_max - size) * sizeof (__u32)); } memcpy (fu_objectid_map (fs), map->m_begin, size * sizeof (__u32)); set_objectid_map_size (fs->s_rs, size); mark_buffer_dirty (SB_BUFFER_WITH_SB (fs)); /* if (fs->fu_job->verbose) fprintf (stderr, "Objectid map corrected\n"); */ } #endif #if 0 /* print the map of objectids */ void print_objectid_list () { int i; printf ("\n control id map: all %d, used:%d", id_map.m_page_count * MAP_SIZE, id_map.m_used_slots_count); for (i = 0; i < id_map.m_used_slots_count; i += 2) printf ("\n[%u-%u]", id_map.m_begin[i], id_map.m_begin[i + 1] - 1); } /* print on-disk map of objectids */ void print_disk_objectid_list (void) { int i; __u32 * objectid_map = (__u32 *)((char *)SB_DISK_SUPER_BLOCK (&g_sb) + (sb_size(&g_sb))); printf ("\n on-disk id map. used:%lu", SB_OBJECTID_MAP_SIZE(&g_sb)); for (i = 0; i < SB_OBJECTID_MAP_SIZE(&g_sb); i += 2) printf ("\n[%u-%u]", objectid_map[i], objectid_map[i + 1] - 1); } #endif void flush_objectid_map (struct id_map * map, reiserfs_filsys_t fs) { int size, max; int sb_size; __u32 * sb_objectid_map; sb_size = (is_reiser2fs_magic_string (fs->s_rs) ? SB_SIZE : SB_SIZE_V1); sb_objectid_map = (__u32 *)((char *)(fs->s_rs) + sb_size); check_objectid_map (map); max = ((fs->s_blocksize - sb_size) >> 3 << 1); set_objectid_map_max_size (fs->s_rs, max); if (map->m_used_slots_count > max) size = max; else size = map->m_used_slots_count; memcpy (sb_objectid_map, map->m_begin, size * sizeof (__u32)); memset (sb_objectid_map + size, 0, (max - size) * sizeof (__u32)); set_objectid_map_size (fs->s_rs, size); if (size == max) /*((__u32 *)((char *)(fs->s_rs) + sb_size))*/ sb_objectid_map [max - 1] = map->m_begin [map->m_used_slots_count - 1]; check_objectid_map (map); } void fetch_objectid_map (struct id_map * map, reiserfs_filsys_t fs) { int sb_size; __u32 * sb_objectid_map; sb_size = (is_reiser2fs_magic_string (fs->s_rs) ? SB_SIZE : SB_SIZE_V1); sb_objectid_map = (__u32 *)((char *)(fs->s_rs) + sb_size); if (map->m_page_count != 1) die ("fetch_objectid_map: can not fetch long map"); grow_id_map (map); memcpy (map->m_begin, sb_objectid_map, rs_objectid_map_size (fs->s_rs) * sizeof (__u32)); map->m_used_slots_count = rs_objectid_map_size (fs->s_rs); } reiserfsprogs-3.x.0j/fsck/ustree.c0000644000076400001440000004703507260373641012774 /* * Copyright 1996-2001 Hans Reiser */ #include "fsck.h" /* key1 and key2 are pointer to deh_offset of the struct reiserfs_de_head */ int comp_dir_entries (void * key1, void * key2) { __u32 off1, off2; off1 = le32_to_cpu (*(__u32 *)key1); off2 = le32_to_cpu (*(__u32 *)key2); if (off1 < off2) return -1; if (off1 > off2) return 1; return 0; } void init_tb_struct (struct tree_balance * tb, struct super_block * s, struct path * path, int size) { memset (tb, '\0', sizeof(struct tree_balance)); tb->tb_sb = s; tb->tb_path = path; PATH_OFFSET_PBUFFER(path, ILLEGAL_PATH_ELEMENT_OFFSET) = NULL; PATH_OFFSET_POSITION(path, ILLEGAL_PATH_ELEMENT_OFFSET) = 0; tb->insert_size[0] = size; } struct tree_balance * cur_tb = 0; void reiserfsck_paste_into_item (struct path * path, const char * body, int size) { struct tree_balance tb; init_tb_struct (&tb, fs, path, size); if (fix_nodes (/*tb.transaction_handle,*/ M_PASTE, &tb, 0/*ih*/) != CARRY_ON) //fix_nodes(options, tree_balance, ih_to_option, body_to_option) die ("reiserfsck_paste_into_item: fix_nodes failed"); do_balance (/*tb.transaction_handle,*/ &tb, 0, body, M_PASTE, 0/*zero num*/); } void reiserfsck_insert_item (struct path * path, struct item_head * ih, const char * body) { struct tree_balance tb; init_tb_struct (&tb, fs, path, IH_SIZE + ih_item_len(ih)); if (fix_nodes (/*tb.transaction_handle,*/ M_INSERT, &tb, ih/*, body*/) != CARRY_ON) die ("reiserfsck_insert_item: fix_nodes failed"); do_balance (/*tb.transaction_handle,*/ &tb, ih, body, M_INSERT, 0/*zero num*/); } static void free_unformatted_nodes (struct item_head * ih, struct buffer_head * bh) { __u32 * punfm = (__u32 *)B_I_PITEM (bh, ih); int i; for (i = 0; i < I_UNFM_NUM (ih); i ++, punfm ++) if (*punfm) { struct buffer_head * to_be_forgotten; to_be_forgotten = find_buffer (fs->s_dev, *punfm, fs->s_blocksize); if (to_be_forgotten) { //atomic_inc(&to_be_forgotten->b_count); to_be_forgotten->b_count ++; bforget (to_be_forgotten); } reiserfs_free_block (fs, *punfm); } } void reiserfsck_delete_item (struct path * path, int temporary) { struct tree_balance tb; struct item_head * ih = PATH_PITEM_HEAD (path); if (is_indirect_ih (ih) && !temporary) free_unformatted_nodes (ih, PATH_PLAST_BUFFER (path)); init_tb_struct (&tb, fs, path, -(IH_SIZE + ih_item_len(ih))); if (fix_nodes (/*tb.transaction_handle,*/ M_DELETE, &tb, 0/*ih*/) != CARRY_ON) die ("reiserfsck_delete_item: fix_nodes failed"); do_balance (/*tb.transaction_handle,*/ &tb, 0, 0, M_DELETE, 0/*zero num*/); } void reiserfsck_cut_from_item (struct path * path, int cut_size) { struct tree_balance tb; struct item_head * ih; if (cut_size >= 0) die ("reiserfsck_cut_from_item: cut size == %d", cut_size); if (is_indirect_ih (ih = PATH_PITEM_HEAD (path))) { __u32 unfm_ptr = B_I_POS_UNFM_POINTER (PATH_PLAST_BUFFER (path), ih, I_UNFM_NUM (ih) - 1); if (unfm_ptr) { struct buffer_head * to_be_forgotten; to_be_forgotten = find_buffer (fs->s_dev, le32_to_cpu (unfm_ptr), fs->s_blocksize); if (to_be_forgotten) { //atomic_inc(&to_be_forgotten->b_count); to_be_forgotten->b_count ++; bforget (to_be_forgotten); } reiserfs_free_block (fs, le32_to_cpu (unfm_ptr)); } } init_tb_struct (&tb, fs, path, cut_size); if (fix_nodes (/*tb.transaction_handle,*/ M_CUT, &tb, 0) != CARRY_ON) die ("reiserfsck_cut_from_item: fix_nodes failed"); do_balance (/*tb.transaction_handle,*/ &tb, 0, 0, M_CUT, 0/*zero num*/); } /* uget_lkey is utils clone of stree.c/get_lkey */ struct key * uget_lkey (struct path * path) { int pos, offset = path->path_length; struct buffer_head * bh; if (offset < FIRST_PATH_ELEMENT_OFFSET) die ("uget_lkey: illegal offset in the path (%d)", offset); /* While not higher in path than first element. */ while (offset-- > FIRST_PATH_ELEMENT_OFFSET) { if (! buffer_uptodate (PATH_OFFSET_PBUFFER (path, offset)) ) die ("uget_lkey: parent is not uptodate"); /* Parent at the path is not in the tree now. */ if (! B_IS_IN_TREE (bh = PATH_OFFSET_PBUFFER (path, offset))) die ("uget_lkey: buffer on the path is not in tree"); /* Check whether position in the parent is correct. */ if ((pos = PATH_OFFSET_POSITION (path, offset)) > B_NR_ITEMS (bh)) die ("uget_lkey: invalid position (%d) in the path", pos); /* Check whether parent at the path really points to the child. */ if (B_N_CHILD_NUM (bh, pos) != PATH_OFFSET_PBUFFER (path, offset + 1)->b_blocknr) die ("uget_lkey: invalid block number (%d). Must be %d", B_N_CHILD_NUM (bh, pos), PATH_OFFSET_PBUFFER (path, offset + 1)->b_blocknr); /* Return delimiting key if position in the parent is not equal to zero. */ if (pos) return B_N_PDELIM_KEY(bh, pos - 1); } /* there is no left delimiting key */ return 0; } /* uget_rkey is utils clone of stree.c/get_rkey */ struct key * uget_rkey (struct path * path) { int pos, offset = path->path_length; struct buffer_head * bh; if (offset < FIRST_PATH_ELEMENT_OFFSET) die ("uget_rkey: illegal offset in the path (%d)", offset); while (offset-- > FIRST_PATH_ELEMENT_OFFSET) { if (! buffer_uptodate (PATH_OFFSET_PBUFFER (path, offset))) die ("uget_rkey: parent is not uptodate"); /* Parent at the path is not in the tree now. */ if (! B_IS_IN_TREE (bh = PATH_OFFSET_PBUFFER (path, offset))) die ("uget_rkey: buffer on the path is not in tree"); /* Check whether position in the parrent is correct. */ if ((pos = PATH_OFFSET_POSITION (path, offset)) > B_NR_ITEMS (bh)) die ("uget_rkey: invalid position (%d) in the path", pos); /* Check whether parent at the path really points to the child. */ if (B_N_CHILD_NUM (bh, pos) != PATH_OFFSET_PBUFFER (path, offset + 1)->b_blocknr) die ("uget_rkey: invalid block number (%d). Must be %d", B_N_CHILD_NUM (bh, pos), PATH_OFFSET_PBUFFER (path, offset + 1)->b_blocknr); /* Return delimiting key if position in the parent is not the last one. */ if (pos != B_NR_ITEMS (bh)) return B_N_PDELIM_KEY(bh, pos); } /* there is no right delimiting key */ return 0; } inline int ubin_search (void * key, void * base, int num, int width, __u32 *ppos, comp_function_t comp_func) { __u32 rbound, lbound, j; lbound = 0; if (num == 0){ *ppos = 0; return ITEM_NOT_FOUND; } rbound = num - 1; for (j = (rbound + lbound) / 2; lbound <= rbound; j = (rbound + lbound) / 2) { switch (comp_func ((void *)((char *)base + j * width), key ) ) { case -1:/* second is greater */ lbound = j + 1; continue; case 1: /* first is greater */ if (j == 0){ *ppos = lbound; return ITEM_NOT_FOUND; } rbound = j - 1; continue; case 0: *ppos = j; return ITEM_FOUND; } } *ppos = lbound; return ITEM_NOT_FOUND; } /* this searches in tree through items */ int usearch_by_key (struct super_block * s, struct key * key, struct path * path) { struct buffer_head * bh; unsigned long block = SB_ROOT_BLOCK (s); struct path_element * curr; int retval; path->path_length = ILLEGAL_PATH_ELEMENT_OFFSET; while (1) { curr = PATH_OFFSET_PELEMENT (path, ++ path->path_length); bh = curr->pe_buffer = bread (s->s_dev, block, s->s_blocksize); if (bh == 0) reiserfs_panic ("usearch_by_key: unable to read %lu block on device 0x%x\n",block, s->s_dev); retval = ubin_search (key, B_N_PKEY (bh, 0), B_NR_ITEMS (bh), is_leaf_node (bh) ? IH_SIZE : KEY_SIZE, &(curr->pe_position), comp_keys); if (retval == ITEM_FOUND) { /* key found, return if this is leaf level */ if (is_leaf_node (bh)) { path->pos_in_item = 0; return ITEM_FOUND; } curr->pe_position ++; } else { /* key not found in the node */ if (is_leaf_node (bh)) return ITEM_NOT_FOUND; } block = B_N_CHILD_NUM (bh, curr->pe_position); } die ("search_by_key: you can not get here"); return 0; } /* key is key of directory entry. This searches in tree through items and in the found directory item as well */ int usearch_by_entry_key (struct super_block * s, struct key * key, struct path * path) { struct buffer_head * bh; struct item_head * ih; struct key tmpkey; if (usearch_by_key (s, key, path) == ITEM_FOUND) { /* entry found */ path->pos_in_item = 0; return POSITION_FOUND; } bh = PATH_PLAST_BUFFER (path); if (PATH_LAST_POSITION (path) == 0) { /* previous item does not exist, that means we are in leftmost leaf of the tree */ if (uget_lkey (path) != 0) die ("search_by_entry_key: invalid position after search_by_key"); if (not_of_one_file (B_N_PKEY (bh, 0), key)) { path->pos_in_item = 0; return DIRECTORY_NOT_FOUND; } if (!is_direntry_ih (get_ih (path))) { fsck_progress ("search_by_entry_key: directory expected to have this key %K\n", key); return REGULAR_FILE_FOUND; } /* position for name insertion is found */ path->pos_in_item = 0; return POSITION_NOT_FOUND; } /* take previous item */ PATH_LAST_POSITION (path) --; ih = PATH_PITEM_HEAD (path); if (not_of_one_file (&(ih->ih_key), key) || !is_direntry_ih(ih)) { /* previous item belongs to another object or is stat data, check next item */ PATH_LAST_POSITION (path) ++; if (PATH_LAST_POSITION (path) < B_NR_ITEMS (bh)) { /* found item is not last item of the node */ struct item_head * next_ih = B_N_PITEM_HEAD (bh, PATH_LAST_POSITION (path)); if (not_of_one_file (&(next_ih->ih_key), key)) { path->pos_in_item = 0; return DIRECTORY_NOT_FOUND; } if (!is_direntry_ih(next_ih)) { /* there is an item in the tree, but it is not a directory item */ reiserfs_warning (stderr, "search_by_entry_key: directory expected to have this key %k\n", key); return REGULAR_FILE_FOUND; } } else { /* found item is last item of the node */ struct key * next_key = uget_rkey (path); if (next_key == 0 || not_of_one_file (next_key, key)) { /* there is not any part of such directory in the tree */ path->pos_in_item = 0; return DIRECTORY_NOT_FOUND; } if (!is_direntry_key (next_key)) { /* there is an item in the tree, but it is not a directory item */ fsck_progress ("search_by_entry_key: directory expected to have this key %k\n", key); return REGULAR_FILE_FOUND; } // we got right delimiting key - search for it - the entry will be // pasted in position 0 copy_key (&tmpkey, next_key); pathrelse (path); if (usearch_by_key (s, &tmpkey, path) != ITEM_FOUND || PATH_LAST_POSITION (path) != 0) die ("search_by_entry_key: item not found by corresponding delimiting key"); } /* next item is the part of this directory */ path->pos_in_item = 0; return POSITION_NOT_FOUND; } /* previous item is part of desired directory */ if (ubin_search (&(key->u.k_offset_v1.k_offset), B_I_DEH (bh, ih), ih_entry_count (ih), DEH_SIZE, &(path->pos_in_item), comp_dir_entries) == ITEM_FOUND) return POSITION_FOUND; return POSITION_NOT_FOUND; } /* key is key of byte in the regular file. This searches in tree through items and in the found item as well */ int usearch_by_position (struct super_block * s, struct key * key, int version, struct path * path) { struct buffer_head * bh; struct item_head * ih; if (usearch_by_key (s, key, path) == ITEM_FOUND) { ih = PATH_PITEM_HEAD (path); if (!is_direct_ih(ih) && !is_indirect_ih(ih)) return DIRECTORY_FOUND; path->pos_in_item = 0; return POSITION_FOUND; } bh = PATH_PLAST_BUFFER (path); ih = PATH_PITEM_HEAD (path); if ( (PATH_LAST_POSITION(path) < B_NR_ITEMS (bh)) && !not_of_one_file (&ih->ih_key, key) && (get_offset(&ih->ih_key) == get_offset(key)) ) { if (!is_direct_ih(ih) && !is_indirect_ih(ih)) return DIRECTORY_FOUND; path->pos_in_item = 0; return POSITION_FOUND; } if (PATH_LAST_POSITION (path) == 0) { /* previous item does not exist, that means we are in leftmost leaf of the tree */ if (!not_of_one_file (B_N_PKEY (bh, 0), key)) { if (!is_direct_ih(ih) && !is_indirect_ih (ih)) return DIRECTORY_FOUND; return POSITION_NOT_FOUND; } return FILE_NOT_FOUND; } /* take previous item */ PATH_LAST_POSITION (path) --; ih = PATH_PITEM_HEAD (path); if (not_of_one_file (&ih->ih_key, key) || is_stat_data_ih(ih)) { struct key * next_key; /* previous item belongs to another object or is a stat data, check next item */ PATH_LAST_POSITION (path) ++; if (PATH_LAST_POSITION (path) < B_NR_ITEMS (PATH_PLAST_BUFFER (path))) /* next key is in the same node */ next_key = B_N_PKEY (PATH_PLAST_BUFFER (path), PATH_LAST_POSITION (path)); else next_key = uget_rkey (path); if (next_key == 0 || not_of_one_file (next_key, key)) { /* there is no any part of such file in the tree */ path->pos_in_item = 0; return FILE_NOT_FOUND; } if (is_direntry_key (next_key)) { fsck_log ("\nusearch_by_position: looking for %k found a directory with the same key\n", next_key); return DIRECTORY_FOUND; } /* next item is the part of this file */ path->pos_in_item = 0; if ( get_offset(next_key) == get_offset(key) ) { pathrelse(path); if (usearch_by_key (s, next_key, path) != ITEM_FOUND) { reiserfs_panic ("usearch_by_position: keys must be equals %k %k", next_key, &PATH_PITEM_HEAD (path)->ih_key); } return POSITION_FOUND; } return POSITION_NOT_FOUND; } if (is_direntry_ih(ih)) { return DIRECTORY_FOUND; } if (is_stat_data_ih(ih)) { PATH_LAST_POSITION (path) ++; return FILE_NOT_FOUND; } /* previous item is part of desired file */ //if (is_key_in_item (bh,ih,key,bh->b_size)) { if (I_K_KEY_IN_ITEM (ih, key, bh->b_size)) { path->pos_in_item = get_offset (key) - get_offset (&ih->ih_key); if (is_indirect_ih (ih) ) path->pos_in_item /= bh->b_size; return POSITION_FOUND; } path->pos_in_item = is_indirect_ih (ih) ? I_UNFM_NUM (ih) : ih_item_len (ih); return POSITION_NOT_FOUND; } static unsigned long first_child (struct buffer_head * bh) { return child_block_number (bh, 0); } #if 0 static unsigned long last_child (struct buffer_head * bh) { return child_block_number (bh, node_item_number (bh)); } #endif static unsigned long get_child (int pos, struct buffer_head * parent) { if (pos == -1) return -1; if (pos > B_NR_ITEMS (parent)) die ("get_child: no child found, should not happen: %d of %d", pos, B_NR_ITEMS (parent)); return child_block_number (parent, pos); /* for (i = 0; i < B_NR_ITEMS (parent); i ++) { if (child_block_number (parent, i) == block) return child_block_number (parent, i + 1); } die ("next_child: no child found: should not happen"); return 0; */ } static void print (int cur, int total) { printf ("/%3d (of %3d)", cur, total);fflush (stdout); } /* erase /XXX(of XXX) */ static void erase (void) { printf ("\b\b\b\b\b\b\b\b\b\b\b\b\b"); printf (" "); printf ("\b\b\b\b\b\b\b\b\b\b\b\b\b"); fflush (stdout); } #if 0 void pass_through_tree2 (struct super_block * s, do_after_read_t action1, do_on_full_path_t action2) { struct buffer_head * path[MAX_HEIGHT] = {0,}; int total[MAX_HEIGHT] = {0,}; int cur[MAX_HEIGHT] = {0,}; int h = 0; unsigned long block = SB_ROOT_BLOCK (s); int del_p; if (block >= SB_BLOCK_COUNT (s) || not_data_block (s, block)) return; while ( 1 ) { if (path[h]) die ("pass_through_tree: empty slot expected"); if (h) print (cur[h - 1], total[h - 1]); path[h] = bread (s->s_dev, block, s->s_blocksize); get_child (-1, path[h]); if (path[h] == 0) reiserfs_warning ("pass_through_tree: unable to read %lu block on device 0x%x\n", block, s->s_dev); del_p = 0; if (path[h] && action1) { if (action1 (s, path, h)) { ; #if 0 // something wrong with a buffer we just have read if (opt_fsck_mode == FSCK_FAST_REBUILD){ //need to change the way we are going on del_p = 1; if (h == 0) break; } else { ; //reiserfs_panic (s, "Run reiserfsck with --rebuild-tree\n"); } #endif } } if (!path[h] || is_leaf_node (path[h])) { if (path[h] && action2) { if (action2 (s, path, h)) { ; #if 0 if (opt_fsck_mode == FSCK_FAST_REBUILD) { //need to change the way we are going on del_p = 1; if (h == 0) break; } else { ; //reiserfs_panic (s, "Run reiserfsck with --rebuild-tree\n"); } #endif } } if (path[h]) brelse (path[h]); if (h) erase (); while (h && (!path[h-1] || cur[h-1] == total[h-1] )) { path[h] = 0; h --; if (path[h]) brelse (path[h]); if (h) erase (); } if (h == 0) { path[h] = 0; break; } if (path[h]) cur[h - 1] ++; if (del_p){ total[h-1]--; del_p = 0; } block = get_child (cur[h - 1] - 1, path[h-1]); path[h] = 0; continue; } total[h] = B_NR_ITEMS (path[h]) + 1; cur[h] = 1; block = first_child (path[h]); h ++; } } #endif void pass_through_tree (struct super_block * s, do_after_read_t action1, do_on_full_path_t action2) { struct buffer_head * path[MAX_HEIGHT] = {0,}; int total[MAX_HEIGHT] = {0,}; int cur[MAX_HEIGHT] = {0,}; int h = 0; unsigned long block = SB_ROOT_BLOCK (s); if (block >= SB_BLOCK_COUNT (s) || not_data_block (s, block)) { fsck_progress ("\nBad root block %lu. (--rebuild-tree did not complete)\n", block); return; } while ( 1 ) { if (path[h]) die ("pass_through_tree: empty slot expected"); if (h) print (cur[h - 1], total[h - 1]); path[h] = bread (s->s_dev, block, s->s_blocksize); if (path[h] == 0) /* FIXME: handle case when read failed */ die ("pass_through_tree: unable to read %lu block on device 0x%x\n", block, s->s_dev); if (action1) action1 (s, path, h); if (is_leaf_node (path[h])) { if (action2) action2 (s, path, h); brelse (path[h]); if (h) erase (); while (h && (cur[h-1] == total[h-1])) { path[h] = 0; h --; brelse (path[h]); if (h) erase (); } if (h == 0) { path[h] = 0; break; } block = get_child (cur[h - 1], path[h-1]); cur[h - 1] ++; path[h] = 0; continue; } total[h] = B_NR_ITEMS (path[h]) + 1; cur[h] = 1; block = first_child (path[h]); h ++; } } reiserfsprogs-3.x.0j/fsck/ufile.c0000644000076400001440000010267307256662267012603 /* * Copyright 1996, 1997, 1998 Hans Reiser */ #include "fsck.h" static int do_items_have_the_same_type (struct item_head * ih, struct key * key) { return (get_type (&ih->ih_key) == get_type (key)) ? 1 : 0; } static int are_items_in_the_same_node (struct path * path) { return (PATH_LAST_POSITION (path) < B_NR_ITEMS (PATH_PLAST_BUFFER (path)) - 1) ? 1 : 0; } /* FIXME: there is get_next_key in pass4.c */ static struct key * get_next_key_2 (struct path * path) { if (PATH_LAST_POSITION (path) < B_NR_ITEMS (get_bh (path)) - 1) return B_N_PKEY (get_bh (path), PATH_LAST_POSITION (path) + 1); return uget_rkey (path); } int do_make_tails () { return 1;/*SB_MAKE_TAIL_FLAG (&g_sb) == MAKE_TAILS ? YES : NO;*/ } static void cut_last_unfm_pointer (struct path * path, struct item_head * ih) { set_free_space(ih, 0); if (I_UNFM_NUM (ih) == 1) reiserfsck_delete_item (path, 0); else reiserfsck_cut_from_item (path, -UNFM_P_SIZE); } // we use this to convert symlinks back to direct items if they were // direct2indirect converted on tree building static unsigned long indirect_to_direct (struct path * path, __u64 *symlink_size) { struct buffer_head * bh = PATH_PLAST_BUFFER (path); struct item_head * ih = PATH_PITEM_HEAD (path); unsigned long unfm_ptr; struct buffer_head * unfm_bh = 0; struct item_head ins_ih; char * buf; int len; __u32 * indirect; char bad_link[] = "broken_link"; /* add_event (INDIRECT_TO_DIRECT);*/ /* direct item to insert */ set_key_format (&ins_ih, ih_key_format (ih)); ins_ih.ih_key.k_dir_id = ih->ih_key.k_dir_id; ins_ih.ih_key.k_objectid = ih->ih_key.k_objectid; set_type_and_offset (ih_key_format (ih), &ins_ih.ih_key, get_offset (&ih->ih_key) + (I_UNFM_NUM (ih) - 1) * bh->b_size, TYPE_DIRECT); // we do not know what length this item should be indirect = get_item (path); unfm_ptr = le32_to_cpu (indirect [I_UNFM_NUM (ih) - 1]); if (unfm_ptr && (unfm_bh = bread (bh->b_dev, unfm_ptr, bh->b_size))) { buf = unfm_bh->b_data; // get length of direct item for (len = 0; buf[len] && len < bh->b_size; len ++); } else { fsck_log ("indirect_to_direct: could not read block %lu, " "making (%K) bad link instead\n", unfm_ptr, &ih->ih_key); buf = bad_link; len = strlen (bad_link); } if (len > MAX_DIRECT_ITEM_LEN (fs->s_blocksize)) { fsck_log ("indirect_to_direct: symlink %K seems too long %d, " "Cutting it down to %d byte\n", &ih->ih_key, len, MAX_DIRECT_ITEM_LEN (fs->s_blocksize) - 8); len = MAX_DIRECT_ITEM_LEN (fs->s_blocksize) - 8; } if (!len) { buf = bad_link; len = strlen (bad_link); } *symlink_size = len; ins_ih.ih_item_len = cpu_to_le16 ((ih_key_format (ih) == KEY_FORMAT_2) ? ROUND_UP(len) : len); set_free_space (&ins_ih, MAX_US_INT); // last last unformatted node pointer path->pos_in_item = I_UNFM_NUM (ih) - 1; cut_last_unfm_pointer (path, ih); /* insert direct item */ if (usearch_by_key (fs, &(ins_ih.ih_key), path) == ITEM_FOUND) die ("indirect_to_direct: key must be not found"); reiserfsck_insert_item (path, &ins_ih, (const char *)(buf)); brelse (unfm_bh); /* put to stat data offset of first byte in direct item */ return get_offset (&ins_ih.ih_key); //offset; } extern inline __u64 get_min_bytes_number (struct item_head * ih, int blocksize) { switch (get_type (&ih->ih_key)) { case TYPE_DIRECT: if (SB_VERSION(fs) == REISERFS_VERSION_2) return ROUND_UP(ih_item_len (ih) - 8); else return ih_item_len (ih); case TYPE_INDIRECT: return (I_UNFM_NUM(ih) - 1) * blocksize; } fsck_log ("get_min_bytes_number: called for wrong type of item %H\n", ih); return 0; } /* returns 1 when file looks correct, -1 if directory items appeared there, 0 - only holes in the file found */ /* when it returns, key->k_offset is offset of the last item of file */ int are_file_items_correct (struct key * key, int key_version, __u64 * size, /*__u64 * min_size,*/ __u32 * blocks, int mark_passed_items, int symlink, __u64 symlink_size) { struct path path; int retval, i; struct item_head * ih; struct key * next_key; int had_direct = 0; set_offset (key_version, key, 1); set_type (key_version, key, TYPE_DIRECT); *size = 0; /* *min_size = 0;*/ *blocks = 0; path.path_length = ILLEGAL_PATH_ELEMENT_OFFSET; do { retval = usearch_by_position (fs, key, key_version, &path); if (retval == POSITION_FOUND && path.pos_in_item != 0) die ("are_file_items_correct: all bytes we look for must be found at position 0"); switch (retval) { case POSITION_FOUND:/**/ ih = PATH_PITEM_HEAD (&path); set_type (ih_key_format (ih), key, get_type (&ih->ih_key)); if (mark_passed_items == 1) { mark_item_reachable (ih, PATH_PLAST_BUFFER (&path)); } // does not change path next_key = get_next_key_2 (&path); if (get_type (&ih->ih_key) == TYPE_INDIRECT) { if (symlink) *blocks = 1; else for (i = 0; i < I_UNFM_NUM (ih); i ++) { __u32 * ind = (__u32 *)get_item(&path); if (ind[i] != 0) *blocks += (fs->s_blocksize >> 9); } }else if ((get_type (&ih->ih_key) == TYPE_DIRECT) && !(had_direct)) { if (symlink) *blocks = (fs->s_blocksize >> 9); else *blocks += (fs->s_blocksize >> 9); had_direct++; } if (next_key == 0 || not_of_one_file (key, next_key) || (!is_indirect_key (next_key) && !is_direct_key(next_key) ) ) { /* next item does not exists or is of another object, therefore all items of file are correct */ /* *min_size = get_offset (key) + get_min_bytes_number (ih, fs->s_blocksize);*/ *size = get_offset (key) + get_bytes_number (ih, fs->s_blocksize) - 1; /* here is a problem: if file system being repaired was full enough, then we should avoid indirect_to_direct conversions. This is because unformatted node we have to free will not get into pool of free blocks, but new direct item is very likely of big size, therefore it may require allocation of new blocks. So, skip it for now */ if (symlink && is_indirect_ih (ih)) { // struct key sd_key; unsigned long first_direct_byte; if (fsck_mode (fs) == FSCK_CHECK) { fsck_log ("are_file_items_correct: symlink found in indirect item %K\n", &ih->ih_key); } else { first_direct_byte = indirect_to_direct (&path, &symlink_size); /* last item of the file is direct item */ set_offset (key_version, key, first_direct_byte); set_type (key_version, key, TYPE_DIRECT); *size = symlink_size; } } else pathrelse (&path); return 1; } /* next item is item of this file */ if ((is_indirect_ih (ih) && (get_offset (&ih->ih_key) + fs->s_blocksize * I_UNFM_NUM (ih) != get_offset (next_key))) || (is_direct_ih (ih) && (get_offset (&ih->ih_key) + ih_item_len (ih) != get_offset (next_key)))) { /* next item has incorrect offset (hole or overlapping) */ *size = get_offset (&ih->ih_key) + get_bytes_number (ih, fs->s_blocksize) - 1; /**min_size = *size;*/ pathrelse (&path); return 0; } if (do_items_have_the_same_type (ih, next_key) == 1 && are_items_in_the_same_node (&path) == 1) { /* two indirect items or two direct items in the same leaf. FIXME: Second will be deleted */ *size = get_offset (&ih->ih_key) + get_bytes_number (ih, fs->s_blocksize) - 1; /**min_size = *size;*/ pathrelse (&path); return 0; } /* items are of different types or are in different nodes */ if (get_offset (&ih->ih_key) + get_bytes_number (ih, fs->s_blocksize) != get_offset (next_key)) { /* indirect item free space is not set properly */ if (!is_indirect_ih (ih) ) //|| get_ih_free_space(ih) == 0) fsck_log ("are_file_items_correct: " "item must be indirect and must have invalid free space (%H)", ih); if (fsck_mode (fs) != FSCK_CHECK) { set_free_space(ih, 0); mark_buffer_dirty (PATH_PLAST_BUFFER (&path)); } } /* next item exists */ set_type_and_offset(key_version, key, get_offset (next_key), get_type(next_key)); if (comp_keys (key, next_key)) die ("are_file_items_correct: keys do not match %k and %k", key, next_key); pathrelse (&path); break; case POSITION_NOT_FOUND: // we always must have next key found. Exception is first // byte. It does not have to exist if (get_offset (key) != 1) die ("are_file_items_correct: key not found %byte can be not found only when it is first byte of file"); pathrelse (&path); return 0; case FILE_NOT_FOUND: if (get_offset (key) != 1) die ("are_file_items_correct: there is no items of this file, byte 0 found though"); pathrelse (&path); return 1; case DIRECTORY_FOUND: pathrelse (&path); return -1; } } while (1); die ("are_file_items_correct: code can not reach here"); return 0; } /* delete all items and put them back (after that file should have correct sequence of items.It is very similar to pass2.c:relocate_file () and should_relocate () */ static void rewrite_file (struct item_head * ih) { struct key key; struct key * rkey; struct path path; struct item_head * path_ih; struct si * si; /* starting with the leftmost one - look for all items of file, store and delete and */ key = ih->ih_key; set_type_and_offset (KEY_FORMAT_1, &key, SD_OFFSET, TYPE_STAT_DATA); si = 0; while (1) { usearch_by_key (fs, &key, &path); if (get_item_pos (&path) == B_NR_ITEMS (get_bh (&path))) { rkey = uget_rkey (&path); if (rkey && !not_of_one_file (&key, rkey)) { /* file continues in the right neighbor */ copy_key (&key, rkey); pathrelse (&path); continue; } /* there is no more items with this key */ pathrelse (&path); break; } path_ih = get_ih (&path); if (not_of_one_file (&key, &(path_ih->ih_key))) { /* there are no more item with this key */ pathrelse (&path); break; } /* ok, item found, but make sure that it is not a directory one */ if ((is_stat_data_ih (path_ih) && !not_a_directory (get_item (&path))) || (is_direntry_ih (path_ih))) reiserfs_panic ("rewrite_file: no directory items of %K are expected", &key); si = save_and_delete_file_item (si, &path); } /* put all items back into tree */ while (si) { insert_item_separately (&(si->si_ih), si->si_dnm_data, 1/*was in tree*/); si = remove_saved_item (si); } } /* file must have correct sequence of items and tail must be stored in unformatted pointer */ static int make_file_writeable (struct item_head * ih) { struct key key; __u64 size;/*, min_size;*/ __u32 blocks; int retval; copy_key (&key, &(ih->ih_key)); retval = are_file_items_correct (&key, ih_key_format (ih), &size,/* &min_size, */ &blocks, 0/*do not mark accessed*/, 0, 0); if (retval == 1) /* file looks correct */ return 1; rewrite_file (ih); stats(fs)->rewritten ++; /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ copy_key (&key, &(ih->ih_key)); size = 0; if (are_file_items_correct (&key, ih_key_format (ih), &size, &blocks, 0/*do not mark accessed*/, 0, 0) == 0) { fsck_progress ("file still incorrect %K\n", &key); } /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ return 1; } /* this inserts __first__ indirect item (having k_offset == 1 and only one unfm pointer) into tree */ static int create_first_item_of_file (struct item_head * ih, char * item, struct path * path, int *pos_in_coming_item, int was_in_tree) { __u32 unfm_ptr; struct buffer_head * unbh; struct item_head indih; int retval; __u32 free_sp = 0; if (get_offset (&ih->ih_key) > fs->s_blocksize) { /* insert indirect item containing 0 unfm pointer */ unfm_ptr = 0; set_free_space (&indih, 0); free_sp = 0; retval = 0; } else { if (is_direct_ih (ih)) { /* copy direct item to new unformatted node. Save information about it */ //__u64 len = get_bytes_number(0, ih, item, CHECK_FREE_BYTES); __u64 len = get_bytes_number (ih, fs->s_blocksize); unbh = reiserfsck_get_new_buffer (PATH_PLAST_BUFFER (path)->b_blocknr); memset (unbh->b_data, 0, unbh->b_size); unfm_ptr = cpu_to_le32 (unbh->b_blocknr); /* this is for check only */ /*mark_block_unformatted (le32_to_cpu (unfm_ptr));*/ memcpy (unbh->b_data + get_offset (&ih->ih_key) - 1, item, len); save_unfm_overwriting (le32_to_cpu (unfm_ptr), ih); set_free_space (&indih, fs->s_blocksize - len - (get_offset (&ih->ih_key) - 1)); free_sp = fs->s_blocksize - len - (get_offset (&ih->ih_key) - 1); mark_buffer_dirty (unbh); // mark_buffer_uptodate (unbh, 0); mark_buffer_uptodate (unbh, 1); brelse (unbh); retval = len; } else { /* take first unformatted pointer from an indirect item */ unfm_ptr = cpu_to_le32 (*(__u32 *)item);/*B_I_POS_UNFM_POINTER (bh, ih, 0);*/ if (!was_in_tree) { if (still_bad_unfm_ptr_2 (unfm_ptr)) die ("create_first_item_of_file: bad unfm pointer %d", unfm_ptr); mark_block_used (unfm_ptr); } //free_sp = ih_get_free_space(0, ih, item); free_sp = ih_free_space (ih); set_free_space (&indih, ((ih_item_len(ih) == UNFM_P_SIZE) ? free_sp /*get_ih_free_space(ih)*/ : 0)); if (ih_item_len (ih) != UNFM_P_SIZE) free_sp = 0; // free_sp = ((ih->ih_item_len == UNFM_P_SIZE) ? ih->u.ih_free_space : 0); retval = fs->s_blocksize - free_sp; (*pos_in_coming_item) ++; } } set_key_format (&indih, ih_key_format (ih)); //ih_version(&indih) = ih_version(ih); copy_key (&(indih.ih_key), &(ih->ih_key)); set_offset (key_format (&(ih->ih_key)), &indih.ih_key, 1); set_type (key_format (&(ih->ih_key)), &indih.ih_key, TYPE_INDIRECT); indih.ih_item_len = cpu_to_le16 (UNFM_P_SIZE); mark_item_unreachable (&indih); reiserfsck_insert_item (path, &indih, (const char *)&unfm_ptr); return retval; } /* path points to first part of tail. Function copies file tail into unformatted node and returns its block number. If we are going to overwrite direct item then keep free space (keep_free_space == YES). Else (we will append file) set free space to 0 */ /* we convert direct item that is on the path to indirect. we need a number of free block for unformatted node. reiserfs_new_blocknrs will start from block number returned by this function */ static unsigned long block_to_start (struct path * path) { struct buffer_head * bh; struct item_head * ih; bh = PATH_PLAST_BUFFER (path); ih = PATH_PITEM_HEAD (path); if (get_offset(&ih->ih_key) == 1 || PATH_LAST_POSITION (path) == 0) return bh->b_blocknr; ih --; return (B_I_POS_UNFM_POINTER (bh, ih, I_UNFM_NUM (ih) - 1)) ?: bh->b_blocknr; } static void direct2indirect2 (unsigned long unfm, struct path * path, int keep_free_space) { struct item_head * ih; struct key key; struct buffer_head * unbh; struct unfm_nodeinfo ni; int copied = 0; ih = PATH_PITEM_HEAD (path); copy_key (&key, &(ih->ih_key)); if (get_offset (&key) % fs->s_blocksize != 1) { /* look for first part of tail */ pathrelse (path); set_offset (key_format (&key), &key, (get_offset (&key) & ~(fs->s_blocksize - 1)) + 1); if (usearch_by_key (fs, &key, path) != ITEM_FOUND) die ("direct2indirect: can not find first part of tail"); } unbh = reiserfsck_get_new_buffer (unfm ?: block_to_start (path)); memset (unbh->b_data, 0, unbh->b_size); /* delete parts of tail coping their contents to new buffer */ do { //__u64 len = get_bytes_number(PATH_PLAST_BUFFER(path), ih, 0, CHECK_FREE_BYTES); __u64 len; ih = PATH_PITEM_HEAD (path); len = get_bytes_number(ih, fs->s_blocksize); memcpy (unbh->b_data + copied, B_I_PITEM (PATH_PLAST_BUFFER (path), ih), len); save_unfm_overwriting (unbh->b_blocknr, ih); copied += len; set_offset (key_format (&key), &key, get_offset (&key) + len); // set_offset (ih_key_format (ih), &key, get_offset (&key) + len); reiserfsck_delete_item (path, 0); } while (usearch_by_key (fs, &key, path) == ITEM_FOUND); ih = PATH_PITEM_HEAD (path); pathrelse (path); /* paste or insert pointer to the unformatted node */ set_offset (key_format (&key), &key, get_offset (&key) - copied); // set_offset (ih_key_format (ih), &key, get_offset (&key) - copied); // key.k_offset -= copied; ni.unfm_nodenum = cpu_to_le32 (unbh->b_blocknr); ni.unfm_freespace = (keep_free_space == 1) ? (fs->s_blocksize - copied) : 0; /* this is for check only */ /*mark_block_unformatted (ni.unfm_nodenum);*/ if (usearch_by_position (fs, &key, key_format (&key), path) == FILE_NOT_FOUND) { struct item_head insih; copy_key (&(insih.ih_key), &key); set_key_format (&insih, key_format (&key)); set_type (ih_key_format (&insih), &insih.ih_key, TYPE_INDIRECT); set_free_space (&insih, ni.unfm_freespace); // insih.u.ih_free_space = ni.unfm_freespace; mark_item_unreachable (&insih); insih.ih_item_len = cpu_to_le16 (UNFM_P_SIZE); reiserfsck_insert_item (path, &insih, (const char *)&(ni.unfm_nodenum)); } else { ih = PATH_PITEM_HEAD (path); if (!is_indirect_ih (ih) || get_offset (&key) != get_bytes_number (ih, fs->s_blocksize) + 1) die ("direct2indirect: incorrect item found"); reiserfsck_paste_into_item (path, (const char *)&ni, UNFM_P_SIZE); } mark_buffer_dirty (unbh); // mark_buffer_uptodate (unbh, 0); mark_buffer_uptodate (unbh, 1); brelse (unbh); if (usearch_by_position (fs, &key, ih_key_format (ih), path) != POSITION_FOUND || !is_indirect_ih (PATH_PITEM_HEAD (path))) die ("direct2indirect: position not found"); return; } static int append_to_unformatted_node (struct item_head * comingih, struct item_head * ih, char * item, struct path * path, __u16 * free_sp, __u64 coming_len) { struct buffer_head * bh, * unbh; __u64 end_of_data; //ih->u.ih_free_space; __u64 offset = get_offset (&comingih->ih_key) % fs->s_blocksize - 1; int zero_number; __u32 unfm_ptr; /* append to free space of the last unformatted node of indirect item ih */ if (*free_sp /*ih->u.ih_free_space*/ < coming_len) { *free_sp = get_offset (&ih->ih_key) + fs->s_blocksize * I_UNFM_NUM (ih) - get_offset (&comingih->ih_key); if (*free_sp < coming_len) die ("reiserfsck_append_file: there is no enough free space in unformatted node"); } end_of_data = fs->s_blocksize - *free_sp; zero_number = offset - end_of_data; bh = PATH_PLAST_BUFFER (path); unfm_ptr = B_I_POS_UNFM_POINTER (bh, ih, I_UNFM_NUM (ih) - 1); /*if (unfm_ptr != 0 && unfm_ptr < SB_BLOCK_COUNT (fs))*/ if (unfm_ptr && !not_data_block (fs, unfm_ptr)) { unbh = bread (fs->s_dev, unfm_ptr, fs->s_blocksize); if (!is_block_used (unfm_ptr)) die ("append_to_unformatted_node: unused block %d", unfm_ptr); if (unbh == 0) unfm_ptr = 0; } else { /* indirect item points to block which can not be pointed or to 0, in any case we have to allocate new node */ /*if (unfm_ptr == 0 || unfm_ptr >= SB_BLOCK_COUNT (fs)) {*/ unbh = reiserfsck_get_new_buffer (bh->b_blocknr); memset (unbh->b_data, 0, unbh->b_size); B_I_POS_UNFM_POINTER (bh, ih, I_UNFM_NUM (ih) - 1) = unbh->b_blocknr; /*mark_block_unformatted (unbh->b_blocknr);*/ mark_buffer_dirty (bh); } memset (unbh->b_data + end_of_data, 0, zero_number); memcpy (unbh->b_data + offset, item, coming_len); save_unfm_overwriting (unbh->b_blocknr, comingih); *free_sp /*ih->u.ih_free_space*/ -= (zero_number + coming_len); set_free_space(ih, ih_free_space(ih) - (zero_number + coming_len)); memset (unbh->b_data + offset + coming_len, 0, *free_sp); // mark_buffer_uptodate (unbh, 0); mark_buffer_uptodate (unbh, 1); mark_buffer_dirty (unbh); brelse (unbh); pathrelse (path); return coming_len; } static void adjust_free_space (struct buffer_head * bh, struct item_head * ih, struct item_head * comingih, __u16 *free_sp) { // printf ("adjust_free_space does nothing\n"); return; if (is_indirect_ih (comingih)) { set_free_space(ih, 0);//?? *free_sp = (__u16)0; } else { if (get_offset (&comingih->ih_key) < get_offset (&ih->ih_key) + fs->s_blocksize * I_UNFM_NUM (ih)) { /* append to the last unformatted node */ set_free_space (ih, fs->s_blocksize - get_offset(&ih->ih_key) % fs->s_blocksize + 1);//?? *free_sp = (__u16)fs->s_blocksize - get_offset(&ih->ih_key) % fs->s_blocksize + 1; } else { set_free_space(ih,0);//?? *free_sp =0; } } mark_buffer_dirty (bh); } /* this appends file with one unformatted node pointer (since balancing algorithm limitation). This pointer can be 0, or new allocated block or pointer from indirect item that is being inserted into tree */ int reiserfsck_append_file (struct item_head * comingih, char * item, int pos, struct path * path, int was_in_tree) { struct unfm_nodeinfo ni; struct buffer_head * unbh; int retval; struct item_head * ih = PATH_PITEM_HEAD (path); __u16 keep_free_space; __u32 bytes_number; if (!is_indirect_ih (ih)) die ("reiserfsck_append_file: can not append to non-indirect item"); //keep_free_space = ih_get_free_space(PATH_PLAST_BUFFER (path), PATH_PITEM_HEAD(path), 0); keep_free_space = ih_free_space (ih); if (get_offset (&ih->ih_key) + get_bytes_number (ih, fs->s_blocksize) //get_bytes_number (PATH_PLAST_BUFFER (path), PATH_PITEM_HEAD(path), 0, CHECK_FREE_BYTES) != get_offset (&comingih->ih_key)){ adjust_free_space (PATH_PLAST_BUFFER (path), ih, comingih, &keep_free_space); } if (is_direct_ih (comingih)) { //__u64 coming_len = get_bytes_number (0,comingih, item, CHECK_FREE_BYTES); __u64 coming_len = get_bytes_number (comingih, fs->s_blocksize); if (get_offset (&comingih->ih_key) < get_offset (&ih->ih_key) + fs->s_blocksize * I_UNFM_NUM (ih)) { /* direct item fits to free space of indirect item */ return append_to_unformatted_node (comingih, ih, item, path, &keep_free_space, coming_len); } unbh = reiserfsck_get_new_buffer (PATH_PLAST_BUFFER (path)->b_blocknr); memset (unbh->b_data, 0, unbh->b_size); /* this is for check only */ /*mark_block_unformatted (unbh->b_blocknr);*/ memcpy (unbh->b_data + get_offset (&comingih->ih_key) % unbh->b_size - 1, item, coming_len); save_unfm_overwriting (unbh->b_blocknr, comingih); mark_buffer_dirty (unbh); // mark_buffer_uptodate (unbh, 0); mark_buffer_uptodate (unbh, 1); ni.unfm_nodenum = unbh->b_blocknr; ni.unfm_freespace = fs->s_blocksize - coming_len - (get_offset (&comingih->ih_key) % unbh->b_size - 1); brelse (unbh); retval = coming_len; } else { /* coming item is indirect item */ //bytes_number = get_bytes_number (PATH_PLAST_BUFFER (path), PATH_PITEM_HEAD(path), 0, CHECK_FREE_BYTES); bytes_number = get_bytes_number (ih, fs->s_blocksize); if (get_offset (&comingih->ih_key) + pos * fs->s_blocksize != get_offset (&ih->ih_key) + bytes_number) fsck_progress ("reiserfsck_append_file: can not append indirect item (%H) to the %H", comingih, ih); /* take unformatted pointer from an indirect item */ ni.unfm_nodenum = *(__u32 *)(item + pos * UNFM_P_SIZE);/*B_I_POS_UNFM_POINTER (bh, ih, pos);*/ if (!was_in_tree) { if (still_bad_unfm_ptr_2 (ni.unfm_nodenum)) die ("reiserfsck_append_file: bad unfm pointer"); mark_block_used (ni.unfm_nodenum); } ni.unfm_freespace = ((pos == (I_UNFM_NUM (comingih) - 1)) ? //ih_get_free_space(0, comingih, item) /*comingih->u.ih_free_space*/ : 0); ih_free_space (comingih) /*comingih->u.ih_free_space*/ : 0); retval = fs->s_blocksize - ni.unfm_freespace; } reiserfsck_paste_into_item (path, (const char *)&ni, UNFM_P_SIZE); return retval; } int must_there_be_a_hole (struct item_head * comingih, struct path * path) { struct item_head * ih = PATH_PITEM_HEAD (path); int keep_free_space; if (is_direct_ih (ih)) { direct2indirect2 (0, path, keep_free_space = 1); ih = PATH_PITEM_HEAD (path); } path->pos_in_item = I_UNFM_NUM (ih); if (get_offset (&ih->ih_key) + (I_UNFM_NUM (ih) + 1) * fs->s_blocksize <= get_offset (&comingih->ih_key)) return 1; return 0; } int reiserfs_append_zero_unfm_ptr (struct path * path) { struct unfm_nodeinfo ni; int keep_free_space; ni.unfm_nodenum = 0; ni.unfm_freespace = 0; if (is_direct_ih (PATH_PITEM_HEAD (path))) /* convert direct item to indirect */ direct2indirect2 (0, path, keep_free_space = 0); reiserfsck_paste_into_item (path, (const char *)&ni, UNFM_P_SIZE); return 0; } /* write direct item to unformatted node */ /* coming item is direct */ static int overwrite_by_direct_item (struct item_head * comingih, char * item, struct path * path) { __u32 unfm_ptr; struct buffer_head * unbh, * bh; struct item_head * ih; int offset; __u64 coming_len = get_bytes_number (comingih, fs->s_blocksize); bh = PATH_PLAST_BUFFER (path); ih = PATH_PITEM_HEAD (path); unfm_ptr = le32_to_cpu (B_I_POS_UNFM_POINTER (bh, ih, path->pos_in_item)); unbh = 0; if (unfm_ptr != 0 && unfm_ptr < SB_BLOCK_COUNT (fs)) { /**/ unbh = bread (fs->s_dev, unfm_ptr, bh->b_size); if (!is_block_used (unfm_ptr)) die ("overwrite_by_direct_item: unused block %d", unfm_ptr); if (unbh == 0) unfm_ptr = 0; } if (unfm_ptr == 0 || unfm_ptr >= SB_BLOCK_COUNT (fs)) { unbh = reiserfsck_get_new_buffer (bh->b_blocknr); memset (unbh->b_data, 0, unbh->b_size); B_I_POS_UNFM_POINTER (bh, ih, path->pos_in_item) = cpu_to_le32 (unbh->b_blocknr); mark_buffer_dirty (bh); } if (!unbh) { die ("overwrite_by_direct_item: could not put direct item in"); } offset = (get_offset (&comingih->ih_key) % bh->b_size) - 1; if (offset + coming_len > MAX_DIRECT_ITEM_LEN (bh->b_size)) die ("overwrite_by_direct_item: direct item too long (offset=%lu, length=%u)", get_offset (&comingih->ih_key), coming_len); memcpy (unbh->b_data + offset, item, coming_len); save_unfm_overwriting (unbh->b_blocknr, comingih); if ((path->pos_in_item == (I_UNFM_NUM (ih) - 1)) && (bh->b_size - ih_free_space (ih)) < (offset + coming_len)) { set_free_space (ih, bh->b_size - (offset + coming_len)) ; mark_buffer_dirty (bh); } mark_buffer_dirty (unbh); // mark_buffer_uptodate (unbh, 0); mark_buffer_uptodate (unbh, 1); brelse (unbh); return coming_len; } void overwrite_unfm_by_unfm (unsigned long unfm_in_tree, unsigned long coming_unfm, int bytes_in_unfm) { struct overwritten_unfm_segment * unfm_os_list;/* list of overwritten segments of the unformatted node */ struct overwritten_unfm_segment unoverwritten_segment; struct buffer_head * bh_in_tree, * coming_bh; if (!test_bit (coming_unfm % (fs->s_blocksize * 8), SB_AP_BITMAP (fs)[coming_unfm / (fs->s_blocksize * 8)]->b_data)) /* block (pointed by indirect item) is free, we do not have to keep its contents */ return; /* coming block is marked as used in disk bitmap. Put its contents to block in tree preserving everything, what has been overwritten there by direct items */ unfm_os_list = find_overwritten_unfm (unfm_in_tree, bytes_in_unfm, &unoverwritten_segment); if (unfm_os_list) { /* add_event (UNFM_OVERWRITING_UNFM);*/ bh_in_tree = bread (fs->s_dev, unfm_in_tree, fs->s_blocksize); coming_bh = bread (fs->s_dev, coming_unfm, fs->s_blocksize); if (bh_in_tree == 0 || coming_bh == 0) return; while (get_unoverwritten_segment (unfm_os_list, &unoverwritten_segment)) { if (unoverwritten_segment.ous_begin < 0 || unoverwritten_segment.ous_end > bytes_in_unfm - 1 || unoverwritten_segment.ous_begin > unoverwritten_segment.ous_end) die ("overwrite_unfm_by_unfm: invalid segment found (%d %d)", unoverwritten_segment.ous_begin, unoverwritten_segment.ous_end); memcpy (bh_in_tree->b_data + unoverwritten_segment.ous_begin, coming_bh->b_data + unoverwritten_segment.ous_begin, unoverwritten_segment.ous_end - unoverwritten_segment.ous_begin + 1); mark_buffer_dirty (bh_in_tree); } brelse (bh_in_tree); brelse (coming_bh); } } /* put unformatted node pointers from incoming item over the in-tree ones */ static int overwrite_by_indirect_item (struct item_head * comingih, __u32 * coming_item, struct path * path, int * pos_in_coming_item) { struct buffer_head * bh = PATH_PLAST_BUFFER (path); struct item_head * ih = PATH_PITEM_HEAD (path); int written; __u32 * item_in_tree; int src_unfm_ptrs, dest_unfm_ptrs, to_copy; int i; __u16 free_sp; item_in_tree = (__u32 *)B_I_PITEM (bh, ih) + path->pos_in_item; coming_item += *pos_in_coming_item; dest_unfm_ptrs = I_UNFM_NUM (ih) - path->pos_in_item; src_unfm_ptrs = I_UNFM_NUM (comingih) - *pos_in_coming_item; if (dest_unfm_ptrs >= src_unfm_ptrs) { /* whole coming item (comingih) fits into item in tree (ih) starting with path->pos_in_item */ //free_sp = ih_get_free_space(0, comingih, (char *)coming_item); free_sp = ih_free_space (comingih); written = get_bytes_number (comingih, fs->s_blocksize) - free_sp - *pos_in_coming_item * fs->s_blocksize; *pos_in_coming_item = I_UNFM_NUM (comingih); to_copy = src_unfm_ptrs; if (dest_unfm_ptrs == src_unfm_ptrs) set_free_space(ih, free_sp); //comingih->u.ih_free_space; } else { /* only part of coming item overlaps item in the tree */ *pos_in_coming_item += dest_unfm_ptrs; written = dest_unfm_ptrs * fs->s_blocksize; to_copy = dest_unfm_ptrs; set_free_space(ih, 0); } for (i = 0; i < to_copy; i ++) { if (!is_block_used (coming_item[i]) && !is_block_uninsertable (coming_item[i])) { if (item_in_tree[i]) { /* do not overwrite unformatted pointer. We must save everything what is there already from direct items */ overwrite_unfm_by_unfm (item_in_tree[i], coming_item[i], fs->s_blocksize); } else { item_in_tree[i] = coming_item[i]; mark_block_used (coming_item[i]); } } } mark_buffer_dirty (bh); return written; } static int reiserfsck_overwrite_file (struct item_head * comingih, char * item, struct path * path, int * pos_in_coming_item, int was_in_tree) { __u32 unfm_ptr; int written = 0; int keep_free_space; struct item_head * ih = PATH_PITEM_HEAD (path); if (not_of_one_file (ih, &(comingih->ih_key))) die ("reiserfsck_overwrite_file: found [%lu %lu], new item [%lu %lu]", ih->ih_key.k_dir_id, ih->ih_key.k_objectid, comingih->ih_key.k_dir_id, comingih->ih_key.k_objectid); if (is_direct_ih (ih)) { unfm_ptr = 0; if (is_indirect_ih (comingih)) { if (get_offset (&ih->ih_key) % fs->s_blocksize != 1) die ("reiserfsck_overwrite_file: second part of tail can not be overwritten by indirect item"); /* use pointer from coming indirect item */ unfm_ptr = le32_to_cpu (*(__u32 *)(item + *pos_in_coming_item * UNFM_P_SIZE)); if (!was_in_tree) { if (still_bad_unfm_ptr_2 (unfm_ptr)) die ("reiserfsck_overwrite_file: still bad "); } } /* */ direct2indirect2 (le32_to_cpu (unfm_ptr), path, keep_free_space = 1); } if (is_direct_ih (comingih)) { written = overwrite_by_direct_item (comingih, item, path); } else { if (was_in_tree) die ("reiserfsck_overwrite_file: item we are going to overwrite with could not be in the tree yet"); written = overwrite_by_indirect_item (comingih, (__u32 *)item, path, pos_in_coming_item); } return written; } /* */ int reiserfsck_file_write (struct item_head * ih, char * item, int was_in_tree) { struct path path; struct item_head * path_ih; int count, pos_in_coming_item; int retval; struct key key; int written; if (make_file_writeable (ih) == -1) { /* write was not completed. Skip that item. Maybe it should be saved to lost_found */ fsck_progress ("reiserfsck_file_write: skip writing %H\n", ih); return 0; } count = get_bytes_number (ih, fs->s_blocksize); pos_in_coming_item = 0; copy_key (&key, &(ih->ih_key)); while (count) { retval = usearch_by_position (fs, &key, key_format (&key), &path); if (retval == DIRECTORY_FOUND) reiserfs_panic ("directory found %k", key); if (retval == POSITION_FOUND) { written = reiserfsck_overwrite_file (ih, item, &path, &pos_in_coming_item, was_in_tree); count -= written; set_offset (key_format (&key), &key, get_offset (&key) + written); } if (retval == FILE_NOT_FOUND) { written = create_first_item_of_file (ih, item, &path, &pos_in_coming_item, was_in_tree); count -= written; set_offset (key_format (&key), &key, get_offset (&key) + written ); } if (retval == POSITION_NOT_FOUND) { path_ih = PATH_PITEM_HEAD (&path); if (must_there_be_a_hole (ih, &path) == 1) { reiserfs_append_zero_unfm_ptr (&path); }else { count -= reiserfsck_append_file (ih, item, pos_in_coming_item, &path, was_in_tree); set_offset (key_format (&key), &key, get_offset (&key) + fs->s_blocksize); pos_in_coming_item ++; } } if (count < 0) die ("reiserfsck_file_write: count < 0 (%d)", count); pathrelse (&path); } return get_bytes_number (ih, fs->s_blocksize); } reiserfsprogs-3.x.0j/fsck/check.c0000644000076400001440000002200607251201266012522 /* * Copyright 1996, 1997 Hans Reiser */ #include "fsck.h" /* this goes through buffers checking delimiting keys */ struct buffer_head * g_left = 0; struct buffer_head * g_right = 0; struct key * g_dkey = 0; static void check_directory_item (struct item_head * ih, struct buffer_head * bh) { int i; struct reiserfs_de_head * deh; for (i = 0, deh = B_I_DEH (bh, ih); i < ih_entry_count (ih) - 1; i ++) if (deh_offset(&deh[i]) > deh_offset(&deh[i + 1])) die ("check_directory_item: entries are not sorted properly"); } static void check_items (struct buffer_head * bh) { int i; struct item_head * ih; for (i = 0; i < B_NR_ITEMS (bh); i++) { ih = B_N_PITEM_HEAD (bh, i); if (is_direntry_ih (ih)) check_directory_item (ih, bh); } } static void compare_neighboring_leaves_in_pass1 (void) { struct key * left = B_N_PKEY (g_left, B_NR_ITEMS (g_left) - 1); if (comp_keys (left, B_N_PKEY (g_right, 0)) != -1/*SECOND_GREATER*/) die ("compare_neighboring_leaves_in_pass1: left key is greater, that the right one"); if (/*comp_keys (B_PRIGHT_DELIM_KEY (g_left), g_dkey) == FIRST_GREATER ||*/ comp_keys (g_dkey, B_N_PKEY (g_right, 0))) { reiserfs_panic (0, "compare_neighboring_leaves_in_pass1: dkey %k, first key in right %k", g_dkey, B_N_PKEY (g_right, 0)); } check_items (g_left); /*&&&&&&&&&&&&&&&&&&&&&&&&&& for (i = 0, ih = B_N_PITEM_HEAD (g_left, i); i < B_NR_ITEMS (g_left); i ++, ih ++) if (is_item_accessed (ih) == YES) die ("compare_neighboring_leaves_in_pass1: item marked as accessed in g_left"); for (i = 0, ih = B_N_PITEM_HEAD (g_right, i); i < B_NR_ITEMS (g_right); i ++, ih ++) if (is_item_accessed (ih) == YES) die ("compare_neighboring_leaves_in_pass1: item marked as accessed in g_right"); &&&&&&&&&&&&&&&&&&&&&&&&&&&*/ } static void is_there_unaccessed_items (struct buffer_head * bh) { int i; struct item_head * ih; ih = B_N_PITEM_HEAD (bh, 0); for (i = 0; i < B_NR_ITEMS (bh); i ++, ih ++) { if (is_objectid_used (fs, ih->ih_key.k_objectid) == 0) die ("is_there_unaccessed_items: %lu is not marked as used", ih->ih_key.k_objectid); if (!is_item_reachable (ih)) { die ("is_there_unaccessed_items: block %lu - unaccessed item found", bh->b_blocknr); } } } static void compare_neighboring_leaves_after_all (void) { struct item_head * left = B_N_PITEM_HEAD(g_left, B_NR_ITEMS (g_left) - 1); struct item_head * right = B_N_PITEM_HEAD(g_right, 0); /* struct key * left = B_N_PKEY (g_left, B_NR_ITEMS (g_left) - 1); struct key * right = B_N_PKEY (g_right, 0);*/ /* if (comp_keys (&left->ih_key, B_PRIGHT_DELIM_KEY (g_left)) != SECOND_GREATER) die ("compare_neighboring_leaves_after_all: invalid right delimiting key"); */ if (comp_keys (&left->ih_key, B_N_PKEY (g_right, 0)) != -1/*SECOND_GREATER*/) die ("compare_neighboring_leaves_after_all: left key is greater than the right one"); if (//comp_le_keys (B_PRIGHT_DELIM_KEY (g_left), g_dkey) != KEYS_IDENTICAL || comp_keys (g_dkey, B_N_PKEY (g_right, 0))) { reiserfs_panic (0, "compare_neighboring_leaves_after all: invalid delimiting keys from left to right (%k %k)", g_dkey, B_N_PKEY (g_right, 0)); } if (!not_of_one_file (&left->ih_key, &right->ih_key)) { // items of one file: check offset correctness if (is_direct_ih (left) || is_indirect_ih (left)) //if (get_offset(&right->ih_key) != get_offset(&left->ih_key) + get_bytes_number (g_left, left /*B_NR_ITEMS (g_left) - 1*/, 0, CHECK_FREE_BYTES)) if (get_offset(&right->ih_key) != get_offset(&left->ih_key) + get_bytes_number (left, g_left->b_size)) die ("compare_neighboring_leaves_after all: hole between items or items are overlapped"); } is_there_unaccessed_items (g_left); } typedef void (check_function_t)(void); /* only directory item can be fatally bad */ static int is_leaf_bad_xx (struct buffer_head * bh) { int i; struct item_head * ih; if (!is_leaf_node (bh)) return 0; for (i = 0, ih = B_N_PITEM_HEAD (bh, 0); i < B_NR_ITEMS (bh); i ++, ih ++) if (is_bad_item (bh, ih, B_I_PITEM (bh, ih))) { return 1; } return 0; } static void reiserfsck_check_tree (int dev, int block, int size, check_function_t comp_func) { struct buffer_head * bh; int what_node; bh = bread (dev, block, size); if (bh == 0) reiserfs_panic("reiserfsck_check_tree: unable to read %lu block on device 0x%x\n", block, dev); if (!B_IS_IN_TREE (bh)) { reiserfs_panic (0, "reiserfsck_check_tree: buffer (%b %z) not in tree", bh, bh); } what_node = who_is_this (bh->b_data, bh->b_size); if (what_node != THE_LEAF && what_node != THE_INTERNAL) die ("Not formatted node"); if (!is_block_used (bh->b_blocknr)) die ("Not marked as used"); if (is_leaf_node (bh) && is_leaf_bad_xx (bh)) die ("Bad leaf"); if (is_internal_node(bh) && is_internal_bad (bh)) die ("bad internal"); if (is_internal_node (bh)) { int i; struct disk_child * dc; dc = B_N_CHILD (bh, 0); for (i = 0; i <= B_NR_ITEMS (bh); i ++, dc ++) { reiserfsck_check_tree (dev, dc->dc_block_number, size, comp_func); g_dkey = B_N_PDELIM_KEY (bh, i); } } else if (is_leaf_node (bh)) { g_right = bh; if (g_left != 0 && g_dkey != 0) { comp_func (); brelse (g_left); } g_left = g_right; return; } else { reiserfs_panic ("reiserfsck_check_tree: block %lu has bad block type (%b)", bh->b_blocknr, bh); } brelse (bh); } static void reiserfsck_check_cached_tree (int dev, int block, int size) { struct buffer_head * bh; int what_node; bh = find_buffer(dev, block, size); if (bh == 0) return; if (!buffer_uptodate (bh)) { die ("reiserfsck_check_cached_tree: found notuptodate buffer"); } bh->b_count ++; if (!B_IS_IN_TREE (bh)) { die ("reiserfsck_check_cached_tree: buffer (%b %z) not in tree", bh, bh); } what_node = who_is_this (bh->b_data, bh->b_size); if ((what_node != THE_LEAF && what_node != THE_INTERNAL) || !is_block_used (bh->b_blocknr) || (is_leaf_node (bh) && is_leaf_bad (bh)) || (is_internal_node(bh) && is_internal_bad (bh))) die ("reiserfsck_check_cached_tree: bad node in the tree"); if (is_internal_node (bh)) { int i; struct disk_child * dc; dc = B_N_CHILD (bh, 0); for (i = 0; i <= B_NR_ITEMS (bh); i ++, dc ++) { reiserfsck_check_cached_tree (dev, dc->dc_block_number, size); g_dkey = B_N_PDELIM_KEY (bh, i); } } else if (is_leaf_node (bh)) { brelse (bh); return; } else { reiserfs_panic ("reiserfsck_check_cached_tree: block %lu has bad block type (%b)", bh->b_blocknr, bh); } brelse (bh); } void reiserfsck_tree_check (check_function_t how_to_compare_neighbors) { g_left = 0; g_dkey = 0; reiserfsck_check_tree (fs->s_dev, SB_ROOT_BLOCK(fs), fs->s_blocksize, how_to_compare_neighbors); brelse (g_right); } void reiserfsck_check_pass1 () { /* if (opt_check == 1)*/ reiserfsck_tree_check (compare_neighboring_leaves_in_pass1); } void check_cached_tree () { reiserfsck_check_cached_tree (fs->s_dev, SB_ROOT_BLOCK (fs), fs->s_blocksize); } void reiserfsck_check_after_all () { reiserfsck_tree_check (compare_neighboring_leaves_after_all); } #if 0 static int is_bad_sd (struct item_head * ih, char * item) { struct stat_data * sd = (struct stat_data *)item; if (!S_ISDIR (sd->sd_mode) && !S_ISREG(sd->sd_mode) && !S_ISCHR (sd->sd_mode) && !S_ISBLK(sd->sd_mode) && !S_ISLNK (sd->sd_mode) && !S_ISFIFO(sd->sd_mode) && !S_ISSOCK(sd->sd_mode)) { fsck_log ("file %k unexpected mode encountered 0%o\n", &ih->ih_key, sd->sd_mode); } return 0; } #endif #include #include int blocks_on_device (int dev, int blocksize) { int size; if (ioctl (dev, BLKGETSIZE, &size) >= 0) { return size / (blocksize / 512); } if (ioctl (dev, BLKGETSIZE, &size) >= 0) { return size / (blocksize / 512); } else { struct stat stat_buf; memset(&stat_buf, '\0', sizeof(struct stat)); if(fstat(dev, &stat_buf) >= 0) { return stat_buf.st_size / (blocksize / 512); } else { die ("can not calculate device size\n"); } } return 0; } int is_internal_bad (struct buffer_head * bh) { struct key * key; int i; if (!is_internal_node(bh)) return 0; for (i = 0; i < B_NR_ITEMS (bh); i ++) { key = B_N_PDELIM_KEY (bh, i); if (//key->k_dir_id >= key->k_objectid || key->u.k_offset_v1.k_uniqueness != V1_DIRENTRY_UNIQUENESS && key->u.k_offset_v1.k_uniqueness != V1_DIRECT_UNIQUENESS && key->u.k_offset_v1.k_uniqueness != V1_INDIRECT_UNIQUENESS && key->u.k_offset_v1.k_uniqueness != V1_SD_UNIQUENESS && key->u.k_offset_v2.k_type != TYPE_DIRENTRY && key->u.k_offset_v2.k_type != TYPE_DIRECT && key->u.k_offset_v2.k_type != TYPE_INDIRECT && key->u.k_offset_v2.k_type != TYPE_STAT_DATA //&& // key->u.k_offset_v1.k_uniqueness != V1_ANY_UNIQUENESS && key->u.k_offset_v2.k_type != TYPE_ANY ) return 1; } return 0; } reiserfsprogs-3.x.0j/fsck/check_tree.c0000644000076400001440000006032307260373640013553 /* * Copyright 1999 Hans Reiser */ #include "fsck.h" // // // check S+ tree of the file system // // check_fs_tree stops and recommends to run fsck --rebuild-tree when: // 1. read fails // 2. node of wrong level found in the tree // 3. something in the tree points to wrong block number // out of filesystem boundary is pointed by tree // to block marked as free in bitmap // the same block is pointed from more than one place // not data blocks (journal area, super block, bitmaps) // 4. bad formatted node found // 5. delimiting keys are incorrect // /* mark every block we see in the tree in control bitmap, so, when to make sure, that no blocks are pointed to from more than one place we use additional bitmap (control_bitmap). If we see pointer to a block we set corresponding bit to 1. If it is set already - run fsck with --rebuild-tree */ static reiserfs_bitmap_t control_bitmap; static int tree_scanning_failed = 0; /* 1 if block is not marked as used in the bitmap */ static int is_block_free (reiserfs_filsys_t fs, unsigned long block) { return !reiserfs_bitmap_test_bit (fsck_disk_bitmap (fs), block); } /* we have seen this block in the tree, mark corresponding bit in the control bitmap */ static void we_met_it (unsigned long block) { reiserfs_bitmap_set_bit (control_bitmap, block); } /* have we seen this block somewhere in the tree before? */ static int did_we_meet_it (unsigned long block) { return reiserfs_bitmap_test_bit (control_bitmap, block); } static void init_control_bitmap (reiserfs_filsys_t fs) { int i; control_bitmap = reiserfs_create_bitmap (SB_BLOCK_COUNT (fs)); if (!control_bitmap) die ("init_control_bitmap: could not create control bitmap"); /* skipped and super block */ for (i = 0; i <= SB_BUFFER_WITH_SB (fs)->b_blocknr; i ++) we_met_it (i); /* bitmaps */ for (i = 0; i < SB_BMAP_NR (fs); i ++) we_met_it (SB_AP_BITMAP (fs)[i]->b_blocknr); for (i = 0; i < rs_journal_size (fs->s_rs) + 1; i ++) we_met_it (i + SB_JOURNAL_BLOCK (fs)); } #if 0 static void show_diff (int n, char * disk, char * control, int bits) { int i; int last_diff = 0; int from, num; fsck_log ("bitmap %d does not match to the correct one\n", n); from = 0; num = 0; for (i = 0; i < bits; i ++) { if (test_bit (i, disk) && !test_bit (i, control)) { if (last_diff == 1) { num ++; continue; } else if (last_diff == 2) { fsck_log ("Block [%d-%d] free in disk bitmap, used in control\n", from, from + num - 1); } num = 1; from = n * bits + i; last_diff = 1; continue; } if (!test_bit (i, disk) && test_bit (i, control)) { if (last_diff == 2) { num ++; continue; } else if (last_diff == 1) { fsck_log ("Block [%d-%d] used in disk bitmap, free in control\n", from, from + num - 1); } num = 1; from = n * bits + i; last_diff = 2; continue; } /* the same bits */ if (last_diff == 1) fsck_log ("Block [%d-%d] used in disk bitmap, free in control\n", from, from + num - 1); if (last_diff == 2) fsck_log ("Block [%d-%d] free in disk bitmap, used in control\n", from, from + num - 1); num = 0; from = 0; last_diff = 0; continue; } } #endif /* if we managed to complete tree scanning and if control bitmap and/or proper amount of free blocks mismatch with bitmap on disk and super block's s_free_blocks - we can fix that */ static void compare_bitmaps (reiserfs_filsys_t fs) { int diff; if (tree_scanning_failed) { fsck_progress ("Could not scan whole tree. " "--rebuild-tree is required\n"); return; } fsck_progress ("Comparing bitmaps.."); /* check free block counter */ if (SB_FREE_BLOCKS (fs) != reiserfs_bitmap_zeros (control_bitmap)) { fsck_log ("free block count %lu mismatches with a correct one %lu. \n", SB_FREE_BLOCKS (fs), reiserfs_bitmap_zeros (control_bitmap)); #if 0 if (fsck_fix_fixable (fs)) { set_free_blocks (fs->s_rs, reiserfs_bitmap_zeros (control_bitmap)); mark_buffer_dirty (fs->s_sbh); mark_filesystem_dirty (fs); fsck_log ("Fixed\n"); } else { fsck_log ("Can be fixed by --fix-fixable\n"); } #endif } diff = reiserfs_bitmap_compare (fsck_disk_bitmap (fs), control_bitmap); if (diff) { fsck_log ("on-disk bitmap does not match to the correct one. %d bytes differ\n", diff); #if 0 if (fsck_fix_fixable (fs)) { reiserfs_flush_bitmap (control_bitmap, fs); mark_filesystem_dirty (fs); fsck_log ("Fixed\n"); } else { fsck_log ("Can be fixed by --fix-fixable\n"); } #endif } fsck_progress ("ok\n"); return; } /* is this block legal to be pointed to by some place of the tree? */ static int bad_block_number (struct super_block * s, unsigned long block) { if (block >= SB_BLOCK_COUNT (s)) { /*reiserfs_warning ("block out of filesystem boundary found\n");*/ return 1; } if (not_data_block (s, block)) { /*reiserfs_warning ("not data block (%lu) is used in the tree\n", block);*/ return 1; } if (is_block_free (s, block)) { fsck_log ("block %lu is not marked as used in the disk bitmap\n", block); return 0; } return 0; } static int got_already (struct super_block * s, unsigned long block) { if (0/*opt_fsck_mode == FSCK_FAST_REBUILD*/){ if (is_block_used(block)){ fsck_log ("block %lu is in tree already\n", block); return 1; } } else { if (did_we_meet_it (block)) { /*fsck_log ("block %lu is in tree already\n", block);*/ return 1; } we_met_it (block); } return 0; } /* 1 if some of fields in the block head of bh look bad */ static int bad_block_head (struct buffer_head * bh) { struct block_head * blkh; blkh = B_BLK_HEAD (bh); if (le16_to_cpu (blkh->blk_nr_item) > (bh->b_size - BLKH_SIZE) / IH_SIZE) { fsck_log ("block %lu has wrong blk_nr_items (%z)\n", bh->b_blocknr, bh); return 1; } if (le16_to_cpu (blkh->blk_free_space) > bh->b_size - BLKH_SIZE - IH_SIZE * le16_to_cpu (blkh->blk_nr_item)) { fsck_log ("block %lu has wrong blk_free_space %z\n", bh->b_blocknr, bh); return 1; } return 0; } /* 1 if it does not look like reasonable stat data */ static int bad_stat_data (struct buffer_head * bh, struct item_head * ih) { unsigned long objectid; int pos; /* if (opt_fsck_mode == FSCK_FAST_REBUILD) return 0; */ objectid = le32_to_cpu (ih->ih_key.k_objectid); if (!is_objectid_used (fs, objectid)) { /* FIXME: this could be cured right here */ fsck_log ("\nbad_stat_data: %lu is marked free, but used by an object %k\n", objectid, &ih->ih_key); } if (is_objectid_really_used (proper_id_map (fs), objectid, &pos)) { fsck_log ("\nbad_stat_data: %lu is shared by at least two files\n", objectid); return 0; } mark_objectid_really_used (proper_id_map (fs), objectid); return 0; } /* it looks like we can check item length only */ static int bad_direct_item (struct buffer_head * bh, struct item_head * ih) { return 0; } /* for each unformatted node pointer: make sure it points to data area and that it is not in the tree yet */ static int bad_indirect_item (reiserfs_filsys_t fs, struct buffer_head * bh, struct item_head * ih) { int i; __u32 * ind = (__u32 *)B_I_PITEM (bh, ih); if (ih_item_len (ih) % 4) { fsck_log ("bad_indirect_item: block %lu: item (%H) has bad length\n", bh->b_blocknr, ih); return 1; } for (i = 0; i < I_UNFM_NUM (ih); i ++) { __u32 unfm_ptr; unfm_ptr = le32_to_cpu (ind [i]); if (!unfm_ptr) continue; /* check unformatted node pointer and mark it used in the control bitmap */ if (bad_block_number (fs, unfm_ptr)) { fsck_log ("bad_indirect_item: block %lu: item %H has bad pointer %d: %lu", bh->b_blocknr, ih, i, unfm_ptr); if (fsck_fix_fixable (fs)) { fsck_log (" - fixed"); ind [i] = 0; mark_buffer_dirty (bh); } fsck_log ("\n"); continue; } if (got_already (fs, unfm_ptr)) { fsck_log ("bad_indirect_item: block %lu: item %H has a pointer %d " "to the block %lu which is in tree already", bh->b_blocknr, ih, i, unfm_ptr); if (fsck_fix_fixable (fs)) { fsck_log (" - fixed"); ind [i] = 0; mark_buffer_dirty (bh); } fsck_log ("\n"); continue; } } /* delete this check for 3.6 */ if (ih_free_space (ih) > fs->s_blocksize - 1) fsck_log ("bad_indirect_item: %H has wrong ih_free_space\n", ih); return 0; } /* FIXME: this was is_bad_directory from pass0.c */ static int bad_directory_item (struct buffer_head * bh, struct item_head * ih) { int i; char * name; int namelen; struct reiserfs_de_head * deh = B_I_DEH (bh, ih); int min_entry_size = 1;/* we have no way to understand whether the filesystem were created in 3.6 format or converted to it. So, we assume that minimal name length is 1 */ __u16 state; /* make sure item looks like a directory */ if (ih_item_len (ih) / (DEH_SIZE + min_entry_size) < ih_entry_count (ih)) /* entry count can not be that big */ return 1; if (deh[ih_entry_count (ih) - 1].deh_location != DEH_SIZE * ih_entry_count (ih)) /* last entry should start right after array of dir entry headers */ return 1; /* check name hashing */ for (i = 0; i < ih_entry_count (ih); i ++, deh ++) { namelen = name_length (ih, deh, i); name = name_in_entry (deh, i); if (!is_properly_hashed (fs, name, namelen, deh_offset (deh))) { return 1; } } deh = B_I_DEH (bh, ih); state = 0; set_bit (DEH_Visible, &state); /* ok, items looks like a directory */ for (i = 0; i < ih_entry_count (ih); i ++, deh ++) { if (deh_state (deh) != state) { fsck_log ("bad_directory_item: block %lu: item %H has entry " "\"%.*s\" with wrong deh_state %o", bh->b_blocknr, ih, name_length (ih, deh, i), name_in_entry (deh, i), deh_state (deh)); if (fsck_fix_fixable (fs)) { deh->deh_state = 0; mark_de_visible (deh); mark_buffer_dirty (bh); fsck_log (" - fixed"); } fsck_log ("\n"); } } return 0; } static int bad_item (struct super_block * s, struct buffer_head * bh, int i) { struct item_head * ih; ih = B_N_PITEM_HEAD (bh, i); if (is_stat_data_ih (ih)) return bad_stat_data (bh, ih); if (is_direct_ih (ih)) return bad_direct_item (bh, ih); if (is_indirect_ih(ih)) return bad_indirect_item (s, bh, ih); return bad_directory_item (bh, ih); } /* 1 if i-th and (i-1)-th items can not be neighbors in a leaf */ int bad_pair (struct super_block * s, struct buffer_head * bh, int i) { struct item_head * ih; ih = B_N_PITEM_HEAD (bh, i); if (comp_keys (&((ih - 1)->ih_key), &ih->ih_key) != -1) return 1; if (is_stat_data_ih (ih)) /* left item must be of another object */ if (comp_short_keys (&((ih - 1)->ih_key), &ih->ih_key) != -1) return 1; if (is_direct_ih(ih)) { /* left item must be indirect or stat data item of the same file */ if (not_of_one_file (&((ih - 1)->ih_key), &ih->ih_key)) return 1; if (!((is_stat_data_ih (ih - 1) && get_offset (&ih->ih_key) == 1) || (is_indirect_ih (ih - 1) && get_offset (&(ih - 1)->ih_key) + get_bytes_number (ih-1, bh->b_size) == //get_bytes_number (bh, ih - 1, 0, CHECK_FREE_BYTES) == get_offset (&ih->ih_key)))) return 1; } if (is_indirect_ih (ih) || is_direntry_ih (ih)) { /* left item must be stat data of the same object */ if (not_of_one_file (&((ih - 1)->ih_key), &ih->ih_key)) return 1; if (!is_stat_data_ih (ih - 1)) return 1; } return 0; } int bad_leaf_2 (struct super_block * s, struct buffer_head * bh) { int i; if (bad_block_head (bh)) return 1; for (i = 0; i < B_NR_ITEMS (bh); i ++) { if (i && bad_pair (s, bh, i)) { fsck_log ("bad_leaf_2: block %lu has wrong order of items\n", bh->b_blocknr); return 1; } } return 0; } /* 1 if block head or any of items is bad */ static int bad_leaf (struct super_block * s, struct buffer_head * bh) { int i; if (bad_block_head (bh)) return 1; for (i = 0; i < B_NR_ITEMS (bh); i ++) { if (bad_item (s, bh, i)) { fsck_log ("bad_leaf: block %lu has invalid item %d: %H\n", bh->b_blocknr, i, B_N_PITEM_HEAD (bh, i)); } if (i && bad_pair (s, bh, i)) { fsck_log ("bad_leaf: block %lu has wrong order of items\n", bh->b_blocknr); } } return 0; } /* 1 if bh does not look like internal node */ static int bad_internal (struct super_block * s, struct buffer_head * bh) { int i; for (i = 0; i <= B_NR_ITEMS (bh); i ++) { if (i != B_NR_ITEMS (bh) && i != B_NR_ITEMS (bh) - 1) if (comp_keys (B_N_PDELIM_KEY (bh, i), B_N_PDELIM_KEY (bh, i + 1)) != -1) return 1; if (bad_block_number(s, child_block_number(bh,i))){ return 1; } } return 0; } /* h == 0 for root level. block head's level == 1 for leaf level */ static inline int h_to_level (struct super_block * s, int h) { return SB_TREE_HEIGHT (s) - h - 1; } /* bh must be formatted node. blk_level must be tree_height - h + 1 */ static int bad_node (struct super_block * s, struct buffer_head ** path, int h) { struct buffer_head ** pbh = &path[h]; if (B_LEVEL (*pbh) != h_to_level (s, h)) { fsck_log ("node (%lu) with wrong level (%d) found in the tree (should be %d)\n", (*pbh)->b_blocknr, B_LEVEL (*pbh), h_to_level (s, h)); return 1; } if (bad_block_number (s, (*pbh)->b_blocknr)) { return 1; } if (got_already (s, (*pbh)->b_blocknr)) return 1; if (is_leaf_node (*pbh)) return bad_leaf (s, *pbh); return bad_internal (s, *pbh); } /* internal node bh must point to block */ static int get_pos (struct buffer_head * bh, unsigned long block) { int i; for (i = 0; i <= B_NR_ITEMS (bh); i ++) { if (child_block_number (bh, i) == block) return i; } die ("get_pos: position for block %lu not found", block); return 0; } /* path[h] - leaf node */ static struct key * lkey (struct buffer_head ** path, int h) { int pos; while (h > 0) { pos = get_pos (path[h - 1], path[h]->b_blocknr); if (pos) return B_N_PDELIM_KEY(path[h - 1], pos - 1); h --; } return 0; } /* path[h] - leaf node */ static struct key * rkey (struct buffer_head ** path, int h) { int pos; while (h > 0) { pos = get_pos (path[h - 1], path[h]->b_blocknr); if (pos != B_NR_ITEMS (path[h - 1])) return B_N_PDELIM_KEY (path[h - 1], pos); h --; } return 0; } /* are all delimiting keys correct */ static int bad_path (struct super_block * s, struct buffer_head ** path, int h1) { int h = 0; struct key * dk; while (path[h]) h ++; h--; // path[h] is leaf if (h != h1) die ("bad_path: wrong path"); dk = lkey (path, h); if (dk && comp_keys (dk, B_N_PKEY (path[h], 0))) // left delimiting key must be equal to the key of 0-th item in the // node return 1; dk = rkey (path, h); if (dk && comp_keys (dk, B_N_PKEY (path[h], node_item_number (path[h]) - 1)) != 1) // right delimiting key must be bigger than the key of the last item // in the node return 1; return 0; } /* pass the S+ tree of filesystem */ void check_fs_tree (struct super_block * s) { init_control_bitmap (s); proper_id_map (s) = init_id_map (); fsck_progress ("Checking S+tree.."); pass_through_tree (s, bad_node, bad_path); /* S+ tree is correct (including all objects have correct sequences of items) */ fsck_progress ("ok\n"); /* compare created bitmap with the original */ compare_bitmaps (s); free_id_map (&proper_id_map (s)); } #if 0 void remove_internal_pointer(struct super_block * s, struct buffer_head ** path) { int h = 0; int pos, items; __u32 block; while (path[h]) h ++; h--; block = path[h]->b_blocknr; printf("\nremove pointer to (%d) block", block); brelse(path[h]); path[h] = 0; h--; while (h>=0) { if (B_NR_ITEMS(path[h]) <= 1) { block = path[h]->b_blocknr; brelse(path[h]); path[h] = 0; mark_block_free(block); /*unmark_block_formatted(block);*/ used_blocks++; h --; continue; } pos = get_pos (path[h], block); if (pos) { memmove (B_N_CHILD(path[h],pos), B_N_CHILD(path[h],pos+1), s->s_blocksize - BLKH_SIZE - B_NR_ITEMS(path[h])*KEY_SIZE - DC_SIZE*(pos+1)); memmove(B_N_PDELIM_KEY(path[h],pos-1), B_N_PDELIM_KEY(path[h],pos), s->s_blocksize - BLKH_SIZE - (pos)*KEY_SIZE); }else{ __u32 move_block = path[h]->b_blocknr; int move_to_pos; int height = h; while(--height >= 0) { move_to_pos = get_pos (path[height], move_block); if (move_to_pos == 0){ move_block = path[height]->b_blocknr; continue; } *B_N_PDELIM_KEY(path[height], move_to_pos-1) = *B_N_PDELIM_KEY(path[h], 0); break; } memmove (B_N_CHILD(path[h], 0), B_N_CHILD(path[h], 1), s->s_blocksize - BLKH_SIZE - B_NR_ITEMS(path[h])*KEY_SIZE - DC_SIZE); memmove(B_N_PDELIM_KEY(path[h], 0), B_N_PDELIM_KEY(path[h], 1), s->s_blocksize - BLKH_SIZE - KEY_SIZE); } set_node_item_number(path[h], node_item_number(path[h]) - 1); mark_buffer_dirty(path[h], 1); break; } if (h == -1) { SB_DISK_SUPER_BLOCK(s)->s_root_block = ~0; SB_DISK_SUPER_BLOCK(s)->s_tree_height = ~0; mark_buffer_dirty(SB_BUFFER_WITH_SB(s), 1); } } void handle_buffer(struct super_block * s, struct buffer_head * bh) { int i, j; struct item_head * ih; if (is_leaf_node (bh)) { for (i = 0, ih = B_N_PITEM_HEAD (bh, 0); i < B_NR_ITEMS (bh); i ++, ih ++) { if (is_indirect_ih(ih)) for (j = 0; j < I_UNFM_NUM (ih); j ++) if (B_I_POS_UNFM_POINTER(bh,ih,j)){ /*mark_block_unformatted(le32_to_cpu(B_I_POS_UNFM_POINTER(bh,ih,j)));*/ mark_block_used(le32_to_cpu(B_I_POS_UNFM_POINTER(bh,ih,j))); used_blocks++; } if (is_stat_data_ih (ih)) { /*add_event (STAT_DATA_ITEMS);*/ if (ih_key_format(ih) == KEY_FORMAT_1) ((struct stat_data_v1 *)B_I_PITEM(bh,ih))->sd_nlink = 0; else ((struct stat_data *)B_I_PITEM(bh,ih))->sd_nlink = 0; mark_buffer_dirty(bh, 1); } } } mark_block_used(bh->b_blocknr); // we_met_it(s, bh->b_blocknr); used_blocks++; } /* bh must be formatted node. blk_level must be tree_height - h + 1 */ static int handle_node (struct super_block * s, struct buffer_head ** path, int h) { if (bad_node(s, path, h)){ remove_internal_pointer(s, path); return 1; } handle_buffer(s, path[h]); return 0; } /* are all delimiting keys correct */ static int handle_path (struct super_block * s, struct buffer_head ** path, int h) { if (bad_path(s, path, h)){ remove_internal_pointer(s, path); return 1; } return 0; } //return 1 to run rebuild tree from scratch void check_internal_structure(struct super_block * s) { /* control bitmap is used to keep all blocks we should not put into tree again */ /* used bitmap is used to keep all inserted blocks. The same as control bitmap plus unfm blocks */ // init_control_bitmap(s); printf ("Checking S+tree.."); pass_through_tree (s, handle_node, handle_path); // compare_bitmaps(s); printf ("ok\n"); } #endif int check_sb (struct super_block * s) { int format_sb = 0; int problem = 0; struct reiserfs_super_block * rs; __u32 block_count; rs = s->s_rs; // in (REISERFS_DISK_OFFSET_IN_BYTES / 4096) block if (is_reiser2fs_magic_string (rs) && SB_JOURNAL_BLOCK(s) == get_journal_start_must (rs_blocksize (rs))) { // 3.6 or >=3.5.22 printf("\t 3.6.x format SB found\n"); format_sb = 1; goto good_format; } if (is_reiserfs_magic_string (rs) && SB_JOURNAL_BLOCK(s) == get_journal_start_must (rs_blocksize (rs))) { // >3.5.9(10) and <=3.5.21 printf("\t>=3.5.9 format SB found\n"); format_sb = 2; goto good_format; } // in 2 block if (is_reiser2fs_magic_string (rs) && SB_JOURNAL_BLOCK(s) == get_journal_old_start_must (rs)) { // <3.5.9(10) converted to new format printf("\t< 3.5.9(10) SB converted to new format found \n"); format_sb = 3; goto good_format; } if (is_reiserfs_magic_string (rs) && SB_JOURNAL_BLOCK(s) == get_journal_old_start_must (rs)) { // <3.5.9(10) printf("\t< 3.5.9(10) format SB found\n"); format_sb = 4; goto good_format; } else die("check SB: wrong SB format found\n"); good_format: printf("\n\t%d-%d\n", SB_BLOCK_COUNT (s), SB_FREE_BLOCKS (s)); if (s->s_blocksize != 4096) { fsck_log("check SB: specified block size (%d) is not correct must be 4096\n", s->s_blocksize); problem++; } //for 4096 blocksize only if ((rs_tree_height(rs) < DISK_LEAF_NODE_LEVEL) || (rs_tree_height(rs) > MAX_HEIGHT)){ fsck_log ("check SB: wrong tree height (%d)\n", rs_tree_height(rs)); problem++; } block_count = count_blocks ("", s->s_blocksize, s->s_dev); if (SB_BLOCK_COUNT(s) > block_count){ fsck_log ("check SB: specified block number (%d) is too high\n", SB_BLOCK_COUNT(s)); problem++; } if ((rs_root_block(rs) >= block_count) || (rs_root_block(rs) < 0)){ fsck_log ("check SB: specified root block number (%d) is too high\n", rs_root_block(rs)); problem++; } if (SB_FREE_BLOCKS(s) > SB_BLOCK_COUNT(s)){ fsck_log ("check SB: specified free block number (%d) is too high\n", SB_FREE_BLOCKS(s)); problem++; } if (SB_REISERFS_STATE(s) != REISERFS_VALID_FS){ fsck_log ("check SB: wrong (%d) state\n", SB_REISERFS_STATE(s)); problem++; } if ( SB_BMAP_NR(s) != SB_BLOCK_COUNT(s) / (s->s_blocksize * 8) + ((SB_BLOCK_COUNT(s) % (s->s_blocksize * 8)) ? 1 : 0)){ fsck_log("check SB: wrong bitmap number (%d)\n", SB_BMAP_NR(s)); problem++; } if (SB_VERSION(s) == REISERFS_VERSION_2 || SB_VERSION(s) == REISERFS_VERSION_1) { if (!(SB_VERSION(s) == REISERFS_VERSION_2 && (format_sb == 1 || format_sb == 3)) && !(SB_VERSION(s) == REISERFS_VERSION_1 && (format_sb == 2 || format_sb == 4))){ fsck_log("check SB: wrong SB version == %d, format == %d\n", SB_VERSION(s), format_sb); problem++; } } else{ fsck_log ("check SB: wrong SB version (%d)\n", SB_VERSION(s)); problem++; } if (SB_VERSION(s) == REISERFS_VERSION_2 && (rs_hash (rs) < 1 || rs_hash (rs) > 3)) { /* FIXME: */ fsck_log("check SB: wrong hash (%d)\n", rs_hash (rs)); problem++; } if ((SB_VERSION(s) == REISERFS_VERSION_2) ? (rs_objectid_map_max_size (rs) != ((s->s_blocksize - SB_SIZE) / sizeof(__u32) / 2 * 2)) : (rs_objectid_map_max_size (rs) != ((s->s_blocksize - SB_SIZE_V1) / sizeof(__u32) / 2 * 2))) { fsck_log("check SB: objectid map corrupted max_size == %d\n", rs_objectid_map_max_size (rs)); problem++; } if (rs_objectid_map_size (rs) < 2 || rs_objectid_map_size (rs) > rs_objectid_map_max_size (rs)) { fsck_log("check SB: objectid map corrupted cur_size == %d\n", rs_objectid_map_size (rs)); problem++; } if (rs_journal_size(rs) != JOURNAL_BLOCK_COUNT){ fsck_log("check SB: specified journal size (%d) is not correct must be %d\n", rs_journal_size(rs), JOURNAL_BLOCK_COUNT); problem++; } if (!problem) { fsck_progress ("\t No problem found\n"); } else if (fsck_log_file (fs) != stderr) fsck_progress ("Look for super block corruptions in the log file\n"); return format_sb; } reiserfsprogs-3.x.0j/fsck/journal.c0000644000076400001440000001454407260327742013137 /* * Copyright 2000 Hans Reiser */ #include "fsck.h" #include /*#include */ #define bh_desc(bh) ((struct reiserfs_journal_desc *)((bh)->b_data)) #define bh_commit(bh) ((struct reiserfs_journal_commit *)((bh)->b_data)) static int next_expected_desc (struct super_block * s, struct buffer_head * d_bh) { int offset; struct reiserfs_journal_desc * desc; desc = (struct reiserfs_journal_desc *)d_bh->b_data; offset = d_bh->b_blocknr - SB_JOURNAL_BLOCK (s); return SB_JOURNAL_BLOCK (s) + ((offset + desc->j_len + 1 + 1) % JOURNAL_BLOCK_COUNT); } static int is_valid_transaction (struct super_block * s, struct buffer_head * d_bh) { struct buffer_head * c_bh; int offset; struct reiserfs_journal_desc *desc = (struct reiserfs_journal_desc *)d_bh->b_data; struct reiserfs_journal_commit *commit ; __u32 block, start_block; offset = d_bh->b_blocknr - SB_JOURNAL_BLOCK (s); /* ok, we have a journal description block, lets see if the transaction was valid */ block = next_expected_desc (s, d_bh) - 1; start_block = d_bh->b_blocknr; while(!(c_bh = bread (s->s_dev, block, s->s_blocksize))){ if (++block == SB_JOURNAL_BLOCK (s) + JOURNAL_BLOCK_COUNT) block = SB_JOURNAL_BLOCK (s); if (block == start_block) return 0; } commit = (struct reiserfs_journal_commit *)c_bh->b_data ; if (does_desc_match_commit (desc, commit)) { // if (journal_compare_desc_commit (s, desc, commit)) { /* printf ("desc and commit block do not match\n");*/ brelse (c_bh) ; return 0; } brelse (c_bh); return 1; } int reiserfs_replay_journal (struct super_block * s) { struct buffer_head * d_bh, * c_bh, * jh_bh; struct reiserfs_journal_header * j_head; struct reiserfs_journal_desc * j_desc; struct reiserfs_journal_commit * j_commit; unsigned long latest_mount_id; unsigned long j_cur; unsigned long j_start; unsigned long j_size; unsigned long mount_id, trans_id; unsigned long t_first, t_last, t_count, t_flushed; unsigned long t_offset; int i; fsck_progress ("Analyzing journal.."); j_start = SB_JOURNAL_BLOCK (s); j_cur = 0; j_size = rs_journal_size (s->s_rs); t_first = 0; t_last = 0; latest_mount_id = 0; /* look for the transactions with the most recent mount_id */ for (j_cur = 0; j_cur < j_size; ) { d_bh = bread (s->s_dev, j_start + j_cur, s->s_blocksize); if (d_bh && who_is_this (d_bh->b_data, d_bh->b_size) == THE_JDESC && is_valid_transaction (s, d_bh)) { j_desc = (struct reiserfs_journal_desc *)d_bh->b_data; mount_id = le32_to_cpu (j_desc->j_mount_id); trans_id = le32_to_cpu (j_desc->j_trans_id); if (mount_id > latest_mount_id) { /* more recent mount_id found */ latest_mount_id = mount_id; t_first = t_last = trans_id; t_offset = j_cur; t_count = 1; } else if (mount_id == latest_mount_id) { t_count ++; if (trans_id > t_last) t_last = trans_id; if (trans_id < t_first) { t_first = trans_id; t_offset = j_cur; } } j_cur += le32_to_cpu (j_desc->j_len) + 1; } j_cur ++; brelse (d_bh); } /* replay only if journal header looks resonable */ jh_bh = bread (s->s_dev, j_start + j_size, s->s_blocksize); j_head = (struct reiserfs_journal_header *)(jh_bh->b_data); if (latest_mount_id != le32_to_cpu (j_head->j_mount_id)) { fsck_progress ("nothing to replay (no transactions match to latest mount id)\n"); brelse (jh_bh); return 0; } /* last transaction flushed - which should not be replayed */ t_flushed = le32_to_cpu (j_head->j_last_flush_trans_id); if (t_flushed >= t_last) { fsck_progress ("nothing to replay (no transactions older than last flushed one found)\n"); brelse (jh_bh); return 0; } if (t_first > t_flushed + 1) { if (t_flushed) fsck_progress ("last flushed trans %lu, the oldest but newer is %lu\n", t_flushed, t_first); } else { /* start replaying with first not flushed transaction */ t_first = t_flushed + 1; t_offset = le32_to_cpu (j_head->j_first_unflushed_offset); } fsck_progress ("last flushed trans %lu, mount_id %lu, " "will replay from %lu up to %lu:Yes?", t_flushed, latest_mount_id, t_first, t_last); if (!fsck_user_confirmed (fs, "", "Yes\n", 1)) die (""); /* replay transactions we have found */ for (j_cur = t_offset; t_first <= t_last; t_first ++) { unsigned long offset; d_bh = bread (s->s_dev, j_start + j_cur, s->s_blocksize); j_desc = (struct reiserfs_journal_desc *)d_bh->b_data; if (who_is_this (d_bh->b_data, d_bh->b_size) != THE_JDESC || le32_to_cpu (j_desc->j_mount_id) != latest_mount_id || le32_to_cpu (j_desc->j_trans_id) != t_first) die ("reiserfs_replay_journal: desc block not found"); offset = j_cur + 1; j_cur += le32_to_cpu (j_desc->j_len) + 1; j_cur %= j_size; c_bh = bread (s->s_dev, j_start + j_cur, s->s_blocksize); j_commit = (struct reiserfs_journal_commit *)c_bh->b_data; if (does_desc_match_commit (j_desc, j_commit)) die ("reiserfs_replay_journal: commit block not found"); fsck_log ("Mount_id %lu, transaction %lu, desc block %lu, commit block %lu: (", latest_mount_id, t_first, d_bh->b_blocknr, c_bh->b_blocknr); /* replay one transaction */ for (i = 0; i < le32_to_cpu (j_desc->j_len); i ++) { struct buffer_head * in_place, * log; unsigned long block; log = bread (s->s_dev, j_start + ((offset + i) % j_size), s->s_blocksize); if (i < JOURNAL_TRANS_HALF) { block = le32_to_cpu (j_desc->j_realblock[i]); } else { block = le32_to_cpu (j_commit->j_realblock[i - JOURNAL_TRANS_HALF]); } if (not_journalable (s, block)) { fsck_log ("transaction %lu, block %d could not be replayed (%lu)\n", t_first, i, block); } else { fsck_log (" %lu", block); in_place = getblk (s->s_dev, block, s->s_blocksize) ; memcpy (in_place->b_data, log->b_data, s->s_blocksize); mark_buffer_dirty (in_place); mark_buffer_uptodate (in_place, 1); bwrite (in_place); brelse (in_place); } brelse (log); } fsck_log (")\n"); brelse (d_bh); brelse (c_bh); j_cur ++; j_cur %= j_size; /* update journal header */ j_head->j_last_flush_trans_id = cpu_to_le32 (t_first); mark_buffer_dirty (jh_bh); bwrite (jh_bh); } brelse (jh_bh); fsck_progress ("Journal replaied\n"); return 0; } reiserfsprogs-3.x.0j/fsck/info.c0000644000076400001440000001111007261175210012372 /* * Copyright 1996-1999 Hans Reiser */ #include "fsck.h" #include int fsck_user_confirmed (reiserfs_filsys_t fs, char * q, char * a, int default_answer) { if (!fsck_interactive (fs)) return default_answer; return user_confirmed (q, a); } void stage_report (int pass, reiserfs_filsys_t fs) { FILE * fp; struct fsck_data * stat; stat = stats (fs); fp = stderr; switch (pass) { case 0: fsck_progress ("\tRead blocks (but not data blocks) %lu\n", stat->analyzed); stat->analyzed = 0; fsck_progress ("\t\tLeaves among those %lu\n", stat->leaves); if (stat->leaves_corrected) fsck_progress ("\t\t\t- corrected leaves %lu\n", stat->leaves_corrected); if (stat->all_contents_removed) fsck_progress ("\t\t\t- eaves all contents of which could not be saved and deleted %lu\n", stat->all_contents_removed); if (stat->pointed_leaves) fsck_progress ("\t\t\t- leaves pointed by indirect items %lu\n", stat->pointed_leaves); if (stat->pointed) fsck_progress ("\t\tBlocks pointed by indirect items %lu\n", stat->pointed); if (stat->pointed_once) fsck_progress ("\t\t\t- once %lu\n", stat->pointed_once); if (stat->pointed_more_than_once) fsck_progress ("\t\t\t- more than once %lu\n", stat->pointed_more_than_once); if (stat->wrong_pointers) fsck_progress ("\t\t\t- pointers to wrong area of filesystem (zeroed) %lu\n", stat->wrong_pointers); /* pass1 will calculate how many pointers were zeeros there */ stat->wrong_pointers = 0; fsck_progress ("\t\tObjectids found %lu\n", proper_id_map (fs)->objectids_marked); /*fsck_progress ("\tblocks marked free %lu\n", stat->free);*/ fsck_progress ("\tallocable %lu blocks\n", stat->allocable); break; case 1: fsck_progress ("\t%lu leaves read\n", stat->analyzed); fsck_progress ("\t\t%lu inserted\n", stat->inserted_leaves); if (stat->uninsertable_leaves) fsck_progress ("\t\t%lu not inserted\n", stat->uninsertable_leaves); if (stat->saved_on_pass1) fsck_progress ("\tSaved %lu items\n", stat->saved_on_pass1); if (stat->wrong_pointers) fsck_progress ("\tPointers to leaves or non-unique (zeroed) %lu\n", stat->wrong_pointers); break; case 2: if (stat->shared_objectids) fsck_progress ("\t%lu shared objectids\n", stat->shared_objectids); if (stat->relocated) fsck_progress ("\tFiles relocated because of key conflicts w/ a directory %lu\n", stat->relocated); if (stat->rewritten) fsck_progress ("\tFiles rewritten %lu\n", stat->rewritten); return; case 3: /* semantic pass */ fsck_progress ("\tFiles found: %ld\n", stat->regular_files); fsck_progress ("\tDirectories found: %ld\n", stat->directories); if (stat->symlinks) fsck_progress ("\tSymlinks found: %ld\n", stat->symlinks); if (stat->others) fsck_progress ("\tOthers: %ld\n", stat->others); if (stat->fixed_sizes) fsck_progress ("\tFiles with fixed size: %ld\n", stat->fixed_sizes); if (stat->oid_sharing) fsck_progress ("\tObjects having used objectids: %lu\n", stat->oid_sharing); if (stat->oid_sharing_files_relocated) fsck_progress ("\t\tfiles fixed %lu\n", stat->oid_sharing_files_relocated); if (stat->oid_sharing_dirs_relocated) fsck_progress ("\t\tdirs fixed %lu\n", stat->oid_sharing_dirs_relocated); stat->oid_sharing = 0; stat->oid_sharing_files_relocated = 0; stat->oid_sharing_dirs_relocated = 0; break; case 0x3a: /* looking for lost files */ if (stat->lost_found) fsck_progress ("\tObjects without names %lu\n", stat->lost_found); if (stat->empty_lost_dirs) fsck_progress ("\tEmpty lost dirs removed %lu\n", stat->empty_lost_dirs); if (stat->lost_found_dirs) fsck_progress ("\tDirs linked to /lost+found: %lu\n", stat->lost_found_dirs); if (stat->dir_recovered) fsck_progress ("\t\tDirs without stat data found %lu\n", stat->dir_recovered); if (stat->lost_found_files) fsck_progress ("\tFiles linked to /lost+found %lu\n", stat->lost_found_files); if (stat->oid_sharing) fsck_progress ("\tObjects having used objectids: %lu\n", stat->oid_sharing); if (stat->oid_sharing_files_relocated) fsck_progress ("\t\tfiles fixed %lu\n", stat->oid_sharing_files_relocated); if (stat->oid_sharing_dirs_relocated) fsck_progress ("\t\tdirs fixed %lu\n", stat->oid_sharing_dirs_relocated); break; case 4: /* removing of unreachable */ if (stat->deleted_items) fsck_progress ("\tDeleted unreachable items %lu\n", stat->deleted_items); break; } if (!fsck_user_confirmed (fs, "Continue? (Yes):", "Yes\n", 1)) { reiserfs_close (fs); exit (0); } } reiserfsprogs-3.x.0j/fsck/segments.c0000644000076400001440000001440607244510760013303 /* * Copyright 1998 Hans Reiser */ /*#include #include */ /*#include #include "../include/reiserfs_fs.h" #include "../include/reiserfs_fs_sb.h" #include "../include/reiserfslib.h"*/ #include "fsck.h" /* there is a situation, when we overwrite contents of unformatted node with direct item. One unformatted node can be overwritten several times by direct items */ /* struct overwritten_unfm_segment { int ous_begin; int ous_end; struct overwritten_unfm_segment * ous_next; }; */ struct overwritten_unfm { unsigned long ou_unfm_ptr; /* block number of unfm node */ unsigned long ou_dir_id; unsigned long ou_objectid; /* key corresponding to an unfm node */ unsigned long ou_offset; struct overwritten_unfm_segment * ou_segments; /* list of segmens, than have been overwritten in ths unfm node */ }; struct overwritten_unfm ** g_overwritten_unfms; int g_overwritten_unfms_amount; /* number of unformatted nodes, which contain direct items */ /* adds segment to the single linked list of segments sorted by begin field. Retuns pointer to first element of list */ static struct overwritten_unfm_segment * add_segment (struct overwritten_unfm_segment * first, int begin, int end) { struct overwritten_unfm_segment * new, * next, * prev; new = getmem (sizeof (struct overwritten_unfm_segment)); new->ous_begin = begin; new->ous_end = end; new->ous_next = 0; next = first; prev = 0; while (next) { if (next->ous_begin > begin) break; prev = next; next = next->ous_next; } if (prev == 0) { /* insert into head of list */ first = new; } else { prev->ous_next = new; } new->ous_next = next; return first; } /* input parameter `list_head` - first element of overlapping segments sorted by left edge `unoverwritten_segment` - returned by previous call of get_unoverwritten_segment or (-2,-2) if called first time */ /* returns 1 and segment unoverwritten by elements of list `list_head` 0 if there isno such segment */ int get_unoverwritten_segment (struct overwritten_unfm_segment * list_head, struct overwritten_unfm_segment * unoverwritten_segment) { int end; /* look for segment, which has begin field greater than end of previous interval */ while (list_head->ous_begin <= unoverwritten_segment->ous_end) { list_head = list_head->ous_next; } /* look for the end of the continuous region covered by otrezkami */ end = list_head->ous_end; while (list_head->ous_next) { if (list_head->ous_next->ous_begin > end + 1) /* intreval found */ break; if (list_head->ous_next->ous_end > end) end = list_head->ous_next->ous_end; list_head = list_head->ous_next; } /* ok, between segment and segment->next we have an interval (segment->next != 0) */ if (list_head->ous_next != 0) { unoverwritten_segment->ous_begin = end + 1; unoverwritten_segment->ous_end = list_head->ous_next->ous_begin - 1; return 1; } return 0; } void print_segments (struct overwritten_unfm_segment * list_head) { struct overwritten_unfm_segment * cur; cur = list_head; while (cur) { printf ("%s%d %d%s", cur == list_head ? "(" : "", cur->ous_begin, cur->ous_end, cur->ous_next ? ", " : ")\n"); cur = cur->ous_next; } } /* this prepare list of segments to extracting of unoverwritten segments */ struct overwritten_unfm_segment * find_overwritten_unfm (unsigned long unfm, int length, struct overwritten_unfm_segment * segment_to_init) { int i; for (i = 0; i < g_overwritten_unfms_amount && g_overwritten_unfms[i] != 0; i ++) if (g_overwritten_unfms[i]->ou_unfm_ptr == unfm) { if (g_overwritten_unfms[i]->ou_segments == 0) die ("find_overwritten_unfm: no segment found"); g_overwritten_unfms[i]->ou_segments = add_segment (g_overwritten_unfms[i]->ou_segments, -1, -1); add_segment (g_overwritten_unfms[i]->ou_segments, length, length); segment_to_init->ous_begin = -2; segment_to_init->ous_end = -2; return g_overwritten_unfms[i]->ou_segments; } return 0; } struct overwritten_unfm * look_for_overwritten_unfm (__u32 unfm) { int i; for (i = 0; i < g_overwritten_unfms_amount && g_overwritten_unfms[i] != 0; i ++) if (g_overwritten_unfms[i]->ou_unfm_ptr == unfm) return g_overwritten_unfms[i]; return 0; } #define GROW_BY 10 struct overwritten_unfm * add_overwritten_unfm (unsigned long unfm, struct item_head * direct_ih) { int i; for (i = 0; i < g_overwritten_unfms_amount && g_overwritten_unfms[i] != 0; i ++) { if (g_overwritten_unfms[i]->ou_unfm_ptr == unfm) return g_overwritten_unfms[i]; } if (i == g_overwritten_unfms_amount) { g_overwritten_unfms = expandmem (g_overwritten_unfms, sizeof (struct overwritten_unfm *) * i, sizeof (struct overwritten_unfm *) * GROW_BY); g_overwritten_unfms_amount += GROW_BY; } g_overwritten_unfms[i] = getmem (sizeof (struct overwritten_unfm)); g_overwritten_unfms[i]->ou_unfm_ptr = unfm; g_overwritten_unfms[i]->ou_dir_id = direct_ih->ih_key.k_dir_id; g_overwritten_unfms[i]->ou_objectid = direct_ih->ih_key.k_objectid; g_overwritten_unfms[i]->ou_offset = get_offset(&direct_ih->ih_key) - (get_offset(&direct_ih->ih_key) - 1) % fs->s_blocksize; return g_overwritten_unfms[i]; } void save_unfm_overwriting (unsigned long unfm, struct item_head * direct_ih) { struct overwritten_unfm * ov_unfm; /* add new overwritten unfm or return existing one */ ov_unfm = add_overwritten_unfm (unfm, direct_ih); ov_unfm->ou_segments = add_segment (ov_unfm->ou_segments, (get_offset(&direct_ih->ih_key) - 1) % fs->s_blocksize, (get_offset(&direct_ih->ih_key) - 1) % fs->s_blocksize + ih_item_len (direct_ih) - 1); } void free_overwritten_unfms (void) { int i; for (i = 0; i < g_overwritten_unfms_amount && g_overwritten_unfms[i]; i ++) { /* free all segments */ while (g_overwritten_unfms[i]->ou_segments) { struct overwritten_unfm_segment * tmp; tmp = g_overwritten_unfms[i]->ou_segments->ous_next; freemem (g_overwritten_unfms[i]->ou_segments); g_overwritten_unfms[i]->ou_segments = tmp; } /* free struct overwritten_unfm */ freemem (g_overwritten_unfms[i]); } /* free array of pointers to overwritten unfms */ if (g_overwritten_unfms) freemem (g_overwritten_unfms); } reiserfsprogs-3.x.0j/fsck/fsck.h0000644000076400001440000003521107261175210012402 /* * Copyright 1996-2001 Hans Reiser */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include "io.h" #include "misc.h" #include "reiserfs_lib.h" /* main.c */ extern reiserfs_filsys_t fs; extern reiserfs_bitmap_t uninsertable_leaf_bitmap; int main (int argc, char * argv []); /* * modes */ #define DO_NOTHING 0 /* -a specified */ #define FSCK_CHECK 1 #define FSCK_SB 2 #define FSCK_REBUILD 3 /* temporary */ #define FSCK_ZERO_FILES 4 #define DO_TEST 5 /* #define FSCK_FAST_REBUILD 4 */ /* * options */ #define OPT_INTERACTIVE 1 #define OPT_FIX_FIXABLE 2 /* not default yet */ #define OPT_FIX_NON_CRITICAL 4 /* not default yet */ #define OPT_QUIET 8 #define OPT_SAVE_EXTERN_BITMAP 16 #define OPT_SILENT 32 extern int g_blocks_to_read; /* pass 0 and 1 read the device NR_TO_READ block in time */ #define NR_TO_READ 8 /* pass0.c */ int pass_0 (reiserfs_filsys_t); int are_there_used_leaves (unsigned long from, int count); int is_used_leaf (unsigned long block); int how_many_leaves_were_there (void); int is_bad_unformatted (unsigned long block); int is_good_unformatted (unsigned long block); void mark_good_unformatted (unsigned long block); int are_there_allocable_blocks (int amout_needed); unsigned long alloc_block (void); void make_allocable (unsigned long block); void register_uninsertable (unsigned long block); unsigned long how_many_uninsertables_were_there (void); void register_saved_item (void); unsigned long how_many_items_were_saved (void); int still_bad_unfm_ptr_1 (unsigned long block); int still_bad_unfm_ptr_2 (unsigned long block); void make_alloc_bitmap (struct super_block * s); #define __is_marked(name,block) reiserfs_bitmap_test_bit (name##_bitmap, block) #define __mark(name,block) reiserfs_bitmap_set_bit (name##_bitmap, block) #define __unmark(name,block) reiserfs_bitmap_clear_bit (name##_bitmap, block) /* unformatted in tree */ extern reiserfs_bitmap_t bad_unfm_in_tree_once_bitmap; #define is_bad_unfm_in_tree_once(block) __is_marked (bad_unfm_in_tree_once, block) #define mark_bad_unfm_in_tree_once(block) __mark (bad_unfm_in_tree_once, block) /* pass1.c */ void pass_1_pass_2_build_the_tree (void); struct buffer_head * make_buffer (int dev, int blocknr, int size, char * data); void build_the_tree (void); extern int g_unaccessed_items; int is_item_reachable (struct item_head * ih); void mark_item_reachable (struct item_head * ih, struct buffer_head * bh); void mark_item_unreachable (struct item_head * ih); void rebuild_sb (reiserfs_filsys_t fs); struct si * remove_saved_item (struct si * si); /* pass2.c */ void insert_item_separately (struct item_head * ih, char * item, int was_in_tree); struct si * save_and_delete_file_item (struct si * si, struct path * path); void take_bad_blocks_put_into_tree (void); void rewrite_object (struct item_head * ih, int do_remap); void pass_2_take_bad_blocks_put_into_tree (void); /*int is_remapped (struct item_head * ih);*/ void link_relocated_files (void); void relocate_file (struct item_head * ih, int change_ih); void relocate_dir (struct item_head * ih, int change_ih); __u32 objectid_for_relocation (struct key * key); /* file.c */ struct si { struct item_head si_ih; char * si_dnm_data; struct si * si_next; __u32 si_blocknr; // changed by XB; struct si * last_known; }; void put_saved_items_into_tree (struct si *); int reiserfsck_file_write (struct item_head * ih, char * item, int); int are_file_items_correct (struct key * key, int key_version, __u64 * size, __u32 * blocks, int mark_passed_items, int symlink, __u64 symlink_size); /* semantic.c */ extern struct key root_dir_key; extern struct key parent_root_dir_key; extern struct key lost_found_dir_key; void pass_3_semantic (void); void semantic_check (void); int check_semantic_tree (struct key * key, struct key * parent, int is_dot_dot, int lost_found, struct item_head * new_ih); void zero_nlink (struct item_head * ih, void * sd); int not_a_directory (void * sd); int is_dot_dot (char * name, int namelen); int is_dot (char * name, int namelen); void create_dir_sd (reiserfs_filsys_t fs, struct path * path, struct key * key); int rebuild_check_regular_file (struct path * path, void * sd, struct item_head * new_ih); int rebuild_semantic_pass (struct key * key, struct key * parent, int is_dot_dot, struct item_head * new_ih); /* access to stat data fields */ void get_set_sd_field (int field, struct item_head * ih, void * sd, void * value, int set); #define GET_SD_MODE 0 #define GET_SD_SIZE 1 #define GET_SD_NLINK 2 #define GET_SD_BLOCKS 3 #define GET_SD_FIRST_DIRECT_BYTE 4 #define get_sd_mode(ih,sd,pmode) get_set_sd_field (GET_SD_MODE, ih, sd, pmode, 0/*get*/) #define set_sd_mode(ih,sd,pmode) get_set_sd_field (GET_SD_MODE, ih, sd, pmode, 1/*set*/) #define get_sd_size(ih,sd,psize) get_set_sd_field (GET_SD_SIZE, ih, sd, psize, 0/*get*/) #define set_sd_size(ih,sd,psize) get_set_sd_field (GET_SD_SIZE, ih, sd, psize, 1/*set*/) #define get_sd_blocks(ih,sd,pblocks) get_set_sd_field (GET_SD_BLOCKS, ih, sd, pblocks, 0/*get*/) #define set_sd_blocks(ih,sd,pblocks) get_set_sd_field (GET_SD_BLOCKS, ih, sd, pblocks, 1/*set*/) #define get_sd_nlink(ih,sd,pnlink) get_set_sd_field (GET_SD_NLINK, ih, sd, pnlink, 0/*get*/) #define set_sd_nlink(ih,sd,pnlink) get_set_sd_field (GET_SD_NLINK, ih, sd, pnlink, 1/*set*/) #define get_sd_first_direct_byte(ih,sd,pfdb) get_set_sd_field (GET_SD_FIRST_DIRECT_BYTE, ih, sd, pfdb, 0/*get*/) #define set_sd_first_direct_byte(ih,sd,pfdb) get_set_sd_field (GET_SD_FIRST_DIRECT_BYTE, ih, sd, pfdb, 1/*set*/) /* lost+found.c */ void pass_3a_look_for_lost (reiserfs_filsys_t s); /* pass4.c */ void get_next_key (struct path * path, int i, struct key * key); int pass_4_check_unaccessed_items (void); /* check.c */ int is_leaf_bad (struct buffer_head * bh); int is_internal_bad (struct buffer_head * bh); int is_bad_item (struct buffer_head * bh, struct item_head *, char *); /*int check_file_system (void);*/ void reiserfsck_check_pass1 (void); void reiserfsck_check_after_all (void); /*char * bad_name (char * name, int namelen);*/ /* to test result of direcotry item recovering on pass 0 */ int is_bad_directory (struct item_head * ih, char * item, int dev, int blocksize); //extern int bad_block_number (struct super_block * s, blocknr_t block); /* check_tree.c */ void check_fs_tree (struct super_block * s); int check_sb (struct super_block * s); int bad_pair (struct super_block * s, struct buffer_head * bh, int i); int bad_leaf_2 (struct super_block * s, struct buffer_head * bh); /* ustree.c */ void init_tb_struct (struct tree_balance * tb, struct super_block * s, struct path * path, int size); void reiserfsck_paste_into_item (struct path * path, const char * body, int size); void reiserfsck_insert_item (struct path * path, struct item_head * ih, const char * body); void reiserfsck_delete_item (struct path * path, int temporary); void reiserfsck_cut_from_item (struct path * path, int cut_size); typedef int (comp_function_t)(void * key1, void * key2); typedef int (comp3_function_t)(void * key1, void * key2, int version); /*typedef int (comp_function_t)(struct key * key1, struct key * key2);*/ int ubin_search_id(__u32 * id, __u32 * base, __u32 number, __u32 * pos); int usearch_by_key (struct super_block * s, struct key * key, struct path * path); int usearch_by_key_3 (struct super_block * s, struct key * key, struct path * path, int * repeat, int stop_level, comp3_function_t comp_func, int version); int usearch_by_entry_key (struct super_block * s, struct key * key, struct path * path); int usearch_by_position (struct super_block * s, struct key * key, int version, struct path * path); struct key * uget_lkey (struct path * path); struct key * uget_rkey (struct path * path); typedef int do_after_read_t (struct super_block * s, struct buffer_head **, int h); typedef int do_on_full_path_t (struct super_block * s, struct buffer_head **, int); void pass_through_tree (struct super_block *, do_after_read_t, do_on_full_path_t); //int comp_keys_3 (void * key1, void * key2); //int comp_dir_entries (void * key1, void * key2); inline int ubin_search (void * key, void * base, int num, int width, __u32 *ppos, comp_function_t comp_func); /* bitmap.c */ int reiserfsck_reiserfs_new_blocknrs (reiserfs_filsys_t fs, unsigned long * pblocknrs, unsigned long start_from, int amount_needed); int reiserfsck_reiserfs_free_block (reiserfs_filsys_t fs, unsigned long block); struct buffer_head * reiserfsck_get_new_buffer (unsigned long start); int is_block_used (unsigned long block); int is_to_be_read (reiserfs_filsys_t fs, unsigned long block); void mark_block_used (unsigned long block); void mark_block_uninsertable (unsigned long block); int is_block_uninsertable (unsigned long block); /* objectid.c */ int is_objectid_used (struct super_block * s, __u32 objectid); void mark_objectid_as_used (struct super_block * s, __u32 objectid); void mark_objectid_as_free (struct super_block * s, __u32 objectid); __u32 get_unused_objectid (struct super_block * s); struct id_map * init_id_map (void); void free_id_map (struct id_map **); int is_objectid_really_used (struct id_map *, __u32 id, int * ppos); int mark_objectid_really_used (struct id_map *, __u32 id); void flush_objectid_map (struct id_map * map, reiserfs_filsys_t fs); void fetch_objectid_map (struct id_map * map, reiserfs_filsys_t fs); /* segments.c */ struct overwritten_unfm_segment { int ous_begin; int ous_end; struct overwritten_unfm_segment * ous_next; }; struct overwritten_unfm * look_for_overwritten_unfm (__u32); struct overwritten_unfm_segment * find_overwritten_unfm (unsigned long unfm, int length, struct overwritten_unfm_segment * segment_to_init); int get_unoverwritten_segment (struct overwritten_unfm_segment * list_head, struct overwritten_unfm_segment * unoverwritten_segment); void save_unfm_overwriting (unsigned long unfm, struct item_head * direct_ih); void free_overwritten_unfms (void); void mark_formatted_pointed_by_indirect (__u32); int is_formatted_pointed_by_indirect (__u32); struct id_map { __u32 * m_begin; /* pointer to map area */ unsigned long m_used_slots_count; int m_page_count; /* objectid map expands by one page at time. This is size of objectid map size in pages */ unsigned long objectids_marked; /* number of objectids marked used in a map */ }; struct fsck_data { unsigned long all_blocks; /* super block's block count */ /* pass 0 */ unsigned long analyzed; /* blocks marked used (not data not included) */ unsigned long free; /* free blocks */ unsigned long not_data; /* super block, bitmap, journal */ unsigned long leaves; /* blocks looking like reiserfs leaves */ unsigned long pointed_leaves; unsigned long pointed; /* by indirect items */ unsigned long pointed_once; unsigned long pointed_more_than_once; unsigned long allocable; unsigned long wrong_pointers; /* out of range or pointers to free area */ unsigned long leaves_corrected; unsigned long all_contents_removed; /* pass 1, 2 */ unsigned long read_leaves; unsigned long uninsertable_leaves; unsigned long inserted_leaves; unsigned long shared_objectids; unsigned long saved_on_pass1; unsigned long relocated; unsigned long rewritten; /* stat of semantic pass */ unsigned long regular_files; unsigned long broken_files; /* files having stat data and broken body */ unsigned long directories; unsigned long symlinks; unsigned long others; unsigned long fixed_sizes; unsigned long deleted_entries; /* entries pointing to nowhere */ unsigned long oid_sharing; /* files relocated due to objectid sharing */ unsigned long oid_sharing_files_relocated; /* relocated files */ unsigned long oid_sharing_dirs_relocated; /* relocated dirs */ unsigned long lost_found; unsigned long empty_lost_dirs; unsigned long lost_found_dirs; unsigned long dir_recovered; unsigned long lost_found_files; /* pass 4 */ unsigned long deleted_items; /* items which were not touched by semantic pass */ /* objectid maps */ struct id_map * proper_id_map; struct id_map * semantic_id_map; /* this objectid map is used to cure objectid sharing problem */ /* bitmaps */ reiserfs_bitmap_t on_disk_bitmap; reiserfs_bitmap_t new_bitmap; reiserfs_bitmap_t allocable_bitmap; char * bitmap_file_name; char * new_bitmap_file_name; unsigned short mode; unsigned long options; /* log file name and handle */ char * log_file_name; FILE * log; /* hash hits stat */ int hash_amount; unsigned long * hash_hits; #define USED_BLOCKS 1 #define EXTERN_BITMAP 2 #define ALL_BLOCKS 3 int scan_area; int test; }; #define stats(s) ((struct fsck_data *)((s)->s_vp)) #define proper_id_map(s) stats(s)->proper_id_map #define semantic_id_map(s) stats(s)->semantic_id_map #define fsck_disk_bitmap(s) stats(s)->on_disk_bitmap #define fsck_new_bitmap(s) stats(s)->new_bitmap #define fsck_allocable_bitmap(s) stats(s)->allocable_bitmap #define fsck_interactive(fs) (stats(fs)->options & OPT_INTERACTIVE) #define fsck_fix_fixable(fs) (stats(fs)->options & OPT_FIX_FIXABLE) /* change unknown modes (corrupted) to mode of regular files, fix file sizes which are bigger than a real file size, relocate files with shared objectids (this slows fsck down (when there are too many files sharing the same objectid), it will also remove other names pointing to this file */ #define fsck_fix_non_critical(fs) (stats(fs)->options & OPT_FIX_NON_CRITICAL) #define fsck_quiet(fs) (stats(fs)->options & OPT_QUIET) #define fsck_silent(fs) (stats(fs)->options & OPT_SILENT) #define fsck_save_leaf_bitmap(fs) (stats(fs)->options & OPT_SAVE_EXTERN_BITMAP) #define fsck_mode(fs) (stats(fs)->mode) #define fsck_log_file(fs) (stats(fs)->log) /* ?? */ extern inline int change_version (int version) { return (version == 1)?0:1; } int fsck_user_confirmed (reiserfs_filsys_t fs, char * q, char * a, int default_answer); void stage_report (int, reiserfs_filsys_t fs); /* journal.c */ int reiserfs_replay_journal (struct super_block * s); #define fsck_log(fmt, list...) \ {\ if (!fsck_silent (fs))\ reiserfs_warning (fsck_log_file (fs), fmt, ## list);\ } #define fsck_progress(fmt, list...) \ {\ reiserfs_warning (stderr, fmt, ## list);\ fflush (stderr);\ } reiserfsprogs-3.x.0j/fsck/reiserfsck.80000644000076400001440000000466107260374607013553 .\" -*- nroff -*- .\" Copyright 1996-2001 Hans Reiser. .\" .TH REISERFSCK 8 "March 2001" "Reiserfsprogs-3.x.0j" .SH NAME reiserfsck \- check a Linux Reiserfs file system .SH SYNOPSIS .B reiserfsck [ .B -arvixoV ] [ .B -l logfilename ] [ .B --rebuild-tree ] [ .B --check ] [ .B --rebuild-sb ] [ .B --interactive ] [ \fB --logfile \fI logfilename ] [ .B --fix-fixable ] .I device .SH DESCRIPTION It looks for reiserfs filesystem on a device, replays transactions which are to be replayed and either check or repair the filesystem .TP .I device is the special file corresponding to the device (e.g /dev/hdXX for IDE disk partition or /dev/sdXX for SCSI disk partition). .SH OPTIONS .TP .B --check This checks filesystem consistency. This is a default action. It may be used on a filesystem mounted read-only .TP .B --rebuild-tree This rebuilds filesystem tree using leaf nodes found on the device. Normally, you do not need this, but if you have to rebuild tree - please backup whole partition first or at least the most important data if you can mount the partition. .TP .B --rebuild-sb .TP .B --interactive, -i This makes \fBreiserfsck\fR to stop after each pass completed. .TP .B --quiet, -q have \fBreiserfsck\fR to not reflect its progress .TP .B --nolog, -n have \fBreiserfsck\fR to not log anything .TP \fB--logfile \fIfilename\fR, \fB-l \fI filename have \fBreiserfsck\fR to put info about found corruptions in logfile rather than on stderr .TP .B --fix-fixable, -x have \fBreiserfsck\fR to recover corruptions which can be fixed w/o --rebuild-tree when it is runnig in check mode. Corruptions which can be fixed so far: bad pointers to data blocks, wrong directory's st_size and st_blocks, directories entries pointing to nowhere can be deleted .TP .B --fix-non-critical, -o have \fBreiserfsck\fR to fix: file sizes when they are bigger than real file size, set file mode to regular file when mode looks wrong and to try to recover "objectid sharing" problem .TP .B -a When it is set - \fBreiserfsck\fR assumes that it is called by fsck -A and just returns even if filesystem seems not umounted cleanly .TP .B -r ignored .TP .B -V Prints version and exits .SH AUTHOR This version of \fBreiserfsck\fR has been written by Hans Reiser . .SH BUGS There are probably few of them. Please, report bugs to Hans Reiser . .SH TODO Faster recovering, signal handling, i/o error handling, etc. .SH SEE ALSO .BR mkreiserfs (8), .BR debugreiserfs (8) reiserfsprogs-3.x.0j/debugreiserfs/0000777000076400001440000000000007261220342013265 5reiserfsprogs-3.x.0j/debugreiserfs/Makefile.in0000644000076400001440000002256707261220342015262 # Makefile.in generated automatically by automake 1.4 from Makefile.am # Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. # This Makefile.in 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. SHELL = @SHELL@ srcdir = @srcdir@ top_srcdir = @top_srcdir@ VPATH = @srcdir@ prefix = @prefix@ exec_prefix = @exec_prefix@ bindir = @bindir@ sbindir = @sbindir@ libexecdir = @libexecdir@ datadir = @datadir@ sysconfdir = @sysconfdir@ sharedstatedir = @sharedstatedir@ localstatedir = @localstatedir@ libdir = @libdir@ infodir = @infodir@ mandir = @mandir@ includedir = @includedir@ oldincludedir = /usr/include DESTDIR = pkgdatadir = $(datadir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ top_builddir = .. ACLOCAL = @ACLOCAL@ AUTOCONF = @AUTOCONF@ AUTOMAKE = @AUTOMAKE@ AUTOHEADER = @AUTOHEADER@ INSTALL = @INSTALL@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS) INSTALL_DATA = @INSTALL_DATA@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ transform = @program_transform_name@ NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : CC = @CC@ MAKEINFO = @MAKEINFO@ PACKAGE = @PACKAGE@ RANLIB = @RANLIB@ VERSION = @VERSION@ sbin_PROGRAMS = debugreiserfs unpack debugreiserfs_SOURCES = debugreiserfs.c pack.c unpack_SOURCES = unpack.c debugreiserfs.h man_MANS = debugreiserfs.8 EXTRA_DIST = $(man_MANS) LDADD = ../lib/libmisc.a ../reiserfscore/libcore.a INCLUDES = -I../include mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs CONFIG_CLEAN_FILES = PROGRAMS = $(sbin_PROGRAMS) DEFS = @DEFS@ -I. -I$(srcdir) CPPFLAGS = @CPPFLAGS@ LDFLAGS = @LDFLAGS@ LIBS = @LIBS@ debugreiserfs_OBJECTS = debugreiserfs.o pack.o debugreiserfs_LDADD = $(LDADD) debugreiserfs_DEPENDENCIES = ../lib/libmisc.a ../reiserfscore/libcore.a debugreiserfs_LDFLAGS = unpack_OBJECTS = unpack.o unpack_LDADD = $(LDADD) unpack_DEPENDENCIES = ../lib/libmisc.a ../reiserfscore/libcore.a unpack_LDFLAGS = CFLAGS = @CFLAGS@ COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ man8dir = $(mandir)/man8 MANS = $(man_MANS) NROFF = nroff DIST_COMMON = Makefile.am Makefile.in DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) TAR = tar GZIP_ENV = --best SOURCES = $(debugreiserfs_SOURCES) $(unpack_SOURCES) OBJECTS = $(debugreiserfs_OBJECTS) $(unpack_OBJECTS) all: all-redirect .SUFFIXES: .SUFFIXES: .S .c .o .s $(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps debugreiserfs/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status cd $(top_builddir) \ && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status mostlyclean-sbinPROGRAMS: clean-sbinPROGRAMS: -test -z "$(sbin_PROGRAMS)" || rm -f $(sbin_PROGRAMS) distclean-sbinPROGRAMS: maintainer-clean-sbinPROGRAMS: install-sbinPROGRAMS: $(sbin_PROGRAMS) @$(NORMAL_INSTALL) $(mkinstalldirs) $(DESTDIR)$(sbindir) @list='$(sbin_PROGRAMS)'; for p in $$list; do \ if test -f $$p; then \ echo " $(INSTALL_PROGRAM) $$p $(DESTDIR)$(sbindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`"; \ $(INSTALL_PROGRAM) $$p $(DESTDIR)$(sbindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \ else :; fi; \ done uninstall-sbinPROGRAMS: @$(NORMAL_UNINSTALL) list='$(sbin_PROGRAMS)'; for p in $$list; do \ rm -f $(DESTDIR)$(sbindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \ done .c.o: $(COMPILE) -c $< .s.o: $(COMPILE) -c $< .S.o: $(COMPILE) -c $< mostlyclean-compile: -rm -f *.o core *.core clean-compile: distclean-compile: -rm -f *.tab.c maintainer-clean-compile: debugreiserfs: $(debugreiserfs_OBJECTS) $(debugreiserfs_DEPENDENCIES) @rm -f debugreiserfs $(LINK) $(debugreiserfs_LDFLAGS) $(debugreiserfs_OBJECTS) $(debugreiserfs_LDADD) $(LIBS) unpack: $(unpack_OBJECTS) $(unpack_DEPENDENCIES) @rm -f unpack $(LINK) $(unpack_LDFLAGS) $(unpack_OBJECTS) $(unpack_LDADD) $(LIBS) install-man8: $(mkinstalldirs) $(DESTDIR)$(man8dir) @list='$(man8_MANS)'; \ l2='$(man_MANS)'; for i in $$l2; do \ case "$$i" in \ *.8*) list="$$list $$i" ;; \ esac; \ done; \ for i in $$list; do \ if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ else file=$$i; fi; \ ext=`echo $$i | sed -e 's/^.*\\.//'`; \ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ inst=`echo $$inst | sed '$(transform)'`.$$ext; \ echo " $(INSTALL_DATA) $$file $(DESTDIR)$(man8dir)/$$inst"; \ $(INSTALL_DATA) $$file $(DESTDIR)$(man8dir)/$$inst; \ done uninstall-man8: @list='$(man8_MANS)'; \ l2='$(man_MANS)'; for i in $$l2; do \ case "$$i" in \ *.8*) list="$$list $$i" ;; \ esac; \ done; \ for i in $$list; do \ ext=`echo $$i | sed -e 's/^.*\\.//'`; \ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ inst=`echo $$inst | sed '$(transform)'`.$$ext; \ echo " rm -f $(DESTDIR)$(man8dir)/$$inst"; \ rm -f $(DESTDIR)$(man8dir)/$$inst; \ done install-man: $(MANS) @$(NORMAL_INSTALL) $(MAKE) $(AM_MAKEFLAGS) install-man8 uninstall-man: @$(NORMAL_UNINSTALL) $(MAKE) $(AM_MAKEFLAGS) uninstall-man8 tags: TAGS ID: $(HEADERS) $(SOURCES) $(LISP) list='$(SOURCES) $(HEADERS)'; \ unique=`for i in $$list; do echo $$i; done | \ awk ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ here=`pwd` && cd $(srcdir) \ && mkid -f$$here/ID $$unique $(LISP) TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) tags=; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS)'; \ unique=`for i in $$list; do echo $$i; done | \ awk ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) mostlyclean-tags: clean-tags: distclean-tags: -rm -f TAGS ID maintainer-clean-tags: distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) subdir = debugreiserfs distdir: $(DISTFILES) @for file in $(DISTFILES); do \ d=$(srcdir); \ if test -d $$d/$$file; then \ cp -pr $$/$$file $(distdir)/$$file; \ else \ test -f $(distdir)/$$file \ || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ || cp -p $$d/$$file $(distdir)/$$file || :; \ fi; \ done debugreiserfs.o: debugreiserfs.c debugreiserfs.h ../include/io.h \ ../include/misc.h ../include/reiserfs_lib.h \ ../include/reiserfs_fs.h ../version.h pack.o: pack.c debugreiserfs.h ../include/io.h ../include/misc.h \ ../include/reiserfs_lib.h ../include/reiserfs_fs.h ../version.h unpack.o: unpack.c debugreiserfs.h ../include/io.h ../include/misc.h \ ../include/reiserfs_lib.h ../include/reiserfs_fs.h ../version.h info-am: info: info-am dvi-am: dvi: dvi-am check-am: all-am check: check-am installcheck-am: installcheck: installcheck-am install-exec-am: install-sbinPROGRAMS install-exec: install-exec-am install-data-am: install-man install-data: install-data-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am install: install-am uninstall-am: uninstall-sbinPROGRAMS uninstall-man uninstall: uninstall-am all-am: Makefile $(PROGRAMS) $(MANS) all-redirect: all-am install-strip: $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install installdirs: $(mkinstalldirs) $(DESTDIR)$(sbindir) $(DESTDIR)$(mandir)/man8 mostlyclean-generic: clean-generic: distclean-generic: -rm -f Makefile $(CONFIG_CLEAN_FILES) -rm -f config.cache config.log stamp-h stamp-h[0-9]* maintainer-clean-generic: mostlyclean-am: mostlyclean-sbinPROGRAMS mostlyclean-compile \ mostlyclean-tags mostlyclean-generic mostlyclean: mostlyclean-am clean-am: clean-sbinPROGRAMS clean-compile clean-tags clean-generic \ mostlyclean-am clean: clean-am distclean-am: distclean-sbinPROGRAMS distclean-compile distclean-tags \ distclean-generic clean-am distclean: distclean-am maintainer-clean-am: maintainer-clean-sbinPROGRAMS \ maintainer-clean-compile maintainer-clean-tags \ maintainer-clean-generic distclean-am @echo "This command is intended for maintainers to use;" @echo "it deletes files that may require special tools to rebuild." maintainer-clean: maintainer-clean-am .PHONY: mostlyclean-sbinPROGRAMS distclean-sbinPROGRAMS \ clean-sbinPROGRAMS maintainer-clean-sbinPROGRAMS uninstall-sbinPROGRAMS \ install-sbinPROGRAMS mostlyclean-compile distclean-compile \ clean-compile maintainer-clean-compile install-man8 uninstall-man8 \ install-man uninstall-man tags mostlyclean-tags distclean-tags \ clean-tags maintainer-clean-tags distdir info-am info dvi-am dvi check \ check-am installcheck-am installcheck install-exec-am install-exec \ install-data-am install-data install-am install uninstall-am uninstall \ all-redirect all-am all installdirs mostlyclean-generic \ distclean-generic clean-generic maintainer-clean-generic clean \ mostlyclean distclean maintainer-clean # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: reiserfsprogs-3.x.0j/debugreiserfs/Makefile.am0000644000076400001440000000040007254174402015236 sbin_PROGRAMS = debugreiserfs unpack debugreiserfs_SOURCES = debugreiserfs.c pack.c unpack_SOURCES = unpack.c debugreiserfs.h man_MANS = debugreiserfs.8 EXTRA_DIST = $(man_MANS) LDADD = ../lib/libmisc.a ../reiserfscore/libcore.a INCLUDES = -I../include reiserfsprogs-3.x.0j/debugreiserfs/debugreiserfs.c0000644000076400001440000006614207260330154016211 /* * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README */ #include "debugreiserfs.h" reiserfs_filsys_t fs; #define print_usage_and_exit() die ("Usage: %s [-b block-to-print][-idc] device\n\ -i Causes to print all items of a leaf\n\ -d content of directory items\n\ -c content of direct items\n\ -m bitmap blocks\n\ -t\n\ -C\n\ -p\n\ -s \n\ -n scan for name\n\ -p [filename]\n\ -P [filename]\n\ ..etc\n", argv[0]); #if 1 struct reiserfs_fsstat { int nr_internals; int nr_leaves; int nr_files; int nr_directories; int nr_unformatted; } g_stat_info; #endif int mode = DO_DUMP; /* * options */ int opt_print_regular_file_content = 0;/* -c */ int opt_print_details = 0; /* -d */ int opt_print_leaf_items = 0; /* -i */ int opt_print_objectid_map = 0; /* -o */ int opt_print_block_map = 0; /* -m */ int opt_print_journal; /* -j */ /* when you want print one block specify -b # */ int opt_block_to_print = -1; /* when you want to corrupt block specify -C # */ int opt_block_to_corrupt = -1; int opt_pack = 0; int opt_quiet = 0; int print_mode (void) { int mode = 0; if (opt_print_leaf_items == 1) mode |= PRINT_LEAF_ITEMS; if (opt_print_details == 1) mode |= (PRINT_LEAF_ITEMS | PRINT_ITEM_DETAILS); if (opt_print_regular_file_content == 1) mode |= (PRINT_LEAF_ITEMS | PRINT_DIRECT_ITEMS); return mode; } static void print_disk_tree (reiserfs_filsys_t fs, int block_nr) { struct buffer_head * bh; bh = bread (fs->s_dev, block_nr, fs->s_blocksize); if (!bh) { die ("Could not read block %d\n", block_nr); } if (is_internal_node (bh)) { int i; struct disk_child * dc; g_stat_info.nr_internals ++; print_block (stdout, fs, bh, print_mode (), -1, -1); dc = B_N_CHILD (bh, 0); for (i = 0; i <= B_NR_ITEMS (bh); i ++, dc ++) print_disk_tree (fs, dc->dc_block_number); } else if (is_leaf_node (bh)) { g_stat_info.nr_leaves ++; print_block (stdout, fs, bh, print_mode (), -1, -1); } else { print_block (stdout, fs, bh, print_mode (), -1, -1); die ("print_disk_tree: bad block type"); } brelse (bh); } void pack_one_block (reiserfs_filsys_t fs, unsigned long block); static void print_one_block (reiserfs_filsys_t fs, int block) { struct buffer_head * bh; if (test_bit (block % (fs->s_blocksize * 8), SB_AP_BITMAP (fs)[block / (fs->s_blocksize * 8)]->b_data)) fprintf (stderr, "%d is used in true bitmap\n", block); else fprintf (stderr, "%d is free in true bitmap\n", block); bh = bread (fs->s_dev, block, fs->s_blocksize); if (!bh) { printf ("print_one_block: bread fialed\n"); return; } if (opt_pack) { pack_one_block (fs, bh->b_blocknr); brelse (bh); return; } if (who_is_this (bh->b_data, fs->s_blocksize) != THE_UNKNOWN) print_block (stdout, fs, bh, PRINT_LEAF_ITEMS | PRINT_ITEM_DETAILS | (opt_print_regular_file_content == 1 ? PRINT_DIRECT_ITEMS : 0), -1, -1); else printf ("Looks like unformatted\n"); brelse (bh); return; } static void corrupt_clobber_hash (char * name, struct item_head * ih, struct reiserfs_de_head * deh) { printf ("\tCorrupting deh_offset of entry \"%s\" of [%u %u]\n", name, ih->ih_key.k_dir_id, ih->ih_key.k_objectid); deh->deh_offset = 700; } /* this reads list of desired corruptions from stdin and perform the corruptions. Format of that list: A hash_code C name objectid - 'C'ut entry 'name' from directory item with 'objectid' H name objectid - clobber 'H'hash of entry 'name' of directory 'objectid' I item_num pos_in_item make pos_in_item-th slot of indirect item to point out of device O item_num - destroy item 'O'rder - make 'item_num'-th to have key bigger than 'item_num' + 1-th item D item_num - 'D'elete item_num-th item S item_num value - change file size (item_num-th item must be stat data) F item_num value - change sd_first_direct_byte of stat data J item_num objectid E name objectid new - change entry's deh_objectid to new P - print the block */ static void do_corrupt_one_block (reiserfs_filsys_t fs, int block) { struct buffer_head * bh; int i, j; struct item_head * ih; int item_num; char * line = 0; int n = 0; char code, name [100]; __u32 objectid, new_objectid; int value; int hash_code; int pos_in_item; if (test_bit (block % (fs->s_blocksize * 8), SB_AP_BITMAP (fs)[block / (fs->s_blocksize * 8)]->b_data)) fprintf (stderr, "%d is used in true bitmap\n", block); else fprintf (stderr, "%d is free in true bitmap\n", block); bh = bread (fs->s_dev, block, fs->s_blocksize); if (!bh) { printf ("corrupt_one_block: bread fialed\n"); return; } if (who_is_this (bh->b_data, fs->s_blocksize) != THE_LEAF) { printf ("Can not corrupt not a leaf node\n"); brelse (bh); return; } printf ("Corrupting block %lu..\n", bh->b_blocknr); while (getline (&line, &n, stdin) != -1) { switch (line[0]) { case '#': case '\n': continue; case '?': printf ("A hash_code - reset hAsh code in super block\n" "C name objectid - Cut entry 'name' from directory item with 'objectid'\n" "H name objectid - clobber Hash of entry 'name' of directory 'objectid'\n" "I item_num pos_in_item make pos_in_tem-th slot of Indirect item to point out of device\n" "O item_num - destroy item Order - make 'item_num'-th to have key bigger than 'item_num' + 1-th item\n" "D item_num - Delete item_num-th item\n" "S item_num value - change file Size (item_num-th item must be stat data)\n" "F item_num value - change sd_First_direct_byte of stat data\n" "J item_num objectid - set 'obJectid' of 'item_num'-th item\n" "E name objectid objectid - set deh_objectid of an entry to objectid\n"); continue; case 'P': print_block (stderr, fs, bh, 3, -1, -1); break; case 'A': /* corrupt hash record in super block */ if (sscanf (line, "%c %d\n", &code, &hash_code) != 2) { printf ("Wrong format \'%c\'\n", line [0]); continue; } break; case 'C': /* cut entry */ case 'H': /* make hash wrong */ if (sscanf (line, "%c %s %u\n", &code, name, &objectid) != 3) { printf ("Wrong format \'%c\'\n", line [0]); continue; } break; case 'J': /* set objectid : used to simulate objectid sharing problem */ if (sscanf (line, "%c %d %d\n", &code, &item_num, &objectid) != 3) { printf ("Wrong format \'%c\'\n", line [0]); continue; } break; case 'E': /* set objectid : used to simulate objectid sharing problem */ if (sscanf (line, "%c %s %u %d\n", &code, name, &objectid, &new_objectid) != 4) { printf ("Wrong format \'%c\'\n", line [0]); continue; } break; case 'I': /* break unformatted node pointer */ if (sscanf (line, "%c %d %d\n", &code, &item_num, &pos_in_item) != 3) { printf ("Wrong format \'%c\'\n", line [0]); continue; } break; case 'D': /* delete item */ case 'O': /* make item out of order */ if (sscanf (line, "%c %d\n", &code, &item_num) != 2) { printf ("Wrong format \'%c\'\n", line [0]); continue; } break; case 'S': /* corrupt st_size */ case 'F': /* st_first_direct_byte */ if (sscanf (line, "%c %d %d\n", &code, &item_num, &value) != 3) { printf ("Wrong format \'%c\'\n", line [0]); continue; } break; } if (code == 'A') { reiserfs_warning (stderr, "Changing %s to %s\n", code2name (rs_hash (fs->s_rs)), code2name (hash_code)); set_hash (fs->s_rs, hash_code); mark_buffer_dirty (fs->s_sbh); continue; } ih = B_N_PITEM_HEAD (bh, 0); for (i = 0; i < node_item_number (bh); i ++, ih ++) { struct reiserfs_de_head * deh; if (code == 'I' && i == item_num) { if (!is_indirect_ih (ih) || pos_in_item >= I_UNFM_NUM (ih)) { reiserfs_warning (stderr, "Not an indirect item or there is " "not so many unfm ptrs in it\n"); continue; } * ((__u32 *)B_I_PITEM (bh, ih) + pos_in_item) = SB_BLOCK_COUNT(fs) + 100; mark_buffer_dirty (bh); goto cont; } if (code == 'J' && i == item_num) { ih->ih_key.k_objectid = objectid; mark_buffer_dirty (bh); goto cont; } if (code == 'S' && i == item_num) { /* fixme: old stat data only */ struct stat_data_v1 * sd; sd = (struct stat_data_v1 *)B_I_PITEM (bh, ih); reiserfs_warning (stderr, "Changing sd_size of %k from %d to %d\n", &ih->ih_key, sd->sd_size, value); sd->sd_size = value; mark_buffer_dirty (bh); goto cont; } if (code == 'F' && i == item_num) { /* fixme: old stat data only */ struct stat_data_v1 * sd; sd = (struct stat_data_v1 *)B_I_PITEM (bh, ih); reiserfs_warning (stderr, "Changing sd_first_direct_byte of %k from %d to %d\n", &ih->ih_key, sd->sd_first_direct_byte, value); sd->sd_first_direct_byte = value; mark_buffer_dirty (bh); goto cont; } if (code == 'D' && i == item_num) { delete_item (fs, bh, item_num); mark_buffer_dirty (bh); goto cont; } if (code == 'O' && i == item_num) { /* destroy item order */ struct key * key; if (i == node_item_number (bh) - 1) { printf ("can not destroy order\n"); continue; } key = &(ih + 1)->ih_key; ih->ih_key.k_dir_id = key->k_dir_id + 1; mark_buffer_dirty (bh); } if (ih->ih_key.k_objectid != objectid || !is_direntry_ih (ih)) continue; deh = B_I_DEH (bh, ih); for (j = 0; j < ih_entry_count (ih); j ++, deh ++) { /* look for proper entry */ if (name_length (ih, deh, j) != strlen (name) || strncmp (name, name_in_entry (deh, j), strlen (name))) continue; /* ok, required entry found, make a corruption */ switch (code) { case 'C': /* cut entry */ cut_entry (fs, bh, i, j, 1); mark_buffer_dirty (bh); if (!B_IS_IN_TREE (bh)) { printf ("NOTE: block is deleted from the tree\n"); exit (0); } goto cont; break; case 'H': /* clobber hash */ corrupt_clobber_hash (name, ih, deh); goto cont; break; case 'E': /* change entry's deh_objectid */ deh->deh_objectid = new_objectid; break; default: printf ("Unknown command found\n"); } mark_buffer_dirty (bh); } } cont: } free (line); printf ("Done\n"); brelse (bh); return; } /* this reads stdin and recover file of given key: */ /* the input has to be in the follwong format: K dirid objectid N name B blocknumber .. then recover_file will read every block, look there specified file and put it into */ static void do_recover (reiserfs_filsys_t fs) { char name [100]; char * line = 0; int n = 0; int fd; struct key key = {0, 0, }; struct buffer_head * bh; struct item_head * ih; unsigned long block; char code; loff_t recovered = 0; int i, j; reiserfs_bitmap_t bitmap; int used, not_used; bitmap = reiserfs_create_bitmap (SB_BLOCK_COUNT (fs)); reiserfs_fetch_disk_bitmap (bitmap, fs); /* we check how many blocks recoverd items point to are free or used */ used = 0; not_used = 0; fd = 0; while (getline (&line, &n, stdin) != -1) { if (line [0] == '#' || line [0] == '\n') continue; switch (line [0]) { case 'K': /* get a key of file which is to be recovered */ if (sscanf (line, "%c %u %u\n", &code, &key.k_dir_id, &key.k_objectid) != 3) { die ("recover_file: wrong input K format"); } printf ("Recovering file (%u, %u)\n", key.k_dir_id, key.k_objectid); break; case 'N': /* get a file name */ recovered = 0; if (sscanf (line, "%c %s\n", &code, name) != 2) { die ("recover_file: wrong input N format"); } fd = open (name, O_RDWR | O_CREAT | O_EXCL, 0644); if (fd == -1) die ("recover_file: could not create file %s: %s", name,strerror (errno)); printf ("Recovering file %s..\n", name); break; case 'B': if (!fd) die ("recover_file: file name is not specified"); if (sscanf (line, "%c %lu\n", &code, &block) != 2) { die ("recover_file: wrong input B format"); } bh = bread (fs->s_dev, block, fs->s_blocksize); if (!bh) { printf ("reading block %lu failed\n", block); continue; } printf ("working with block %lu..\n", block); ih = B_N_PITEM_HEAD (bh, 0); for (i = 0; i < node_item_number (bh); i ++, ih ++) { __u32 * indirect; struct buffer_head * tmp_bh; if (!is_indirect_ih (ih) || key.k_dir_id != ih->ih_key.k_dir_id || key.k_objectid != ih->ih_key.k_objectid) continue; indirect = (__u32 *)B_I_PITEM (bh, ih); for (j = 0; j < I_UNFM_NUM (ih); j ++) { block = le32_to_cpu (indirect [j]); if (!block) continue; tmp_bh = bread (fs->s_dev, block, fs->s_blocksize); if (!tmp_bh) { printf ("reading block %Lu failed\n", (loff_t)block * fs->s_blocksize); continue; } if (lseek64 (fd, get_offset (&ih->ih_key) + j * fs->s_blocksize - 1, SEEK_SET) == (loff_t)-1) { printf ("llseek failed to pos %Ld\n", (loff_t)block * fs->s_blocksize); brelse (tmp_bh); continue; } if (reiserfs_bitmap_test_bit (bitmap, block)) used ++; else not_used ++; /*printf ("block of file %Ld gets block %lu\n", (get_offset (&ih->ih_key) - 1) / fs->s_blocksize + j, block);*/ if (write (fd, tmp_bh->b_data, tmp_bh->b_size) != tmp_bh->b_size) { printf ("write failed to pos %Ld\n", (loff_t)block * fs->s_blocksize); brelse (tmp_bh); continue; } recovered += fs->s_blocksize; brelse (tmp_bh); } } brelse (bh); break; } } printf ("recover_file: %Ld bytes recovered of file %s, key %u %u, %d blocks are free and %d are used\n", recovered, name, key.k_dir_id, key.k_objectid, not_used, used); } /* debugreiserfs -p or -P compresses reiserfs meta data: super block, journal, bitmap blocks and blocks looking like leaves. It may save "bitmap" of blocks they packed in the file of special format. Reiserfsck can then load "bitmap" saved in that file and build the tree of blocks marked used in that "bitmap" */ char * where_to_save; static char * parse_options (int argc, char * argv []) { int c; char * tmp; while ((c = getopt (argc, argv, "b:C:icdmoMp:P:l:jsnrtu:q")) != EOF) { switch (c) { case 'b': /* print a single node */ opt_block_to_print = strtol (optarg, &tmp, 0); if (*tmp) die ("parse_options: bad block number"); break; case 'C': mode = DO_CORRUPT; opt_block_to_corrupt = strtol (optarg, &tmp, 0); if (*tmp) die ("parse_options: bad block number"); break; case 'p': mode = DO_PACK; if (optarg) /* save bitmap of packed blocks in the file 'optarg' */ asprintf (&where_to_save, "%s", optarg); break; case 'P': /* scan whole device and pack all blocks looking like a leaf */ mode = DO_PACK_ALL; fprintf (stderr, "optarg %s\n", optarg); if (optarg) /* save bitmap of packed blocks in the file 'optarg' */ asprintf (&where_to_save, "%s", optarg); break; case 'i': /* print items of a leaf */ opt_print_leaf_items = 1; break; case 'd': /* print directories */ opt_print_details = 1; break; case 'c': /* print contents of a regular file */ opt_print_regular_file_content = 1; break; case 'o': /* print a objectid map */ opt_print_objectid_map = 1; break; case 'm': /* print a block map */ opt_print_block_map = 1; break; case 'M': /* print a block map with details */ opt_print_block_map = 2; break; case 'j': opt_print_journal = 1; break; /* print journal */ case 's': mode = DO_SCAN; break; /* read the device and print what reiserfs blocks were found */ case 'n': mode = DO_SCAN_FOR_NAME; break; case 'r': mode = DO_RECOVER; break; case 't': mode = DO_TEST; break; case 'q': /* this makes packing to not show speed info during -p or -P */ opt_quiet = 1; break; } } if (optind != argc - 1) /* only one non-option argument is permitted */ print_usage_and_exit(); return argv[optind]; } /* print all valid transactions and found dec blocks */ static void print_journal (struct super_block * s) { struct buffer_head * d_bh, * c_bh; struct reiserfs_journal_desc * desc ; struct reiserfs_journal_commit *commit ; int end_journal; int start_journal; int i, j; int first_desc_block = 0; int wrapped = 0; int valid_transactions = 0; start_journal = SB_JOURNAL_BLOCK (s); end_journal = start_journal + JOURNAL_BLOCK_COUNT; reiserfs_warning (stdout, "Start scanning from %d\n", start_journal); d_bh = 0; desc = 0; for (i = start_journal; i < end_journal; i ++) { d_bh = bread (s->s_dev, i, s->s_blocksize); if (who_is_this (d_bh->b_data, d_bh->b_size) == THE_JDESC) { int commit_block; if (first_desc_block == 0) /* store where first desc block found */ first_desc_block = i; print_block (stdout, s, d_bh); /* reiserfs_journal_desc structure will be printed */ desc = (struct reiserfs_journal_desc *)(d_bh->b_data); commit_block = d_bh->b_blocknr + desc->j_len + 1; if (commit_block >= end_journal) { reiserfs_warning (stdout, "-- wrapped?"); wrapped = 1; break; } c_bh = bread (s->s_dev, commit_block, s->s_blocksize); commit = bh_commit (c_bh); if (does_desc_match_commit (desc, commit)) { reiserfs_warning (stdout, "commit block %d (trans_id %ld, j_len %ld) does not match\n", commit_block, commit->j_trans_id, commit->j_len); brelse (c_bh) ; brelse (d_bh); continue; } valid_transactions ++; reiserfs_warning (stdout, "(commit block %d) - logged blocks (", commit_block); #if 1 for (j = 0; j < desc->j_len; j ++) { unsigned long block; if (j < JOURNAL_TRANS_HALF) block = le32_to_cpu (desc->j_realblock[j]); else block = le32_to_cpu (commit->j_realblock[i - JOURNAL_TRANS_HALF]); if (not_journalable (s, block)) reiserfs_warning (stdout, " xxxx"); else { reiserfs_warning (stdout, " %ld", desc->j_realblock[j]); if (block_of_bitmap (s, desc->j_realblock[j])) reiserfs_warning (stdout, "(bmp)"); } if (j && (j + 1) % 10 == 0) reiserfs_warning (stdout, "\n"); } #endif reiserfs_warning (stdout, ")\n"); i += desc->j_len + 1; brelse (c_bh); } brelse (d_bh); } if (wrapped) { c_bh = bread (s->s_dev, first_desc_block - 1, s->s_blocksize); commit = bh_commit (c_bh); if (does_desc_match_commit (desc, commit)) { reiserfs_warning (stdout, "No! commit block %d (trans_id %ld, j_len %ld) does not match\n", first_desc_block - 1, commit->j_trans_id, commit->j_len); } else { reiserfs_warning (stdout, "Yes! (commit block %d) - logged blocks (\n", first_desc_block - 1); #if 1 for (j = 0; j < desc->j_len; j ++) { unsigned long block; if (j < JOURNAL_TRANS_HALF) block = le32_to_cpu (desc->j_realblock[j]); else block = le32_to_cpu (commit->j_realblock[i - JOURNAL_TRANS_HALF]); if (not_journalable (s, block)) reiserfs_warning (stdout, " xxxx"); else { reiserfs_warning (stdout, " %ld", desc->j_realblock[j]); if (block_of_bitmap (s, desc->j_realblock[j])) reiserfs_warning (stdout, "(bmp)"); } } #endif reiserfs_warning (stdout, "\n"); } brelse (c_bh) ; brelse (d_bh); } reiserfs_warning (stdout, "%d valid transactions found\n", valid_transactions); { struct buffer_head * bh; struct reiserfs_journal_header * j_head; bh = bread (s->s_dev, SB_JOURNAL_BLOCK (s) + rs_journal_size (s->s_rs), s->s_blocksize); j_head = (struct reiserfs_journal_header *)(bh->b_data); reiserfs_warning (stdout, "#######################\nJournal header:\n" "j_last_flush_trans_id %ld\n" "j_first_unflushed_offset %ld\n" "j_mount_id %ld\n", j_head->j_last_flush_trans_id, j_head->j_first_unflushed_offset, j_head->j_mount_id); brelse (bh); } } void pack_partition (reiserfs_filsys_t fs); static void do_pack (reiserfs_filsys_t fs) { if (opt_block_to_print != -1) pack_one_block (fs, opt_block_to_print); else pack_partition (fs); } /* FIXME: statistics does not work */ static void do_dump_tree (reiserfs_filsys_t fs) { if (opt_block_to_print != -1) { print_one_block (fs, opt_block_to_print); return; } print_block (stdout, fs, SB_BUFFER_WITH_SB (fs)); if (opt_print_journal) print_journal (fs); if (opt_print_objectid_map == 1) print_objectid_map (stdout, fs); if (opt_print_block_map) print_bmap (stdout, fs, opt_print_block_map == 1 ? 1 : 0); if (opt_print_regular_file_content || opt_print_details || opt_print_leaf_items) { print_disk_tree (fs, SB_ROOT_BLOCK (fs)); /* print the statistic */ printf ("File system uses %d internal + %d leaves + %d unformatted nodes = %d blocks\n", g_stat_info.nr_internals, g_stat_info.nr_leaves, g_stat_info.nr_unformatted, g_stat_info.nr_internals + g_stat_info.nr_leaves + g_stat_info.nr_unformatted); } } FILE * log; static void look_for_key (struct buffer_head * bh, struct key * key) { int i, j; struct item_head * ih; struct reiserfs_de_head * deh; ih = B_N_PITEM_HEAD (bh, 0); for (i = 0; i < B_NR_ITEMS (bh); i ++, ih ++) { if ((ih->ih_key.k_dir_id == key->k_dir_id || (int)key->k_dir_id == -1) && ih->ih_key.k_objectid == key->k_objectid) { reiserfs_warning (log, "%d-th item of block %lu is item of file %K: %H\n", i, bh->b_blocknr, key, ih); } if (!is_direntry_ih (ih)) continue; deh = B_I_DEH (bh, ih); for (j = 0; j < ih_entry_count (ih); j ++, deh ++) { if ((deh->deh_dir_id == key->k_dir_id || (int)key->k_dir_id == -1) && deh->deh_objectid == key->k_objectid) { reiserfs_warning (log, "dir item %d (%H) of block %lu has " "entry (%d-th) %.*s pointing to %K\n", i, ih, bh->b_blocknr, j, name_length (ih, deh, j), name_in_entry (deh, j), key); } } } return; } static void look_for_name (struct buffer_head * bh, char * name) { int i, j; struct item_head * ih; struct reiserfs_de_head * deh; int namelen; char * p; ih = B_N_PITEM_HEAD (bh, 0); for (i = 0; i < B_NR_ITEMS (bh); i ++, ih ++) { if (!is_direntry_ih (ih)) continue; deh = B_I_DEH (bh, ih); for (j = 0; j < ih_entry_count (ih); j ++, deh ++) { p = name_in_entry (deh, j); namelen = name_length (ih, deh, j); if (namelen == strlen (name) && !strncmp (name, p, namelen)) { fprintf (log, "block %lu, item %d, entry %d is %s\n", bh->b_blocknr, i, j, name);fflush (log); } } } return; } static void do_scan (reiserfs_filsys_t fs) { unsigned long i; struct buffer_head * bh; int type; char * answer = 0; size_t n = 0; struct key key = {0, 0, }; unsigned long done, total; reiserfs_bitmap_t bitmap; bitmap = reiserfs_bitmap_load (".bitmap"); total = reiserfs_bitmap_ones (bitmap); /* bitmap = reiserfs_create_bitmap (SB_BLOCK_COUNT (fs)); reiserfs_fetch_disk_bitmap (bitmap, fs); */ log = fopen ("scan.log", "w+"); if (mode == DO_SCAN_FOR_NAME) { printf ("What name do you want to look for?"); getline (&answer, &n, stdin); answer [strlen (answer) - 1] = 0; printf ("Looking for name \"%s\"..\n", answer); key.k_dir_id = 1; } else { printf ("What key do you want to find: dirid?"); getline (&answer, &n, stdin); key.k_dir_id = atoi (answer); printf ("objectid?"); getline (&answer, &n, stdin); key.k_objectid = atoi (answer); printf ("looking for (%u %u)\n", key.k_dir_id, key.k_objectid); } done = 0; for (i = 0; i < SB_BLOCK_COUNT (fs); i ++) { if (!reiserfs_bitmap_test_bit (bitmap, i)) continue; bh = bread (fs->s_dev, i, fs->s_blocksize); if (!bh) { printf ("could not read block %lu\n", i); continue; } type = who_is_this (bh->b_data, bh->b_size); switch (type) { case THE_JDESC: if (!key.k_dir_id) printf ("block %lu is journal descriptor\n", i); break; case THE_SUPER: if (!key.k_dir_id) printf ("block %lu is reiserfs super block\n", i); break; case THE_INTERNAL: if (!key.k_dir_id) printf ("block %lu is reiserfs internal node\n", i); break; case THE_LEAF: if (mode == DO_SCAN_FOR_NAME) { look_for_name (bh, answer); } else if (key.k_dir_id) { look_for_key (bh, &key); } else { printf ("block %lu is reiserfs leaf node\n", i); } break; } brelse (bh); print_how_far (&done, total, 1, 0); } } #if 0 static void do_test (reiserfs_filsys_t fs, unsigned long block) { struct buffer_head * bh; fprintf (stderr, "=========== BLock %lu ============\n", block); bh = bread (fs->s_dev, block, fs->s_blocksize); if (!bh) die ("do_test: bread failed"); if (is_leaf_bad (bh)) fprintf (stderr, "\n######### BAD before repairing ############\n"); else fprintf (stderr, "\n========= OK before repairing ==================\n"); print_block (fs, bh, 3, -1, -1); fprintf (stderr, "\n>>> repairing >>>>........\n\n"); /* function to test */pass0_correct_leaf (fs, bh); if (is_leaf_bad (bh)) fprintf (stderr, "\n######### still BAD after repairing ############\n"); else fprintf (stderr, "\n========= OK after repairing ==================\n"); print_block (fs, bh, 3, -1, -1); brelse (bh); } #endif static void do_test (reiserfs_filsys_t fs) { struct key root_dir_key = {REISERFS_ROOT_PARENT_OBJECTID, REISERFS_ROOT_OBJECTID, {{0, 0},}}; int gen_counter; if (reiserfs_find_entry (fs, &root_dir_key, "lost+found", &gen_counter)) reiserfs_add_entry (fs, &root_dir_key, "lost+found", &root_dir_key, 0); } /* FIXME: need to open reiserfs filesystem first */ int main (int argc, char * argv[]) { char * file_name; int error; print_banner ("debugreiserfs"); file_name = parse_options (argc, argv); fs = reiserfs_open (file_name, O_RDONLY, &error, 0); if (!fs) { fprintf (stderr, "\n\ndumpreiserfs: can not open reiserfs on \"%s\": %s\n\n", file_name, error ? strerror (error) : "there is no one"); return 0; } switch (mode) { case DO_PACK: case DO_PACK_ALL: do_pack (fs); break; case DO_CORRUPT: reiserfs_reopen (fs, O_RDWR); do_corrupt_one_block (fs, opt_block_to_corrupt); break; case DO_DUMP: do_dump_tree (fs); break; case DO_SCAN: case DO_SCAN_FOR_NAME: do_scan (fs); break; case DO_RECOVER: do_recover (fs); break; case DO_TEST: { do_test (fs); #if 0 int i; int arr[] = {53033}; if (opt_block_to_print != -1) { do_test (fs, opt_block_to_print); break; } bad blocks found on Joop partition 53033, 179201, 844702, 844913, 877768, 879067, 907631, 925323, 2241275, 2241343, 2241397, 2241511, 2241553, 2241635, 2241644, 2241654, 2241711, 2241721, 2241727, 2241740, 2241762, 2241766, 2241770, 2241812, 2241820, 2241827, 2241831, 2241878, 2241886, 2241971 }; /* blocks containing broken directory items on Joop's filesystem */ int arr[] = {/*53033,*/ 838396/*, 1597036*//*, 1919589, 2715962*/}; for (i = 0; i < sizeof (arr) / sizeof (arr[0]); i ++) do_test (fs, arr[i]); break; #endif } } reiserfs_close (fs); return 0; } reiserfsprogs-3.x.0j/debugreiserfs/pack.c0000644000076400001440000004403507260635212014276 /* * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README */ #include "debugreiserfs.h" reiserfs_bitmap_t what_to_pack; reiserfs_bitmap_t what_packed; int packed_leaves, bad_leaves, full_blocks, internals, descs, full_of_journal; /* these are to calculate compression */ unsigned long sent; /* how many bytes sent to stdout */ unsigned long had_to_be_sent; /* how many bytes were to be sent */ static void pack_key (struct packed_item * pi, struct item_head * ih) { if (pi->mask & DIR_ID) { fwrite32 (&ih->ih_key.k_dir_id); sent += sizeof (__u32); } if (pi->mask & OBJECT_ID) { fwrite32 (&ih->ih_key.k_objectid); sent += sizeof (__u32); } if (pi->mask & OFFSET_BITS_64) { __u64 offset; offset = get_offset (&ih->ih_key); fwrite64 (&offset); sent += sizeof (__u64); } if (pi->mask & OFFSET_BITS_32) { __u32 offset; offset = get_offset (&ih->ih_key); fwrite32 (&offset); sent += sizeof (__u32); } } static void pack_direct (struct packed_item * pi, struct buffer_head * bh, struct item_head * ih) { pi->mask |= DIRECT_ITEM; /* send packed item header to stdout */ fwrite (pi, sizeof (*pi), 1, stdout); sent += sizeof (*pi); /* send key components which are to be sent */ pack_key (pi, ih); } /* if there is at least one extent longer than 2 - it is worth packing */ static int should_pack_indirect (__u32 * ind_item, int unfm_num) { int i, len; for (i = 1, len = 1; i < unfm_num; i ++) { if ((!ind_item [i] && !ind_item [i - 1]) || /* hole continues */ ind_item [i] == ind_item [i - 1] + 1) { /* subsequent blocks */ len ++; if (len > 2) return 1; } else { /* sequence of blocks or hole broke */ len = 1; } } return 0; } /* indirect item can be either packed using "extents" (when it is worth doing) or be stored as is. Size of item in packed form is not stored. Unpacking will stop when full item length is reached */ static void pack_indirect (struct packed_item * pi, struct buffer_head * bh, struct item_head * ih) { int i; __u32 * ind_item; __u16 len; pi->mask |= INDIRECT_ITEM; if (ih_entry_count (ih)) pi->mask |= ENTRY_COUNT; ind_item = (__u32 *)B_I_PITEM (bh, ih); if (!should_pack_indirect (ind_item, I_UNFM_NUM (ih))) pi->mask |= WHOLE_INDIRECT; /* send packed item header to stdout */ fwrite (pi, sizeof (*pi), 1, stdout); sent += sizeof (*pi); /* send key components which are to be sent */ pack_key (pi, ih); if (pi->mask & ENTRY_COUNT) { __u16 ih_free_space; ih_free_space = ih_entry_count (ih); fwrite16 (&ih_free_space); sent += sizeof (__u16); } if (pi->mask & WHOLE_INDIRECT) { fwrite (ind_item, ih_item_len (ih), 1, stdout); sent += ih_item_len (ih); return; } fwrite32 (&ind_item [0]); sent += sizeof (__u32); for (i = 1, len = 1; i < I_UNFM_NUM (ih); i ++) { if ((!ind_item [i] && !ind_item [i - 1]) || /* hole continues */ ind_item [i] == ind_item[ i - 1] + 1) { /* subsequent blocks */ len ++; } else { fwrite16 (&len); fwrite32 (&ind_item[i]); sent += (sizeof (__u32) + sizeof (__u16)); len = 1; } } fwrite16 (&len); sent += sizeof (__u16); return; } /* directory item is packed: entry count - 16 bits for each entry mask (8 bits) - it shows whether there are any of (deh_dir_id, gen counter, deh_state) entry length 16 bits entry itself deh_objectid - 32 bits maybe deh_dir_id (32 bits) maybe gencounter (16) maybe deh_state (16) */ static void pack_direntry (reiserfs_filsys_t fs, struct packed_item * pi, struct buffer_head * bh, struct item_head * ih) { int i; struct reiserfs_de_head * deh; struct packed_dir_entry pe; __u16 entry_count, gen_counter; pi->mask |= (DIRENTRY_ITEM | ENTRY_COUNT); /* send packed item header to stdout */ fwrite (pi, sizeof (*pi), 1, stdout); sent += sizeof (*pi); /* send key components which are to be sent */ pack_key (pi, ih); /* entry count is sent unconditionally */ entry_count = ih_entry_count (ih); fwrite16 (&entry_count); deh = B_I_DEH (bh, ih); for (i = 0; i < entry_count; i ++, deh ++) { pe.entrylen = entry_length (ih, deh, i); pe.mask = 0; if (deh_dir_id (deh) != le32_to_cpu (ih->ih_key.k_objectid)) /* entry points to name of another directory, store deh_dir_id */ pe.mask |= HAS_DIR_ID; gen_counter = GET_GENERATION_NUMBER (deh_offset (deh)); if (gen_counter != 0) /* store generation counter if it is != 0 */ pe.mask |= HAS_GEN_COUNTER; if (le16_to_cpu (deh->deh_state) != 4) /* something unusual in deh_state. Store it */ pe.mask |= HAS_STATE; fwrite8 (&pe.mask); fwrite16 (&pe.entrylen); fwrite (name_in_entry (deh, i), pe.entrylen, 1, stdout); fwrite32 (&(deh->deh_objectid)); sent += (sizeof (__u8) + sizeof (__u16) + pe.entrylen + sizeof (__u32)); if (pe.mask & HAS_DIR_ID) { fwrite32 (&deh->deh_dir_id); sent += sizeof (__u32); } if (pe.mask & HAS_GEN_COUNTER) { fwrite16 (&gen_counter); sent += sizeof (__u16); } if (pe.mask & HAS_STATE) { fwrite16 (&deh->deh_state); sent += sizeof (__u16); } } } static void pack_stat_data (struct packed_item * pi, struct buffer_head * bh, struct item_head * ih) { pi->mask |= STAT_DATA_ITEM; if (stat_data_v1 (ih)) { /* for old stat data: we take mode - 16 bits nlink - 16 bits size - 32 bits blocks/rdev - 32 bits maybe first_direct byte 32 bits */ struct stat_data_v1 * sd_v1; sd_v1 = (struct stat_data_v1 *)B_I_PITEM (bh, ih); if (sd_v1->sd_first_direct_byte != 0xffffffff) pi->mask |= WITH_SD_FIRST_DIRECT_BYTE; /* we are done with packed_item send packed it to stdout */ fwrite (pi, sizeof (*pi), 1, stdout); sent += sizeof (*pi); /* send key components which are to be sent */ pack_key (pi, ih); fwrite16 (&sd_v1->sd_mode); fwrite16 (&sd_v1->sd_nlink); fwrite32 (&sd_v1->sd_size); fwrite32 (&sd_v1->u.sd_blocks); sent += (sizeof (__u16) * 2 + sizeof (__u32) * 2); if (pi->mask & WITH_SD_FIRST_DIRECT_BYTE) { fwrite32 (&sd_v1->sd_first_direct_byte); sent += sizeof (__u32); } } else { /* for new stat data mode - 16 bits nlink in either 16 or 32 bits size in either 32 or 64 bits blocks - 32 bits */ struct stat_data * sd; __u16 nlink16; __u32 nlink32, size32; __u64 size64; sd = (struct stat_data *)B_I_PITEM (bh, ih); if (sd->sd_nlink > 0xffff) { pi->mask |= NLINK_BITS_32; nlink32 = sd->sd_nlink; } else { nlink16 = sd->sd_nlink; } if (sd->sd_size > 0xffffffff) { pi->mask |= SIZE_BITS_64; size64 = sd->sd_size; } else { size32 = sd->sd_size; } /* we are done with packed_item send packed it to stdout */ fwrite (pi, sizeof (*pi), 1, stdout); sent += sizeof (*pi); /* send key components which are to be sent */ pack_key (pi, ih); fwrite16 (&sd->sd_mode); sent += sizeof (__u16); if (pi->mask & NLINK_BITS_32) { fwrite32 (&nlink32); sent += sizeof (__u32); } else { fwrite16 (&nlink16); sent += sizeof (__u16); } if (pi->mask & SIZE_BITS_64) { fwrite64 (&size64); sent += sizeof (__u64); } else { fwrite32 (&size32); sent += sizeof (__u32); } fwrite32 (&sd->sd_blocks); sent += sizeof (__u32); } } static void pack_full_block (reiserfs_filsys_t fs, struct buffer_head * bh) { __u16 magic; __u32 block; magic = FULL_BLOCK_START_MAGIC; fwrite16 (&magic); block = bh->b_blocknr; fwrite32 (&block); fwrite (bh->b_data, 4096, 1, stdout); sent += 4096; had_to_be_sent += 4096; full_blocks ++; if (who_is_this (bh->b_data, bh->b_size) == THE_JDESC) descs ++; if (who_is_this (bh->b_data, bh->b_size) == THE_INTERNAL) internals ++; if (block_of_journal (fs, bh->b_blocknr)) full_of_journal ++; } /* unformatted node pointer is considered bad when it points either to blocks of journal, bitmap blocks, super block or is transparently out of range of disk block numbers */ static int check_unfm_ptr (reiserfs_filsys_t fs, __u32 block) { if (block >= SB_BLOCK_COUNT (fs)) return 1; if (not_data_block (fs, block)) return 1; return 0; } /* we only pack leaves which do not have any corruptions */ static int can_pack_leaf (reiserfs_filsys_t fs, struct buffer_head * bh) { int i; struct item_head * ih; ih = B_N_PITEM_HEAD (bh, 0); for (i = 0; i < node_item_number (bh); i ++, ih ++) { if (is_it_bad_item (fs, ih, B_I_PITEM (bh, ih), check_unfm_ptr, 1/*bad dir*/)) return 0; } return 1; } /* pack leaf only if all its items are correct: keys are correct, direntries are hashed properly and hash function is defined, indirect items are correct, stat data ?, */ static void pack_leaf (reiserfs_filsys_t fs, struct buffer_head * bh) { int i; struct item_head * ih; struct packed_item pi; __u16 v16; if (!can_pack_leaf (fs, bh)) { /* if something looks suspicious in this leaf - pack whole block */ pack_full_block (fs, bh); fprintf (stderr, "leaf %lu is bad\n", bh->b_blocknr); bad_leaves ++; return; } /* start magic in low 8 bits, hash code in high 8 bits */ v16 = (LEAF_START_MAGIC | (func2code (fs->s_hash_function) << 8)); fwrite16 (&v16); /* block number */ fwrite32 (&bh->b_blocknr); /* item number */ v16 = node_item_number (bh); fwrite16 (&v16); ih = B_N_PITEM_HEAD (bh, 0); for (i = 0; i < node_item_number (bh); i ++, ih ++) { #if 0 v32 = ITEM_START_MAGIC; fwrite32 (&v32); #endif pi.mask = 0; pi.item_len = ih_item_len (ih); // format if (ih_key_format (ih) == KEY_FORMAT_2) pi.mask |= NEW_FORMAT; // k_dir_id if (!i || (i && ih->ih_key.k_dir_id != (ih - 1)->ih_key.k_dir_id)) { /* if item is first in the leaf or if previous item has different k_dir_id - store it */ pi.mask |= DIR_ID; } // k_object_id if (!i || (i && ih->ih_key.k_objectid != (ih - 1)->ih_key.k_objectid)) { /* if item is first in the leaf or if previous item has different k_objectid - store it */ pi.mask |= OBJECT_ID; } /* store offset if it is != 0 in 32 or 64 bits */ if (get_offset (&ih->ih_key)) { if (get_offset (&ih->ih_key) > 0xffffffffULL) pi.mask |= OFFSET_BITS_64; else pi.mask |= OFFSET_BITS_32; } if (is_direct_ih (ih)) { pack_direct (&pi, bh, ih); } else if (is_indirect_ih (ih)) pack_indirect (&pi, bh, ih); else if (is_direntry_ih (ih)) pack_direntry (fs, &pi, bh, ih); else if (is_stat_data_ih (ih)) pack_stat_data (&pi, bh, ih); else die ("pack_leaf: unknown item found"); #if 0 v32 = ITEM_END_MAGIC; fwrite32 (&v32); #endif } v16 = LEAF_END_MAGIC; fwrite16 (&v16); packed_leaves ++; had_to_be_sent += 4096; return; } static int can_pack_internal (reiserfs_filsys_t fs, struct buffer_head * bh) { return 0; } /* pack internal node as a full block */ static void pack_internal (reiserfs_filsys_t fs, struct buffer_head * bh) { if (!can_pack_internal (fs, bh)) { pack_full_block (fs, bh); return; } reiserfs_panic ("pack_internal: packing code is not ready"); } static int how_many_to_pack (reiserfs_filsys_t fs, unsigned long first, int count) { int i; int used; used = 0; for (i = 0; i < count; i ++) { if ((SB_BLOCK_COUNT (fs) > (first + i)) && reiserfs_bitmap_test_bit (what_to_pack, first + i)) used ++; } return used; } /* packed blocks are marked free in the bitmap*/ static void send_block (reiserfs_filsys_t fs, struct buffer_head * bh) { int type; if ((type = who_is_this (bh->b_data, bh->b_size)) != THE_LEAF) { if (type == THE_INTERNAL) { pack_internal (fs, bh); } else if (!not_data_block (fs, bh->b_blocknr)) { /* unformatted */ return; } else /* bitmaps, super block, blocks of journal - not leaves */ pack_full_block (fs, bh); } else pack_leaf (fs, bh); reiserfs_bitmap_set_bit (what_packed, bh->b_blocknr); reiserfs_bitmap_clear_bit (what_to_pack, bh->b_blocknr); } /* super block, journal, bitmaps */ static void pack_frozen_data (reiserfs_filsys_t fs) { int i; struct buffer_head * bh; /* super block */ reiserfs_warning (stderr, "super block..");fflush (stderr); send_block (fs, fs->s_sbh); reiserfs_warning (stderr, "ok\nbitmaps..(%d).. ", SB_BMAP_NR (fs)); fflush (stderr); /* bitmaps */ for (i = 0; i < SB_BMAP_NR (fs); i ++) { send_block (fs, SB_AP_BITMAP (fs)[i]); } reiserfs_warning (stderr, "ok\njournal (from %lu to %lu)..", rs_journal_start (fs->s_rs), rs_journal_start (fs->s_rs) + rs_journal_size (fs->s_rs)); fflush (stderr); /* journal */ for (i = rs_journal_start (fs->s_rs); i <= rs_journal_start (fs->s_rs) + rs_journal_size (fs->s_rs); i ++) { bh = bread (fs->s_dev, i, fs->s_blocksize); send_block (fs, bh); brelse (bh); } reiserfs_warning (stderr, "ok\n");fflush (stderr); } /* pack all "not data blocks" and correct leaf */ void pack_partition (reiserfs_filsys_t fs) { int i, j; struct buffer_head tmp, * bh; int nr_to_read = BLOCKS_PER_READ; __u32 magic32; __u16 blocksize; __u16 magic16; unsigned long done = 0, total; magic32 = REISERFS_SUPER_MAGIC; fwrite32 (&magic32); blocksize = fs->s_blocksize; fwrite16 (&blocksize); tmp.b_size = blocksize; /* will save information about what packed here */ what_packed = reiserfs_create_bitmap (SB_BLOCK_COUNT (fs)); /* will get information about what is to be packed */ what_to_pack = reiserfs_create_bitmap (SB_BLOCK_COUNT (fs)); if (!what_to_pack) die ("pack_partition: could not create bitmap"); if (mode == DO_PACK) { /* read blocks marked used and pack them */ reiserfs_fetch_disk_bitmap (what_to_pack, fs); reiserfs_warning (stderr, "Packing blocks marked used on the device %d\n", reiserfs_bitmap_ones (what_to_pack)); } else { reiserfs_bitmap_fill (what_to_pack); reiserfs_warning (stderr, "Packing all blocks of the device %d\n", reiserfs_bitmap_ones (what_to_pack)); } /* super block, journal, bitmaps */ pack_frozen_data (fs); reiserfs_warning (stderr, "Super block, bitmaps, journal - %d blocks - done, %d blocks left\n", reiserfs_bitmap_ones (what_packed), reiserfs_bitmap_ones (what_to_pack)); total = reiserfs_bitmap_ones (what_to_pack); for (i = 0; i < SB_BLOCK_COUNT (fs); i += nr_to_read) { int to_pack; to_pack = how_many_to_pack (fs, i, nr_to_read); if (to_pack) { print_how_far (&done, total, to_pack, opt_quiet); bh = bread (fs->s_dev, i / nr_to_read, blocksize * nr_to_read); if (bh) { for (j = 0; j < nr_to_read; j ++) { if (reiserfs_bitmap_test_bit (what_to_pack, i + j)) { tmp.b_data = bh->b_data + j * tmp.b_size; tmp.b_blocknr = i + j; send_block (fs, &tmp); } } brelse (bh); } else { /* bread failed */ if (nr_to_read != 1) { /* we tryied to read bunch of blocks. Try to read them by one */ nr_to_read = 1; i --; continue; } else { /* we were reading one block at time, and failed, so mark block bad */ reiserfs_warning (stderr, "could not read block %lu\n", i); } } } } magic16 = END_MAGIC; fwrite16 (&magic16); fprintf (stderr, "Packed\n\tleaves %d\n" "\tfull blocks %d\n" "\t\tof journal %d\n" "\t\tcorrupted leaves %d\n" "\t\tinternals %d\n" "\t\tdescriptors %d\n", packed_leaves, full_blocks, full_of_journal, bad_leaves, internals, descs); fprintf (stderr, "data packed with ratio %.2f\n", (double)sent / had_to_be_sent); if (where_to_save) reiserfs_bitmap_save (where_to_save, what_packed); } void pack_one_block (reiserfs_filsys_t fs, unsigned long block) { __u32 magic32; __u16 magic16; struct buffer_head * bh; // reiserfs magic magic32 = REISERFS_SUPER_MAGIC; fwrite32 (&magic32); // blocksize fwrite16 (&fs->s_blocksize); bh = bread (fs->s_dev, block, fs->s_blocksize); if (who_is_this (bh->b_data, bh->b_size) == THE_LEAF) pack_leaf (fs, bh); else pack_full_block (fs, bh); brelse (bh); // end magic magic16 = END_MAGIC; fwrite16 (&magic16); fprintf (stderr, "Packed\n\tleaves %d\n\tfull block %d\n\tcorrupted leaves %d\n", packed_leaves, full_blocks, bad_leaves); } #if 0 // // this test program has two modes: 'pack file blocknr' // and 'unpack file' // in the first mode blocknr-th 4k block of the 'file' will be packed out to stdout // the the second mode standart input will be converted to the reiserfs leaf on 'file' // static int do_unpack (char * file) { char * buf; int fd; fd = open (file, O_RDONLY); if (fd == -1) { perror ("open failed"); return 0; } buf = malloc (4096); if (!buf) { perror ("malloc failed"); return 0; } fread (buf, 4096, 1, stdin); if (!feof (stdin)) { printf ("fread returned not eof\n"); return 0; } unpack_leaf (buf, fd); free (buf); close (fd); return 0; } static int do_pack (char * file, int block) { int fd; struct buffer_head * bh; char * buf; int len; fprintf (stderr, "dumping block %d of the \"%s\"\n", block, file); fd = open (file, O_RDONLY); if (fd == -1) { perror ("open failed"); return 0; } bh = bread (fd, block, 4096); if (!bh) { fprintf (stderr, "bread failed\n"); return 0; } if (who_is_this (bh->b_data, bh->b_size) != THE_LEAF) { fprintf (stderr, "block %d is not a leaf\n", block); return 0; } len = pack_leaf (bh, buf); fwrite (buf, len, 1, stdout); free (buf); close (fd); return 0; } int main (int argc, char ** argv) { if (argc == 3 && !strcmp (argv[1], "unpack")) return do_unpack (argv[2]); if (argc == 4 && !strcmp (argv[1], "pack")) return do_pack (argv[2], atoi (argv[3])); fprintf (stderr, "Usage: \n\t%s pack filename block\nor\n" "\t%s unpack filename\n", argv[0], argv[0]); return 0; } #endif reiserfsprogs-3.x.0j/debugreiserfs/unpack.c0000644000076400001440000003077207260635516014653 /* * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README */ #include "debugreiserfs.h" #include #define print_usage_and_exit() die ("Usage: %s [-v] [-b filename] device\n\ -v prints blocks number of every block unpacked\n\ -b filename makes unpack to save bitmap of blocks unpacked\n", argv[0]); /* when super block gets unpacked for the first time - create a bitmap and mark in it what have been unpacked. Save that bitmap at the end */ reiserfs_bitmap_t what_unpacked = 0; int unpacked, data_blocks_unpacked; int verbose = 0; static void unpack_offset (struct packed_item * pi, struct item_head * ih) { if (pi->mask & OFFSET_BITS_64) { __u64 v64; if (ih_key_format (ih) != KEY_FORMAT_2) die ("unpack_offset: key format is not set or wrong"); fread64 (&v64); set_offset (KEY_FORMAT_2, &ih->ih_key, v64); return; } if (pi->mask & OFFSET_BITS_32) { __u32 v32; fread32 (&v32); set_offset (ih_key_format (ih), &ih->ih_key, v32); return; } // offset is 0 return; } static void unpack_type (struct packed_item * pi, struct item_head * ih) { if (pi->mask & DIRECT_ITEM) set_type (ih_key_format (ih), &ih->ih_key, TYPE_DIRECT); else if (pi->mask & STAT_DATA_ITEM) set_type (ih_key_format (ih), &ih->ih_key, TYPE_STAT_DATA); else if (pi->mask & INDIRECT_ITEM) set_type (ih_key_format (ih), &ih->ih_key, TYPE_INDIRECT); else if (pi->mask & DIRENTRY_ITEM) set_type (ih_key_format (ih), &ih->ih_key, TYPE_DIRENTRY); else reiserfs_panic (0, "%h, mask 0%o\n", ih, pi->mask); } /* direntry item comes in the following format: entry count - 16 bits for each entry mask - 8 bits entry length - 16 bits entry itself deh_objectid - 32 bits maybe deh_dir_id (32 bits) maybe gencounter (16) maybe deh_state (16) */ static void unpack_direntry (struct packed_item * pi, struct buffer_head * bh, struct item_head * ih, hashf_t hash_func) { __u16 entry_count, namelen, gen_counter, entry_len; __u8 mask; int i; struct reiserfs_de_head * deh; int location; char * item; if (!hash_func) die ("unpack_direntry: hash function is not set"); fread16 (&entry_count); set_entry_count (ih, entry_count); item = bh->b_data + ih_location (ih); deh = (struct reiserfs_de_head *)item; location = pi->item_len; for (i = 0; i < entry_count; i ++, deh ++) { fread8 (&mask); fread16 (&entry_len); location -= entry_len; deh->deh_location = location; fread (item + location, entry_len, 1, stdin); /* find name length */ if (*(item + location + entry_len - 1)) namelen = entry_len; else namelen = strlen (item + location); fread32 (&deh->deh_objectid); if (mask & HAS_DIR_ID) fread32 (&deh->deh_dir_id); else deh->deh_dir_id = ih->ih_key.k_objectid; if (*(item + location) == '.' && namelen == 1) /* old or new "." */ deh->deh_offset = DOT_OFFSET; else if (*(item + location) == '.' && *(item + location + 1) == '.' && namelen == 2) /* old or new ".." */ deh->deh_offset = DOT_DOT_OFFSET; else deh->deh_offset = GET_HASH_VALUE (hash_func (item + location, namelen)); if (mask & HAS_GEN_COUNTER) { fread16 (&gen_counter); deh->deh_offset |= gen_counter; } if (mask & HAS_STATE) fread16 (&deh->deh_state); else deh->deh_state = (1 << DEH_Visible); } return; } /* struct packed_item is already unpacked */ static void unpack_stat_data (struct packed_item * pi, struct buffer_head * bh, struct item_head * ih) { set_entry_count (ih, 0xffff); if (ih_key_format (ih) == KEY_FORMAT_1) { /* stat data comes in the following format: if this is old stat data: mode - 16 bits nlink - 16 bits size - 32 bits blocks/rdev - 32 bits maybe first_direct byte 32 bits */ struct stat_data_v1 * sd; sd = (struct stat_data_v1 *)B_I_PITEM (bh, ih); memset (sd, 0, sizeof (sd)); fread16 (&sd->sd_mode); fread16 (&sd->sd_nlink); fread32 (&sd->sd_size); fread32 (&sd->u.sd_blocks); if (pi->mask & WITH_SD_FIRST_DIRECT_BYTE) { fread32 (&sd->sd_first_direct_byte); } else { sd->sd_first_direct_byte = 0xffffffff; } } else { /* for new stat data mode - 16 bits nlink in either 16 or 32 bits size in either 32 or 64 bits blocks - 32 bits */ struct stat_data * sd; sd = (struct stat_data *)B_I_PITEM (bh, ih); memset (sd, 0, sizeof (sd)); fread16 (&sd->sd_mode); if (pi->mask & NLINK_BITS_32) { fread32 (&sd->sd_nlink); } else { __u16 nlink16; fread16 (&nlink16); sd->sd_nlink = nlink16; } if (pi->mask & SIZE_BITS_64) { fread64 (&sd->sd_size); } else { __u32 size32; fread32 (&size32); sd->sd_size = size32; } fread32 (&sd->sd_blocks); } return; } /* indirect item comes either in packed form or as is. ih_free_space can go first */ static void unpack_indirect (struct packed_item * pi, struct buffer_head * bh, struct item_head * ih) { __u32 * ind_item, * end; int i; __u16 v16; v16 = 0; if (pi->mask & ENTRY_COUNT) fread16 (&v16); set_entry_count (ih, v16); ind_item = (__u32 *)B_I_PITEM (bh, ih); if (pi->mask & WHOLE_INDIRECT) { fread (ind_item, pi->item_len, 1, stdin); return; } end = ind_item + I_UNFM_NUM (ih); while (ind_item < end) { fread32 (ind_item); fread16 (&v16); for (i = 1; i < v16; i ++) { if (ind_item[0]) ind_item [i] = ind_item[0] + i; else ind_item [i] = 0; } ind_item += i; } return; } // FIXME: we have no way to preserve symlinks static void unpack_direct (struct packed_item * pi, struct buffer_head * bh, struct item_head * ih) { set_entry_count (ih, 0xffff); memset (bh->b_data + ih_location (ih), 'a', pi->item_len); return; } static void unpack_leaf (int dev, hashf_t hash_func) { static int unpacked_leaves = 0; struct buffer_head * bh; struct packed_item pi; struct item_head * ih; int i; __u16 v16; __u32 v32; /* block number */ fread32 (&v32); /* item number */ fread16 (&v16); if (verbose) fprintf (stderr, "leaf %d\n", v32); bh = getblk (dev, v32, 4096); if (!bh) die ("unpack_leaf: getblk failed"); set_node_item_number (bh, v16); set_node_level (bh, DISK_LEAF_NODE_LEVEL); set_node_free_space (bh, bh->b_size - BLKH_SIZE); ih = B_N_PITEM_HEAD (bh, 0); for (i = 0; i < v16; i ++, ih ++) { #if 0 fread32 (&v32); if (v32 != ITEM_START_MAGIC) die ("unpack_leaf: no start item magic found: block %lu, item %i", bh->b_blocknr, i); #endif fread (&pi, sizeof (struct packed_item), 1, stdin); /* dir_id - if it is there */ if (pi.mask & DIR_ID) { fread32 (&v32); ih->ih_key.k_dir_id = v32; } else { if (!i) die ("unpack_leaf: dir_id is not set"); ih->ih_key.k_dir_id = (ih - 1)->ih_key.k_dir_id; } /* object_id - if it is there */ if (pi.mask & OBJECT_ID) { fread32 (&v32); ih->ih_key.k_objectid = v32; } else { if (!i) die ("unpack_leaf: object_id is not set"); ih->ih_key.k_objectid = (ih - 1)->ih_key.k_objectid; } // we need to set item format before offset unpacking set_key_format (ih, (pi.mask & NEW_FORMAT) ? KEY_FORMAT_2 : KEY_FORMAT_1); // offset unpack_offset (&pi, ih); /* type */ unpack_type (&pi, ih); /* item length and item location */ set_ih_item_len (ih, pi.item_len); set_ih_location (ih, (i ? ih_location (ih - 1) : bh->b_size) - pi.item_len); // item itself if (is_direct_ih (ih)) { unpack_direct (&pi, bh, ih); } else if (is_indirect_ih (ih)) { unpack_indirect (&pi, bh, ih); } else if (is_direntry_ih (ih)) { unpack_direntry (&pi, bh, ih, hash_func); } else if (is_stat_data_ih (ih)) { unpack_stat_data (&pi, bh, ih); } set_node_free_space (bh, node_free_space (bh) - (IH_SIZE + ih_item_len (ih))); #if 0 fread32 (&v32); if (v32 != ITEM_END_MAGIC) die ("unpack_leaf: no end item magic found: block %lu, item %i", bh->b_blocknr, i); #endif } fread16 (&v16); if (v16 != LEAF_END_MAGIC) die ("unpack_leaf: wrong end signature found - %x, block %lu", v16, bh->b_blocknr); mark_buffer_uptodate (bh, 1); mark_buffer_dirty (bh); bwrite (bh); /* if (!not_data_block (bh->b_blocknr)) data_blocks_unpacked ++; */ brelse (bh); if (what_unpacked) reiserfs_bitmap_set_bit (what_unpacked, bh->b_blocknr); unpacked ++; if (!(++ unpacked_leaves % 10)) fprintf (stderr, "#"); } static void unpack_full_block (int dev, int blocksize) { static int full_blocks_unpacked = 0; __u32 block; struct buffer_head * bh; fread32 (&block); if (verbose) fprintf (stderr, "full #%d\n", block); bh = getblk (dev, block, blocksize); if (!bh) die ("unpack_full_block: getblk failed"); fread (bh->b_data, bh->b_size, 1, stdin); if (who_is_this (bh->b_data, bh->b_size) == THE_SUPER && !what_unpacked) { unsigned long blocks; blocks = rs_block_count ((struct reiserfs_super_block *)(bh->b_data)); fprintf (stderr, "There were %lu blocks on the device\n", blocks); what_unpacked = reiserfs_create_bitmap (blocks); } mark_buffer_uptodate (bh, 1); mark_buffer_dirty (bh); bwrite (bh); /* if (!not_data_block (bh->b_blocknr)) data_blocks_unpacked ++; */ brelse (bh); if (what_unpacked) reiserfs_bitmap_set_bit (what_unpacked, block); unpacked ++; if (!(++ full_blocks_unpacked % 50)) fprintf (stderr, "."); } /* just skip bitmaps of unformatted nodes */ static void unpack_unformatted_bitmap (int dev, int blocksize) { __u16 bmap_num; __u32 block_count; int i; char * buf; fread16 (&bmap_num); fread32 (&block_count); buf = malloc (blocksize); if (!buf) reiserfs_panic ("unpack_unformatted_bitmap: malloc failed: %m"); for (i = 0; i < bmap_num; i ++) { if (fread (buf, blocksize, 1, stdin) != 1) reiserfs_panic ("unpack_unformatted_bitmap: " "could not read bitmap #%d: %m", i); } free (buf); } // read packed reiserfs partition metadata from stdin void unpack_partition (int dev) { __u32 magic32; __u16 magic16; __u16 blocksize; fread32 (&magic32); if (magic32 != REISERFS_SUPER_MAGIC) die ("unpack_partition: reiserfs magic number not found"); fread16 (&blocksize); if (verbose) fprintf (stderr, "Blocksize %d\n", blocksize); while (!feof (stdin)) { char c[2]; fread (c, 1, 1, stdin); switch (c[0]) { case '.': if (verbose) fprintf (stderr, "\".\" skipped\n"); continue; case '1': fread (c, 1, 1, stdin); /* that was 100%, read in first 0 */ case '2': case '4': case '6': case '8': fread (c, 1, 1, stdin); case '0': fread (c + 1, 1, 1, stdin); /* read % */ if (c[0] != '0' || c[1] != '%') die ("0%% expected\n"); if (verbose) fprintf (stderr, "0%% skipped\n"); continue; } fread (c + 1, 1, 1, stdin); magic16 = *(__u16 *)c; /*fread16 (&magic16);*/ switch (magic16 & 0xff) { case LEAF_START_MAGIC: unpack_leaf (dev, code2func (magic16 >> 8)); break; case FULL_BLOCK_START_MAGIC: unpack_full_block (dev, blocksize); break; case UNFORMATTED_BITMAP_START_MAGIC: fprintf (stderr, "\nBitmap of unformatted - ignored\n"); unpack_unformatted_bitmap (dev, blocksize); break; case END_MAGIC: break; default: die ("unpack_partition: bad magic found - %x", magic16 & 0xff); } } fprintf (stderr, "Unpacked %d (%d) blocks\n", unpacked, what_unpacked ? reiserfs_bitmap_ones (what_unpacked) : 0); /* fclose (block_list);*/ } int main (int argc, char ** argv) { int fd; int c; char * filename = ".bitmap"; struct rlimit lim = {0xffffffff, 0xffffffff}; print_banner ("unpack"); /* with this 2.4.0-test9's file_write does not send SIGXFSZ */ if (setrlimit (RLIMIT_FSIZE, &lim)) { fprintf (stderr, "sertlimit failed: %m\n"); } while ((c = getopt (argc, argv, "vb:")) != EOF) { switch (c) { case 'v': verbose = 1; case 'b': asprintf (&filename, "%s", optarg); break; } } if (optind != argc - 1) /* only one non-option argument is permitted */ print_usage_and_exit(); if (is_mounted (argv[optind])) reiserfs_panic ("%s seems mounted, umount it first\n", argv[optind]); fd = open (argv[optind], O_RDWR | O_LARGEFILE); if (fd == -1) { perror ("open failed"); return 0; } unpack_partition (fd); if (what_unpacked && filename) reiserfs_bitmap_save (filename, what_unpacked); close (fd); return 0; } reiserfsprogs-3.x.0j/debugreiserfs/debugreiserfs.h0000644000076400001440000000653107254142434016217 /* * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include "io.h" #include "misc.h" #include "reiserfs_lib.h" #include "../version.h" /* * modes */ #define DO_DUMP 1 /* not a real dump, just printing to stdout contents of tree nodes */ #define DO_CORRUPT 2 /* used to make filesystem corruption and then test fsck */ #define DO_SCAN 3 #define DO_SCAN_FOR_NAME 4 #define DO_RECOVER 5 #define DO_TEST 6 #define DO_PACK 7 /* -p extract meta data of reiserfs filesystem */ #define DO_PACK_ALL 8 /* -p */ extern int opt_quiet; extern int mode; // the leaf is stored in compact form: // start magic number // block number __u32 // item number __u16 // struct packed_item // .. // end magic number /* we store hash code in high byte of 16 bits */ #define LEAF_START_MAGIC 0xa5 #define LEAF_END_MAGIC 0x5a #define FULL_BLOCK_START_MAGIC 0xb6 #define FULL_BLOCK_END_MAGIC 0x6b #define UNFORMATTED_BITMAP_START_MAGIC 0xc7 #define UNFORMATTED_BITMAP_END_MAGIC 0x7c #define END_MAGIC 0x8d #define INTERNAL_START_MAGIC #define INTERNAL_START_MAGIC #define ITEM_START_MAGIC 0x476576 #define ITEM_END_MAGIC 0x2906504 /* flags in packed item mask */ #define NEW_FORMAT 1 // 0 here means - old format, 1 - new format #define DIR_ID 2 #define OBJECT_ID 4 #define OFFSET_BITS_32 8 #define OFFSET_BITS_64 16 #define ENTRY_COUNT 32 // shows whether ih_free_space/ih_entry_count is stored #define INDIRECT_ITEM 64 #define DIRENTRY_ITEM 128 #define DIRECT_ITEM 256 #define STAT_DATA_ITEM 512 #define ITEM_BODY 1024 #define WHOLE_INDIRECT 128 #define WITH_SD_FIRST_DIRECT_BYTE 8192 /* for old stat data first_direct_byte is stored */ #define NLINK_BITS_32 8192 /* nlinks stored in 32 bits */ #define SIZE_BITS_64 16384 /* size has to be stored in 64 bit */ struct packed_item { /*__u16 length;*/ // length of the area we store item in __u16 mask; // what is stored: dirid, objectid, 32 bit offset or 64 bit offset, type __u16 item_len; }; #define HAS_DIR_ID 1 #define HAS_GEN_COUNTER 2 #define HAS_STATE 4 #define YURA 8 #define TEA 16 #define R5 32 struct packed_dir_entry { __u8 mask; __u16 entrylen; }; #define fread8(pv) fread (pv, sizeof (__u8), 1, stdin) #define fread16(pv) fread (pv, sizeof (__u16), 1, stdin) #define fread32(pv) fread (pv, sizeof (__u32), 1, stdin) #define fread64(pv) fread (pv, sizeof (__u64), 1, stdin) #define fwrite8(pv) {\ if (fwrite (pv, sizeof (__u8), 1, stdout) != 1)\ reiserfs_panic ("fwrite8 failed: %m");\ } #define fwrite16(pv) {\ if (fwrite (pv, sizeof (__u16), 1, stdout) != 1)\ reiserfs_panic ("fwrite16 failed: %m");\ } #define fwrite32(pv) {\ if (fwrite (pv, sizeof (__u32), 1, stdout) != 1)\ reiserfs_panic ("fwrite32 failed: %m");\ } #define fwrite64(pv) {\ if (fwrite (pv, sizeof (__u64), 1, stdout) != 1)\ reiserfs_panic ("fwrite64 failed: %m");\ } /* #define fwrite16(pv) fwrite (pv, sizeof (__u16), 1, stdout) #define fwrite32(pv) fwrite (pv, sizeof (__u32), 1, stdout) #define fwrite64(pv) fwrite (pv, sizeof (__u64), 1, stdout) */ #define BLOCKS_PER_READ 8 extern char * where_to_save; reiserfsprogs-3.x.0j/debugreiserfs/debugreiserfs.80000644000076400001440000000356307260374605016145 .\" -*- nroff -*- .\" Copyright 1996-2001 Hans Reiser. .\" .TH DEBUGREISERFS 8 "March 2001" "Reiserfsprogs 3.x.0j" .SH NAME debugreiserfs .SH SYNOPSIS .B debugreiserfs [ .B -jdcmos ] [ .B -b \fIblocknumber ] [ .B -p \fIfilename.bmp ] [ .B -P \fIfilename.bmp ] .I device .SH DESCRIPTION It helps sometimes to solve problems with reiserfs filesystems. Being called w/o options it prints super block of reiserfs filesystem found on the \fIdevice\fR. .TP .I device is the special file corresponding to the device (e.g /dev/hdXX for IDE disk partition or /dev/sdXX for SCSI disk partition). .SH OPTIONS .TP \fB-j print contents of journal .TP \fB-d print formatted nodes of the filesystem .TP \fB-c print contents of direct items .TP \fB-m print contents of bitmap (not very useful) .TP \fB-o print objectid map (not very useful) .TP \fB-s scans the partition and prints a line when any kind of reiserfs formatted nodes found .TP \fB-b \fIblocknumber print specified block of the filesystem .TP \fB-p \fIfilename \fB-P \fIfilename Makes \fBdebugreiserfs\fR to find filesystem metadata These exist to help reiserfsck debugging. If reiserfsck fails - you may extract filesystem metadata with \fBdebugreiserfs\fR -p filename /dev/xxx |gzip -c > xxx.gz. We download that data and make the filesystem similar to your with gunzip -c xxx.gz | unpack /dev/xxx (unpack is included into reiserfsprogs package). This usually allows to reproduce and debug the problem quickly. When data file is not too large. -P will cause \fBdebugreiserfs\fR to find and pack metadata from all the device whereas with -p it will only go through blocks marked used in filesystem bitmaps .SH AUTHOR This version of \fBdebugreiserfs\fR has been written by Hans Reiser . .SH BUGS There are probably few of them. Please, report bugs to Hans Reiser . .SH SEE ALSO .BR reiserfsck (8), .BR mkreiserfs (8) reiserfsprogs-3.x.0j/resize_reiserfs/0000777000076400001440000000000007261220344013641 5reiserfsprogs-3.x.0j/resize_reiserfs/Makefile.in0000644000076400001440000002211507261220344015623 # Makefile.in generated automatically by automake 1.4 from Makefile.am # Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. # This Makefile.in 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. SHELL = @SHELL@ srcdir = @srcdir@ top_srcdir = @top_srcdir@ VPATH = @srcdir@ prefix = @prefix@ exec_prefix = @exec_prefix@ bindir = @bindir@ sbindir = @sbindir@ libexecdir = @libexecdir@ datadir = @datadir@ sysconfdir = @sysconfdir@ sharedstatedir = @sharedstatedir@ localstatedir = @localstatedir@ libdir = @libdir@ infodir = @infodir@ mandir = @mandir@ includedir = @includedir@ oldincludedir = /usr/include DESTDIR = pkgdatadir = $(datadir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ top_builddir = .. ACLOCAL = @ACLOCAL@ AUTOCONF = @AUTOCONF@ AUTOMAKE = @AUTOMAKE@ AUTOHEADER = @AUTOHEADER@ INSTALL = @INSTALL@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS) INSTALL_DATA = @INSTALL_DATA@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ transform = @program_transform_name@ NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : CC = @CC@ MAKEINFO = @MAKEINFO@ PACKAGE = @PACKAGE@ RANLIB = @RANLIB@ VERSION = @VERSION@ sbin_PROGRAMS = resize_reiserfs resize_reiserfs_SOURCES = fe.c resize_reiserfs.c do_shrink.c resize.h man_MANS = resize_reiserfs.8 EXTRA_DIST = $(man_MANS) LDADD = ../lib/libmisc.a ../reiserfscore/libcore.a INCLUDES = -I../include mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs CONFIG_CLEAN_FILES = PROGRAMS = $(sbin_PROGRAMS) DEFS = @DEFS@ -I. -I$(srcdir) CPPFLAGS = @CPPFLAGS@ LDFLAGS = @LDFLAGS@ LIBS = @LIBS@ resize_reiserfs_OBJECTS = fe.o resize_reiserfs.o do_shrink.o resize_reiserfs_LDADD = $(LDADD) resize_reiserfs_DEPENDENCIES = ../lib/libmisc.a \ ../reiserfscore/libcore.a resize_reiserfs_LDFLAGS = CFLAGS = @CFLAGS@ COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ man8dir = $(mandir)/man8 MANS = $(man_MANS) NROFF = nroff DIST_COMMON = Makefile.am Makefile.in DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) TAR = tar GZIP_ENV = --best SOURCES = $(resize_reiserfs_SOURCES) OBJECTS = $(resize_reiserfs_OBJECTS) all: all-redirect .SUFFIXES: .SUFFIXES: .S .c .o .s $(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps resize_reiserfs/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status cd $(top_builddir) \ && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status mostlyclean-sbinPROGRAMS: clean-sbinPROGRAMS: -test -z "$(sbin_PROGRAMS)" || rm -f $(sbin_PROGRAMS) distclean-sbinPROGRAMS: maintainer-clean-sbinPROGRAMS: install-sbinPROGRAMS: $(sbin_PROGRAMS) @$(NORMAL_INSTALL) $(mkinstalldirs) $(DESTDIR)$(sbindir) @list='$(sbin_PROGRAMS)'; for p in $$list; do \ if test -f $$p; then \ echo " $(INSTALL_PROGRAM) $$p $(DESTDIR)$(sbindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`"; \ $(INSTALL_PROGRAM) $$p $(DESTDIR)$(sbindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \ else :; fi; \ done uninstall-sbinPROGRAMS: @$(NORMAL_UNINSTALL) list='$(sbin_PROGRAMS)'; for p in $$list; do \ rm -f $(DESTDIR)$(sbindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \ done .c.o: $(COMPILE) -c $< .s.o: $(COMPILE) -c $< .S.o: $(COMPILE) -c $< mostlyclean-compile: -rm -f *.o core *.core clean-compile: distclean-compile: -rm -f *.tab.c maintainer-clean-compile: resize_reiserfs: $(resize_reiserfs_OBJECTS) $(resize_reiserfs_DEPENDENCIES) @rm -f resize_reiserfs $(LINK) $(resize_reiserfs_LDFLAGS) $(resize_reiserfs_OBJECTS) $(resize_reiserfs_LDADD) $(LIBS) install-man8: $(mkinstalldirs) $(DESTDIR)$(man8dir) @list='$(man8_MANS)'; \ l2='$(man_MANS)'; for i in $$l2; do \ case "$$i" in \ *.8*) list="$$list $$i" ;; \ esac; \ done; \ for i in $$list; do \ if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ else file=$$i; fi; \ ext=`echo $$i | sed -e 's/^.*\\.//'`; \ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ inst=`echo $$inst | sed '$(transform)'`.$$ext; \ echo " $(INSTALL_DATA) $$file $(DESTDIR)$(man8dir)/$$inst"; \ $(INSTALL_DATA) $$file $(DESTDIR)$(man8dir)/$$inst; \ done uninstall-man8: @list='$(man8_MANS)'; \ l2='$(man_MANS)'; for i in $$l2; do \ case "$$i" in \ *.8*) list="$$list $$i" ;; \ esac; \ done; \ for i in $$list; do \ ext=`echo $$i | sed -e 's/^.*\\.//'`; \ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ inst=`echo $$inst | sed '$(transform)'`.$$ext; \ echo " rm -f $(DESTDIR)$(man8dir)/$$inst"; \ rm -f $(DESTDIR)$(man8dir)/$$inst; \ done install-man: $(MANS) @$(NORMAL_INSTALL) $(MAKE) $(AM_MAKEFLAGS) install-man8 uninstall-man: @$(NORMAL_UNINSTALL) $(MAKE) $(AM_MAKEFLAGS) uninstall-man8 tags: TAGS ID: $(HEADERS) $(SOURCES) $(LISP) list='$(SOURCES) $(HEADERS)'; \ unique=`for i in $$list; do echo $$i; done | \ awk ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ here=`pwd` && cd $(srcdir) \ && mkid -f$$here/ID $$unique $(LISP) TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) tags=; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS)'; \ unique=`for i in $$list; do echo $$i; done | \ awk ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) mostlyclean-tags: clean-tags: distclean-tags: -rm -f TAGS ID maintainer-clean-tags: distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) subdir = resize_reiserfs distdir: $(DISTFILES) @for file in $(DISTFILES); do \ d=$(srcdir); \ if test -d $$d/$$file; then \ cp -pr $$/$$file $(distdir)/$$file; \ else \ test -f $(distdir)/$$file \ || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ || cp -p $$d/$$file $(distdir)/$$file || :; \ fi; \ done do_shrink.o: do_shrink.c resize.h ../include/io.h ../include/misc.h \ ../include/reiserfs_lib.h ../include/reiserfs_fs.h ../version.h fe.o: fe.c resize.h ../include/io.h ../include/misc.h \ ../include/reiserfs_lib.h ../include/reiserfs_fs.h ../version.h resize_reiserfs.o: resize_reiserfs.c resize.h ../include/io.h \ ../include/misc.h ../include/reiserfs_lib.h \ ../include/reiserfs_fs.h ../version.h info-am: info: info-am dvi-am: dvi: dvi-am check-am: all-am check: check-am installcheck-am: installcheck: installcheck-am install-exec-am: install-sbinPROGRAMS install-exec: install-exec-am install-data-am: install-man install-data: install-data-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am install: install-am uninstall-am: uninstall-sbinPROGRAMS uninstall-man uninstall: uninstall-am all-am: Makefile $(PROGRAMS) $(MANS) all-redirect: all-am install-strip: $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install installdirs: $(mkinstalldirs) $(DESTDIR)$(sbindir) $(DESTDIR)$(mandir)/man8 mostlyclean-generic: clean-generic: distclean-generic: -rm -f Makefile $(CONFIG_CLEAN_FILES) -rm -f config.cache config.log stamp-h stamp-h[0-9]* maintainer-clean-generic: mostlyclean-am: mostlyclean-sbinPROGRAMS mostlyclean-compile \ mostlyclean-tags mostlyclean-generic mostlyclean: mostlyclean-am clean-am: clean-sbinPROGRAMS clean-compile clean-tags clean-generic \ mostlyclean-am clean: clean-am distclean-am: distclean-sbinPROGRAMS distclean-compile distclean-tags \ distclean-generic clean-am distclean: distclean-am maintainer-clean-am: maintainer-clean-sbinPROGRAMS \ maintainer-clean-compile maintainer-clean-tags \ maintainer-clean-generic distclean-am @echo "This command is intended for maintainers to use;" @echo "it deletes files that may require special tools to rebuild." maintainer-clean: maintainer-clean-am .PHONY: mostlyclean-sbinPROGRAMS distclean-sbinPROGRAMS \ clean-sbinPROGRAMS maintainer-clean-sbinPROGRAMS uninstall-sbinPROGRAMS \ install-sbinPROGRAMS mostlyclean-compile distclean-compile \ clean-compile maintainer-clean-compile install-man8 uninstall-man8 \ install-man uninstall-man tags mostlyclean-tags distclean-tags \ clean-tags maintainer-clean-tags distdir info-am info dvi-am dvi check \ check-am installcheck-am installcheck install-exec-am install-exec \ install-data-am install-data install-am install uninstall-am uninstall \ all-redirect all-am all installdirs mostlyclean-generic \ distclean-generic clean-generic maintainer-clean-generic clean \ mostlyclean distclean maintainer-clean # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: reiserfsprogs-3.x.0j/resize_reiserfs/Makefile.am0000644000076400001440000000035207251155756015626 sbin_PROGRAMS = resize_reiserfs resize_reiserfs_SOURCES = fe.c resize_reiserfs.c do_shrink.c resize.h man_MANS = resize_reiserfs.8 EXTRA_DIST = $(man_MANS) LDADD = ../lib/libmisc.a ../reiserfscore/libcore.a INCLUDES = -I../include reiserfsprogs-3.x.0j/resize_reiserfs/fe.c0000644000076400001440000000156407250656464014337 /* * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README */ #include "resize.h" /* the front-end for kernel on-line resizer */ int resize_fs_online(char * devname, unsigned long blocks) { static char buf[40]; FILE * f; struct mntent * mnt; if ((f = setmntent (MOUNTED, "r")) == NULL) goto fail; while ((mnt = getmntent (f)) != NULL) if(strcmp(devname, mnt->mnt_fsname) == 0) { if (strcmp(mnt->mnt_type,"reiserfs")) die ("resize_reiserfs: can\'t resize fs other than reiserfs\n"); sprintf(buf,"resize=%lu", blocks); if (mount(mnt->mnt_fsname, mnt->mnt_dir, mnt->mnt_type, (unsigned long)(MS_MGC_VAL | MS_REMOUNT), buf)) die ("resize_reiserfs: remount failed: %s\n", strerror(errno)); endmntent(f); return 0; } fail: die ("resize_reiserfs: can't find mount entry\n"); return 1; } reiserfsprogs-3.x.0j/resize_reiserfs/resize_reiserfs.c0000644000076400001440000001415307255406146017141 /* * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README */ /* * Written by Alexander Zarochentcev. * * FS resize utility * */ #include "resize.h" int opt_force = 0; int opt_verbose = 1; /* now "verbose" option is default */ int opt_nowrite = 0; int opt_safe = 0; #if 0 /* Given a file descriptor and an offset, check whether the offset is a valid offset for the file - return 0 if it isn't valid or 1 if it is */ int valid_offset( int fd, loff_t offset ) { char ch; if (lseek64 (fd, offset, 0) < 0) return 0; if (read (fd, &ch, 1) < 1) return 0; return 1; } #endif /* calculate the new fs size (in blocks) from old fs size and the string representation of new size */ static unsigned long calc_new_fs_size(unsigned long count, int bs, char *bytes_str) { long long int bytes; unsigned long blocks; int c; bytes = atoll(bytes_str); c = bytes_str[strlen(bytes_str) - 1]; switch (c) { case 'G': case 'g': bytes *= 1024; case 'M': case 'm': bytes *= 1024; case 'K': case 'k': bytes *= 1024; } blocks = bytes / bs; if (bytes_str[0] == '+' || bytes_str[0] == '-') return (count + blocks); return blocks; } /* print some fs parameters */ static void sb_report(struct reiserfs_super_block * sb1, struct reiserfs_super_block * sb2) { printf( "ReiserFS report:\n" "blocksize %d\n" "block count %d (%d)\n" "free blocks %d (%d)\n" "bitmap block count %d (%d)\n", rs_blocksize(sb1), rs_block_count(sb1), rs_block_count(sb2), rs_free_blocks(sb1), rs_free_blocks(sb2), rs_bmap_nr(sb1), rs_bmap_nr(sb2)); }; /* conditional bwrite */ static int bwrite_cond (struct buffer_head * bh) { if(!opt_nowrite) { mark_buffer_uptodate(bh,1); mark_buffer_dirty(bh); bwrite(bh); } return 0; } /* the first one of the mainest functions */ int expand_fs (reiserfs_filsys_t fs, unsigned long block_count_new) { int block_r, block_r_new; unsigned int bmap_nr_new, bmap_nr_old; int i; reiserfs_bitmap_t bmp; struct reiserfs_super_block * rs = fs->s_rs; reiserfs_reopen(fs, O_RDWR); set_state (fs->s_rs, REISERFS_ERROR_FS); bwrite_cond(SB_BUFFER_WITH_SB(fs)); bmp = reiserfs_create_bitmap(rs_block_count(rs)); if (!bmp) die ("cannot create bitmap\n"); reiserfs_fetch_disk_bitmap(bmp, fs); reiserfs_free_bitmap_blocks(fs); if (reiserfs_expand_bitmap(bmp, block_count_new)) die ("cannot expand bitmap\n"); /* clean bits in old bitmap tail */ for (i = rs_block_count(rs); i < rs_bmap_nr(rs) * rs_blocksize(rs) * 8 && i < block_count_new; i++) { reiserfs_bitmap_clear_bit(bmp, i); } /* count used bits in last bitmap block */ block_r = rs_block_count(rs) - ((rs_bmap_nr(rs) - 1) * rs_blocksize(rs) * 8); /* count bitmap blocks in new fs */ bmap_nr_new = (block_count_new - 1) / (rs_blocksize(rs) * 8) + 1; block_r_new = block_count_new - (bmap_nr_new - 1) * rs_blocksize(rs) * 8; bmap_nr_old = rs_bmap_nr(rs); /* update super block buffer*/ set_free_blocks (rs, rs_free_blocks(rs) + block_count_new - rs_block_count(rs) - (bmap_nr_new - rs_bmap_nr(rs))); set_block_count (rs, block_count_new); set_bmap_nr (rs, bmap_nr_new); reiserfs_read_bitmap_blocks(fs); for (i = bmap_nr_old; i < bmap_nr_new; i++) /* fix new bitmap blocks */ reiserfs_bitmap_set_bit(bmp, SB_AP_BITMAP(fs)[i]->b_blocknr); reiserfs_flush_bitmap(bmp, fs); return 0; } int main(int argc, char *argv[]) { char * bytes_count_str = NULL; char * devname; reiserfs_filsys_t fs; struct reiserfs_super_block * rs; int c; int error; struct reiserfs_super_block *sb_old; unsigned long block_count_new; print_banner ("resize_reiserfs"); while ((c = getopt(argc, argv, "fvcqs:")) != EOF) { switch (c) { case 's' : if (!optarg) die("%s: Missing argument to -s option", argv[0]); bytes_count_str = optarg; break; case 'f': opt_force = 1; break; case 'v': opt_verbose++; break; case 'n': /* no nowrite option at this moment */ /* opt_nowrite = 1; */ break; case 'c': opt_safe = 1; break; case 'q': opt_verbose = 0; break; default: print_usage_and_exit (); } } if (optind == argc ) print_usage_and_exit(); devname = argv[optind]; fs = reiserfs_open(devname, O_RDONLY, &error, 0); if (!fs) die ("%s: can not open '%s': %s", argv[0], devname, strerror(error)); if (no_reiserfs_found (fs)) { die ("resize_reiserfs: no reiserfs found on the device"); } if (!spread_bitmaps (fs)) { die ("resize_reiserfs: cannot resize reiserfs in old (not spread bitmap) format.\n"); } rs = fs->s_rs; if(bytes_count_str) { /* new fs size is specified by user */ block_count_new = calc_new_fs_size(rs_block_count(rs), fs->s_blocksize, bytes_count_str); } else { /* use whole device */ block_count_new = count_blocks(devname, fs->s_blocksize, -1); } if (is_mounted (devname)) { reiserfs_close(fs); return resize_fs_online(devname, block_count_new); } if (rs_state(rs) != REISERFS_VALID_FS) die ("%s: the file system isn't in valid state\n", argv[0]); if(!valid_offset(fs->s_dev, (loff_t) block_count_new * fs->s_blocksize - 1)) die ("%s: %s too small", argv[0], devname); sb_old = 0; /* Needed to keep idiot compiler from issuing false warning */ /* save SB for reporting */ if(opt_verbose) { sb_old = getmem(SB_SIZE); memcpy(sb_old, SB_DISK_SUPER_BLOCK(fs), SB_SIZE); } if (block_count_new == SB_BLOCK_COUNT(fs)) die ("%s: Calculated fs size is the same as the previous one.", argv[0]); if (block_count_new > SB_BLOCK_COUNT(fs)) expand_fs(fs, block_count_new); else shrink_fs(fs, block_count_new); if(opt_verbose) { sb_report(rs, sb_old); freemem(sb_old); } set_state (rs, REISERFS_VALID_FS); bwrite_cond(SB_BUFFER_WITH_SB(fs)); if (opt_verbose) { printf("\nSyncing.."); fflush(stdout); } reiserfs_close (fs); if (opt_verbose) printf("done\n"); return 0; } reiserfsprogs-3.x.0j/resize_reiserfs/do_shrink.c0000644000076400001440000001542207252426430015711 /* * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README */ #include #include "resize.h" static unsigned long int_node_cnt = 0, int_moved_cnt = 0; static unsigned long leaf_node_cnt = 0, leaf_moved_cnt = 0; static unsigned long unfm_node_cnt = 0, unfm_moved_cnt = 0; static unsigned long total_node_cnt = 0; static unsigned long total_moved_cnt = 0; static unsigned long unused_block; static unsigned long blocks_used; static int block_count_mismatch = 0; static reiserfs_bitmap_t bmp; static reiserfs_filsys_t fs; static struct reiserfs_super_block * rs; /* abnornal exit from block reallocation process */ static void quit_resizer() { /* save changes to bitmap blocks */ reiserfs_flush_bitmap (bmp, fs); reiserfs_close (fs); /* leave fs in ERROR state */ die ("resize_reiserfs: fs shrinking was not completed successfully, run reiserfsck.\n"); } /* block moving */ static unsigned long move_generic_block(unsigned long block, unsigned long bnd, int h) { struct buffer_head * bh, * bh2; /* primitive fsck */ if (block > rs_block_count(rs)) { fprintf(stderr, "resize_reiserfs: invalid block number (%lu) found.\n", block); quit_resizer(); } /* progress bar, 3D style :) */ if (opt_verbose) print_how_far(&total_node_cnt, blocks_used, 1, 0); else total_node_cnt ++; /* infinite loop check */ if( total_node_cnt > blocks_used && !block_count_mismatch) { fputs("resize_reiserfs: warning: block count exeeded\n",stderr); block_count_mismatch = 1; } if (block < bnd) /* block will not be moved */ return 0; /* move wrong block */ bh = bread(fs->s_dev, block, fs->s_blocksize); reiserfs_bitmap_find_zero_bit(bmp, &unused_block); if (unused_block == 0 || unused_block >= bnd) { fputs ("resize_reiserfs: can\'t find free block\n", stderr); quit_resizer(); } /* blocknr changing */ bh2 = getblk(fs->s_dev, unused_block, fs->s_blocksize); memcpy(bh2->b_data, bh->b_data, bh2->b_size); reiserfs_bitmap_clear_bit(bmp, block); reiserfs_bitmap_set_bit(bmp, unused_block); brelse(bh); mark_buffer_uptodate(bh2,1); mark_buffer_dirty(bh2); bwrite(bh2); brelse(bh2); total_moved_cnt++; return unused_block; } static unsigned long move_unformatted_block(unsigned long block, unsigned long bnd, int h) { unsigned long b; unfm_node_cnt++; b = move_generic_block(block, bnd, h); if (b) unfm_moved_cnt++; return b; } /* recursive function processing all tree nodes */ static unsigned long move_formatted_block(unsigned long block, unsigned long bnd, int h) { struct buffer_head * bh; struct item_head *ih; unsigned long new_blocknr = 0; int node_is_internal = 0; int i, j; bh = bread(fs->s_dev, block, fs->s_blocksize); if (is_leaf_node (bh)) { leaf_node_cnt++; for (i=0; i < B_NR_ITEMS(bh); i++) { ih = B_N_PITEM_HEAD(bh, i); if (is_indirect_ih(ih)) { __u32 * indirect; indirect = (__u32 *)B_I_PITEM (bh, ih); for (j = 0; j < I_UNFM_NUM(ih); j++) { unsigned long unfm_block; if (indirect [j] == 0) /* hole */ continue; unfm_block = move_unformatted_block(le32_to_cpu (indirect [j]), bnd, h + 1); if (unfm_block) { indirect [j] = cpu_to_le32 (unfm_block); mark_buffer_dirty(bh); } } } } } else if (is_internal_node (bh)) { /* internal node */ int_node_cnt++; node_is_internal = 1; for (i=0; i <= B_NR_ITEMS(bh); i++) { unsigned long moved_block; moved_block = move_formatted_block(B_N_CHILD_NUM(bh, i), bnd, h+1); if (moved_block) { set_dc_block_number (bh, i, moved_block); mark_buffer_dirty(bh); } } } else { die ("resize_reiserfs: block (%lu) has invalid format\n", block); } if (buffer_dirty(bh)) { mark_buffer_uptodate(bh,1); bwrite(bh); } brelse(bh); new_blocknr = move_generic_block(block, bnd, h); if (new_blocknr) { if (node_is_internal) int_moved_cnt++; else leaf_moved_cnt++; } return new_blocknr; } int shrink_fs(reiserfs_filsys_t reiserfs, unsigned long blocks) { unsigned long n_root_block; unsigned int bmap_nr_new; unsigned long int i; fs = reiserfs; rs = fs->s_rs; /* warn about alpha version */ { int c; printf( "You are running BETA version of reiserfs shrinker.\n" "This version is only for testing or VERY CAREFUL use.\n" "Backup of you data is recommended.\n\n" "Do you want to continue? [y/N]:" ); c = getchar(); if (c != 'y' && c != 'Y') exit(1); } bmap_nr_new = (blocks - 1) / (8 * fs->s_blocksize) + 1; /* is shrinking possible ? */ if (rs_block_count(rs) - blocks > rs_free_blocks(rs) + rs_bmap_nr(rs) - bmap_nr_new) { fprintf(stderr, "resize_reiserfs: can\'t shrink fs; too many blocks already allocated\n"); return -1; } reiserfs_reopen(fs, O_RDWR); set_state (fs->s_rs, REISERFS_ERROR_FS); mark_buffer_uptodate(SB_BUFFER_WITH_SB(fs), 1); mark_buffer_dirty(SB_BUFFER_WITH_SB(fs)); bwrite(SB_BUFFER_WITH_SB(fs)); /* calculate number of data blocks */ blocks_used = SB_BLOCK_COUNT(fs) - SB_FREE_BLOCKS(fs) - SB_BMAP_NR(fs) - SB_JOURNAL_SIZE(fs) - REISERFS_DISK_OFFSET_IN_BYTES / fs->s_blocksize - 2; /* superblock itself and 1 descriptor after the journal */ bmp = reiserfs_create_bitmap(rs_block_count(rs)); reiserfs_fetch_disk_bitmap(bmp, fs); unused_block = 1; if (opt_verbose) { printf("Processing the tree: "); fflush(stdout); } n_root_block = move_formatted_block(rs_root_block(rs), blocks, 0); if (n_root_block) { set_root_block (rs, n_root_block); } if (opt_verbose) printf ("\n\nnodes processed (moved):\n" "int %lu (%lu),\n" "leaves %lu (%lu),\n" "unfm %lu (%lu),\n" "total %lu (%lu).\n\n", int_node_cnt, int_moved_cnt, leaf_node_cnt, leaf_moved_cnt, unfm_node_cnt, unfm_moved_cnt, (unsigned long)total_node_cnt, total_moved_cnt); if (block_count_mismatch) { fprintf(stderr, "resize_reiserfs: data block count %lu" " doesn\'t match data block count %lu from super block\n", (unsigned long)total_node_cnt, blocks_used); } #if 0 printf("check for used blocks in truncated region\n"); { unsigned long l; for (l = blocks; l < rs_block_count(rs); l++) if (is_block_used(bmp, l)) printf("<%lu>", l); printf("\n"); } #endif /* 0 */ reiserfs_free_bitmap_blocks(fs); set_free_blocks (rs, rs_free_blocks(rs) - (rs_block_count(rs) - blocks) + (rs_bmap_nr(rs) - bmap_nr_new)); set_block_count (rs, blocks); set_bmap_nr (rs, bmap_nr_new); reiserfs_read_bitmap_blocks(fs); for (i = blocks; i < bmap_nr_new * fs->s_blocksize; i++) reiserfs_bitmap_set_bit(bmp, i); #if 0 PUT_SB_FREE_BLOCKS(s, SB_FREE_BLOCKS(s) - (SB_BLOCK_COUNT(s) - blocks) + (SB_BMAP_NR(s) - bmap_nr_new)); PUT_SB_BLOCK_COUNT(s, blocks); PUT_SB_BMAP_NR(s, bmap_nr_new); #endif reiserfs_flush_bitmap(bmp, fs); return 0; } reiserfsprogs-3.x.0j/resize_reiserfs/resize.h0000644000076400001440000000166007260615647015247 /* * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #if __GLIBC__ >= 2 #include #else #include #endif #include "io.h" #include "misc.h" #include "reiserfs_lib.h" #include "../version.h" #define print_usage_and_exit()\ die ("Usage: %s [-s[+|-]#[G|M|K]] [-fqv] device", argv[0]) /* reiserfs_resize.c */ extern struct buffer_head * g_sb_bh; extern int opt_force; extern int opt_verbose; extern int opt_nowrite; extern int opt_safe; int expand_fs(struct super_block * s, unsigned long block_count_new); /* fe.c */ int resize_fs_online(char * devname, unsigned long blocks); /* do_shrink.c */ int shrink_fs(struct super_block * s, unsigned long blocks); reiserfsprogs-3.x.0j/resize_reiserfs/resize_reiserfs.80000644000076400001440000000540107260374650017062 .\" -*- nroff -*- .\" Copyright 1996-2001 Hans Reiser. .\" .TH RESIZE_REISERFS 8 "March 2001" "Reiserfsprogs-3.x.0j" .SH NAME resize_reiserfs \- Reiserfs filesystem resizer .SH SYNOPSIS .BR resize_reiserfs [ .B \-s .IR \fR[\fB+\fR|\fB\- ]\fIsize [\fBK\fR|\fBM\fR|\fBG\fR] ] [ .B \-fqv ] .I device .SH DESCRIPTION The .B resize_reiserfs tool resizes an unmounted reiserfs file system. It enlarges or shrinks an reiserfs file system located on a .I device so that it will have .I size bytes or size=old_size +(\-) .I size bytes if the + or \- prefix is used. If the .B \-s option is not specified, the filesystem will be resized to fill the given device. The .I size parameter may have one of the optional modifiers .BR K ", " M ", " G , which means the .I size parameter is given in kilo\-, mega\-, gigabytes respectively. .PP The .B resize_reiserfs program does not manipulate the size of the device. If you wish to enlarge a filesystem, you must make sure you expand the underlying device first. This can be done using .BR cfdisk (8) for partitions, by deleting the partition and recreating it with a larger size (assuming there is free space .I after the partition in question). Make sure you re\-create it with the same starting disk cylinder as before! Otherwise, the resize operation will certainly not work, and you may lose your entire filesystem. .PP The .B resize_reiserfs program allows to grow a reiserfs on-line if there is a free space on block .I device. .PP If you wish to shrink an reiserfs partition, first use .B resize_reiserfs to shrink the file system. You may then use .BR cfdisk (8) to shrink the device. When shrinking the size of the device, make sure you do not make it smaller than the reduced size of the reiserfs filesystem. .SH OPTIONS .TP .BR \-s\ [+|\-]\fIsize Set the new size in bytes. .TP .BR \-f Force, do not perform checks. .TP .BR \-q Do not print anything but error messages. .TP .BR \-v Turn on extra progress status messages (default). .SH RETURN VALUES 0 Resizing successful. .TP \-1 In another case. .SH EXAMPLES The following example shows how to test .B resize_reiserfs\fR. Suppose 2Gb reiserfs filesystem is created on the device /dev/hda8 and is mounted on /mnt. For shrinking the device we need to unmount it first, then run .B resize_reiserfs with a .I size \fR parameter (in this case -1Gb): .PP \ df .br \ umount /mnt .br \ resize_reiserfs -s -1G /dev/hda8 .br \ mount /dev/hda8 /mnt .br \ df /mnt .SH WARNING Note that this is a BETA program and may corrupt filesystems. .SH AUTHOR This version of .B resize_reiserfs has been written by Alexander Zarochentcev . .SH BUGS Please, report about the bugs to Alexander Zarochentcev or to Hans Reiser . .SH SEE ALSO .BR cfsck (8), .BR debugreiserfs (8)