aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrint E. Kriebel <bekit@cyngn.com>2014-11-03 18:57:56 -0800
committerBrint E. Kriebel <bekit@cyngn.com>2014-11-03 18:57:56 -0800
commitf25e7804729d25bcfde575b78b501e06a8cbb708 (patch)
treed98e3220a7522671e6ce82a2d40bf878dfa3eccc
parent5668a2234ad79ffd45838679692d10236a3e965f (diff)
parent4f5a66a6eb77baa896d3adfb12139a830573f609 (diff)
downloadandroid_external_f2fs-tools-stable/cm-11.0-XNF9X.tar.gz
android_external_f2fs-tools-stable/cm-11.0-XNF9X.tar.bz2
android_external_f2fs-tools-stable/cm-11.0-XNF9X.zip
Conflicts: Android.mk VERSION fsck/dump.c fsck/f2fs.h fsck/fsck.c fsck/main.c fsck/mount.c include/f2fs_fs.h include/f2fs_version.h lib/libf2fs.c mkfs/Makefile.am mkfs/f2fs_format.c mkfs/f2fs_format_utils.c mkfs/f2fs_format_utils.h tools/f2fstat.c tools/fibmap.c Change-Id: I5cc044a6fe47bac6cab8d845f8d63729f765de50
-rw-r--r--Android.mk6
-rw-r--r--COPYING513
-rw-r--r--README (renamed from README.md)15
-rw-r--r--VERSION4
-rw-r--r--configure.ac2
-rw-r--r--fsck/dump.c170
-rw-r--r--fsck/f2fs.h79
-rw-r--r--fsck/fsck.c833
-rw-r--r--fsck/fsck.h116
-rw-r--r--fsck/main.c203
-rw-r--r--fsck/mount.c518
-rw-r--r--include/f2fs_fs.h132
-rw-r--r--include/f2fs_version.h7
-rw-r--r--include/list.h6
-rw-r--r--lib/Makefile.am2
-rw-r--r--lib/libf2fs.c87
-rw-r--r--lib/libf2fs_io.c100
-rw-r--r--mkfs/Makefile.am4
-rw-r--r--mkfs/f2fs_format.c326
-rw-r--r--mkfs/f2fs_format_main.c146
-rw-r--r--mkfs/f2fs_format_utils.c33
-rw-r--r--mkfs/f2fs_format_utils.h13
-rwxr-xr-xscripts/dumpf2fs.sh61
-rwxr-xr-xscripts/spo_test.sh70
-rwxr-xr-xscripts/tracepoint.sh65
-rw-r--r--tools/f2fstat.c90
-rw-r--r--tools/fibmap.c31
27 files changed, 2545 insertions, 1087 deletions
diff --git a/Android.mk b/Android.mk
index f2cb232..406df2c 100644
--- a/Android.mk
+++ b/Android.mk
@@ -1,7 +1,9 @@
LOCAL_PATH:= $(call my-dir)
+LOCAL_CFLAGS := -DANDROID
+
include $(CLEAR_VARS)
-LOCAL_SRC_FILES := mkfs/f2fs_format.c mkfs/f2fs_format_utils.c lib/libf2fs.c
+LOCAL_SRC_FILES := mkfs/f2fs_format.c mkfs/f2fs_format_main.c mkfs/f2fs_format_utils.c lib/libf2fs.c lib/libf2fs_io.c
LOCAL_MODULE := libmake_f2fs
LOCAL_MODULE_TAGS := optional
include $(BUILD_STATIC_LIBRARY)
@@ -15,7 +17,7 @@ LOCAL_STATIC_LIBRARIES := libmake_f2fs libcutils liblog libc
include $(BUILD_EXECUTABLE)
include $(CLEAR_VARS)
-LOCAL_SRC_FILES := fsck/main.c fsck/fsck.c fsck/dump.c fsck/mount.c lib/libf2fs.c
+LOCAL_SRC_FILES := fsck/main.c fsck/fsck.c fsck/dump.c fsck/mount.c lib/libf2fs.c lib/libf2fs_io.c
LOCAL_MODULE := libfsck_f2fs
LOCAL_MODULE_TAGS := optional
include $(BUILD_STATIC_LIBRARY)
diff --git a/COPYING b/COPYING
index 21cd6db..52f956d 100644
--- a/COPYING
+++ b/COPYING
@@ -1,5 +1,15 @@
The tools for F2FS are covered by GNU Public License version 2.
+Exceptionally, the following files are also covered by the GNU Lesser General
+Public License Version 2.1 as the dual licenses.
+- include/f2fs_fs.h
+- lib/libf2fs.c
+- lib/libf2fs_io.c
+- mkfs/f2fs_format.c
+- mkfs/f2fs_format_main.c
+- mkfs/f2fs_format_utils.c
+- mkfs/f2fs_format_utils.h
+================================================================================
Copyright (c) 2012 Samsung Electronics Co., Ltd.
http://www.samsung.com/
@@ -348,4 +358,507 @@ 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.
+
================================================================================
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/README.md b/README
index cbb492e..222cbc3 100644
--- a/README.md
+++ b/README
@@ -11,6 +11,7 @@ Your should install the following packages.
- libuuid-devel or uuid-dev
- pkg-config
- autoconf
+ - libtool
Initial compilation
-------------------
@@ -25,6 +26,20 @@ How to compile
# ./configure
# make
+How to cross-compile (e.g., for ARM)
+------------------------------------
+
+ 1. Add the below line into mkfs/Makefile.am:
+ mkfs_f2fs_LDFLAGS = -all-static
+
+ 2. Add the below line into fsck/Makefile.am:
+ fsck_f2fs_LDFLAGS = -all-static
+
+ 3. then, do:
+ # LDFLAGS=--static ./configure \
+ --host=arm-none-linux-gnueabi --target=arm-none-linux-gnueabi
+ # make
+
How to run by default
---------------------
diff --git a/VERSION b/VERSION
index e62017f..c3a3dd8 100644
--- a/VERSION
+++ b/VERSION
@@ -1,2 +1,2 @@
-1.3.0
-2014-02-06
+1.2.0
+2013-10-25
diff --git a/configure.ac b/configure.ac
index c2dafb0..0111e72 100644
--- a/configure.ac
+++ b/configure.ac
@@ -56,7 +56,7 @@ AC_PATH_PROG([LDCONFIG], [ldconfig],
PKG_CHECK_MODULES([libuuid], [uuid])
# Checks for header files.
-AC_CHECK_HEADERS([fcntl.h mntent.h stdlib.h string.h \
+AC_CHECK_HEADERS([linux/fs.h fcntl.h mntent.h stdlib.h string.h \
sys/ioctl.h sys/mount.h unistd.h])
# Checks for typedefs, structures, and compiler characteristics.
diff --git a/fsck/dump.c b/fsck/dump.c
index 765e9db..4bb906f 100644
--- a/fsck/dump.c
+++ b/fsck/dump.c
@@ -8,6 +8,8 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
+#include <inttypes.h>
+
#include "fsck.h"
#define BUF_SZ 80
@@ -57,7 +59,7 @@ void sit_dump(struct f2fs_sb_info *sbi, int start_sit, int end_sit)
ASSERT(ret >= 0);
close(fd);
- DBG(1, "Blocks [0x%lx] Free Segs [0x%x]\n", valid_blocks, free_segs);
+ DBG(1, "Blocks [0x%" PRIx64 "] Free Segs [0x%x]\n", valid_blocks, free_segs);
}
void ssa_dump(struct f2fs_sb_info *sbi, int start_ssa, int end_ssa)
@@ -113,15 +115,164 @@ void ssa_dump(struct f2fs_sb_info *sbi, int start_ssa, int end_ssa)
close(fd);
}
-int dump_node(struct f2fs_sb_info *sbi, nid_t nid)
+static void dump_data_blk(__u64 offset, u32 blkaddr)
+{
+ char buf[F2FS_BLKSIZE];
+
+ if (blkaddr == NULL_ADDR)
+ return;
+
+ /* get data */
+ if (blkaddr == NEW_ADDR) {
+ memset(buf, 0, F2FS_BLKSIZE);
+ } else {
+ int ret;
+ ret = dev_read_block(buf, blkaddr);
+ ASSERT(ret >= 0);
+ }
+
+ /* write blkaddr */
+ dev_write_dump(buf, offset, F2FS_BLKSIZE);
+}
+
+static void dump_node_blk(struct f2fs_sb_info *sbi, int ntype,
+ u32 nid, u64 *ofs)
{
struct node_info ni;
struct f2fs_node *node_blk;
+ u32 skip = 0;
+ u32 i, idx;
+
+ switch (ntype) {
+ case TYPE_DIRECT_NODE:
+ skip = idx = ADDRS_PER_BLOCK;
+ break;
+ case TYPE_INDIRECT_NODE:
+ idx = NIDS_PER_BLOCK;
+ skip = idx * ADDRS_PER_BLOCK;
+ break;
+ case TYPE_DOUBLE_INDIRECT_NODE:
+ skip = 0;
+ idx = NIDS_PER_BLOCK;
+ break;
+ }
+
+ if (nid == 0) {
+ *ofs += skip;
+ return;
+ }
+
+ get_node_info(sbi, nid, &ni);
+
+ node_blk = calloc(BLOCK_SZ, 1);
+ dev_read_block(node_blk, ni.blk_addr);
+
+ for (i = 0; i < idx; i++, (*ofs)++) {
+ switch (ntype) {
+ case TYPE_DIRECT_NODE:
+ dump_data_blk(*ofs * F2FS_BLKSIZE,
+ le32_to_cpu(node_blk->dn.addr[i]));
+ break;
+ case TYPE_INDIRECT_NODE:
+ dump_node_blk(sbi, TYPE_DIRECT_NODE,
+ le32_to_cpu(node_blk->in.nid[i]), ofs);
+ break;
+ case TYPE_DOUBLE_INDIRECT_NODE:
+ dump_node_blk(sbi, TYPE_INDIRECT_NODE,
+ le32_to_cpu(node_blk->in.nid[i]), ofs);
+ break;
+ }
+ }
+ free(node_blk);
+}
+
+static void dump_inode_blk(struct f2fs_sb_info *sbi, u32 nid,
+ struct f2fs_node *node_blk)
+{
+ u32 i = 0;
+ u64 ofs = 0;
+
+ /* TODO: need to dump xattr */
+
+ if((node_blk->i.i_inline & F2FS_INLINE_DATA)){
+ DBG(3, "ino[0x%x] has inline data!\n", nid);
+ /* recover from inline data */
+ dev_write_dump(((unsigned char *)node_blk) + INLINE_DATA_OFFSET,
+ 0, MAX_INLINE_DATA);
+ return;
+ }
+
+ /* check data blocks in inode */
+ for (i = 0; i < ADDRS_PER_INODE(&node_blk->i); i++, ofs++)
+ dump_data_blk(ofs * F2FS_BLKSIZE,
+ le32_to_cpu(node_blk->i.i_addr[i]));
+
+ /* check node blocks in inode */
+ for (i = 0; i < 5; i++) {
+ if (i == 0 || i == 1)
+ dump_node_blk(sbi, TYPE_DIRECT_NODE,
+ node_blk->i.i_nid[i], &ofs);
+ else if (i == 2 || i == 3)
+ dump_node_blk(sbi, TYPE_INDIRECT_NODE,
+ node_blk->i.i_nid[i], &ofs);
+ else if (i == 4)
+ dump_node_blk(sbi, TYPE_DOUBLE_INDIRECT_NODE,
+ node_blk->i.i_nid[i], &ofs);
+ else
+ ASSERT(0);
+ }
+}
+
+void dump_file(struct f2fs_sb_info *sbi, struct node_info *ni,
+ struct f2fs_node *node_blk)
+{
+ struct f2fs_inode *inode = &node_blk->i;
+ u32 imode = le32_to_cpu(inode->i_mode);
+ char name[255] = {0};
+ char path[1024] = {0};
+ char ans[255] = {0};
int ret;
- ret = get_node_info(sbi, nid, &ni);
+ if (!S_ISREG(imode)) {
+ MSG(0, "Not a regular file\n\n");
+ return;
+ }
+
+ printf("Do you want to dump this file into ./lost_found/? [Y/N] ");
+ ret = scanf("%s", ans);
ASSERT(ret >= 0);
+ if (!strcasecmp(ans, "y")) {
+ ret = system("mkdir -p ./lost_found");
+ ASSERT(ret >= 0);
+
+ /* make a file */
+ strncpy(name, (const char *)inode->i_name,
+ le32_to_cpu(inode->i_namelen));
+ name[le32_to_cpu(inode->i_namelen)] = 0;
+ sprintf(path, "./lost_found/%s", name);
+
+ config.dump_fd = open(path, O_TRUNC|O_CREAT|O_RDWR, 0666);
+ ASSERT(config.dump_fd >= 0);
+
+ /* dump file's data */
+ dump_inode_blk(sbi, ni->ino, node_blk);
+
+ /* adjust file size */
+ ret = ftruncate(config.dump_fd, le32_to_cpu(inode->i_size));
+ ASSERT(ret >= 0);
+
+ close(config.dump_fd);
+ }
+}
+
+void dump_node(struct f2fs_sb_info *sbi, nid_t nid)
+{
+ struct node_info ni;
+ struct f2fs_node *node_blk;
+
+ get_node_info(sbi, nid, &ni);
+
node_blk = calloc(BLOCK_SZ, 1);
dev_read_block(node_blk, ni.blk_addr);
@@ -130,9 +281,8 @@ int dump_node(struct f2fs_sb_info *sbi, nid_t nid)
DBG(1, "nat_entry.version [0x%x]\n", ni.version);
DBG(1, "nat_entry.ino [0x%x]\n", ni.ino);
- if (ni.blk_addr == 0x0) {
+ if (ni.blk_addr == 0x0)
MSG(0, "Invalid nat entry\n\n");
- }
DBG(1, "node_blk.footer.ino [0x%x]\n", le32_to_cpu(node_blk->footer.ino));
DBG(1, "node_blk.footer.nid [0x%x]\n", le32_to_cpu(node_blk->footer.nid));
@@ -140,12 +290,12 @@ int dump_node(struct f2fs_sb_info *sbi, nid_t nid)
if (le32_to_cpu(node_blk->footer.ino) == ni.ino &&
le32_to_cpu(node_blk->footer.nid) == ni.nid) {
print_node_info(node_blk);
+ dump_file(sbi, &ni, node_blk);
} else {
MSG(0, "Invalid node block\n\n");
}
free(node_blk);
- return 0;
}
int dump_inode_from_blkaddr(struct f2fs_sb_info *sbi, u32 blk_addr)
@@ -159,8 +309,7 @@ int dump_inode_from_blkaddr(struct f2fs_sb_info *sbi, u32 blk_addr)
type = get_sum_entry(sbi, blk_addr, &sum_entry);
nid = le32_to_cpu(sum_entry.nid);
- ret = get_node_info(sbi, nid, &ni);
- ASSERT(ret >= 0);
+ get_node_info(sbi, nid, &ni);
DBG(1, "Note: blkaddr = main_blkaddr + segno * 512 + offset\n");
DBG(1, "Block_addr [0x%x]\n", blk_addr);
@@ -176,7 +325,8 @@ int dump_inode_from_blkaddr(struct f2fs_sb_info *sbi, u32 blk_addr)
node_blk = calloc(BLOCK_SZ, 1);
read_node_blk:
- dev_read_block(node_blk, blk_addr);
+ ret = dev_read_block(node_blk, blk_addr);
+ ASSERT(ret >= 0);
ino = le32_to_cpu(node_blk->footer.ino);
nid = le32_to_cpu(node_blk->footer.nid);
@@ -184,7 +334,7 @@ read_node_blk:
if (ino == nid) {
print_node_info(node_blk);
} else {
- ret = get_node_info(sbi, ino, &ni);
+ get_node_info(sbi, ino, &ni);
goto read_node_blk;
}
diff --git a/fsck/f2fs.h b/fsck/f2fs.h
index 5b42ed1..ef045e0 100644
--- a/fsck/f2fs.h
+++ b/fsck/f2fs.h
@@ -26,15 +26,21 @@
#include <sys/mount.h>
#include <assert.h>
-#include "include/list.h"
+#ifndef ANDROID
+#include <f2fs_fs.h>
+#else
#include "include/f2fs_fs.h"
-#include "include/f2fs_version.h"
+#endif
#define EXIT_ERR_CODE (-1)
#define ver_after(a, b) (typecheck(unsigned long long, a) && \
typecheck(unsigned long long, b) && \
((long long)((a) - (b)) > 0))
+struct list_head {
+ struct list_head *next, *prev;
+};
+
enum {
NAT_BITMAP,
SIT_BITMAP
@@ -127,6 +133,7 @@ struct f2fs_sb_info {
struct f2fs_nm_info *nm_info;
struct f2fs_sm_info *sm_info;
struct f2fs_checkpoint *ckpt;
+ int cur_cp;
struct list_head orphan_inode_list;
unsigned int n_orphans;
@@ -204,9 +211,17 @@ static inline unsigned long __bitmap_size(struct f2fs_sb_info *sbi, int flag)
static inline void *__bitmap_ptr(struct f2fs_sb_info *sbi, int flag)
{
struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
- int offset = (flag == NAT_BITMAP) ?
- le32_to_cpu(ckpt->sit_ver_bitmap_bytesize) : 0;
- return &ckpt->sit_nat_version_bitmap + offset;
+ int offset;
+ if (le32_to_cpu(F2FS_RAW_SUPER(sbi)->cp_payload) > 0) {
+ if (flag == NAT_BITMAP)
+ return &ckpt->sit_nat_version_bitmap;
+ else
+ return ((char *)ckpt + F2FS_BLKSIZE);
+ } else {
+ offset = (flag == NAT_BITMAP) ?
+ le32_to_cpu(ckpt->sit_ver_bitmap_bytesize) : 0;
+ return &ckpt->sit_nat_version_bitmap + offset;
+ }
}
static inline bool is_set_ckpt_flags(struct f2fs_checkpoint *cp, unsigned int f)
@@ -258,10 +273,15 @@ static inline block_t __start_sum_addr(struct f2fs_sb_info *sbi)
#define GET_SEGNO_FROM_SEG0(sbi, blk_addr) \
(GET_SEGOFF_FROM_SEG0(sbi, blk_addr) >> sbi->log_blocks_per_seg)
-#define FREE_I_START_SEGNO(sbi) GET_SEGNO_FROM_SEG0(sbi, SM_I(sbi)->main_blkaddr)
+#define GET_BLKOFF_FROM_SEG0(sbi, blk_addr) \
+ (GET_SEGOFF_FROM_SEG0(sbi, blk_addr) & (sbi->blocks_per_seg - 1))
+
+#define FREE_I_START_SEGNO(sbi) \
+ GET_SEGNO_FROM_SEG0(sbi, SM_I(sbi)->main_blkaddr)
#define GET_R2L_SEGNO(sbi, segno) (segno + FREE_I_START_SEGNO(sbi))
-#define START_BLOCK(sbi, segno) (SM_I(sbi)->main_blkaddr + (segno << sbi->log_blocks_per_seg))
+#define START_BLOCK(sbi, segno) (SM_I(sbi)->main_blkaddr + \
+ (segno << sbi->log_blocks_per_seg))
static inline struct curseg_info *CURSEG_I(struct f2fs_sb_info *sbi, int type)
{
@@ -294,23 +314,34 @@ static inline block_t sum_blk_addr(struct f2fs_sb_info *sbi, int base, int type)
(segno / SIT_ENTRY_PER_BLOCK)
#define TOTAL_SEGS(sbi) (SM_I(sbi)->main_segments)
-#define IS_VALID_NID(sbi, nid) \
- do { \
- ASSERT(nid <= (NAT_ENTRY_PER_BLOCK * \
- F2FS_RAW_SUPER(sbi)->segment_count_nat \
- << (sbi->log_blocks_per_seg - 1))); \
- } while (0);
-
-#define IS_VALID_BLK_ADDR(sbi, addr) \
- do { \
- if (addr >= F2FS_RAW_SUPER(sbi)->block_count || \
- addr < SM_I(sbi)->main_blkaddr) \
- { \
- DBG(0, "block addr [0x%x]\n", addr); \
- ASSERT(addr < F2FS_RAW_SUPER(sbi)->block_count); \
- ASSERT(addr >= SM_I(sbi)->main_blkaddr); \
- } \
- } while (0);
+static inline bool IS_VALID_NID(struct f2fs_sb_info *sbi, u32 nid)
+{
+ return (nid <= (NAT_ENTRY_PER_BLOCK *
+ F2FS_RAW_SUPER(sbi)->segment_count_nat
+ << (sbi->log_blocks_per_seg - 1)));
+}
+
+static inline bool IS_VALID_BLK_ADDR(struct f2fs_sb_info *sbi, u32 addr)
+{
+ int i;
+
+ if (addr >= F2FS_RAW_SUPER(sbi)->block_count ||
+ addr < SM_I(sbi)->main_blkaddr) {
+ DBG(0, "block addr [0x%x]\n", addr);
+ ASSERT(addr < F2FS_RAW_SUPER(sbi)->block_count);
+ ASSERT(addr >= SM_I(sbi)->main_blkaddr);
+ return 0;
+ }
+
+ for (i = 0; i < NO_CHECK_TYPE; i++) {
+ struct curseg_info *curseg = CURSEG_I(sbi, i);
+
+ if (START_BLOCK(sbi, curseg->segno) +
+ curseg->next_blkoff == addr)
+ return 0;
+ }
+ return 1;
+}
static inline u64 BLKOFF_FROM_MAIN(struct f2fs_sb_info *sbi, u64 blk_addr)
{
diff --git a/fsck/fsck.c b/fsck/fsck.c
index ba29ab7..d0819c4 100644
--- a/fsck/fsck.c
+++ b/fsck/fsck.c
@@ -11,9 +11,32 @@
#include "fsck.h"
char *tree_mark;
-int tree_mark_size = 256;
+uint32_t tree_mark_size = 256;
-static int add_into_hard_link_list(struct f2fs_sb_info *sbi, u32 nid, u32 link_cnt)
+static inline int f2fs_set_main_bitmap(struct f2fs_sb_info *sbi, u32 blk)
+{
+ struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
+
+ return f2fs_set_bit(BLKOFF_FROM_MAIN(sbi, blk), fsck->main_area_bitmap);
+}
+
+static inline int f2fs_test_main_bitmap(struct f2fs_sb_info *sbi, u32 blk)
+{
+ struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
+
+ return f2fs_test_bit(BLKOFF_FROM_MAIN(sbi, blk),
+ fsck->main_area_bitmap);
+}
+
+static inline int f2fs_test_sit_bitmap(struct f2fs_sb_info *sbi, u32 blk)
+{
+ struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
+
+ return f2fs_test_bit(BLKOFF_FROM_MAIN(sbi, blk), fsck->sit_area_bitmap);
+}
+
+static int add_into_hard_link_list(struct f2fs_sb_info *sbi,
+ u32 nid, u32 link_cnt)
{
struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
struct hard_link_node *node = NULL, *tmp = NULL, *prev = NULL;
@@ -57,10 +80,8 @@ static int find_and_dec_hard_link_list(struct f2fs_sb_info *sbi, u32 nid)
struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
struct hard_link_node *node = NULL, *prev = NULL;
- if (fsck->hard_link_list_head == NULL) {
- ASSERT(0);
- return -1;
- }
+ if (fsck->hard_link_list_head == NULL)
+ return -EINVAL;
node = fsck->hard_link_list_head;
@@ -69,10 +90,8 @@ static int find_and_dec_hard_link_list(struct f2fs_sb_info *sbi, u32 nid)
node = node->next;
}
- if (node == NULL || (nid != node->nid)) {
- ASSERT(0);
- return -1;
- }
+ if (node == NULL || (nid != node->nid))
+ return -EINVAL;
/* Decrease link count */
node->links = node->links - 1;
@@ -85,40 +104,38 @@ static int find_and_dec_hard_link_list(struct f2fs_sb_info *sbi, u32 nid)
prev->next = node->next;
free(node);
}
-
return 0;
-
}
-static int is_valid_ssa_node_blk(struct f2fs_sb_info *sbi, u32 nid, u32 blk_addr)
+static int is_valid_ssa_node_blk(struct f2fs_sb_info *sbi, u32 nid,
+ u32 blk_addr)
{
int ret = 0;
struct f2fs_summary sum_entry;
ret = get_sum_entry(sbi, blk_addr, &sum_entry);
- ASSERT(ret >= 0);
- if (ret == SEG_TYPE_DATA || ret == SEG_TYPE_CUR_DATA) {
- ASSERT_MSG(0, "Summary footer is not a node segment summary\n");;
- } else if (ret == SEG_TYPE_NODE) {
- if (le32_to_cpu(sum_entry.nid) != nid) {
- DBG(0, "nid [0x%x]\n", nid);
- DBG(0, "target blk_addr [0x%x]\n", blk_addr);
- DBG(0, "summary blk_addr [0x%x]\n",
- GET_SUM_BLKADDR(sbi, GET_SEGNO(sbi, blk_addr)));
- DBG(0, "seg no / offset [0x%x / 0x%x]\n",
- GET_SEGNO(sbi, blk_addr), OFFSET_IN_SEG(sbi, blk_addr));
- DBG(0, "summary_entry.nid [0x%x]\n", le32_to_cpu(sum_entry.nid));
- DBG(0, "--> node block's nid [0x%x]\n", nid);
- ASSERT_MSG(0, "Invalid node seg summary\n");
- }
- } else if (ret == SEG_TYPE_CUR_NODE) {
- /* current node segment has no ssa */
- } else {
- ASSERT_MSG(0, "Invalid return value of 'get_sum_entry'");
+ if (ret != SEG_TYPE_NODE && ret != SEG_TYPE_CUR_NODE) {
+ ASSERT_MSG("Summary footer is not for node segment");
+ return -EINVAL;
+ }
+
+ if (le32_to_cpu(sum_entry.nid) != nid) {
+ DBG(0, "nid [0x%x]\n", nid);
+ DBG(0, "target blk_addr [0x%x]\n", blk_addr);
+ DBG(0, "summary blk_addr [0x%x]\n",
+ GET_SUM_BLKADDR(sbi,
+ GET_SEGNO(sbi, blk_addr)));
+ DBG(0, "seg no / offset [0x%x / 0x%x]\n",
+ GET_SEGNO(sbi, blk_addr),
+ OFFSET_IN_SEG(sbi, blk_addr));
+ DBG(0, "summary_entry.nid [0x%x]\n",
+ le32_to_cpu(sum_entry.nid));
+ DBG(0, "--> node block's nid [0x%x]\n", nid);
+ ASSERT_MSG("Invalid node seg summary\n");
+ return -EINVAL;
}
-
- return 1;
+ return 0;
}
static int is_valid_ssa_data_blk(struct f2fs_sb_info *sbi, u32 blk_addr,
@@ -128,204 +145,250 @@ static int is_valid_ssa_data_blk(struct f2fs_sb_info *sbi, u32 blk_addr,
struct f2fs_summary sum_entry;
ret = get_sum_entry(sbi, blk_addr, &sum_entry);
- ASSERT(ret == SEG_TYPE_DATA || ret == SEG_TYPE_CUR_DATA);
+
+ if (ret != SEG_TYPE_DATA && ret != SEG_TYPE_CUR_DATA) {
+ ASSERT_MSG("Summary footer is not for data segment");
+ return -EINVAL;
+ }
if (le32_to_cpu(sum_entry.nid) != parent_nid ||
sum_entry.version != version ||
le16_to_cpu(sum_entry.ofs_in_node) != idx_in_node) {
- DBG(0, "summary_entry.nid [0x%x]\n", le32_to_cpu(sum_entry.nid));
- DBG(0, "summary_entry.version [0x%x]\n", sum_entry.version);
- DBG(0, "summary_entry.ofs_in_node [0x%x]\n", le16_to_cpu(sum_entry.ofs_in_node));
-
+ DBG(0, "summary_entry.nid [0x%x]\n",
+ le32_to_cpu(sum_entry.nid));
+ DBG(0, "summary_entry.version [0x%x]\n",
+ sum_entry.version);
+ DBG(0, "summary_entry.ofs_in_node [0x%x]\n",
+ le16_to_cpu(sum_entry.ofs_in_node));
DBG(0, "parent nid [0x%x]\n", parent_nid);
DBG(0, "version from nat [0x%x]\n", version);
DBG(0, "idx in parent node [0x%x]\n", idx_in_node);
DBG(0, "Target data block addr [0x%x]\n", blk_addr);
- ASSERT_MSG(0, "Invalid data seg summary\n");
+ ASSERT_MSG("Invalid data seg summary\n");
+ return -EINVAL;
}
-
- return 1;
+ return 0;
}
-int fsck_chk_node_blk(struct f2fs_sb_info *sbi,
- struct f2fs_inode *inode,
- u32 nid,
- enum FILE_TYPE ftype,
- enum NODE_TYPE ntype,
- u32 *blk_cnt)
+static int sanity_check_nid(struct f2fs_sb_info *sbi, u32 nid,
+ struct f2fs_node *node_blk,
+ enum FILE_TYPE ftype, enum NODE_TYPE ntype,
+ struct node_info *ni)
{
struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
- struct node_info ni;
- struct f2fs_node *node_blk = NULL;
- int ret = 0;
+ int ret;
+
+ if (!IS_VALID_NID(sbi, nid)) {
+ ASSERT_MSG("nid is not valid. [0x%x]", nid);
+ return -EINVAL;
+ }
- IS_VALID_NID(sbi, nid);
+ get_node_info(sbi, nid, ni);
+ if (ni->blk_addr == NEW_ADDR) {
+ ASSERT_MSG("nid is NEW_ADDR. [0x%x]", nid);
+ return -EINVAL;
+ }
- if (ftype != F2FS_FT_ORPHAN ||
- f2fs_test_bit(nid, fsck->nat_area_bitmap) != 0x0)
- f2fs_clear_bit(nid, fsck->nat_area_bitmap);
- else
- ASSERT_MSG(0, "nid duplicated [0x%x]\n", nid);
+ if (!IS_VALID_BLK_ADDR(sbi, ni->blk_addr)) {
+ ASSERT_MSG("blkaddres is not valid. [0x%x]", ni->blk_addr);
+ return -EINVAL;
+ }
- ret = get_node_info(sbi, nid, &ni);
+ if (is_valid_ssa_node_blk(sbi, nid, ni->blk_addr)) {
+ ASSERT_MSG("summary node block is not valid. [0x%x]", nid);
+ return -EINVAL;
+ }
+
+ ret = dev_read_block(node_blk, ni->blk_addr);
ASSERT(ret >= 0);
- /* Is it reserved block?
- * if block addresss was 0xffff,ffff,ffff,ffff
- * it means that block was already allocated, but not stored in disk
- */
- if (ni.blk_addr == NEW_ADDR) {
- fsck->chk.valid_blk_cnt++;
- fsck->chk.valid_node_cnt++;
- if (ntype == TYPE_INODE)
- fsck->chk.valid_inode_cnt++;
- return 0;
+ if (ntype == TYPE_INODE &&
+ node_blk->footer.nid != node_blk->footer.ino) {
+ ASSERT_MSG("nid[0x%x] footer.nid[0x%x] footer.ino[0x%x]",
+ nid, le32_to_cpu(node_blk->footer.nid),
+ le32_to_cpu(node_blk->footer.ino));
+ return -EINVAL;
+ }
+ if (ntype != TYPE_INODE &&
+ node_blk->footer.nid == node_blk->footer.ino) {
+ ASSERT_MSG("nid[0x%x] footer.nid[0x%x] footer.ino[0x%x]",
+ nid, le32_to_cpu(node_blk->footer.nid),
+ le32_to_cpu(node_blk->footer.ino));
+ return -EINVAL;
}
- IS_VALID_BLK_ADDR(sbi, ni.blk_addr);
+ if (le32_to_cpu(node_blk->footer.nid) != nid) {
+ ASSERT_MSG("nid[0x%x] blk_addr[0x%x] footer.nid[0x%x]",
+ nid, ni->blk_addr,
+ le32_to_cpu(node_blk->footer.nid));
+ return -EINVAL;
+ }
- is_valid_ssa_node_blk(sbi, nid, ni.blk_addr);
+ if (ntype == TYPE_XATTR) {
+ u32 flag = le32_to_cpu(node_blk->footer.flag);
- if (f2fs_test_bit(BLKOFF_FROM_MAIN(sbi, ni.blk_addr), fsck->sit_area_bitmap) == 0x0) {
- DBG(0, "SIT bitmap is 0x0. blk_addr[0x%x]\n", ni.blk_addr);
- ASSERT(0);
+ if ((flag >> OFFSET_BIT_SHIFT) != XATTR_NODE_OFFSET) {
+ ASSERT_MSG("xnid[0x%x] has wrong ofs:[0x%x]",
+ nid, flag);
+ return -EINVAL;
+ }
+ }
+
+ if ((ntype == TYPE_INODE && ftype == F2FS_FT_DIR) ||
+ (ntype == TYPE_XATTR && ftype == F2FS_FT_XATTR)) {
+ /* not included '.' & '..' */
+ if (f2fs_test_main_bitmap(sbi, ni->blk_addr) != 0) {
+ ASSERT_MSG("Duplicated node blk. nid[0x%x][0x%x]\n",
+ nid, ni->blk_addr);
+ return -EINVAL;
+ }
}
- if (f2fs_test_bit(BLKOFF_FROM_MAIN(sbi, ni.blk_addr), fsck->main_area_bitmap) == 0x0) {
+ /* workaround to fix later */
+ if (ftype != F2FS_FT_ORPHAN ||
+ f2fs_test_bit(nid, fsck->nat_area_bitmap) != 0)
+ f2fs_clear_bit(nid, fsck->nat_area_bitmap);
+ else
+ ASSERT_MSG("orphan or xattr nid is duplicated [0x%x]\n",
+ nid);
+
+ if (f2fs_test_sit_bitmap(sbi, ni->blk_addr) == 0)
+ ASSERT_MSG("SIT bitmap is 0x0. blk_addr[0x%x]",
+ ni->blk_addr);
+
+ if (f2fs_test_main_bitmap(sbi, ni->blk_addr) == 0) {
fsck->chk.valid_blk_cnt++;
fsck->chk.valid_node_cnt++;
}
+ return 0;
+}
+
+static int fsck_chk_xattr_blk(struct f2fs_sb_info *sbi, u32 ino,
+ u32 x_nid, u32 *blk_cnt)
+{
+ struct f2fs_node *node_blk = NULL;
+ struct node_info ni;
+ int ret = 0;
+
+ if (x_nid == 0x0)
+ return 0;
node_blk = (struct f2fs_node *)calloc(BLOCK_SZ, 1);
ASSERT(node_blk != NULL);
- ret = dev_read_block(node_blk, ni.blk_addr);
- ASSERT(ret >= 0);
+ /* Sanity check */
+ if (sanity_check_nid(sbi, x_nid, node_blk,
+ F2FS_FT_XATTR, TYPE_XATTR, &ni)) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ *blk_cnt = *blk_cnt + 1;
+ f2fs_set_main_bitmap(sbi, ni.blk_addr);
+ DBG(2, "ino[0x%x] x_nid[0x%x]\n", ino, x_nid);
+out:
+ free(node_blk);
+ return ret;
+}
- ASSERT_MSG(nid == le32_to_cpu(node_blk->footer.nid),
- "nid[0x%x] blk_addr[0x%x] footer.nid[0x%x]\n",
- nid, ni.blk_addr, le32_to_cpu(node_blk->footer.nid));
+int fsck_chk_node_blk(struct f2fs_sb_info *sbi, struct f2fs_inode *inode,
+ u32 nid, enum FILE_TYPE ftype, enum NODE_TYPE ntype,
+ u32 *blk_cnt)
+{
+ struct node_info ni;
+ struct f2fs_node *node_blk = NULL;
+
+ node_blk = (struct f2fs_node *)calloc(BLOCK_SZ, 1);
+ ASSERT(node_blk != NULL);
+
+ if (sanity_check_nid(sbi, nid, node_blk, ftype, ntype, &ni))
+ goto err;
if (ntype == TYPE_INODE) {
- ret = fsck_chk_inode_blk(sbi,
- nid,
- ftype,
- node_blk,
- blk_cnt,
- &ni);
+ fsck_chk_inode_blk(sbi, nid, ftype, node_blk, blk_cnt, &ni);
} else {
- /* it's not inode */
- ASSERT(node_blk->footer.nid != node_blk->footer.ino);
-
- if (f2fs_test_bit(BLKOFF_FROM_MAIN(sbi, ni.blk_addr), fsck->main_area_bitmap) != 0) {
- DBG(0, "Duplicated node block. ino[0x%x][0x%x]\n", nid, ni.blk_addr);
- ASSERT(0);
- }
- f2fs_set_bit(BLKOFF_FROM_MAIN(sbi, ni.blk_addr), fsck->main_area_bitmap);
+ f2fs_set_main_bitmap(sbi, ni.blk_addr);
switch (ntype) {
case TYPE_DIRECT_NODE:
- ret = fsck_chk_dnode_blk(sbi,
- inode,
- nid,
- ftype,
- node_blk,
- blk_cnt,
- &ni);
+ fsck_chk_dnode_blk(sbi, inode, nid, ftype, node_blk,
+ blk_cnt, &ni);
break;
case TYPE_INDIRECT_NODE:
- ret = fsck_chk_idnode_blk(sbi,
- inode,
- nid,
- ftype,
- node_blk,
+ fsck_chk_idnode_blk(sbi, inode, ftype, node_blk,
blk_cnt);
break;
case TYPE_DOUBLE_INDIRECT_NODE:
- ret = fsck_chk_didnode_blk(sbi,
- inode,
- nid,
- ftype,
- node_blk,
+ fsck_chk_didnode_blk(sbi, inode, ftype, node_blk,
blk_cnt);
break;
default:
ASSERT(0);
}
}
- ASSERT(ret >= 0);
-
free(node_blk);
return 0;
+err:
+ free(node_blk);
+ return -EINVAL;
}
-int fsck_chk_inode_blk(struct f2fs_sb_info *sbi,
- u32 nid,
- enum FILE_TYPE ftype,
- struct f2fs_node *node_blk,
- u32 *blk_cnt,
- struct node_info *ni)
+/* start with valid nid and blkaddr */
+void fsck_chk_inode_blk(struct f2fs_sb_info *sbi, u32 nid,
+ enum FILE_TYPE ftype, struct f2fs_node *node_blk,
+ u32 *blk_cnt, struct node_info *ni)
{
struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
u32 child_cnt = 0, child_files = 0;
enum NODE_TYPE ntype;
u32 i_links = le32_to_cpu(node_blk->i.i_links);
u64 i_blocks = le64_to_cpu(node_blk->i.i_blocks);
- int idx = 0;
- int ret = 0;
-
- ASSERT(node_blk->footer.nid == node_blk->footer.ino);
- ASSERT(le32_to_cpu(node_blk->footer.nid) == nid);
+ unsigned int idx = 0;
+ int need_fix = 0;
+ int ret;
- if (f2fs_test_bit(BLKOFF_FROM_MAIN(sbi, ni->blk_addr), fsck->main_area_bitmap) == 0x0)
+ if (f2fs_test_main_bitmap(sbi, ni->blk_addr) == 0)
fsck->chk.valid_inode_cnt++;
- /* Orphan node. i_links should be 0 */
- if (ftype == F2FS_FT_ORPHAN) {
- ASSERT(i_links == 0);
- } else {
- ASSERT(i_links > 0);
- }
-
if (ftype == F2FS_FT_DIR) {
-
- /* not included '.' & '..' */
- if (f2fs_test_bit(BLKOFF_FROM_MAIN(sbi, ni->blk_addr), fsck->main_area_bitmap) != 0) {
- DBG(0, "Duplicated inode blk. ino[0x%x][0x%x]\n", nid, ni->blk_addr);
- ASSERT(0);
- }
- f2fs_set_bit(BLKOFF_FROM_MAIN(sbi, ni->blk_addr), fsck->main_area_bitmap);
-
+ f2fs_set_main_bitmap(sbi, ni->blk_addr);
} else {
-
- if (f2fs_test_bit(BLKOFF_FROM_MAIN(sbi, ni->blk_addr), fsck->main_area_bitmap) == 0x0) {
- f2fs_set_bit(BLKOFF_FROM_MAIN(sbi, ni->blk_addr), fsck->main_area_bitmap);
+ if (f2fs_test_main_bitmap(sbi, ni->blk_addr) == 0) {
+ f2fs_set_main_bitmap(sbi, ni->blk_addr);
if (i_links > 1) {
/* First time. Create new hard link node */
add_into_hard_link_list(sbi, nid, i_links);
fsck->chk.multi_hard_link_files++;
}
} else {
- if (i_links <= 1) {
- DBG(0, "Error. Node ID [0x%x]."
- " There are one more hard links."
- " But i_links is [0x%x]\n",
+ DBG(3, "[0x%x] has hard links [0x%x]\n", nid, i_links);
+ if (find_and_dec_hard_link_list(sbi, nid)) {
+ ASSERT_MSG("[0x%x] needs more i_links=0x%x",
nid, i_links);
- ASSERT(0);
+ if (config.fix_on) {
+ node_blk->i.i_links =
+ cpu_to_le32(i_links + 1);
+ need_fix = 1;
+ FIX_MSG("File: 0x%x "
+ "i_links= 0x%x -> 0x%x",
+ nid, i_links, i_links + 1);
+ }
}
-
- DBG(3, "ino[0x%x] has hard links [0x%x]\n", nid, i_links);
- ret = find_and_dec_hard_link_list(sbi, nid);
- ASSERT(ret >= 0);
-
/* No need to go deep into the node */
- goto out;
+ return;
}
}
- fsck_chk_xattr_blk(sbi, nid, le32_to_cpu(node_blk->i.i_xattr_nid), blk_cnt);
+ if (fsck_chk_xattr_blk(sbi, nid,
+ le32_to_cpu(node_blk->i.i_xattr_nid), blk_cnt) &&
+ config.fix_on) {
+ node_blk->i.i_xattr_nid = 0;
+ need_fix = 1;
+ FIX_MSG("Remove xattr block: 0x%x, x_nid = 0x%x",
+ nid, le32_to_cpu(node_blk->i.i_xattr_nid));
+ }
if (ftype == F2FS_FT_CHRDEV || ftype == F2FS_FT_BLKDEV ||
ftype == F2FS_FT_FIFO || ftype == F2FS_FT_SOCK)
@@ -338,18 +401,18 @@ int fsck_chk_inode_blk(struct f2fs_sb_info *sbi,
/* check data blocks in inode */
for (idx = 0; idx < ADDRS_PER_INODE(&node_blk->i); idx++) {
if (le32_to_cpu(node_blk->i.i_addr[idx]) != 0) {
- *blk_cnt = *blk_cnt + 1;
ret = fsck_chk_data_blk(sbi,
- &node_blk->i,
le32_to_cpu(node_blk->i.i_addr[idx]),
- &child_cnt,
- &child_files,
+ &child_cnt, &child_files,
(i_blocks == *blk_cnt),
- ftype,
- nid,
- idx,
- ni->version);
- ASSERT(ret >= 0);
+ ftype, nid, idx, ni->version);
+ if (!ret) {
+ *blk_cnt = *blk_cnt + 1;
+ } else if (config.fix_on) {
+ node_blk->i.i_addr[idx] = 0;
+ need_fix = 1;
+ FIX_MSG("[0x%x] i_addr[%d] = 0", nid, idx);
+ }
}
}
@@ -365,114 +428,120 @@ int fsck_chk_inode_blk(struct f2fs_sb_info *sbi,
ASSERT(0);
if (le32_to_cpu(node_blk->i.i_nid[idx]) != 0) {
- *blk_cnt = *blk_cnt + 1;
- ret = fsck_chk_node_blk(sbi,
- &node_blk->i,
+ ret = fsck_chk_node_blk(sbi, &node_blk->i,
le32_to_cpu(node_blk->i.i_nid[idx]),
- ftype,
- ntype,
- blk_cnt);
- ASSERT(ret >= 0);
+ ftype, ntype, blk_cnt);
+ if (!ret) {
+ *blk_cnt = *blk_cnt + 1;
+ } else if (config.fix_on) {
+ node_blk->i.i_nid[idx] = 0;
+ need_fix = 1;
+ FIX_MSG("[0x%x] i_nid[%d] = 0", nid, idx);
+ }
}
}
check:
if (ftype == F2FS_FT_DIR)
- DBG(1, "Directory Inode: ino: %x name: %s depth: %d child files: %d\n\n",
- le32_to_cpu(node_blk->footer.ino), node_blk->i.i_name,
- le32_to_cpu(node_blk->i.i_current_depth), child_files);
+ DBG(1, "Directory Inode: 0x%x [%s] depth: %d has %d files\n\n",
+ le32_to_cpu(node_blk->footer.ino),
+ node_blk->i.i_name,
+ le32_to_cpu(node_blk->i.i_current_depth),
+ child_files);
if (ftype == F2FS_FT_ORPHAN)
- DBG(1, "Orphan Inode: ino: %x name: %s i_blocks: %lu\n\n",
- le32_to_cpu(node_blk->footer.ino), node_blk->i.i_name,
- i_blocks);
- if ((ftype == F2FS_FT_DIR && i_links != child_cnt) ||
- (i_blocks != *blk_cnt)) {
- print_node_info(node_blk);
- DBG(1, "blk cnt [0x%x]\n", *blk_cnt);
- DBG(1, "child cnt [0x%x]\n", child_cnt);
+ DBG(1, "Orphan Inode: 0x%x [%s] i_blocks: %u\n\n",
+ le32_to_cpu(node_blk->footer.ino),
+ node_blk->i.i_name,
+ (u32)i_blocks);
+
+ if (i_blocks != *blk_cnt) {
+ ASSERT_MSG("ino: 0x%x has i_blocks: %08"PRIx64", "
+ "but has %u blocks",
+ nid, i_blocks, *blk_cnt);
+ if (config.fix_on) {
+ node_blk->i.i_blocks = cpu_to_le64(*blk_cnt);
+ need_fix = 1;
+ FIX_MSG("[0x%x] i_blocks=0x%08"PRIx64" -> 0x%x",
+ nid, i_blocks, *blk_cnt);
+ }
+ }
+ if (ftype == F2FS_FT_DIR && i_links != child_cnt) {
+ ASSERT_MSG("ino: 0x%x has i_links: %u but real links: %u",
+ nid, i_links, child_cnt);
+ if (config.fix_on) {
+ node_blk->i.i_links = cpu_to_le32(child_cnt);
+ need_fix = 1;
+ FIX_MSG("Dir: 0x%x i_links= 0x%x -> 0x%x",
+ nid, i_links, child_cnt);
+ }
}
- ASSERT(i_blocks == *blk_cnt);
- if (ftype == F2FS_FT_DIR)
- ASSERT(i_links == child_cnt);
-out:
- return 0;
+ if (ftype == F2FS_FT_ORPHAN && i_links)
+ ASSERT_MSG("ino: 0x%x is orphan inode, but has i_links: %u",
+ nid, i_links);
+ if (need_fix) {
+ ret = dev_write_block(node_blk, ni->blk_addr);
+ ASSERT(ret >= 0);
+ }
}
-int fsck_chk_dnode_blk(struct f2fs_sb_info *sbi,
- struct f2fs_inode *inode,
- u32 nid,
- enum FILE_TYPE ftype,
- struct f2fs_node *node_blk,
- u32 *blk_cnt,
- struct node_info *ni)
+int fsck_chk_dnode_blk(struct f2fs_sb_info *sbi, struct f2fs_inode *inode,
+ u32 nid, enum FILE_TYPE ftype, struct f2fs_node *node_blk,
+ u32 *blk_cnt, struct node_info *ni)
{
- int idx;
+ int idx, ret;
u32 child_cnt = 0, child_files = 0;
for (idx = 0; idx < ADDRS_PER_BLOCK; idx++) {
if (le32_to_cpu(node_blk->dn.addr[idx]) == 0x0)
continue;
- *blk_cnt = *blk_cnt + 1;
- fsck_chk_data_blk(sbi,
- inode,
- le32_to_cpu(node_blk->dn.addr[idx]),
- &child_cnt,
- &child_files,
- le64_to_cpu(inode->i_blocks) == *blk_cnt,
- ftype,
- nid,
- idx,
- ni->version);
+ ret = fsck_chk_data_blk(sbi,
+ le32_to_cpu(node_blk->dn.addr[idx]),
+ &child_cnt, &child_files,
+ le64_to_cpu(inode->i_blocks) == *blk_cnt, ftype,
+ nid, idx, ni->version);
+ if (!ret)
+ *blk_cnt = *blk_cnt + 1;
}
-
return 0;
}
-int fsck_chk_idnode_blk(struct f2fs_sb_info *sbi,
- struct f2fs_inode *inode,
- u32 nid,
- enum FILE_TYPE ftype,
- struct f2fs_node *node_blk,
- u32 *blk_cnt)
+int fsck_chk_idnode_blk(struct f2fs_sb_info *sbi, struct f2fs_inode *inode,
+ enum FILE_TYPE ftype, struct f2fs_node *node_blk, u32 *blk_cnt)
{
+ int ret;
int i = 0;
for (i = 0 ; i < NIDS_PER_BLOCK; i++) {
if (le32_to_cpu(node_blk->in.nid[i]) == 0x0)
continue;
- *blk_cnt = *blk_cnt + 1;
- fsck_chk_node_blk(sbi,
- inode,
+ ret = fsck_chk_node_blk(sbi, inode,
le32_to_cpu(node_blk->in.nid[i]),
- ftype,
- TYPE_DIRECT_NODE,
- blk_cnt);
+ ftype, TYPE_DIRECT_NODE, blk_cnt);
+ if (!ret)
+ *blk_cnt = *blk_cnt + 1;
+ else if (ret == -EINVAL)
+ printf("delete in.nid[i] = 0;\n");
}
-
return 0;
}
-int fsck_chk_didnode_blk(struct f2fs_sb_info *sbi,
- struct f2fs_inode *inode,
- u32 nid,
- enum FILE_TYPE ftype,
- struct f2fs_node *node_blk,
- u32 *blk_cnt)
+int fsck_chk_didnode_blk(struct f2fs_sb_info *sbi, struct f2fs_inode *inode,
+ enum FILE_TYPE ftype, struct f2fs_node *node_blk, u32 *blk_cnt)
{
int i = 0;
+ int ret = 0;
for (i = 0; i < NIDS_PER_BLOCK; i++) {
if (le32_to_cpu(node_blk->in.nid[i]) == 0x0)
continue;
- *blk_cnt = *blk_cnt + 1;
- fsck_chk_node_blk(sbi,
- inode,
+ ret = fsck_chk_node_blk(sbi, inode,
le32_to_cpu(node_blk->in.nid[i]),
- ftype,
- TYPE_INDIRECT_NODE,
- blk_cnt);
+ ftype, TYPE_INDIRECT_NODE, blk_cnt);
+ if (!ret)
+ *blk_cnt = *blk_cnt + 1;
+ else if (ret == -EINVAL)
+ printf("delete in.nid[i] = 0;\n");
}
-
return 0;
}
@@ -482,7 +551,7 @@ static void print_dentry(__u32 depth, __u8 *name,
int last_de = 0;
int next_idx = 0;
int name_len;
- int i;
+ unsigned int i;
int bit_offset;
if (config.dbg_lv != -1)
@@ -512,15 +581,12 @@ static void print_dentry(__u32 depth, __u8 *name,
for (i = 1; i < depth; i++)
printf("%c ", tree_mark[i]);
- printf("%c-- %s\n", last_de ? '`' : '|', name);
+ printf("%c-- %s 0x%x\n", last_de ? '`' : '|',
+ name, le32_to_cpu(de_blk->dentry[idx].ino));
}
-int fsck_chk_dentry_blk(struct f2fs_sb_info *sbi,
- struct f2fs_inode *inode,
- u32 blk_addr,
- u32 *child_cnt,
- u32 *child_files,
- int last_blk)
+int fsck_chk_dentry_blk(struct f2fs_sb_info *sbi, u32 blk_addr,
+ u32 *child_cnt, u32 *child_files, int last_blk)
{
struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
int i;
@@ -543,16 +609,17 @@ int fsck_chk_dentry_blk(struct f2fs_sb_info *sbi,
fsck->dentry_depth++;
for (i = 0; i < NR_DENTRY_IN_BLOCK;) {
- if (test_bit(i, (unsigned long *)de_blk->dentry_bitmap) == 0x0) {
+ if (test_bit(i, (unsigned long *)de_blk->dentry_bitmap) == 0) {
i++;
continue;
}
- name_len = le32_to_cpu(de_blk->dentry[i].name_len);
+ name_len = le16_to_cpu(de_blk->dentry[i].name_len);
name = calloc(name_len + 1, 1);
memcpy(name, de_blk->filename[i], name_len);
+ hash_code = f2fs_dentry_hash((const unsigned char *)name,
+ name_len);
- hash_code = f2fs_dentry_hash((const char *)name, name_len);
ASSERT(le32_to_cpu(de_blk->dentry[i].hash_code) == hash_code);
ftype = de_blk->dentry[i].file_type;
@@ -560,15 +627,16 @@ int fsck_chk_dentry_blk(struct f2fs_sb_info *sbi,
/* Becareful. 'dentry.file_type' is not imode. */
if (ftype == F2FS_FT_DIR) {
*child_cnt = *child_cnt + 1;
- if ((name[0] == '.' && name[1] == '.' && name_len == 2) ||
- (name[0] == '.' && name_len == 1)) {
+ if ((name[0] == '.' && name_len == 1) ||
+ (name[0] == '.' && name[1] == '.' &&
+ name_len == 2)) {
i++;
free(name);
continue;
}
}
- DBG(2, "[%3u] - no[0x%x] name[%s] len[0x%x] ino[0x%x] type[0x%x]\n",
+ DBG(1, "[%3u]-[0x%x] name[%s] len[0x%x] ino[0x%x] type[0x%x]\n",
fsck->dentry_depth, i, name, name_len,
le32_to_cpu(de_blk->dentry[i].ino),
de_blk->dentry[i].file_type);
@@ -583,7 +651,21 @@ int fsck_chk_dentry_blk(struct f2fs_sb_info *sbi,
TYPE_INODE,
&blk_cnt);
- ASSERT(ret >= 0);
+ if (ret && config.fix_on) {
+ int j;
+ int slots = (name_len + F2FS_SLOT_LEN - 1) /
+ F2FS_SLOT_LEN;
+ for (j = 0; j < slots; j++)
+ clear_bit(i + j,
+ (unsigned long *)de_blk->dentry_bitmap);
+ FIX_MSG("Unlink [0x%x] - %s len[0x%x], type[0x%x]",
+ le32_to_cpu(de_blk->dentry[i].ino),
+ name, name_len,
+ de_blk->dentry[i].file_type);
+ i += slots;
+ free(name);
+ continue;
+ }
i += (name_len + F2FS_SLOT_LEN - 1) / F2FS_SLOT_LEN;
dentries++;
@@ -591,24 +673,19 @@ int fsck_chk_dentry_blk(struct f2fs_sb_info *sbi,
free(name);
}
- DBG(1, "[%3d] Dentry Block [0x%x] Done : dentries:%d in %d slots (len:%d)\n\n",
- fsck->dentry_depth, blk_addr, dentries, NR_DENTRY_IN_BLOCK, F2FS_NAME_LEN);
+ DBG(1, "[%3d] Dentry Block [0x%x] Done : "
+ "dentries:%d in %d slots (len:%d)\n\n",
+ fsck->dentry_depth, blk_addr, dentries,
+ NR_DENTRY_IN_BLOCK, F2FS_NAME_LEN);
fsck->dentry_depth--;
free(de_blk);
return 0;
}
-int fsck_chk_data_blk(struct f2fs_sb_info *sbi,
- struct f2fs_inode *inode,
- u32 blk_addr,
- u32 *child_cnt,
- u32 *child_files,
- int last_blk,
- enum FILE_TYPE ftype,
- u32 parent_nid,
- u16 idx_in_node,
- u8 ver)
+int fsck_chk_data_blk(struct f2fs_sb_info *sbi, u32 blk_addr,
+ u32 *child_cnt, u32 *child_files, int last_blk,
+ enum FILE_TYPE ftype, u32 parent_nid, u16 idx_in_node, u8 ver)
{
struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
@@ -618,112 +695,80 @@ int fsck_chk_data_blk(struct f2fs_sb_info *sbi,
return 0;
}
- IS_VALID_BLK_ADDR(sbi, blk_addr);
-
- is_valid_ssa_data_blk(sbi, blk_addr, parent_nid, idx_in_node, ver);
-
- if (f2fs_test_bit(BLKOFF_FROM_MAIN(sbi, blk_addr), fsck->sit_area_bitmap) == 0x0) {
- ASSERT_MSG(0, "SIT bitmap is 0x0. blk_addr[0x%x]\n", blk_addr);
+ if (!IS_VALID_BLK_ADDR(sbi, blk_addr)) {
+ ASSERT_MSG("blkaddres is not valid. [0x%x]", blk_addr);
+ return -EINVAL;
}
- if (f2fs_test_bit(BLKOFF_FROM_MAIN(sbi, blk_addr), fsck->main_area_bitmap) != 0) {
- ASSERT_MSG(0, "Duplicated data block. pnid[0x%x] idx[0x%x] blk_addr[0x%x]\n",
- parent_nid, idx_in_node, blk_addr);
+ if (is_valid_ssa_data_blk(sbi, blk_addr, parent_nid,
+ idx_in_node, ver)) {
+ ASSERT_MSG("summary data block is not valid. [0x%x]",
+ parent_nid);
+ return -EINVAL;
}
- f2fs_set_bit(BLKOFF_FROM_MAIN(sbi, blk_addr), fsck->main_area_bitmap);
- fsck->chk.valid_blk_cnt++;
+ if (f2fs_test_sit_bitmap(sbi, blk_addr) == 0)
+ ASSERT_MSG("SIT bitmap is 0x0. blk_addr[0x%x]", blk_addr);
- if (ftype == F2FS_FT_DIR) {
- fsck_chk_dentry_blk(sbi,
- inode,
- blk_addr,
- child_cnt,
- child_files,
- last_blk);
- }
+ if (f2fs_test_main_bitmap(sbi, blk_addr) != 0)
+ ASSERT_MSG("Duplicated data [0x%x]. pnid[0x%x] idx[0x%x]",
+ blk_addr, parent_nid, idx_in_node);
+
+ f2fs_set_main_bitmap(sbi, blk_addr);
+
+ fsck->chk.valid_blk_cnt++;
+ if (ftype == F2FS_FT_DIR)
+ return fsck_chk_dentry_blk(sbi, blk_addr, child_cnt,
+ child_files, last_blk);
return 0;
}
-int fsck_chk_orphan_node(struct f2fs_sb_info *sbi)
+void fsck_chk_orphan_node(struct f2fs_sb_info *sbi)
{
- int ret = 0;
u32 blk_cnt = 0;
-
block_t start_blk, orphan_blkaddr, i, j;
struct f2fs_orphan_block *orphan_blk;
+ struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
- if (!is_set_ckpt_flags(F2FS_CKPT(sbi), CP_ORPHAN_PRESENT_FLAG))
- return 0;
+ if (!is_set_ckpt_flags(ckpt, CP_ORPHAN_PRESENT_FLAG))
+ return;
- start_blk = __start_cp_addr(sbi) + 1;
- orphan_blkaddr = __start_sum_addr(sbi) - 1;
+ if (config.fix_on)
+ return;
+ start_blk = __start_cp_addr(sbi) + 1 +
+ le32_to_cpu(F2FS_RAW_SUPER(sbi)->cp_payload);
+ orphan_blkaddr = __start_sum_addr(sbi) - 1;
orphan_blk = calloc(BLOCK_SZ, 1);
for (i = 0; i < orphan_blkaddr; i++) {
- dev_read_block(orphan_blk, start_blk + i);
+ int ret = dev_read_block(orphan_blk, start_blk + i);
+
+ ASSERT(ret >= 0);
for (j = 0; j < le32_to_cpu(orphan_blk->entry_count); j++) {
nid_t ino = le32_to_cpu(orphan_blk->ino[j]);
DBG(1, "[%3d] ino [0x%x]\n", i, ino);
blk_cnt = 1;
- ret = fsck_chk_node_blk(sbi,
- NULL,
- ino,
- F2FS_FT_ORPHAN,
- TYPE_INODE,
- &blk_cnt);
- ASSERT(ret >= 0);
+ fsck_chk_node_blk(sbi, NULL, ino,
+ F2FS_FT_ORPHAN, TYPE_INODE, &blk_cnt);
}
memset(orphan_blk, 0, BLOCK_SZ);
}
free(orphan_blk);
-
-
- return 0;
}
-int fsck_chk_xattr_blk(struct f2fs_sb_info *sbi, u32 ino, u32 x_nid, u32 *blk_cnt)
-{
- struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
- struct node_info ni;
-
- if (x_nid == 0x0)
- return 0;
-
- if (f2fs_test_bit(x_nid, fsck->nat_area_bitmap) != 0x0) {
- f2fs_clear_bit(x_nid, fsck->nat_area_bitmap);
- } else {
- ASSERT_MSG(0, "xattr_nid duplicated [0x%x]\n", x_nid);
- }
-
- *blk_cnt = *blk_cnt + 1;
- fsck->chk.valid_blk_cnt++;
- fsck->chk.valid_node_cnt++;
-
- ASSERT(get_node_info(sbi, x_nid, &ni) >= 0);
-
- if (f2fs_test_bit(BLKOFF_FROM_MAIN(sbi, ni.blk_addr), fsck->main_area_bitmap) != 0) {
- ASSERT_MSG(0, "Duplicated node block for x_attr. "
- "x_nid[0x%x] block addr[0x%x]\n",
- x_nid, ni.blk_addr);
- }
- f2fs_set_bit(BLKOFF_FROM_MAIN(sbi, ni.blk_addr), fsck->main_area_bitmap);
-
- DBG(2, "ino[0x%x] x_nid[0x%x]\n", ino, x_nid);
- return 0;
-}
-
-int fsck_init(struct f2fs_sb_info *sbi)
+void fsck_init(struct f2fs_sb_info *sbi)
{
struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
struct f2fs_sm_info *sm_i = SM_I(sbi);
/*
- * We build three bitmap for main/sit/nat so that may check consistency of filesystem.
- * 1. main_area_bitmap will be used to check whether all blocks of main area is used or not.
+ * We build three bitmap for main/sit/nat so that may check consistency
+ * of filesystem.
+ * 1. main_area_bitmap will be used to check whether all blocks of main
+ * area is used or not.
* 2. nat_area_bitmap has bitmap information of used nid in NAT.
* 3. sit_area_bitmap has bitmap information of used main block.
* At Last sequence, we compare main_area_bitmap with sit_area_bitmap.
@@ -738,12 +783,89 @@ int fsck_init(struct f2fs_sb_info *sbi)
build_sit_area_bitmap(sbi);
tree_mark = calloc(tree_mark_size, 1);
+ ASSERT(tree_mark != NULL);
+}
+
+static void fix_nat_entries(struct f2fs_sb_info *sbi)
+{
+ struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
+ u32 i;
+
+ for (i = 0; i < fsck->nr_nat_entries; i++)
+ if (f2fs_test_bit(i, fsck->nat_area_bitmap) != 0)
+ nullify_nat_entry(sbi, i);
+}
+
+static void fix_checkpoint(struct f2fs_sb_info *sbi)
+{
+ struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
+ struct f2fs_super_block *raw_sb = sbi->raw_super;
+ struct f2fs_checkpoint *ckp = F2FS_CKPT(sbi);
+ unsigned long long cp_blk_no;
+ u32 i;
+ int ret;
+ u_int32_t crc = 0;
+
+ ckp->ckpt_flags = cpu_to_le32(CP_UMOUNT_FLAG);
+ ckp->cp_pack_total_block_count =
+ cpu_to_le32(8 + le32_to_cpu(raw_sb->cp_payload));
+ ckp->cp_pack_start_sum = cpu_to_le32(1 +
+ le32_to_cpu(raw_sb->cp_payload));
+
+ ckp->free_segment_count = cpu_to_le32(fsck->chk.free_segs);
+ ckp->valid_block_count = cpu_to_le32(fsck->chk.valid_blk_cnt);
+ ckp->valid_node_count = cpu_to_le32(fsck->chk.valid_node_cnt);
+ ckp->valid_inode_count = cpu_to_le32(fsck->chk.valid_inode_cnt);
+
+ crc = f2fs_cal_crc32(F2FS_SUPER_MAGIC, ckp, CHECKSUM_OFFSET);
+ *((__le32 *)((unsigned char *)ckp + CHECKSUM_OFFSET)) =
+ cpu_to_le32(crc);
+
+ cp_blk_no = le32_to_cpu(raw_sb->cp_blkaddr);
+ if (sbi->cur_cp == 2)
+ cp_blk_no += 1 << le32_to_cpu(raw_sb->log_blocks_per_seg);
+
+ ret = dev_write_block(ckp, cp_blk_no++);
+ ASSERT(ret >= 0);
+
+ for (i = 0; i < le32_to_cpu(raw_sb->cp_payload); i++) {
+ ret = dev_write_block(((unsigned char *)ckp) + i * F2FS_BLKSIZE,
+ cp_blk_no++);
+ ASSERT(ret >= 0);
+ }
+
+ for (i = 0; i < NO_CHECK_TYPE; i++) {
+ struct curseg_info *curseg = CURSEG_I(sbi, i);
+
+ ret = dev_write_block(curseg->sum_blk, cp_blk_no++);
+ ASSERT(ret >= 0);
+ }
+
+ ret = dev_write_block(ckp, cp_blk_no++);
+ ASSERT(ret >= 0);
+}
+
+int check_curseg_offset(struct f2fs_sb_info *sbi)
+{
+ int i;
+
+ for (i = 0; i < NO_CHECK_TYPE; i++) {
+ struct curseg_info *curseg = CURSEG_I(sbi, i);
+ struct seg_entry *se;
+
+ se = get_seg_entry(sbi, curseg->segno);
+ if (f2fs_test_bit(curseg->next_blkoff,
+ (const char *)se->cur_valid_map) == 1) {
+ ASSERT_MSG("Next block offset is not free, type:%d", i);
+ return -EINVAL;
+ }
+ }
return 0;
}
int fsck_verify(struct f2fs_sb_info *sbi)
{
- int i = 0;
+ unsigned int i = 0;
int ret = 0;
u32 nr_unref_nid = 0;
struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
@@ -765,6 +887,7 @@ int fsck_verify(struct f2fs_sb_info *sbi)
node->nid, node->links);
node = node->next;
}
+ config.bug_on = 1;
}
printf("[FSCK] Unreachable nat entries ");
@@ -773,14 +896,17 @@ int fsck_verify(struct f2fs_sb_info *sbi)
} else {
printf(" [Fail] [0x%x]\n", nr_unref_nid);
ret = EXIT_ERR_CODE;
+ config.bug_on = 1;
}
printf("[FSCK] SIT valid block bitmap checking ");
- if (memcmp(fsck->sit_area_bitmap, fsck->main_area_bitmap, fsck->sit_area_bitmap_sz) == 0x0) {
+ if (memcmp(fsck->sit_area_bitmap, fsck->main_area_bitmap,
+ fsck->sit_area_bitmap_sz) == 0x0) {
printf("[Ok..]\n");
} else {
printf("[Fail]\n");
ret = EXIT_ERR_CODE;
+ config.bug_on = 1;
}
printf("[FSCK] Hard link checking for regular file ");
@@ -789,14 +915,16 @@ int fsck_verify(struct f2fs_sb_info *sbi)
} else {
printf(" [Fail] [0x%x]\n", fsck->chk.multi_hard_link_files);
ret = EXIT_ERR_CODE;
+ config.bug_on = 1;
}
printf("[FSCK] valid_block_count matching with CP ");
if (sbi->total_valid_block_count == fsck->chk.valid_blk_cnt) {
- printf(" [Ok..] [0x%lx]\n", fsck->chk.valid_blk_cnt);
+ printf(" [Ok..] [0x%x]\n", (u32)fsck->chk.valid_blk_cnt);
} else {
- printf(" [Fail] [0x%lx]\n", fsck->chk.valid_blk_cnt);
+ printf(" [Fail] [0x%x]\n", (u32)fsck->chk.valid_blk_cnt);
ret = EXIT_ERR_CODE;
+ config.bug_on = 1;
}
printf("[FSCK] valid_node_count matcing with CP (de lookup) ");
@@ -805,6 +933,7 @@ int fsck_verify(struct f2fs_sb_info *sbi)
} else {
printf(" [Fail] [0x%x]\n", fsck->chk.valid_node_cnt);
ret = EXIT_ERR_CODE;
+ config.bug_on = 1;
}
printf("[FSCK] valid_node_count matcing with CP (nat lookup) ");
@@ -813,6 +942,7 @@ int fsck_verify(struct f2fs_sb_info *sbi)
} else {
printf(" [Fail] [0x%x]\n", fsck->chk.valid_nat_entry_cnt);
ret = EXIT_ERR_CODE;
+ config.bug_on = 1;
}
printf("[FSCK] valid_inode_count matched with CP ");
@@ -821,8 +951,43 @@ int fsck_verify(struct f2fs_sb_info *sbi)
} else {
printf(" [Fail] [0x%x]\n", fsck->chk.valid_inode_cnt);
ret = EXIT_ERR_CODE;
+ config.bug_on = 1;
}
+ printf("[FSCK] free segment_count matched with CP ");
+ if (le32_to_cpu(F2FS_CKPT(sbi)->free_segment_count) ==
+ fsck->chk.sit_free_segs) {
+ printf(" [Ok..] [0x%x]\n", fsck->chk.sit_free_segs);
+ } else {
+ printf(" [Fail] [0x%x]\n", fsck->chk.sit_free_segs);
+ ret = EXIT_ERR_CODE;
+ config.bug_on = 1;
+ }
+
+ printf("[FSCK] next block offset is free ");
+ if (check_curseg_offset(sbi) == 0) {
+ printf(" [Ok..]\n");
+ } else {
+ printf(" [Fail]\n");
+ ret = EXIT_ERR_CODE;
+ config.bug_on = 1;
+ }
+
+ printf("[FSCK] other corrupted bugs ");
+ if (config.bug_on == 0) {
+ printf(" [Ok..]\n");
+ } else {
+ printf(" [Fail]\n");
+ ret = EXIT_ERR_CODE;
+ config.bug_on = 1;
+ }
+
+ /* fix global metadata */
+ if (config.bug_on && config.fix_on) {
+ fix_nat_entries(sbi);
+ rewrite_sit_area_bitmap(sbi);
+ fix_checkpoint(sbi);
+ }
return ret;
}
diff --git a/fsck/fsck.h b/fsck/fsck.h
index 8c98c93..64b9984 100644
--- a/fsck/fsck.h
+++ b/fsck/fsck.h
@@ -31,6 +31,7 @@ struct f2fs_fsck {
u32 multi_hard_link_files;
u64 sit_valid_blocks;
u32 sit_free_segs;
+ u32 free_segs;
} chk;
struct hard_link_node *hard_link_list_head;
@@ -59,7 +60,8 @@ enum NODE_TYPE {
TYPE_INODE = 37,
TYPE_DIRECT_NODE = 43,
TYPE_INDIRECT_NODE = 53,
- TYPE_DOUBLE_INDIRECT_NODE = 67
+ TYPE_DOUBLE_INDIRECT_NODE = 67,
+ TYPE_XATTR = 77
};
struct hard_link_node {
@@ -76,76 +78,38 @@ enum seg_type {
SEG_TYPE_MAX,
};
-extern int fsck_chk_xattr_blk(struct f2fs_sb_info *sbi, u32 ino, u32 x_nid, u32 *blk_cnt);
-extern int fsck_chk_orphan_node(struct f2fs_sb_info *sbi);
-
-extern int fsck_chk_node_blk(struct f2fs_sb_info *sbi,
- struct f2fs_inode *inode,
- u32 nid,
- enum FILE_TYPE ftype,
- enum NODE_TYPE ntype,
- u32 *blk_cnt);
-
-extern int fsck_chk_inode_blk(struct f2fs_sb_info *sbi,
- u32 nid,
- enum FILE_TYPE ftype,
- struct f2fs_node *node_blk,
- u32 *blk_cnt,
- struct node_info *ni);
-
-extern int fsck_chk_dnode_blk(struct f2fs_sb_info *sbi,
- struct f2fs_inode *inode,
- u32 nid,
- enum FILE_TYPE ftype,
- struct f2fs_node *node_blk,
- u32 *blk_cnt,
- struct node_info *ni);
-
-extern int fsck_chk_idnode_blk(struct f2fs_sb_info *sbi,
- struct f2fs_inode *inode,
- u32 nid,
- enum FILE_TYPE ftype,
- struct f2fs_node *node_blk,
- u32 *blk_cnt);
-
-extern int fsck_chk_didnode_blk(struct f2fs_sb_info *sbi,
- struct f2fs_inode *inode,
- u32 nid,
- enum FILE_TYPE ftype,
- struct f2fs_node *node_blk,
- u32 *blk_cnt);
-
-extern int fsck_chk_data_blk(struct f2fs_sb_info *sbi,
- struct f2fs_inode *inode,
- u32 blk_addr,
- u32 *child_cnt,
- u32 *child_files,
- int last_blk,
- enum FILE_TYPE ftype,
- u32 parent_nid,
- u16 idx_in_node,
- u8 ver);
-
-extern int fsck_chk_dentry_blk(struct f2fs_sb_info *sbi,
- struct f2fs_inode *inode,
- u32 blk_addr,
- u32 *child_cnt,
- u32 *child_files,
- int last_blk);
-
-extern void print_node_info(struct f2fs_node *node_block);
-extern void print_inode_info(struct f2fs_inode *inode);
-extern struct seg_entry *get_seg_entry(struct f2fs_sb_info *sbi, unsigned int segno);
-extern int get_sum_block(struct f2fs_sb_info *sbi, unsigned int segno, struct f2fs_summary_block *sum_blk);
-extern int get_sum_entry(struct f2fs_sb_info *sbi, u32 blk_addr, struct f2fs_summary *sum_entry);
-extern int get_node_info(struct f2fs_sb_info *sbi, nid_t nid, struct node_info *ni);
-extern void build_nat_area_bitmap(struct f2fs_sb_info *sbi);
-extern int build_sit_area_bitmap(struct f2fs_sb_info *sbi);
-extern int fsck_init(struct f2fs_sb_info *sbi);
-extern int fsck_verify(struct f2fs_sb_info *sbi);
-extern void fsck_free(struct f2fs_sb_info *sbi);
-extern int f2fs_do_mount(struct f2fs_sb_info *sbi);
-extern void f2fs_do_umount(struct f2fs_sb_info *sbi);
+extern void fsck_chk_orphan_node(struct f2fs_sb_info *);
+extern int fsck_chk_node_blk(struct f2fs_sb_info *, struct f2fs_inode *, u32,
+ enum FILE_TYPE, enum NODE_TYPE, u32 *);
+extern void fsck_chk_inode_blk(struct f2fs_sb_info *, u32, enum FILE_TYPE,
+ struct f2fs_node *, u32 *, struct node_info *);
+extern int fsck_chk_dnode_blk(struct f2fs_sb_info *, struct f2fs_inode *,
+ u32, enum FILE_TYPE, struct f2fs_node *, u32 *,
+ struct node_info *);
+extern int fsck_chk_idnode_blk(struct f2fs_sb_info *, struct f2fs_inode *,
+ enum FILE_TYPE, struct f2fs_node *, u32 *);
+extern int fsck_chk_didnode_blk(struct f2fs_sb_info *, struct f2fs_inode *,
+ enum FILE_TYPE, struct f2fs_node *, u32 *);
+extern int fsck_chk_data_blk(struct f2fs_sb_info *sbi, u32, u32 *, u32 *,
+ int, enum FILE_TYPE, u32, u16, u8);
+extern int fsck_chk_dentry_blk(struct f2fs_sb_info *, u32, u32 *, u32 *, int);
+
+extern void print_node_info(struct f2fs_node *);
+extern void print_inode_info(struct f2fs_inode *);
+extern struct seg_entry *get_seg_entry(struct f2fs_sb_info *, unsigned int);
+extern int get_sum_block(struct f2fs_sb_info *, unsigned int,
+ struct f2fs_summary_block *);
+extern int get_sum_entry(struct f2fs_sb_info *, u32, struct f2fs_summary *);
+extern void get_node_info(struct f2fs_sb_info *, nid_t, struct node_info *);
+extern void nullify_nat_entry(struct f2fs_sb_info *, u32);
+extern void rewrite_sit_area_bitmap(struct f2fs_sb_info *);
+extern void build_nat_area_bitmap(struct f2fs_sb_info *);
+extern void build_sit_area_bitmap(struct f2fs_sb_info *);
+extern void fsck_init(struct f2fs_sb_info *);
+extern int fsck_verify(struct f2fs_sb_info *);
+extern void fsck_free(struct f2fs_sb_info *);
+extern int f2fs_do_mount(struct f2fs_sb_info *);
+extern void f2fs_do_umount(struct f2fs_sb_info *);
/* dump.c */
struct dump_option {
@@ -154,12 +118,12 @@ struct dump_option {
int end_sit;
int start_ssa;
int end_ssa;
- u32 blk_addr;
+ int32_t blk_addr;
};
-extern void sit_dump(struct f2fs_sb_info *sbi, int start_sit, int end_sit);
-extern void ssa_dump(struct f2fs_sb_info *sbi, int start_ssa, int end_ssa);
-extern int dump_node(struct f2fs_sb_info *sbi, nid_t nid);
-extern int dump_inode_from_blkaddr(struct f2fs_sb_info *sbi, u32 blk_addr);
+extern void sit_dump(struct f2fs_sb_info *, int, int);
+extern void ssa_dump(struct f2fs_sb_info *, int, int);
+extern void dump_node(struct f2fs_sb_info *, nid_t);
+extern int dump_inode_from_blkaddr(struct f2fs_sb_info *, u32);
#endif /* _FSCK_H_ */
diff --git a/fsck/main.c b/fsck/main.c
index 87f009c..31eeeed 100644
--- a/fsck/main.c
+++ b/fsck/main.c
@@ -11,15 +11,16 @@
#include "fsck.h"
#include <libgen.h>
-struct f2fs_fsck gfsck = {
- .sbi.fsck = &gfsck,
-};
+struct f2fs_fsck gfsck;
void fsck_usage()
{
MSG(0, "\nUsage: fsck.f2fs [options] device\n");
MSG(0, "[options]:\n");
+ MSG(0, " -a check/fix potential corruption, reported by f2fs\n");
MSG(0, " -d debug level [default:0]\n");
+ MSG(0, " -f check/fix entire partition\n");
+ MSG(0, " -t show directory tree [-d -1]\n");
exit(1);
}
@@ -42,24 +43,33 @@ void f2fs_parse_options(int argc, char *argv[])
char *prog = basename(argv[0]);
if (!strcmp("fsck.f2fs", prog)) {
- const char *option_string = "d:t";
+ const char *option_string = "ad:ft";
MSG(0, "\n\tF2FS-tools: fsck.f2fs Ver: %s (%s)\n\n",
- F2FS_TOOLS_VERSION,
- F2FS_TOOLS_DATE);
+ F2FS_TOOLS_VERSION, F2FS_TOOLS_DATE);
+
config.func = FSCK;
while ((option = getopt(argc, argv, option_string)) != EOF) {
switch (option) {
- case 'd':
- config.dbg_lv = atoi(optarg);
- MSG(0, "Info: Debug level = %d\n", config.dbg_lv);
- break;
- case 't':
- config.dbg_lv = -1;
- break;
- default:
- fsck_usage();
- break;
+ case 'a':
+ config.auto_fix = 1;
+ MSG(0, "Info: Fix the reported corruption.\n");
+ break;
+ case 'd':
+ config.dbg_lv = atoi(optarg);
+ MSG(0, "Info: Debug level = %d\n",
+ config.dbg_lv);
+ break;
+ case 'f':
+ config.fix_on = 1;
+ MSG(0, "Info: Force to fix corruption\n");
+ break;
+ case 't':
+ config.dbg_lv = -1;
+ break;
+ default:
+ fsck_usage();
+ break;
}
}
} else if (!strcmp("dump.f2fs", prog)) {
@@ -74,37 +84,49 @@ void f2fs_parse_options(int argc, char *argv[])
};
MSG(0, "\n\tF2FS-tools: dump.f2fs Ver: %s (%s)\n\n",
- F2FS_TOOLS_VERSION,
- F2FS_TOOLS_DATE);
+ F2FS_TOOLS_VERSION, F2FS_TOOLS_DATE);
+
config.func = DUMP;
while ((option = getopt(argc, argv, option_string)) != EOF) {
+ int ret = 0;
+
switch (option) {
- case 'd':
- config.dbg_lv = atoi(optarg);
- MSG(0, "Info: Debug level = %d\n", config.dbg_lv);
- break;
- case 'i':
- if (strncmp(optarg, "0x", 2))
- sscanf(optarg, "%d", &dump_opt.nid);
- else
- sscanf(optarg, "%x", &dump_opt.nid);
- break;
- case 's':
- sscanf(optarg, "%d~%d", &dump_opt.start_sit, &dump_opt.end_sit);
- break;
- case 'a':
- sscanf(optarg, "%d~%d", &dump_opt.start_ssa, &dump_opt.end_ssa);
- break;
- case 'b':
- if (strncmp(optarg, "0x", 2))
- sscanf(optarg, "%d", &dump_opt.blk_addr);
- else
- sscanf(optarg, "%x", &dump_opt.blk_addr);
- break;
- default:
- dump_usage();
- break;
+ case 'd':
+ config.dbg_lv = atoi(optarg);
+ MSG(0, "Info: Debug level = %d\n",
+ config.dbg_lv);
+ break;
+ case 'i':
+ if (strncmp(optarg, "0x", 2))
+ ret = sscanf(optarg, "%d",
+ &dump_opt.nid);
+ else
+ ret = sscanf(optarg, "%x",
+ &dump_opt.nid);
+ break;
+ case 's':
+ ret = sscanf(optarg, "%d~%d",
+ &dump_opt.start_sit,
+ &dump_opt.end_sit);
+ break;
+ case 'a':
+ ret = sscanf(optarg, "%d~%d",
+ &dump_opt.start_ssa,
+ &dump_opt.end_ssa);
+ break;
+ case 'b':
+ if (strncmp(optarg, "0x", 2))
+ ret = sscanf(optarg, "%d",
+ &dump_opt.blk_addr);
+ else
+ ret = sscanf(optarg, "%x",
+ &dump_opt.blk_addr);
+ break;
+ default:
+ dump_usage();
+ break;
}
+ ASSERT(ret >= 0);
}
config.private = &dump_opt;
@@ -120,43 +142,27 @@ void f2fs_parse_options(int argc, char *argv[])
config.device_name = argv[optind];
}
-int do_fsck(struct f2fs_sb_info *sbi)
+static void do_fsck(struct f2fs_sb_info *sbi)
{
u32 blk_cnt;
- int ret;
- ret = fsck_init(sbi);
- if (ret < 0)
- return ret;
+ fsck_init(sbi);
fsck_chk_orphan_node(sbi);
- /* Travses all block recursively from root inode */
+ /* Traverse all block recursively from root inode */
blk_cnt = 1;
- ret = fsck_chk_node_blk(sbi,
- NULL,
- sbi->root_ino_num,
- F2FS_FT_DIR,
- TYPE_INODE,
- &blk_cnt);
- if (ret < 0)
- goto out1;
-
- ret = fsck_verify(sbi);
-
-out1:
+ fsck_chk_node_blk(sbi, NULL, sbi->root_ino_num,
+ F2FS_FT_DIR, TYPE_INODE, &blk_cnt);
+ fsck_verify(sbi);
fsck_free(sbi);
- return ret;
}
-int do_dump(struct f2fs_sb_info *sbi)
+static void do_dump(struct f2fs_sb_info *sbi)
{
struct dump_option *opt = (struct dump_option *)config.private;
- int ret;
- ret = fsck_init(sbi);
- if (ret < 0)
- return ret;
+ fsck_init(sbi);
if (opt->end_sit == -1)
opt->end_sit = SM_I(sbi)->main_segments;
@@ -170,45 +176,76 @@ int do_dump(struct f2fs_sb_info *sbi)
dump_inode_from_blkaddr(sbi, opt->blk_addr);
goto cleanup;
}
-
dump_node(sbi, opt->nid);
-
cleanup:
fsck_free(sbi);
- return 0;
}
-int fsck_f2fs_main (int argc, char **argv)
+#ifndef ANDROID
+int main(int argc, char **argv)
+#else
+int fsck_f2fs_main(int argc, char **argv)
+#endif
{
- struct f2fs_sb_info *sbi = &gfsck.sbi;
+ struct f2fs_sb_info *sbi;
int ret = 0;
f2fs_init_configuration(&config);
f2fs_parse_options(argc, argv);
- /*
+#ifndef ANDROID
if (f2fs_dev_is_umounted(&config) < 0)
return -1;
- */
+#endif
/* Get device */
if (f2fs_get_device_info(&config) < 0)
return -1;
-
- if (f2fs_do_mount(sbi) < 0)
+fsck_again:
+ memset(&gfsck, 0, sizeof(gfsck));
+ gfsck.sbi.fsck = &gfsck;
+ sbi = &gfsck.sbi;
+
+ ret = f2fs_do_mount(sbi);
+ if (ret == 1) {
+ free(sbi->ckpt);
+ free(sbi->raw_super);
+ goto out;
+ } else if (ret < 0)
return -1;
switch (config.func) {
- case FSCK:
- ret = do_fsck(sbi);
- break;
- case DUMP:
- ret = do_dump(sbi);
- break;
+ case FSCK:
+ do_fsck(sbi);
+ break;
+ case DUMP:
+ do_dump(sbi);
+ break;
}
f2fs_do_umount(sbi);
+out:
+ if (config.func == FSCK && config.bug_on) {
+ if (config.fix_on == 0 && config.auto_fix == 0) {
+ char ans[255] = {0};
+retry:
+ printf("Do you want to fix this partition? [Y/N] ");
+ ret = scanf("%s", ans);
+ ASSERT(ret >= 0);
+ if (!strcasecmp(ans, "y"))
+ config.fix_on = 1;
+ else if (!strcasecmp(ans, "n"))
+ config.fix_on = 0;
+ else
+ goto retry;
+
+ if (config.fix_on)
+ goto fsck_again;
+ }
+ }
+ f2fs_finalize_device(&config);
+
printf("\nDone.\n");
- return ret;
+ return 0;
}
diff --git a/fsck/mount.c b/fsck/mount.c
index e2f3ace..415f977 100644
--- a/fsck/mount.c
+++ b/fsck/mount.c
@@ -12,7 +12,7 @@
void print_inode_info(struct f2fs_inode *inode)
{
- int i = 0;
+ unsigned int i = 0;
int namelen = le32_to_cpu(inode->i_namelen);
DISP_u32(inode, i_mode);
@@ -53,7 +53,7 @@ void print_inode_info(struct f2fs_inode *inode)
for (i = 4; i < ADDRS_PER_INODE(inode); i++) {
if (inode->i_addr[i] != 0x0) {
- printf("i_addr[0x%x] points data block\r\t\t\t\t[0x%4x]\n",
+ printf("i_addr[0x%x] points data block\r\t\t[0x%4x]\n",
i, inode->i_addr[i]);
break;
}
@@ -79,9 +79,11 @@ void print_node_info(struct f2fs_node *node_block)
} else {
int i;
u32 *dump_blk = (u32 *)node_block;
- DBG(0, "Node ID [0x%x:%u] is direct node or indirect node.\n", nid, nid);
+ DBG(0, "Node ID [0x%x:%u] is direct node or indirect node.\n",
+ nid, nid);
for (i = 0; i <= 10; i++)
- MSG(0, "[%d]\t\t\t[0x%8x : %d]\n", i, dump_blk[i], dump_blk[i]);
+ MSG(0, "[%d]\t\t\t[0x%8x : %d]\n",
+ i, dump_blk[i], dump_blk[i]);
}
}
@@ -129,6 +131,7 @@ void print_raw_sb_info(struct f2fs_sb_info *sbi)
DISP_u32(sb, root_ino);
DISP_u32(sb, node_ino);
DISP_u32(sb, meta_ino);
+ DISP_u32(sb, cp_payload);
printf("\n");
}
@@ -210,7 +213,8 @@ int sanity_check_raw_super(struct f2fs_super_block *raw_super)
return -1;
}
- if (F2FS_LOG_SECTORS_PER_BLOCK != le32_to_cpu(raw_super->log_sectors_per_block)) {
+ if (F2FS_LOG_SECTORS_PER_BLOCK !=
+ le32_to_cpu(raw_super->log_sectors_per_block)) {
return -1;
}
@@ -229,7 +233,7 @@ int validate_super_block(struct f2fs_sb_info *sbi, int block)
return 0;
free(sbi->raw_super);
- MSG(0, "\tCan't find a valid F2FS filesystem in %d superblock\n", block);
+ MSG(0, "\tCan't find a valid F2FS superblock at 0x%x\n", block);
return -EINVAL;
}
@@ -257,7 +261,8 @@ int init_sb_info(struct f2fs_sb_info *sbi)
return 0;
}
-void *validate_checkpoint(struct f2fs_sb_info *sbi, block_t cp_addr, unsigned long long *version)
+void *validate_checkpoint(struct f2fs_sb_info *sbi, block_t cp_addr,
+ unsigned long long *version)
{
void *cp_page_1, *cp_page_2;
struct f2fs_checkpoint *cp_block;
@@ -285,6 +290,7 @@ void *validate_checkpoint(struct f2fs_sb_info *sbi, block_t cp_addr, unsigned lo
/* Read the 2nd cp block in this CP pack */
cp_page_2 = malloc(PAGE_SIZE);
cp_addr += le32_to_cpu(cp_block->cp_pack_total_block_count) - 1;
+
if (dev_read_block(cp_page_2, cp_addr) < 0)
goto invalid_cp2;
@@ -295,7 +301,7 @@ void *validate_checkpoint(struct f2fs_sb_info *sbi, block_t cp_addr, unsigned lo
crc = *(unsigned int *)((unsigned char *)cp_block + crc_offset);
if (f2fs_crc_valid(crc, cp_block, crc_offset))
- goto invalid_cp1;
+ goto invalid_cp2;
cur_version = le64_to_cpu(cp_block->checkpoint_ver);
@@ -319,8 +325,10 @@ int get_valid_checkpoint(struct f2fs_sb_info *sbi)
unsigned long blk_size = sbi->blocksize;
unsigned long long cp1_version = 0, cp2_version = 0;
unsigned long long cp_start_blk_no;
+ unsigned int cp_blks = 1 + le32_to_cpu(F2FS_RAW_SUPER(sbi)->cp_payload);
+ int ret;
- sbi->ckpt = malloc(blk_size);
+ sbi->ckpt = malloc(cp_blks * blk_size);
if (!sbi->ckpt)
return -ENOMEM;
/*
@@ -335,14 +343,19 @@ int get_valid_checkpoint(struct f2fs_sb_info *sbi)
cp2 = validate_checkpoint(sbi, cp_start_blk_no, &cp2_version);
if (cp1 && cp2) {
- if (ver_after(cp2_version, cp1_version))
+ if (ver_after(cp2_version, cp1_version)) {
cur_page = cp2;
- else
+ sbi->cur_cp = 2;
+ } else {
cur_page = cp1;
+ sbi->cur_cp = 1;
+ }
} else if (cp1) {
cur_page = cp1;
+ sbi->cur_cp = 1;
} else if (cp2) {
cur_page = cp2;
+ sbi->cur_cp = 2;
} else {
free(cp1);
free(cp2);
@@ -351,6 +364,22 @@ int get_valid_checkpoint(struct f2fs_sb_info *sbi)
memcpy(sbi->ckpt, cur_page, blk_size);
+ if (cp_blks > 1) {
+ unsigned int i;
+ unsigned long long cp_blk_no;
+
+ cp_blk_no = le32_to_cpu(raw_sb->cp_blkaddr);
+ if (cur_page == cp2)
+ cp_blk_no += 1 <<
+ le32_to_cpu(raw_sb->log_blocks_per_seg);
+ /* copy sit bitmap */
+ for (i = 1; i < cp_blks; i++) {
+ unsigned char *ckpt = (unsigned char *)sbi->ckpt;
+ ret = dev_read_block(cur_page, cp_blk_no + i);
+ ASSERT(ret >= 0);
+ memcpy(ckpt + i * blk_size, cur_page, blk_size);
+ }
+ }
free(cp1);
free(cp2);
return 0;
@@ -470,199 +499,181 @@ int build_sit_info(struct f2fs_sb_info *sbi)
return 0;
}
-void reset_curseg(struct f2fs_sb_info *sbi, int type, int modified)
+void reset_curseg(struct f2fs_sb_info *sbi, int type)
{
struct curseg_info *curseg = CURSEG_I(sbi, type);
+ struct summary_footer *sum_footer;
+ struct seg_entry *se;
- curseg->segno = curseg->next_segno;
- curseg->zone = GET_ZONENO_FROM_SEGNO(sbi, curseg->segno);
- curseg->next_blkoff = 0;
- curseg->next_segno = NULL_SEGNO;
-
+ sum_footer = &(curseg->sum_blk->footer);
+ memset(sum_footer, 0, sizeof(struct summary_footer));
+ if (IS_DATASEG(type))
+ SET_SUM_TYPE(sum_footer, SUM_TYPE_DATA);
+ if (IS_NODESEG(type))
+ SET_SUM_TYPE(sum_footer, SUM_TYPE_NODE);
+ se = get_seg_entry(sbi, curseg->segno);
+ se->type = type;
}
-int read_compacted_summaries(struct f2fs_sb_info *sbi)
+static void read_compacted_summaries(struct f2fs_sb_info *sbi)
{
- struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
struct curseg_info *curseg;
+ unsigned int i, j, offset;
block_t start;
char *kaddr;
- unsigned int i, j, offset;
+ int ret;
start = start_sum_block(sbi);
kaddr = (char *)malloc(PAGE_SIZE);
- dev_read_block(kaddr, start++);
+ ret = dev_read_block(kaddr, start++);
+ ASSERT(ret >= 0);
curseg = CURSEG_I(sbi, CURSEG_HOT_DATA);
memcpy(&curseg->sum_blk->n_nats, kaddr, SUM_JOURNAL_SIZE);
curseg = CURSEG_I(sbi, CURSEG_COLD_DATA);
- memcpy(&curseg->sum_blk->n_sits, kaddr + SUM_JOURNAL_SIZE, SUM_JOURNAL_SIZE);
+ memcpy(&curseg->sum_blk->n_sits, kaddr + SUM_JOURNAL_SIZE,
+ SUM_JOURNAL_SIZE);
offset = 2 * SUM_JOURNAL_SIZE;
for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_DATA; i++) {
unsigned short blk_off;
- unsigned int segno;
+ struct curseg_info *curseg = CURSEG_I(sbi, i);
- curseg = CURSEG_I(sbi, i);
- segno = le32_to_cpu(ckpt->cur_data_segno[i]);
- blk_off = le16_to_cpu(ckpt->cur_data_blkoff[i]);
- curseg->next_segno = segno;
- reset_curseg(sbi, i, 0);
- curseg->alloc_type = ckpt->alloc_type[i];
- curseg->next_blkoff = blk_off;
+ reset_curseg(sbi, i);
if (curseg->alloc_type == SSR)
blk_off = sbi->blocks_per_seg;
+ else
+ blk_off = curseg->next_blkoff;
for (j = 0; j < blk_off; j++) {
struct f2fs_summary *s;
s = (struct f2fs_summary *)(kaddr + offset);
curseg->sum_blk->entries[j] = *s;
offset += SUMMARY_SIZE;
- if (offset + SUMMARY_SIZE <= PAGE_CACHE_SIZE - SUM_FOOTER_SIZE)
+ if (offset + SUMMARY_SIZE <=
+ PAGE_CACHE_SIZE - SUM_FOOTER_SIZE)
continue;
memset(kaddr, 0, PAGE_SIZE);
- dev_read_block(kaddr, start++);
+ ret = dev_read_block(kaddr, start++);
+ ASSERT(ret >= 0);
offset = 0;
}
}
-
free(kaddr);
- return 0;
}
-int restore_node_summary(struct f2fs_sb_info *sbi,
+static void restore_node_summary(struct f2fs_sb_info *sbi,
unsigned int segno, struct f2fs_summary_block *sum_blk)
{
struct f2fs_node *node_blk;
struct f2fs_summary *sum_entry;
- void *page;
block_t addr;
- int i;
+ unsigned int i;
+ int ret;
- page = malloc(PAGE_SIZE);
- if (!page)
- return -ENOMEM;
+ node_blk = malloc(F2FS_BLKSIZE);
+ ASSERT(node_blk);
/* scan the node segment */
addr = START_BLOCK(sbi, segno);
sum_entry = &sum_blk->entries[0];
for (i = 0; i < sbi->blocks_per_seg; i++, sum_entry++) {
- if (dev_read_block(page, addr))
- goto out;
-
- node_blk = (struct f2fs_node *)page;
+ ret = dev_read_block(node_blk, addr);
+ ASSERT(ret >= 0);
sum_entry->nid = node_blk->footer.nid;
- /* do not change original value */
-#if 0
- sum_entry->version = 0;
- sum_entry->ofs_in_node = 0;
-#endif
addr++;
-
}
-out:
- free(page);
- return 0;
+ free(node_blk);
}
-int read_normal_summaries(struct f2fs_sb_info *sbi, int type)
+static void read_normal_summaries(struct f2fs_sb_info *sbi, int type)
{
struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
struct f2fs_summary_block *sum_blk;
struct curseg_info *curseg;
- unsigned short blk_off;
unsigned int segno = 0;
block_t blk_addr = 0;
+ int ret;
if (IS_DATASEG(type)) {
segno = le32_to_cpu(ckpt->cur_data_segno[type]);
- blk_off = le16_to_cpu(ckpt->cur_data_blkoff[type - CURSEG_HOT_DATA]);
-
if (is_set_ckpt_flags(ckpt, CP_UMOUNT_FLAG))
blk_addr = sum_blk_addr(sbi, NR_CURSEG_TYPE, type);
else
blk_addr = sum_blk_addr(sbi, NR_CURSEG_DATA_TYPE, type);
} else {
- segno = le32_to_cpu(ckpt->cur_node_segno[type - CURSEG_HOT_NODE]);
- blk_off = le16_to_cpu(ckpt->cur_node_blkoff[type - CURSEG_HOT_NODE]);
-
+ segno = le32_to_cpu(ckpt->cur_node_segno[type -
+ CURSEG_HOT_NODE]);
if (is_set_ckpt_flags(ckpt, CP_UMOUNT_FLAG))
- blk_addr = sum_blk_addr(sbi, NR_CURSEG_NODE_TYPE, type - CURSEG_HOT_NODE);
+ blk_addr = sum_blk_addr(sbi, NR_CURSEG_NODE_TYPE,
+ type - CURSEG_HOT_NODE);
else
blk_addr = GET_SUM_BLKADDR(sbi, segno);
}
sum_blk = (struct f2fs_summary_block *)malloc(PAGE_SIZE);
- dev_read_block(sum_blk, blk_addr);
-
- if (IS_NODESEG(type)) {
- if (is_set_ckpt_flags(ckpt, CP_UMOUNT_FLAG)) {
- struct f2fs_summary *sum_entry = &sum_blk->entries[0];
- int i;
- for (i = 0; i < sbi->blocks_per_seg; i++, sum_entry++) {
- /* do not change original value */
-#if 0
- sum_entry->version = 0;
- sum_entry->ofs_in_node = 0;
-#endif
- }
- } else {
- if (restore_node_summary(sbi, segno, sum_blk)) {
- free(sum_blk);
- return -EINVAL;
- }
- }
- }
+ ret = dev_read_block(sum_blk, blk_addr);
+ ASSERT(ret >= 0);
+
+ if (IS_NODESEG(type) && !is_set_ckpt_flags(ckpt, CP_UMOUNT_FLAG))
+ restore_node_summary(sbi, segno, sum_blk);
curseg = CURSEG_I(sbi, type);
memcpy(curseg->sum_blk, sum_blk, PAGE_CACHE_SIZE);
- curseg->next_segno = segno;
- reset_curseg(sbi, type, 0);
- curseg->alloc_type = ckpt->alloc_type[type];
- curseg->next_blkoff = blk_off;
+ reset_curseg(sbi, type);
free(sum_blk);
-
- return 0;
}
-int restore_curseg_summaries(struct f2fs_sb_info *sbi)
+static void restore_curseg_summaries(struct f2fs_sb_info *sbi)
{
int type = CURSEG_HOT_DATA;
if (is_set_ckpt_flags(F2FS_CKPT(sbi), CP_COMPACT_SUM_FLAG)) {
- if (read_compacted_summaries(sbi))
- return -EINVAL;
+ read_compacted_summaries(sbi);
type = CURSEG_HOT_NODE;
}
- for (; type <= CURSEG_COLD_NODE; type++) {
- if (read_normal_summaries(sbi, type))
- return -EINVAL;
- }
- return 0;
+ for (; type <= CURSEG_COLD_NODE; type++)
+ read_normal_summaries(sbi, type);
}
-int build_curseg(struct f2fs_sb_info *sbi)
+static void build_curseg(struct f2fs_sb_info *sbi)
{
+ struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
struct curseg_info *array;
+ unsigned short blk_off;
+ unsigned int segno;
int i;
array = malloc(sizeof(*array) * NR_CURSEG_TYPE);
+ ASSERT(array);
SM_I(sbi)->curseg_array = array;
for (i = 0; i < NR_CURSEG_TYPE; i++) {
array[i].sum_blk = malloc(PAGE_CACHE_SIZE);
- if (!array[i].sum_blk)
- return -ENOMEM;
- array[i].segno = NULL_SEGNO;
- array[i].next_blkoff = 0;
+ ASSERT(array[i].sum_blk);
+ if (i <= CURSEG_COLD_DATA) {
+ blk_off = le16_to_cpu(ckpt->cur_data_blkoff[i]);
+ segno = le32_to_cpu(ckpt->cur_data_segno[i]);
+ }
+ if (i > CURSEG_COLD_DATA) {
+ blk_off = le16_to_cpu(ckpt->cur_node_blkoff[i -
+ CURSEG_HOT_NODE]);
+ segno = le32_to_cpu(ckpt->cur_node_segno[i -
+ CURSEG_HOT_NODE]);
+ }
+ array[i].segno = segno;
+ array[i].zone = GET_ZONENO_FROM_SEGNO(sbi, segno);
+ array[i].next_segno = NULL_SEGNO;
+ array[i].next_blkoff = blk_off;
+ array[i].alloc_type = ckpt->alloc_type[i];
}
- return restore_curseg_summaries(sbi);
+ restore_curseg_summaries(sbi);
}
inline void check_seg_range(struct f2fs_sb_info *sbi, unsigned int segno)
@@ -671,12 +682,14 @@ inline void check_seg_range(struct f2fs_sb_info *sbi, unsigned int segno)
ASSERT(segno <= end_segno);
}
-struct f2fs_sit_block *get_current_sit_page(struct f2fs_sb_info *sbi, unsigned int segno)
+static struct f2fs_sit_block *get_current_sit_page(struct f2fs_sb_info *sbi,
+ unsigned int segno)
{
struct sit_info *sit_i = SIT_I(sbi);
unsigned int offset = SIT_BLOCK_OFFSET(sit_i, segno);
block_t blk_addr = sit_i->sit_base_addr + offset;
struct f2fs_sit_block *sit_blk = calloc(BLOCK_SZ, 1);
+ int ret;
check_seg_range(sbi, segno);
@@ -684,30 +697,56 @@ struct f2fs_sit_block *get_current_sit_page(struct f2fs_sb_info *sbi, unsigned i
if (f2fs_test_bit(offset, sit_i->sit_bitmap))
blk_addr += sit_i->sit_blocks;
- dev_read_block(sit_blk, blk_addr);
+ ret = dev_read_block(sit_blk, blk_addr);
+ ASSERT(ret >= 0);
return sit_blk;
}
+void rewrite_current_sit_page(struct f2fs_sb_info *sbi,
+ unsigned int segno, struct f2fs_sit_block *sit_blk)
+{
+ struct sit_info *sit_i = SIT_I(sbi);
+ unsigned int offset = SIT_BLOCK_OFFSET(sit_i, segno);
+ block_t blk_addr = sit_i->sit_base_addr + offset;
+ int ret;
+
+ /* calculate sit block address */
+ if (f2fs_test_bit(offset, sit_i->sit_bitmap))
+ blk_addr += sit_i->sit_blocks;
+
+ ret = dev_write_block(sit_blk, blk_addr);
+ ASSERT(ret >= 0);
+}
+
void check_block_count(struct f2fs_sb_info *sbi,
- int segno, struct f2fs_sit_entry *raw_sit)
+ unsigned int segno, struct f2fs_sit_entry *raw_sit)
{
struct f2fs_sm_info *sm_info = SM_I(sbi);
unsigned int end_segno = sm_info->segment_count - 1;
int valid_blocks = 0;
- int i;
+ unsigned int i;
/* check segment usage */
- ASSERT(GET_SIT_VBLOCKS(raw_sit) <= sbi->blocks_per_seg);
+ if (GET_SIT_VBLOCKS(raw_sit) > sbi->blocks_per_seg)
+ ASSERT_MSG("Invalid SIT vblocks: segno=0x%x, %u",
+ segno, GET_SIT_VBLOCKS(raw_sit));
/* check boundary of a given segment number */
- ASSERT(segno <= end_segno);
+ if (segno > end_segno)
+ ASSERT_MSG("Invalid SEGNO: 0x%x", segno);
/* check bitmap with valid block count */
- for (i = 0; i < sbi->blocks_per_seg; i++)
- if (f2fs_test_bit(i, (char *)raw_sit->valid_map))
- valid_blocks++;
- ASSERT(GET_SIT_VBLOCKS(raw_sit) == valid_blocks);
+ for (i = 0; i < SIT_VBLOCK_MAP_SIZE; i++)
+ valid_blocks += get_bits_in_byte(raw_sit->valid_map[i]);
+
+ if (GET_SIT_VBLOCKS(raw_sit) != valid_blocks)
+ ASSERT_MSG("Wrong SIT valid blocks: segno=0x%x, %u vs. %u",
+ segno, GET_SIT_VBLOCKS(raw_sit), valid_blocks);
+
+ if (GET_SIT_TYPE(raw_sit) >= NO_CHECK_TYPE)
+ ASSERT_MSG("Wrong SIT type: segno=0x%x, %u",
+ segno, GET_SIT_TYPE(raw_sit));
}
void seg_info_from_raw_sit(struct seg_entry *se,
@@ -728,7 +767,8 @@ struct seg_entry *get_seg_entry(struct f2fs_sb_info *sbi,
return &sit_i->sentries[segno];
}
-int get_sum_block(struct f2fs_sb_info *sbi, unsigned int segno, struct f2fs_summary_block *sum_blk)
+int get_sum_block(struct f2fs_sb_info *sbi, unsigned int segno,
+ struct f2fs_summary_block *sum_blk)
{
struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
struct curseg_info *curseg;
@@ -739,18 +779,30 @@ int get_sum_block(struct f2fs_sb_info *sbi, unsigned int segno, struct f2fs_summ
for (type = 0; type < NR_CURSEG_NODE_TYPE; type++) {
if (segno == ckpt->cur_node_segno[type]) {
curseg = CURSEG_I(sbi, CURSEG_HOT_NODE + type);
+ if (!IS_SUM_NODE_SEG(curseg->sum_blk->footer)) {
+ ASSERT_MSG("segno [0x%x] indicates a data "
+ "segment, but should be node",
+ segno);
+ return -EINVAL;
+ }
memcpy(sum_blk, curseg->sum_blk, BLOCK_SZ);
- return SEG_TYPE_CUR_NODE; /* current node seg was not stored */
+ return SEG_TYPE_CUR_NODE;
}
}
for (type = 0; type < NR_CURSEG_DATA_TYPE; type++) {
if (segno == ckpt->cur_data_segno[type]) {
curseg = CURSEG_I(sbi, type);
+ if (IS_SUM_NODE_SEG(curseg->sum_blk->footer)) {
+ ASSERT_MSG("segno [0x%x] indicates a node "
+ "segment, but should be data",
+ segno);
+ return -EINVAL;
+ }
+ DBG(2, "segno [0x%x] is current data seg[0x%x]\n",
+ segno, type);
memcpy(sum_blk, curseg->sum_blk, BLOCK_SZ);
- ASSERT(!IS_SUM_NODE_SEG(sum_blk->footer));
- DBG(2, "segno [0x%x] is current data seg[0x%x]\n", segno, type);
- return SEG_TYPE_CUR_DATA; /* current data seg was not stored */
+ return SEG_TYPE_CUR_DATA;
}
}
@@ -764,7 +816,8 @@ int get_sum_block(struct f2fs_sb_info *sbi, unsigned int segno, struct f2fs_summ
}
-int get_sum_entry(struct f2fs_sb_info *sbi, u32 blk_addr, struct f2fs_summary *sum_entry)
+int get_sum_entry(struct f2fs_sb_info *sbi, u32 blk_addr,
+ struct f2fs_summary *sum_entry)
{
struct f2fs_summary_block *sum_blk;
u32 segno, offset;
@@ -776,16 +829,15 @@ int get_sum_entry(struct f2fs_sb_info *sbi, u32 blk_addr, struct f2fs_summary *s
sum_blk = calloc(BLOCK_SZ, 1);
ret = get_sum_block(sbi, segno, sum_blk);
-
- memcpy(sum_entry, &(sum_blk->entries[offset]), sizeof(struct f2fs_summary));
-
+ memcpy(sum_entry, &(sum_blk->entries[offset]),
+ sizeof(struct f2fs_summary));
free(sum_blk);
return ret;
}
-int get_nat_entry(struct f2fs_sb_info *sbi, nid_t nid, struct f2fs_nat_entry *raw_nat)
+static void get_nat_entry(struct f2fs_sb_info *sbi, nid_t nid,
+ struct f2fs_nat_entry *raw_nat)
{
- struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
struct f2fs_nm_info *nm_i = NM_I(sbi);
struct f2fs_nat_block *nat_block;
pgoff_t block_off;
@@ -793,13 +845,8 @@ int get_nat_entry(struct f2fs_sb_info *sbi, nid_t nid, struct f2fs_nat_entry *ra
int seg_off, entry_off;
int ret;
- if ((nid / NAT_ENTRY_PER_BLOCK) > fsck->nr_nat_entries) {
- DBG(0, "nid is over max nid\n");
- return -EINVAL;
- }
-
if (lookup_nat_in_journal(sbi, nid, raw_nat) >= 0)
- return 0;
+ return;
nat_block = (struct f2fs_nat_block *)calloc(BLOCK_SZ, 1);
@@ -817,21 +864,17 @@ int get_nat_entry(struct f2fs_sb_info *sbi, nid_t nid, struct f2fs_nat_entry *ra
ret = dev_read_block(nat_block, block_addr);
ASSERT(ret >= 0);
- memcpy(raw_nat, &nat_block->entries[entry_off], sizeof(struct f2fs_nat_entry));
+ memcpy(raw_nat, &nat_block->entries[entry_off],
+ sizeof(struct f2fs_nat_entry));
free(nat_block);
-
- return 0;
}
-int get_node_info(struct f2fs_sb_info *sbi, nid_t nid, struct node_info *ni)
+void get_node_info(struct f2fs_sb_info *sbi, nid_t nid, struct node_info *ni)
{
struct f2fs_nat_entry raw_nat;
- int ret;
-
- ret = get_nat_entry(sbi, nid, &raw_nat);
+ get_nat_entry(sbi, nid, &raw_nat);
ni->nid = nid;
node_info_from_raw_nat(ni, &raw_nat);
- return ret;
}
void build_sit_entries(struct f2fs_sb_info *sbi)
@@ -892,17 +935,14 @@ int build_segment_manager(struct f2fs_sb_info *sbi)
return 0;
}
-int build_sit_area_bitmap(struct f2fs_sb_info *sbi)
+void build_sit_area_bitmap(struct f2fs_sb_info *sbi)
{
struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
struct f2fs_sm_info *sm_i = SM_I(sbi);
- int segno = 0, j = 0;
+ unsigned int segno = 0;
char *ptr = NULL;
-
u32 sum_vblocks = 0;
u32 free_segs = 0;
- u32 vblocks = 0;
-
struct seg_entry *se;
fsck->sit_area_bitmap_sz = sm_i->main_segments * SIT_VBLOCK_MAP_SIZE;
@@ -911,20 +951,13 @@ int build_sit_area_bitmap(struct f2fs_sb_info *sbi)
ASSERT(fsck->sit_area_bitmap_sz == fsck->main_area_bitmap_sz);
- for (segno = 0; segno < sm_i->main_segments; segno++) {
+ for (segno = 0; segno < TOTAL_SEGS(sbi); segno++) {
se = get_seg_entry(sbi, segno);
memcpy(ptr, se->cur_valid_map, SIT_VBLOCK_MAP_SIZE);
ptr += SIT_VBLOCK_MAP_SIZE;
- vblocks = 0;
- for (j = 0; j < SIT_VBLOCK_MAP_SIZE; j++) {
- vblocks += get_bits_in_byte(se->cur_valid_map[j]);
- }
- ASSERT(vblocks == se->valid_blocks);
-
if (se->valid_blocks == 0x0) {
-
if (sbi->ckpt->cur_node_segno[0] == segno ||
sbi->ckpt->cur_data_segno[0] == segno ||
sbi->ckpt->cur_node_segno[1] == segno ||
@@ -935,22 +968,76 @@ int build_sit_area_bitmap(struct f2fs_sb_info *sbi)
} else {
free_segs++;
}
-
} else {
- ASSERT(se->valid_blocks <= 512);
sum_vblocks += se->valid_blocks;
}
}
-
fsck->chk.sit_valid_blocks = sum_vblocks;
fsck->chk.sit_free_segs = free_segs;
- DBG(1, "Blocks [0x%x : %d] Free Segs [0x%x : %d]\n\n", sum_vblocks, sum_vblocks,
+ DBG(1, "Blocks [0x%x : %d] Free Segs [0x%x : %d]\n\n",
+ sum_vblocks, sum_vblocks,
free_segs, free_segs);
- return 0;
}
-int lookup_nat_in_journal(struct f2fs_sb_info *sbi, u32 nid, struct f2fs_nat_entry *raw_nat)
+void rewrite_sit_area_bitmap(struct f2fs_sb_info *sbi)
+{
+ struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
+ struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_COLD_DATA);
+ struct sit_info *sit_i = SIT_I(sbi);
+ unsigned int segno = 0;
+ struct f2fs_summary_block *sum = curseg->sum_blk;
+ char *ptr = NULL;
+
+ /* remove sit journal */
+ sum->n_sits = 0;
+
+ fsck->chk.free_segs = 0;
+
+ ptr = fsck->main_area_bitmap;
+
+ for (segno = 0; segno < TOTAL_SEGS(sbi); segno++) {
+ struct f2fs_sit_block *sit_blk;
+ struct f2fs_sit_entry *sit;
+ struct seg_entry *se;
+ u16 valid_blocks = 0;
+ u16 type;
+ int i;
+
+ sit_blk = get_current_sit_page(sbi, segno);
+ sit = &sit_blk->entries[SIT_ENTRY_OFFSET(sit_i, segno)];
+ memcpy(sit->valid_map, ptr, SIT_VBLOCK_MAP_SIZE);
+
+ /* update valid block count */
+ for (i = 0; i < SIT_VBLOCK_MAP_SIZE; i++)
+ valid_blocks += get_bits_in_byte(sit->valid_map[i]);
+
+ se = get_seg_entry(sbi, segno);
+ type = se->type;
+ if (type >= NO_CHECK_TYPE) {
+ ASSERT(valid_blocks);
+ type = 0;
+ }
+ sit->vblocks = cpu_to_le16((type << SIT_VBLOCKS_SHIFT) |
+ valid_blocks);
+ rewrite_current_sit_page(sbi, segno, sit_blk);
+ free(sit_blk);
+
+ if (valid_blocks == 0 &&
+ sbi->ckpt->cur_node_segno[0] != segno &&
+ sbi->ckpt->cur_data_segno[0] != segno &&
+ sbi->ckpt->cur_node_segno[1] != segno &&
+ sbi->ckpt->cur_data_segno[1] != segno &&
+ sbi->ckpt->cur_node_segno[2] != segno &&
+ sbi->ckpt->cur_data_segno[2] != segno)
+ fsck->chk.free_segs++;
+
+ ptr += SIT_VBLOCK_MAP_SIZE;
+ }
+}
+
+int lookup_nat_in_journal(struct f2fs_sb_info *sbi, u32 nid,
+ struct f2fs_nat_entry *raw_nat)
{
struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_HOT_DATA);
struct f2fs_summary_block *sum = curseg->sum_blk;
@@ -958,7 +1045,8 @@ int lookup_nat_in_journal(struct f2fs_sb_info *sbi, u32 nid, struct f2fs_nat_ent
for (i = 0; i < nats_in_cursum(sum); i++) {
if (le32_to_cpu(nid_in_journal(sum, i)) == nid) {
- memcpy(raw_nat, &nat_in_journal(sum, i), sizeof(struct f2fs_nat_entry));
+ memcpy(raw_nat, &nat_in_journal(sum, i),
+ sizeof(struct f2fs_nat_entry));
DBG(3, "==> Found nid [0x%x] in nat cache\n", nid);
return i;
}
@@ -966,6 +1054,51 @@ int lookup_nat_in_journal(struct f2fs_sb_info *sbi, u32 nid, struct f2fs_nat_ent
return -1;
}
+void nullify_nat_entry(struct f2fs_sb_info *sbi, u32 nid)
+{
+ struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_HOT_DATA);
+ struct f2fs_summary_block *sum = curseg->sum_blk;
+ struct f2fs_nm_info *nm_i = NM_I(sbi);
+ struct f2fs_nat_block *nat_block;
+ pgoff_t block_off;
+ pgoff_t block_addr;
+ int seg_off, entry_off;
+ int ret;
+ int i = 0;
+
+ /* check in journal */
+ for (i = 0; i < nats_in_cursum(sum); i++) {
+ if (le32_to_cpu(nid_in_journal(sum, i)) == nid) {
+ memset(&nat_in_journal(sum, i), 0,
+ sizeof(struct f2fs_nat_entry));
+ FIX_MSG("Remove nid [0x%x] in nat journal\n", nid);
+ return;
+ }
+ }
+ nat_block = (struct f2fs_nat_block *)calloc(BLOCK_SZ, 1);
+
+ block_off = nid / NAT_ENTRY_PER_BLOCK;
+ entry_off = nid % NAT_ENTRY_PER_BLOCK;
+
+ seg_off = block_off >> sbi->log_blocks_per_seg;
+ block_addr = (pgoff_t)(nm_i->nat_blkaddr +
+ (seg_off << sbi->log_blocks_per_seg << 1) +
+ (block_off & ((1 << sbi->log_blocks_per_seg) - 1)));
+
+ if (f2fs_test_bit(block_off, nm_i->nat_bitmap))
+ block_addr += sbi->blocks_per_seg;
+
+ ret = dev_read_block(nat_block, block_addr);
+ ASSERT(ret >= 0);
+
+ memset(&nat_block->entries[entry_off], 0,
+ sizeof(struct f2fs_nat_entry));
+
+ ret = dev_write_block(nat_block, block_addr);
+ ASSERT(ret >= 0);
+ free(nat_block);
+}
+
void build_nat_area_bitmap(struct f2fs_sb_info *sbi)
{
struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
@@ -973,17 +1106,18 @@ void build_nat_area_bitmap(struct f2fs_sb_info *sbi)
struct f2fs_nm_info *nm_i = NM_I(sbi);
struct f2fs_nat_block *nat_block;
u32 nid, nr_nat_blks;
-
pgoff_t block_off;
pgoff_t block_addr;
int seg_off;
- int ret, i;
-
+ int ret;
+ unsigned int i;
nat_block = (struct f2fs_nat_block *)calloc(BLOCK_SZ, 1);
+ ASSERT(nat_block);
/* Alloc & build nat entry bitmap */
- nr_nat_blks = (le32_to_cpu(raw_sb->segment_count_nat) / 2) << sbi->log_blocks_per_seg;
+ nr_nat_blks = (le32_to_cpu(raw_sb->segment_count_nat) / 2) <<
+ sbi->log_blocks_per_seg;
fsck->nr_nat_entries = nr_nat_blks * NAT_ENTRY_PER_BLOCK;
fsck->nat_area_bitmap_sz = (fsck->nr_nat_entries + 7) / 8;
@@ -994,8 +1128,8 @@ void build_nat_area_bitmap(struct f2fs_sb_info *sbi)
seg_off = block_off >> sbi->log_blocks_per_seg;
block_addr = (pgoff_t)(nm_i->nat_blkaddr +
- (seg_off << sbi->log_blocks_per_seg << 1) +
- (block_off & ((1 << sbi->log_blocks_per_seg) - 1)));
+ (seg_off << sbi->log_blocks_per_seg << 1) +
+ (block_off & ((1 << sbi->log_blocks_per_seg) - 1)));
if (f2fs_test_bit(block_off, nm_i->nat_bitmap))
block_addr += sbi->blocks_per_seg;
@@ -1009,44 +1143,47 @@ void build_nat_area_bitmap(struct f2fs_sb_info *sbi)
struct node_info ni;
ni.nid = nid + i;
- if ((nid + i) == F2FS_NODE_INO(sbi) || (nid + i) == F2FS_META_INO(sbi)) {
+ if ((nid + i) == F2FS_NODE_INO(sbi) ||
+ (nid + i) == F2FS_META_INO(sbi)) {
ASSERT(nat_block->entries[i].block_addr != 0x0);
continue;
}
- if (lookup_nat_in_journal(sbi, nid + i, &raw_nat) >= 0) {
+ if (lookup_nat_in_journal(sbi, nid + i,
+ &raw_nat) >= 0) {
node_info_from_raw_nat(&ni, &raw_nat);
if (ni.blk_addr != 0x0) {
- f2fs_set_bit(nid + i, fsck->nat_area_bitmap);
+ f2fs_set_bit(nid + i,
+ fsck->nat_area_bitmap);
fsck->chk.valid_nat_entry_cnt++;
- DBG(3, "nid[0x%x] in nat cache\n", nid + i);
+ DBG(3, "nid[0x%x] in nat cache\n",
+ nid + i);
}
} else {
- node_info_from_raw_nat(&ni, &nat_block->entries[i]);
- if (ni.blk_addr != 0) {
- ASSERT(nid + i != 0x0);
-
- DBG(3, "nid[0x%8x] in nat entry [0x%16x] [0x%8x]\n",
- nid + i,
- ni.blk_addr,
- ni.ino);
-
- f2fs_set_bit(nid + i, fsck->nat_area_bitmap);
- fsck->chk.valid_nat_entry_cnt++;
- }
+ node_info_from_raw_nat(&ni,
+ &nat_block->entries[i]);
+ if (ni.blk_addr == 0)
+ continue;
+ ASSERT(nid + i != 0x0);
+
+ DBG(3, "nid[0x%8x] addr[0x%16x] ino[0x%8x]\n",
+ nid + i, ni.blk_addr, ni.ino);
+ f2fs_set_bit(nid + i, fsck->nat_area_bitmap);
+ fsck->chk.valid_nat_entry_cnt++;
}
}
}
free(nat_block);
DBG(1, "valid nat entries (block_addr != 0x0) [0x%8x : %u]\n",
- fsck->chk.valid_nat_entry_cnt, fsck->chk.valid_nat_entry_cnt);
-
+ fsck->chk.valid_nat_entry_cnt,
+ fsck->chk.valid_nat_entry_cnt);
}
int f2fs_do_mount(struct f2fs_sb_info *sbi)
{
int ret;
+
sbi->active_logs = NR_CURSEG_TYPE;
ret = validate_super_block(sbi, 0);
if (ret) {
@@ -1072,10 +1209,23 @@ int f2fs_do_mount(struct f2fs_sb_info *sbi)
print_ckpt_info(sbi);
+ if (config.auto_fix) {
+ u32 flag = le32_to_cpu(sbi->ckpt->ckpt_flags);
+
+ if (flag & CP_FSCK_FLAG)
+ config.fix_on = 1;
+ else
+ return 1;
+ }
+
+ config.bug_on = 0;
+
sbi->total_valid_node_count = le32_to_cpu(sbi->ckpt->valid_node_count);
- sbi->total_valid_inode_count = le32_to_cpu(sbi->ckpt->valid_inode_count);
+ sbi->total_valid_inode_count =
+ le32_to_cpu(sbi->ckpt->valid_inode_count);
sbi->user_block_count = le64_to_cpu(sbi->ckpt->user_block_count);
- sbi->total_valid_block_count = le64_to_cpu(sbi->ckpt->valid_block_count);
+ sbi->total_valid_block_count =
+ le64_to_cpu(sbi->ckpt->valid_block_count);
sbi->last_valid_block_count = sbi->total_valid_block_count;
sbi->alloc_valid_block_count = 0;
@@ -1089,7 +1239,7 @@ int f2fs_do_mount(struct f2fs_sb_info *sbi)
return -1;
}
- return ret;
+ return 0;
}
void f2fs_do_umount(struct f2fs_sb_info *sbi)
@@ -1097,7 +1247,7 @@ void f2fs_do_umount(struct f2fs_sb_info *sbi)
struct sit_info *sit_i = SIT_I(sbi);
struct f2fs_sm_info *sm_i = SM_I(sbi);
struct f2fs_nm_info *nm_i = NM_I(sbi);
- int i;
+ unsigned int i;
/* free nm_info */
free(nm_i->nat_bitmap);
diff --git a/include/f2fs_fs.h b/include/f2fs_fs.h
index 3f39676..8b744aa 100644
--- a/include/f2fs_fs.h
+++ b/include/f2fs_fs.h
@@ -4,9 +4,7 @@
* Copyright (c) 2012 Samsung Electronics Co., Ltd.
* http://www.samsung.com/
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
+ * Dual licensed under the GPL or LGPL version 2 licenses.
*/
#ifndef __F2FS_FS_H__
#define __F2FS_FS_H__
@@ -14,11 +12,13 @@
#include <inttypes.h>
#include <linux/types.h>
#include <sys/types.h>
-#include <endian.h>
-#include <byteswap.h>
#ifdef HAVE_CONFIG_H
#include <config.h>
+#else
+#ifdef ANDROID
+#include "include/f2fs_version.h"
+#endif
#endif
typedef u_int64_t u64;
@@ -58,37 +58,39 @@ typedef unsigned long pgoff_t;
/*
* Debugging interfaces
*/
-#define ASSERT_MSG(exp, fmt, ...) \
+#define FIX_MSG(fmt, ...) \
do { \
- if (!(exp)) { \
- printf("\nAssertion failed!\n"); \
- printf("[%s:%4d] " #exp, __func__, __LINE__); \
- printf("\n --> "fmt, ##__VA_ARGS__); \
- exit(-1); \
- } \
- } while (0);
+ printf("[FIX] (%s:%4d) ", __func__, __LINE__); \
+ printf(" --> "fmt"\n", ##__VA_ARGS__); \
+ } while (0)
+
+#define ASSERT_MSG(fmt, ...) \
+ do { \
+ printf("[ASSERT] (%s:%4d) ", __func__, __LINE__); \
+ printf(" --> "fmt"\n", ##__VA_ARGS__); \
+ config.bug_on = 1; \
+ } while (0)
#define ASSERT(exp) \
do { \
if (!(exp)) { \
- printf("\nAssertion failed!\n"); \
- printf("[%s:%4d] " #exp"\n", __func__, __LINE__);\
+ printf("[ASSERT] (%s:%4d) " #exp"\n", \
+ __func__, __LINE__); \
exit(-1); \
} \
- } while (0);
+ } while (0)
#define ERR_MSG(fmt, ...) \
do { \
- printf("[%s:%d] " fmt, __func__, __LINE__, ##__VA_ARGS__); \
- } while (0);
-
+ printf("[%s:%d] " fmt, __func__, __LINE__, ##__VA_ARGS__); \
+ } while (0)
#define MSG(n, fmt, ...) \
do { \
if (config.dbg_lv >= n) { \
printf(fmt, ##__VA_ARGS__); \
} \
- } while (0);
+ } while (0)
#define DBG(n, fmt, ...) \
do { \
@@ -96,55 +98,57 @@ typedef unsigned long pgoff_t;
printf("[%s:%4d] " fmt, \
__func__, __LINE__, ##__VA_ARGS__); \
} \
- } while (0);
+ } while (0)
/* Display on console */
#define DISP(fmt, ptr, member) \
do { \
printf("%-30s" fmt, #member, ((ptr)->member)); \
- } while (0);
+ } while (0)
#define DISP_u32(ptr, member) \
do { \
assert(sizeof((ptr)->member) <= 4); \
printf("%-30s" "\t\t[0x%8x : %u]\n", \
- #member, ((ptr)->member), ((ptr)->member) ); \
- } while (0);
+ #member, ((ptr)->member), ((ptr)->member)); \
+ } while (0)
#define DISP_u64(ptr, member) \
do { \
assert(sizeof((ptr)->member) == 8); \
printf("%-30s" "\t\t[0x%8llx : %llu]\n", \
- #member, ((ptr)->member), ((ptr)->member) ); \
- } while (0);
+ #member, ((ptr)->member), ((ptr)->member)); \
+ } while (0)
#define DISP_utf(ptr, member) \
do { \
- printf("%-30s" "\t\t[%s]\n", #member, ((ptr)->member) ); \
- } while (0);
+ printf("%-30s" "\t\t[%s]\n", #member, ((ptr)->member)); \
+ } while (0)
/* Display to buffer */
-#define BUF_DISP_u32(buf, data, len, ptr, member) \
- do { \
- assert(sizeof((ptr)->member) <= 4); \
- snprintf(buf, len, #member); \
- snprintf(data, len, "0x%x : %u", ((ptr)->member), ((ptr)->member)); \
- } while (0);
-
-#define BUF_DISP_u64(buf, data, len, ptr, member) \
- do { \
- assert(sizeof((ptr)->member) == 8); \
- snprintf(buf, len, #member); \
- snprintf(data, len, "0x%llx : %llu", ((ptr)->member), ((ptr)->member)); \
- } while (0);
-
-#define BUF_DISP_utf(buf, data, len, ptr, member) \
- do { \
- snprintf(buf, len, #member); \
- } while (0);
+#define BUF_DISP_u32(buf, data, len, ptr, member) \
+ do { \
+ assert(sizeof((ptr)->member) <= 4); \
+ snprintf(buf, len, #member); \
+ snprintf(data, len, "0x%x : %u", ((ptr)->member), \
+ ((ptr)->member)); \
+ } while (0)
+
+#define BUF_DISP_u64(buf, data, len, ptr, member) \
+ do { \
+ assert(sizeof((ptr)->member) == 8); \
+ snprintf(buf, len, #member); \
+ snprintf(data, len, "0x%llx : %llu", ((ptr)->member), \
+ ((ptr)->member)); \
+ } while (0)
+
+#define BUF_DISP_utf(buf, data, len, ptr, member) \
+ snprintf(buf, len, #member)
/* these are defined in kernel */
-// #define PAGE_SIZE 4096
+#ifndef PAGE_SIZE
+#define PAGE_SIZE 4096
+#endif
#define PAGE_CACHE_SIZE 4096
#define BITS_PER_BYTE 8
#define F2FS_SUPER_MAGIC 0xF2F52010 /* F2FS Magic Number */
@@ -177,12 +181,16 @@ struct f2fs_configuration {
char *vol_label;
int heap;
int32_t fd;
+ int32_t dump_fd;
char *device_name;
char *extension_list;
int dbg_lv;
int trim;
int func;
void *private;
+ int fix_on;
+ int bug_on;
+ int auto_fix;
} __attribute__((packed));
#ifdef CONFIG_64BIT
@@ -225,6 +233,7 @@ enum {
#define F2FS_LOG_SECTORS_PER_BLOCK 3 /* 4KB: F2FS_BLKSIZE */
#define F2FS_BLKSIZE 4096 /* support only 4KB block */
#define F2FS_MAX_EXTENSION 64 /* # of extension entries */
+#define F2FS_BLK_ALIGN(x) (((x) + F2FS_BLKSIZE - 1) / F2FS_BLKSIZE)
#define NULL_ADDR 0x0U
#define NEW_ADDR -1U
@@ -281,11 +290,13 @@ struct f2fs_super_block {
__le16 volume_name[512]; /* volume name */
__le32 extension_count; /* # of extensions below */
__u8 extension_list[F2FS_MAX_EXTENSION][8]; /* extension array */
+ __le32 cp_payload;
} __attribute__((packed));
/*
* For checkpoint
*/
+#define CP_FSCK_FLAG 0x00000010
#define CP_ERROR_FLAG 0x00000008
#define CP_COMPACT_SUM_FLAG 0x00000004
#define CP_ORPHAN_PRESENT_FLAG 0x00000002
@@ -366,6 +377,8 @@ struct f2fs_extent {
#define INLINE_DATA_OFFSET (PAGE_CACHE_SIZE - sizeof(struct node_footer) \
- sizeof(__le32)*(DEF_ADDRS_PER_INODE + 5 - 1))
+#define DEF_DIR_LEVEL 0
+
struct f2fs_inode {
__le16 i_mode; /* file mode */
__u8 i_advise; /* file hints */
@@ -388,7 +401,7 @@ struct f2fs_inode {
__le32 i_pino; /* parent inode number */
__le32 i_namelen; /* file name length */
__u8 i_name[F2FS_NAME_LEN]; /* file name for SPOR */
- __u8 i_reserved2; /* for backward compatibility */
+ __u8 i_dir_level; /* dentry_level for large dir */
struct f2fs_extent i_ext; /* caching a largest extent */
@@ -413,6 +426,9 @@ enum {
OFFSET_BIT_SHIFT
};
+#define XATTR_NODE_OFFSET ((((unsigned int)-1) << OFFSET_BIT_SHIFT) \
+ >> OFFSET_BIT_SHIFT)
+
struct node_footer {
__le32 nid; /* node id */
__le32 ino; /* inode nunmber */
@@ -457,6 +473,13 @@ struct f2fs_nat_block {
#define SIT_ENTRY_PER_BLOCK (PAGE_CACHE_SIZE / sizeof(struct f2fs_sit_entry))
/*
+ * F2FS uses 4 bytes to represent block address. As a result, supported size of
+ * disk is 16 TB and it equals to 16 * 1024 * 1024 / 2 segments.
+ */
+#define F2FS_MAX_SEGMENT ((16 * 1024 * 1024) / 2)
+#define MAX_SIT_BITMAP_SIZE ((F2FS_MAX_SEGMENT / SIT_ENTRY_PER_BLOCK) / 8)
+
+/*
* Note that f2fs_sit_entry->vblocks has the following bit-field information.
* [15:10] : allocation type such as CURSEG_XXXX_TYPE
* [9:0] : valid block count
@@ -633,6 +656,7 @@ enum FILE_TYPE {
F2FS_FT_MAX,
/* added for fsck */
F2FS_FT_ORPHAN,
+ F2FS_FT_XATTR,
};
/* from f2fs/segment.h */
@@ -652,22 +676,30 @@ extern int test_bit(unsigned int nr, const void * addr);
extern int f2fs_test_bit(unsigned int, const char *);
extern int f2fs_set_bit(unsigned int, char *);
extern int f2fs_clear_bit(unsigned int, char *);
-extern unsigned long find_next_bit(const unsigned long *, unsigned long, unsigned long);
+extern unsigned long find_next_bit(const unsigned long *,
+ unsigned long, unsigned long);
extern u_int32_t f2fs_cal_crc32(u_int32_t, void *, int);
extern int f2fs_crc_valid(u_int32_t blk_crc, void *buf, int len);
extern void f2fs_init_configuration(struct f2fs_configuration *);
+#ifndef ANDROID
extern int f2fs_dev_is_umounted(struct f2fs_configuration *);
+#endif
extern int f2fs_get_device_info(struct f2fs_configuration *);
+extern void f2fs_finalize_device(struct f2fs_configuration *);
extern int dev_read(void *, __u64, size_t);
extern int dev_write(void *, __u64, size_t);
+extern int dev_write_block(void *, __u64);
+extern int dev_write_dump(void *, __u64, size_t);
+/* All bytes in the buffer must be 0 use dev_fill(). */
+extern int dev_fill(void *, __u64, size_t);
extern int dev_read_block(void *, __u64);
extern int dev_read_blocks(void *, __u64, __u32 );
-f2fs_hash_t f2fs_dentry_hash(const char *, int);
+f2fs_hash_t f2fs_dentry_hash(const unsigned char *, int);
extern struct f2fs_configuration config;
diff --git a/include/f2fs_version.h b/include/f2fs_version.h
index dfd15b4..9a10fb8 100644
--- a/include/f2fs_version.h
+++ b/include/f2fs_version.h
@@ -1,5 +1,4 @@
#define F2FS_MAJOR_VERSION 1
-#define F2FS_MINOR_VERSION 3
-#define F2FS_TOOLS_VERSION "1.3.0"
-#define F2FS_TOOLS_DATE "2014-02-06"
-
+#define F2FS_MINOR_VERSION 4
+#define F2FS_TOOLS_VERSION "1.4.0"
+#define F2FS_TOOLS_DATE "2014-09-18"
diff --git a/include/list.h b/include/list.h
index b1b1ca3..571cd5c 100644
--- a/include/list.h
+++ b/include/list.h
@@ -1,9 +1,11 @@
#define POISON_POINTER_DELTA 0
-#define LIST_POISON1 ((void *) 0x00100100 + POISON_POINTER_DELTA)
-#define LIST_POISON2 ((void *) 0x00200200 + POISON_POINTER_DELTA)
+#define LIST_POISON1 ((void *) (0x00100100 + POISON_POINTER_DELTA))
+#define LIST_POISON2 ((void *) (0x00200200 + POISON_POINTER_DELTA))
+#if !defined(offsetof)
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+#endif
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 6498df9..a6b304c 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -2,6 +2,6 @@
lib_LTLIBRARIES = libf2fs.la
-libf2fs_la_SOURCES = libf2fs.c
+libf2fs_la_SOURCES = libf2fs.c libf2fs_io.c
libf2fs_la_CFLAGS = -Wall
libf2fs_la_CPPFLAGS = -I$(top_srcdir)/include
diff --git a/lib/libf2fs.c b/lib/libf2fs.c
index 7753ab7..651138e 100644
--- a/lib/libf2fs.c
+++ b/lib/libf2fs.c
@@ -4,9 +4,7 @@
* Copyright (c) 2013 Samsung Electronics Co., Ltd.
* http://www.samsung.com/
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
+ * Dual licensed under the GPL or LGPL version 2 licenses.
*/
#define _LARGEFILE64_SOURCE
@@ -22,11 +20,12 @@
#include <sys/mount.h>
#include <sys/ioctl.h>
#include <linux/hdreg.h>
-#include <linux/fs.h>
+#ifndef ANDROID
+#include <f2fs_fs.h>
+#else
#include "include/f2fs_fs.h"
-
-struct f2fs_configuration config;
+#endif
void ASCIIToUNICODE(u_int16_t *out_buf, u_int8_t *in_buf)
{
@@ -240,7 +239,8 @@ static void TEA_transform(unsigned int buf[4], unsigned int const in[])
}
-static void str2hashbuf(const char *msg, int len, unsigned int *buf, int num)
+static void str2hashbuf(const unsigned char *msg, int len,
+ unsigned int *buf, int num)
{
unsigned pad, val;
int i;
@@ -274,24 +274,17 @@ static void str2hashbuf(const char *msg, int len, unsigned int *buf, int num)
* @param len name lenth
* @return return on success hash value, errno on failure
*/
-f2fs_hash_t f2fs_dentry_hash(const char *name, int len)
+f2fs_hash_t f2fs_dentry_hash(const unsigned char *name, int len)
{
__u32 hash;
f2fs_hash_t f2fs_hash;
- const char *p;
+ const unsigned char *p;
__u32 in[8], buf[4];
/* special hash codes for special dentries */
- if (name[0] == '.') {
- if (name[1] == '\0') {
- f2fs_hash = F2FS_DOT_HASH;
- goto exit;
- }
- if (name[1] == '.' && name[2] == '\0') {
- f2fs_hash = F2FS_DDOT_HASH;
- goto exit;
- }
- }
+ if ((len <= 2) && (name[0] == '.') &&
+ (name[1] == '.' || name[1] == '\0'))
+ return 0;
/* Initialize the default seed for the hash checksum functions */
buf[0] = 0x67452301;
@@ -300,18 +293,17 @@ f2fs_hash_t f2fs_dentry_hash(const char *name, int len)
buf[3] = 0x10325476;
p = name;
- while (len > 0) {
+ while (1) {
str2hashbuf(p, len, in, 4);
TEA_transform(buf, in);
- len -= 16;
p += 16;
+ if (len <= 16)
+ break;
+ len -= 16;
}
hash = buf[0];
- f2fs_hash = hash;
-exit:
- f2fs_hash &= ~F2FS_HASH_COL_BIT;
-
+ f2fs_hash = cpu_to_le32(hash & ~F2FS_HASH_COL_BIT);
return f2fs_hash;
}
@@ -346,8 +338,8 @@ int f2fs_crc_valid(u_int32_t blk_crc, void *buf, int len)
cal_crc = f2fs_cal_crc32(F2FS_SUPER_MAGIC, buf, len);
if (cal_crc != blk_crc) {
- DBG(0,"CRC validation failed: cal_crc = %u \
- blk_crc = %u buff_size = 0x%x",
+ DBG(0,"CRC validation failed: cal_crc = %u, "
+ "blk_crc = %u buff_size = 0x%x\n",
cal_crc, blk_crc, len);
return -1;
}
@@ -359,6 +351,7 @@ int f2fs_crc_valid(u_int32_t blk_crc, void *buf, int len)
*/
void f2fs_init_configuration(struct f2fs_configuration *c)
{
+ c->total_sectors = 0;
c->sector_size = DEFAULT_SECTOR_SIZE;
c->sectors_per_blk = DEFAULT_SECTORS_PER_BLOCK;
c->blks_per_seg = DEFAULT_BLOCKS_PER_SEGMENT;
@@ -374,7 +367,7 @@ void f2fs_init_configuration(struct f2fs_configuration *c)
c->trim = 1;
}
-#if 0
+#ifndef ANDROID
static int is_mounted(const char *mpt, const char *device)
{
FILE *file = NULL;
@@ -434,9 +427,10 @@ int f2fs_dev_is_umounted(struct f2fs_configuration *c)
int f2fs_get_device_info(struct f2fs_configuration *c)
{
int32_t fd = 0;
- int32_t sector_size;
+ uint32_t sector_size;
struct stat stat_buf;
struct hd_geometry geom;
+ u_int64_t wanted_total_sectors = c->total_sectors;
fd = open(c->device_name, O_RDWR);
if (fd < 0) {
@@ -479,7 +473,12 @@ int f2fs_get_device_info(struct f2fs_configuration *c)
MSG(0, "\tError: Volume type is not supported!!!\n");
return -1;
}
+ if (wanted_total_sectors && wanted_total_sectors < c->total_sectors) {
+ MSG(0, "Info: total device sectors = %"PRIu64" (in 512bytes)\n",
+ c->total_sectors);
+ c->total_sectors = wanted_total_sectors;
+ }
MSG(0, "Info: sector size = %u\n", c->sector_size);
MSG(0, "Info: total sectors = %"PRIu64" (in 512bytes)\n",
c->total_sectors);
@@ -493,33 +492,3 @@ int f2fs_get_device_info(struct f2fs_configuration *c)
return 0;
}
-/*
- * IO interfaces
- */
-int dev_read(void *buf, __u64 offset, size_t len)
-{
- if (lseek64(config.fd, (off64_t)offset, SEEK_SET) < 0)
- return -1;
- if (read(config.fd, buf, len) < 0)
- return -1;
- return 0;
-}
-
-int dev_write(void *buf, __u64 offset, size_t len)
-{
- if (lseek64(config.fd, (off64_t)offset, SEEK_SET) < 0)
- return -1;
- if (write(config.fd, buf, len) < 0)
- return -1;
- return 0;
-}
-
-int dev_read_block(void *buf, __u64 blk_addr)
-{
- return dev_read(buf, blk_addr * F2FS_BLKSIZE, F2FS_BLKSIZE);
-}
-
-int dev_read_blocks(void *buf, __u64 addr, __u32 nr_blks)
-{
- return dev_read(buf, addr * F2FS_BLKSIZE, nr_blks * F2FS_BLKSIZE);
-}
diff --git a/lib/libf2fs_io.c b/lib/libf2fs_io.c
new file mode 100644
index 0000000..7cd71de
--- /dev/null
+++ b/lib/libf2fs_io.c
@@ -0,0 +1,100 @@
+/**
+ * libf2fs.c
+ *
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * Dual licensed under the GPL or LGPL version 2 licenses.
+ */
+#define _LARGEFILE64_SOURCE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <mntent.h>
+#include <time.h>
+#include <sys/stat.h>
+#include <sys/mount.h>
+#include <sys/ioctl.h>
+#include <linux/hdreg.h>
+
+#ifndef ANDROID
+#include <f2fs_fs.h>
+#else
+#include "include/f2fs_fs.h"
+#endif
+
+struct f2fs_configuration config;
+
+/*
+ * IO interfaces
+ */
+int dev_read(void *buf, __u64 offset, size_t len)
+{
+ if (lseek64(config.fd, (off64_t)offset, SEEK_SET) < 0)
+ return -1;
+ if (read(config.fd, buf, len) < 0)
+ return -1;
+ return 0;
+}
+
+int dev_write(void *buf, __u64 offset, size_t len)
+{
+ if (lseek64(config.fd, (off64_t)offset, SEEK_SET) < 0)
+ return -1;
+ if (write(config.fd, buf, len) < 0)
+ return -1;
+ return 0;
+}
+
+int dev_write_block(void *buf, __u64 blk_addr)
+{
+ return dev_write(buf, blk_addr * F2FS_BLKSIZE, F2FS_BLKSIZE);
+}
+
+int dev_write_dump(void *buf, __u64 offset, size_t len)
+{
+ if (lseek64(config.dump_fd, (off64_t)offset, SEEK_SET) < 0)
+ return -1;
+ if (write(config.dump_fd, buf, len) < 0)
+ return -1;
+ return 0;
+}
+
+int dev_fill(void *buf, __u64 offset, size_t len)
+{
+ /* Only allow fill to zero */
+ if (*((__u8*)buf))
+ return -1;
+ if (lseek64(config.fd, (off64_t)offset, SEEK_SET) < 0)
+ return -1;
+ if (write(config.fd, buf, len) < 0)
+ return -1;
+ return 0;
+}
+
+int dev_read_block(void *buf, __u64 blk_addr)
+{
+ return dev_read(buf, blk_addr * F2FS_BLKSIZE, F2FS_BLKSIZE);
+}
+
+int dev_read_blocks(void *buf, __u64 addr, __u32 nr_blks)
+{
+ return dev_read(buf, addr * F2FS_BLKSIZE, nr_blks * F2FS_BLKSIZE);
+}
+
+void f2fs_finalize_device(struct f2fs_configuration *c)
+{
+ /*
+ * We should call fsync() to flush out all the dirty pages
+ * in the block device page cache.
+ */
+ if (fsync(c->fd) < 0)
+ MSG(0, "\tError: Could not conduct fsync!!!\n");
+
+ if (close(c->fd) < 0)
+ MSG(0, "\tError: Failed to close device file!!!\n");
+}
diff --git a/mkfs/Makefile.am b/mkfs/Makefile.am
index 79cbec2..fa48699 100644
--- a/mkfs/Makefile.am
+++ b/mkfs/Makefile.am
@@ -1,7 +1,7 @@
## Makefile.am
AM_CPPFLAGS = ${libuuid_CFLAGS} -I$(top_srcdir)/include
-AM_CFLAGS = -Wall
+AM_CFLAGS = -Wall -DWITH_BLKDISCARD
sbin_PROGRAMS = mkfs.f2fs
-mkfs_f2fs_SOURCES = f2fs_format.c f2fs_format_utils.c
+mkfs_f2fs_SOURCES = f2fs_format_main.c f2fs_format.c f2fs_format_utils.c
mkfs_f2fs_LDADD = ${libuuid_LIBS} $(top_builddir)/lib/libf2fs.la
diff --git a/mkfs/f2fs_format.c b/mkfs/f2fs_format.c
index 3dd534c..e09baf5 100644
--- a/mkfs/f2fs_format.c
+++ b/mkfs/f2fs_format.c
@@ -4,9 +4,7 @@
* Copyright (c) 2012 Samsung Electronics Co., Ltd.
* http://www.samsung.com/
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
+ * Dual licensed under the GPL or LGPL version 2 licenses.
*/
#define _LARGEFILE64_SOURCE
@@ -18,131 +16,19 @@
#include <sys/stat.h>
#include <sys/mount.h>
#include <time.h>
-#include <linux/fs.h>
-//#include <uuid/uuid.h>
+#ifndef ANDROID
+#include <uuid/uuid.h>
+#include "f2fs_fs.h"
+#else
#include "include/f2fs_fs.h"
-#include "f2fs_format_utils.h"
+#endif
-#define BLKDISCARD _IO(0x12,119)
+#include "f2fs_format_utils.h"
extern struct f2fs_configuration config;
struct f2fs_super_block super_block;
-/*
- This generates a version 4 universally unique identifier (UUID).
- The format is: xxxxxxxx-xxxx-4xxx-8xxx-xxxxxxxxxxxx
- where each x is 4 bits populated by /dev/urandom.
- The algorithm is derived from Theodore T'so's original e2fsprogs source.
-
- 16 bytes will be written to the passed pointer, so allocate
- at least that much space before calling uuid_generate.
-*/
-#define RANDOM "/dev/urandom"
-void uuid_generate(unsigned char *uuid)
-{
- int fd;
-
- fd = open(RANDOM, O_RDONLY);
- if(-1 == fd)
- {
- perror("Error while opening " RANDOM);
- return;
- }
-
- if(16 != read(fd, uuid, 16))
- {
- perror("Error while reading from " RANDOM);
- }
-
- uuid[6] &= 0x0F;
- uuid[6] |= 0x40;
-
- uuid[8] &= 0x3F;
- uuid[8] |= 0x80;
-
- close(fd);
-}
-
-static void mkfs_usage()
-{
- MSG(0, "\nUsage: mkfs.f2fs [options] device\n");
- MSG(0, "[options]:\n");
- MSG(0, " -a heap-based allocation [default:1]\n");
- MSG(0, " -d debug level [default:0]\n");
- MSG(0, " -e [extension list] e.g. \"mp3,gif,mov\"\n");
- MSG(0, " -l label\n");
- MSG(0, " -o overprovision ratio [default:5]\n");
- MSG(0, " -s # of segments per section [default:1]\n");
- MSG(0, " -z # of sections per zone [default:1]\n");
- MSG(0, " -t 0: nodiscard, 1: discard [default:1]\n");
- exit(1);
-}
-
-static void f2fs_parse_options(int argc, char *argv[])
-{
- static const char *option_string = "a:d:e:l:o:s:z:t:";
- int32_t option=0;
-
- while ((option = getopt(argc,argv,option_string)) != EOF) {
- switch (option) {
- case 'a':
- config.heap = atoi(optarg);
- if (config.heap == 0)
- MSG(0, "Info: Disable heap-based policy\n");
- break;
- case 'd':
- config.dbg_lv = atoi(optarg);
- MSG(0, "Info: Debug level = %d\n", config.dbg_lv);
- break;
- case 'e':
- config.extension_list = strdup(optarg);
- MSG(0, "Info: Add new extension list\n");
- break;
- case 'l': /*v: volume label */
- if (strlen(optarg) > 512) {
- MSG(0, "Error: Volume Label should be less than\
- 512 characters\n");
- mkfs_usage();
- }
- config.vol_label = optarg;
- MSG(0, "Info: Label = %s\n", config.vol_label);
- break;
- case 'o':
- config.overprovision = atoi(optarg);
- MSG(0, "Info: Overprovision ratio = %u%%\n",
- atoi(optarg));
- break;
- case 's':
- config.segs_per_sec = atoi(optarg);
- MSG(0, "Info: Segments per section = %d\n",
- atoi(optarg));
- break;
- case 'z':
- config.secs_per_zone = atoi(optarg);
- MSG(0, "Info: Sections per zone = %d\n", atoi(optarg));
- break;
- case 't':
- config.trim = atoi(optarg);
- MSG(0, "Info: Trim is %s\n", config.trim ? "enabled": "disabled");
- break;
- default:
- mkfs_usage();
- break;
- }
- }
-
- if ((optind + 1) != argc) {
- MSG(0, "\tError: Device not specified\n");
- mkfs_usage();
- }
-
- config.reserved_segments =
- (2 * (100 / config.overprovision + 1) + 6)
- * config.segs_per_sec;
- config.device_name = argv[optind];
-}
-
const char *media_ext_lists[] = {
"jpg",
"gif",
@@ -190,7 +76,7 @@ static void configure_extension_list(void)
memcpy(super_block.extension_list[i++], *extlist, name_len);
extlist++;
}
- super_block.extension_count = i - 1;
+ super_block.extension_count = i;
if (!ext_str)
return;
@@ -201,15 +87,52 @@ static void configure_extension_list(void)
name_len = strlen(ue);
memcpy(super_block.extension_list[i++], ue, name_len);
ue = strtok(NULL, ",");
- if (i > F2FS_MAX_EXTENSION)
+ if (i >= F2FS_MAX_EXTENSION)
break;
}
- super_block.extension_count = i - 1;
+ super_block.extension_count = i;
free(config.extension_list);
}
+#ifdef ANDROID
+/*
+ This generates a version 4 universally unique identifier (UUID).
+ The format is: xxxxxxxx-xxxx-4xxx-8xxx-xxxxxxxxxxxx
+ where each x is 4 bits populated by /dev/urandom.
+ The algorithm is derived from Theodore T'so's original e2fsprogs source.
+
+ 16 bytes will be written to the passed pointer, so allocate
+ at least that much space before calling uuid_generate.
+*/
+#define RANDOM "/dev/urandom"
+void uuid_generate(unsigned char *uuid)
+{
+ int fd;
+
+ fd = open(RANDOM, O_RDONLY);
+ if(-1 == fd)
+ {
+ perror("Error while opening " RANDOM);
+ return;
+ }
+
+ if(16 != read(fd, uuid, 16))
+ {
+ perror("Error while reading from " RANDOM);
+ }
+
+ uuid[6] &= 0x0F;
+ uuid[6] |= 0x40;
+
+ uuid[8] &= 0x3F;
+ uuid[8] |= 0x80;
+
+ close(fd);
+}
+#endif
+
static int f2fs_prepare_super_block(void)
{
u_int32_t blk_size_bytes;
@@ -220,7 +143,8 @@ static int f2fs_prepare_super_block(void)
u_int32_t blocks_for_sit, blocks_for_nat, blocks_for_ssa;
u_int32_t total_valid_blks_available;
u_int64_t zone_align_start_offset, diff, total_meta_segments;
- u_int32_t sit_bitmap_size, max_nat_bitmap_size, max_nat_segments;
+ u_int32_t sit_bitmap_size, max_sit_bitmap_size;
+ u_int32_t max_nat_bitmap_size, max_nat_segments;
u_int32_t total_zones;
super_block.magic = cpu_to_le32(F2FS_SUPER_MAGIC);
@@ -233,30 +157,11 @@ static int f2fs_prepare_super_block(void)
log_blks_per_seg = log_base_2(config.blks_per_seg);
super_block.log_sectorsize = cpu_to_le32(log_sectorsize);
-
- if (log_sectorsize < 0) {
- MSG(1, "\tError: Failed to get the sector size: %u!\n",
- config.sector_size);
- return -1;
- }
-
super_block.log_sectors_per_block = cpu_to_le32(log_sectors_per_block);
- if (log_sectors_per_block < 0) {
- MSG(1, "\tError: Failed to get sectors per block: %u!\n",
- config.sectors_per_blk);
- return -1;
- }
-
super_block.log_blocksize = cpu_to_le32(log_blocksize);
super_block.log_blocks_per_seg = cpu_to_le32(log_blks_per_seg);
- if (log_blks_per_seg < 0) {
- MSG(1, "\tError: Failed to get block per segment: %u!\n",
- config.blks_per_seg);
- return -1;
- }
-
super_block.segs_per_sec = cpu_to_le32(config.segs_per_sec);
super_block.secs_per_zone = cpu_to_le32(config.secs_per_zone);
blk_size_bytes = 1 << log_blocksize;
@@ -335,8 +240,26 @@ static int f2fs_prepare_super_block(void)
*/
sit_bitmap_size = ((le32_to_cpu(super_block.segment_count_sit) / 2) <<
log_blks_per_seg) / 8;
- max_nat_bitmap_size = CHECKSUM_OFFSET - sizeof(struct f2fs_checkpoint) + 1 -
- sit_bitmap_size;
+
+ if (sit_bitmap_size > MAX_SIT_BITMAP_SIZE)
+ max_sit_bitmap_size = MAX_SIT_BITMAP_SIZE;
+ else
+ max_sit_bitmap_size = sit_bitmap_size;
+
+ /*
+ * It should be reserved minimum 1 segment for nat.
+ * When sit is too large, we should expand cp area. It requires more pages for cp.
+ */
+ if (max_sit_bitmap_size >
+ (CHECKSUM_OFFSET - sizeof(struct f2fs_checkpoint) + 65)) {
+ max_nat_bitmap_size = CHECKSUM_OFFSET - sizeof(struct f2fs_checkpoint) + 1;
+ super_block.cp_payload = F2FS_BLK_ALIGN(max_sit_bitmap_size);
+ } else {
+ max_nat_bitmap_size = CHECKSUM_OFFSET - sizeof(struct f2fs_checkpoint) + 1
+ - max_sit_bitmap_size;
+ super_block.cp_payload = 0;
+ }
+
max_nat_segments = (max_nat_bitmap_size * 8) >> log_blks_per_seg;
if (le32_to_cpu(super_block.segment_count_nat) > max_nat_segments)
@@ -492,10 +415,11 @@ static int f2fs_init_sit_area(void)
sit_seg_addr = le32_to_cpu(super_block.sit_blkaddr);
sit_seg_addr *= blk_size;
+ DBG(1, "\tFilling sit area at offset 0x%08"PRIx64"\n", sit_seg_addr);
for (index = 0;
index < (le32_to_cpu(super_block.segment_count_sit) / 2);
index++) {
- if (dev_write(zero_buf, sit_seg_addr, seg_size)) {
+ if (dev_fill(zero_buf, sit_seg_addr, seg_size)) {
MSG(1, "\tError: While zeroing out the sit area \
on disk!!!\n");
return -1;
@@ -527,10 +451,11 @@ static int f2fs_init_nat_area(void)
nat_seg_addr = le32_to_cpu(super_block.nat_blkaddr);
nat_seg_addr *= blk_size;
+ DBG(1, "\tFilling nat area at offset 0x%08"PRIx64"\n", nat_seg_addr);
for (index = 0;
index < (le32_to_cpu(super_block.segment_count_nat) / 2);
index++) {
- if (dev_write(nat_buf, nat_seg_addr, seg_size)) {
+ if (dev_fill(nat_buf, nat_seg_addr, seg_size)) {
MSG(1, "\tError: While zeroing out the nat area \
on disk!!!\n");
return -1;
@@ -549,7 +474,8 @@ static int f2fs_write_check_point_pack(void)
u_int32_t blk_size_bytes;
u_int64_t cp_seg_blk_offset = 0;
u_int32_t crc = 0;
- int i;
+ unsigned int i;
+ char *cp_payload = NULL;
ckp = calloc(F2FS_BLKSIZE, 1);
if (ckp == NULL) {
@@ -563,6 +489,12 @@ static int f2fs_write_check_point_pack(void)
return -1;
}
+ cp_payload = calloc(F2FS_BLKSIZE, 1);
+ if (cp_payload == NULL) {
+ MSG(1, "\tError: Calloc Failed for cp_payload!!!\n");
+ return -1;
+ }
+
/* 1. cp page 1 of checkpoint pack 1 */
ckp->checkpoint_ver = cpu_to_le64(1);
ckp->cur_node_segno[0] =
@@ -601,13 +533,14 @@ static int f2fs_write_check_point_pack(void)
((le32_to_cpu(ckp->free_segment_count) + 6 -
le32_to_cpu(ckp->overprov_segment_count)) *
config.blks_per_seg));
- ckp->cp_pack_total_block_count = cpu_to_le32(8);
+ ckp->cp_pack_total_block_count =
+ cpu_to_le32(8 + le32_to_cpu(super_block.cp_payload));
ckp->ckpt_flags = cpu_to_le32(CP_UMOUNT_FLAG);
- ckp->cp_pack_start_sum = cpu_to_le32(1);
+ ckp->cp_pack_start_sum = cpu_to_le32(1 + le32_to_cpu(super_block.cp_payload));
ckp->valid_node_count = cpu_to_le32(1);
ckp->valid_inode_count = cpu_to_le32(1);
- ckp->next_free_nid = cpu_to_le32(0xc00000);
-
+ ckp->next_free_nid = cpu_to_le32(
+ le32_to_cpu(super_block.root_ino) + 1);
ckp->sit_ver_bitmap_bytesize = cpu_to_le32(
((le32_to_cpu(super_block.segment_count_sit) / 2) <<
le32_to_cpu(super_block.log_blocks_per_seg)) / 8);
@@ -626,11 +559,21 @@ static int f2fs_write_check_point_pack(void)
cp_seg_blk_offset = le32_to_cpu(super_block.segment0_blkaddr);
cp_seg_blk_offset *= blk_size_bytes;
- if (dev_write(ckp, cp_seg_blk_offset, F2FS_BLKSIZE)) {
+ DBG(1, "\tWriting main segments, ckp at offset 0x%08"PRIx64"\n", cp_seg_blk_offset);
+ if (dev_write(ckp, cp_seg_blk_offset, blk_size_bytes)) {
MSG(1, "\tError: While writing the ckp to disk!!!\n");
return -1;
}
+ for (i = 0; i < le32_to_cpu(super_block.cp_payload); i++) {
+ cp_seg_blk_offset += blk_size_bytes;
+ if (dev_fill(cp_payload, cp_seg_blk_offset, blk_size_bytes)) {
+ MSG(1, "\tError: While zeroing out the sit bitmap area \
+ on disk!!!\n");
+ return -1;
+ }
+ }
+
/* 2. Prepare and write Segment summary for data blocks */
memset(sum, 0, sizeof(struct f2fs_summary_block));
SET_SUM_TYPE((&sum->footer), SUM_TYPE_DATA);
@@ -639,7 +582,8 @@ static int f2fs_write_check_point_pack(void)
sum->entries[0].ofs_in_node = 0;
cp_seg_blk_offset += blk_size_bytes;
- if (dev_write(sum, cp_seg_blk_offset, F2FS_BLKSIZE)) {
+ DBG(1, "\tWriting segment summary for data, ckp at offset 0x%08"PRIx64"\n", cp_seg_blk_offset);
+ if (dev_write(sum, cp_seg_blk_offset, blk_size_bytes)) {
MSG(1, "\tError: While writing the sum_blk to disk!!!\n");
return -1;
}
@@ -649,7 +593,8 @@ static int f2fs_write_check_point_pack(void)
SET_SUM_TYPE((&sum->footer), SUM_TYPE_DATA);
cp_seg_blk_offset += blk_size_bytes;
- if (dev_write(sum, cp_seg_blk_offset, F2FS_BLKSIZE)) {
+ DBG(1, "\tWriting segment summary, ckp at offset 0x%08"PRIx64"\n", cp_seg_blk_offset);
+ if (dev_write(sum, cp_seg_blk_offset, blk_size_bytes)) {
MSG(1, "\tError: While writing the sum_blk to disk!!!\n");
return -1;
}
@@ -678,7 +623,8 @@ static int f2fs_write_check_point_pack(void)
sum->sit_j.entries[5].se.vblocks = cpu_to_le16((CURSEG_COLD_DATA << 10));
cp_seg_blk_offset += blk_size_bytes;
- if (dev_write(sum, cp_seg_blk_offset, F2FS_BLKSIZE)) {
+ DBG(1, "\tWriting data sit for root, at offset 0x%08"PRIx64"\n", cp_seg_blk_offset);
+ if (dev_write(sum, cp_seg_blk_offset, blk_size_bytes)) {
MSG(1, "\tError: While writing the sum_blk to disk!!!\n");
return -1;
}
@@ -691,7 +637,8 @@ static int f2fs_write_check_point_pack(void)
sum->entries[0].ofs_in_node = 0;
cp_seg_blk_offset += blk_size_bytes;
- if (dev_write(sum, cp_seg_blk_offset, F2FS_BLKSIZE)) {
+ DBG(1, "\tWriting Segment summary for node blocks, at offset 0x%08"PRIx64"\n", cp_seg_blk_offset);
+ if (dev_write(sum, cp_seg_blk_offset, blk_size_bytes)) {
MSG(1, "\tError: While writing the sum_blk to disk!!!\n");
return -1;
}
@@ -701,7 +648,8 @@ static int f2fs_write_check_point_pack(void)
SET_SUM_TYPE((&sum->footer), SUM_TYPE_NODE);
cp_seg_blk_offset += blk_size_bytes;
- if (dev_write(sum, cp_seg_blk_offset, F2FS_BLKSIZE)) {
+ DBG(1, "\tWriting Segment summary for data block (1/2), at offset 0x%08"PRIx64"\n", cp_seg_blk_offset);
+ if (dev_write(sum, cp_seg_blk_offset, blk_size_bytes)) {
MSG(1, "\tError: While writing the sum_blk to disk!!!\n");
return -1;
}
@@ -710,14 +658,16 @@ static int f2fs_write_check_point_pack(void)
memset(sum, 0, sizeof(struct f2fs_summary_block));
SET_SUM_TYPE((&sum->footer), SUM_TYPE_NODE);
cp_seg_blk_offset += blk_size_bytes;
- if (dev_write(sum, cp_seg_blk_offset, F2FS_BLKSIZE)) {
+ DBG(1, "\tWriting Segment summary for data block (2/2), at offset 0x%08"PRIx64"\n", cp_seg_blk_offset);
+ if (dev_write(sum, cp_seg_blk_offset, blk_size_bytes)) {
MSG(1, "\tError: While writing the sum_blk to disk!!!\n");
return -1;
}
/* 8. cp page2 */
cp_seg_blk_offset += blk_size_bytes;
- if (dev_write(ckp, cp_seg_blk_offset, F2FS_BLKSIZE)) {
+ DBG(1, "\tWriting cp page2, at offset 0x%08"PRIx64"\n", cp_seg_blk_offset);
+ if (dev_write(ckp, cp_seg_blk_offset, blk_size_bytes)) {
MSG(1, "\tError: While writing the ckp to disk!!!\n");
return -1;
}
@@ -733,20 +683,33 @@ static int f2fs_write_check_point_pack(void)
cp_seg_blk_offset = (le32_to_cpu(super_block.segment0_blkaddr) +
config.blks_per_seg) *
blk_size_bytes;
- if (dev_write(ckp, cp_seg_blk_offset, F2FS_BLKSIZE)) {
+ DBG(1, "\tWriting cp page 1 of checkpoint pack 2, at offset 0x%08"PRIx64"\n", cp_seg_blk_offset);
+ if (dev_write(ckp, cp_seg_blk_offset, blk_size_bytes)) {
MSG(1, "\tError: While writing the ckp to disk!!!\n");
return -1;
}
+ for (i = 0; i < le32_to_cpu(super_block.cp_payload); i++) {
+ cp_seg_blk_offset += blk_size_bytes;
+ if (dev_fill(cp_payload, cp_seg_blk_offset, blk_size_bytes)) {
+ MSG(1, "\tError: While zeroing out the sit bitmap area \
+ on disk!!!\n");
+ return -1;
+ }
+ }
+
/* 10. cp page 2 of check point pack 2 */
- cp_seg_blk_offset += blk_size_bytes * (le32_to_cpu(ckp->cp_pack_total_block_count) - 1);
- if (dev_write(ckp, cp_seg_blk_offset, F2FS_BLKSIZE)) {
+ cp_seg_blk_offset += blk_size_bytes * (le32_to_cpu(ckp->cp_pack_total_block_count)
+ - le32_to_cpu(super_block.cp_payload) - 1);
+ DBG(1, "\tWriting cp page 2 of checkpoint pack 2, at offset 0x%08"PRIx64"\n", cp_seg_blk_offset);
+ if (dev_write(ckp, cp_seg_blk_offset, blk_size_bytes)) {
MSG(1, "\tError: While writing the ckp to disk!!!\n");
return -1;
}
free(sum) ;
free(ckp) ;
+ free(cp_payload);
return 0;
}
@@ -759,6 +722,7 @@ static int f2fs_write_super_block(void)
memcpy(zero_buff + F2FS_SUPER_OFFSET, &super_block,
sizeof(super_block));
+ DBG(1, "\tWriting super block, at offset 0x%08x\n", 0);
for (index = 0; index < 2; index++) {
if (dev_write(zero_buff, index * F2FS_BLKSIZE, F2FS_BLKSIZE)) {
MSG(1, "\tError: While while writing supe_blk \
@@ -810,6 +774,7 @@ static int f2fs_write_root_inode(void)
raw_node->i.i_xattr_nid = 0;
raw_node->i.i_flags = 0;
raw_node->i.i_current_depth = cpu_to_le32(1);
+ raw_node->i.i_dir_level = DEF_DIR_LEVEL;
data_blk_nor = le32_to_cpu(super_block.main_blkaddr) +
config.cur_seg[CURSEG_HOT_DATA] * config.blks_per_seg;
@@ -824,6 +789,7 @@ static int f2fs_write_root_inode(void)
config.blks_per_seg;
main_area_node_seg_blk_offset *= blk_size_bytes;
+ DBG(1, "\tWriting root inode (hot node), at offset 0x%08"PRIx64"\n", main_area_node_seg_blk_offset);
if (dev_write(raw_node, main_area_node_seg_blk_offset, F2FS_BLKSIZE)) {
MSG(1, "\tError: While writing the raw_node to disk!!!\n");
return -1;
@@ -837,6 +803,7 @@ static int f2fs_write_root_inode(void)
config.blks_per_seg;
main_area_node_seg_blk_offset *= blk_size_bytes;
+ DBG(1, "\tWriting root inode (warm node), at offset 0x%08"PRIx64"\n", main_area_node_seg_blk_offset);
if (dev_write(raw_node, main_area_node_seg_blk_offset, F2FS_BLKSIZE)) {
MSG(1, "\tError: While writing the raw_node to disk!!!\n");
return -1;
@@ -874,6 +841,7 @@ static int f2fs_update_nat_root(void)
nat_seg_blk_offset = le32_to_cpu(super_block.nat_blkaddr);
nat_seg_blk_offset *= blk_size_bytes;
+ DBG(1, "\tWriting nat root, at offset 0x%08"PRIx64"\n", nat_seg_blk_offset);
if (dev_write(nat_blk, nat_seg_blk_offset, F2FS_BLKSIZE)) {
MSG(1, "\tError: While writing the nat_blk set0 to disk!\n");
return -1;
@@ -914,6 +882,7 @@ static int f2fs_add_default_dentry_root(void)
config.blks_per_seg;
data_blk_offset *= blk_size_bytes;
+ DBG(1, "\tWriting default dentry root, at offset 0x%08"PRIx64"\n", data_blk_offset);
if (dev_write(dent_blk, data_blk_offset, F2FS_BLKSIZE)) {
MSG(1, "\tError: While writing the dentry_blk to disk!!!\n");
return -1;
@@ -951,7 +920,7 @@ exit:
return err;
}
-static int f2fs_format_device(void)
+int f2fs_format_device(void)
{
int err = 0;
@@ -1000,32 +969,5 @@ exit:
if (err)
MSG(0, "\tError: Could not format the device!!!\n");
- f2fs_finalize_device();
-
return err;
}
-
-int make_f2fs_main(int argc, char *argv[])
-{
- MSG(0, "\n\tF2FS-tools: mkfs.f2fs Ver: %s (%s)\n\n",
- F2FS_TOOLS_VERSION,
- F2FS_TOOLS_DATE);
- f2fs_init_configuration(&config);
-
- f2fs_parse_options(argc, argv);
-
- /*
- if (f2fs_dev_is_umounted(&config) < 0)
- return -1;
- */
-
- if (f2fs_get_device_info(&config) < 0)
- return -1;
-
- if (f2fs_format_device() < 0)
- return -1;
-
- MSG(0, "Info: format successful\n");
-
- return 0;
-}
diff --git a/mkfs/f2fs_format_main.c b/mkfs/f2fs_format_main.c
new file mode 100644
index 0000000..fa92845
--- /dev/null
+++ b/mkfs/f2fs_format_main.c
@@ -0,0 +1,146 @@
+/**
+ * f2fs_format.c
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * Dual licensed under the GPL or LGPL version 2 licenses.
+ */
+#define _LARGEFILE64_SOURCE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/mount.h>
+#include <time.h>
+//#include <linux/fs.h>
+#ifndef ANDROID
+#include <uuid/uuid.h>
+
+#include "f2fs_fs.h"
+#else
+#include "include/f2fs_fs.h"
+#endif
+#include "f2fs_format_utils.h"
+
+extern struct f2fs_configuration config;
+
+static void mkfs_usage()
+{
+ MSG(0, "\nUsage: mkfs.f2fs [options] device [sectors]\n");
+ MSG(0, "[options]:\n");
+ MSG(0, " -a heap-based allocation [default:1]\n");
+ MSG(0, " -d debug level [default:0]\n");
+ MSG(0, " -e [extension list] e.g. \"mp3,gif,mov\"\n");
+ MSG(0, " -l label\n");
+ MSG(0, " -o overprovision ratio [default:5]\n");
+ MSG(0, " -s # of segments per section [default:1]\n");
+ MSG(0, " -z # of sections per zone [default:1]\n");
+ MSG(0, " -t 0: nodiscard, 1: discard [default:1]\n");
+ MSG(0, "sectors: number of sectors. [default: determined by device size]\n");
+ exit(1);
+}
+
+static void f2fs_parse_options(int argc, char *argv[])
+{
+ static const char *option_string = "a:d:e:l:o:s:z:t:";
+ int32_t option=0;
+
+ while ((option = getopt(argc,argv,option_string)) != EOF) {
+ switch (option) {
+ case 'a':
+ config.heap = atoi(optarg);
+ if (config.heap == 0)
+ MSG(0, "Info: Disable heap-based policy\n");
+ break;
+ case 'd':
+ config.dbg_lv = atoi(optarg);
+ MSG(0, "Info: Debug level = %d\n", config.dbg_lv);
+ break;
+ case 'e':
+ config.extension_list = strdup(optarg);
+ MSG(0, "Info: Add new extension list\n");
+ break;
+ case 'l': /*v: volume label */
+ if (strlen(optarg) > 512) {
+ MSG(0, "Error: Volume Label should be less than\
+ 512 characters\n");
+ mkfs_usage();
+ }
+ config.vol_label = optarg;
+ MSG(0, "Info: Label = %s\n", config.vol_label);
+ break;
+ case 'o':
+ config.overprovision = atoi(optarg);
+ MSG(0, "Info: Overprovision ratio = %u%%\n",
+ atoi(optarg));
+ break;
+ case 's':
+ config.segs_per_sec = atoi(optarg);
+ MSG(0, "Info: Segments per section = %d\n",
+ atoi(optarg));
+ break;
+ case 'z':
+ config.secs_per_zone = atoi(optarg);
+ MSG(0, "Info: Sections per zone = %d\n", atoi(optarg));
+ break;
+ case 't':
+ config.trim = atoi(optarg);
+ MSG(0, "Info: Trim is %s\n", config.trim ? "enabled": "disabled");
+ break;
+ default:
+ mkfs_usage();
+ break;
+ }
+ }
+
+ if (optind >= argc) {
+ MSG(0, "\tError: Device not specified\n");
+ mkfs_usage();
+ }
+ config.device_name = argv[optind];
+
+ if ((optind + 1) < argc) {
+ /* We have a sector count. */
+ config.total_sectors = atoll(argv[optind+1]);
+ MSG(0, "\ttotal_sectors=%lu (%s bytes)\n", config.total_sectors, argv[optind+1]);
+ }
+
+ config.reserved_segments =
+ (2 * (100 / config.overprovision + 1) + 6)
+ * config.segs_per_sec;
+}
+
+#ifndef ANDROID
+int main(int argc, char *argv[])
+#else
+int make_f2fs_main(int argc, char *argv[])
+#endif
+{
+ MSG(0, "\n\tF2FS-tools: mkfs.f2fs Ver: %s (%s)\n\n",
+ F2FS_TOOLS_VERSION,
+ F2FS_TOOLS_DATE);
+ f2fs_init_configuration(&config);
+
+ f2fs_parse_options(argc, argv);
+
+#ifndef ANDROID
+ if (f2fs_dev_is_umounted(&config) < 0)
+ return -1;
+#endif
+
+ if (f2fs_get_device_info(&config) < 0)
+ return -1;
+
+ if (f2fs_format_device() < 0)
+ return -1;
+
+ f2fs_finalize_device(&config);
+
+ MSG(0, "Info: format successful\n");
+
+ return 0;
+}
diff --git a/mkfs/f2fs_format_utils.c b/mkfs/f2fs_format_utils.c
index 5e466bc..6792ce0 100644
--- a/mkfs/f2fs_format_utils.c
+++ b/mkfs/f2fs_format_utils.c
@@ -4,9 +4,7 @@
* Copyright (c) 2014 Samsung Electronics Co., Ltd.
* http://www.samsung.com/
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
+ * Dual licensed under the GPL or LGPL version 2 licenses.
*/
#define _LARGEFILE64_SOURCE
@@ -14,23 +12,16 @@
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
-#include <linux/fs.h>
+#ifndef ANDROID
+#include "f2fs_fs.h"
+#else
#include "include/f2fs_fs.h"
+#endif
-void f2fs_finalize_device()
-{
- /*
- * We should call fsync() to flush out all the dirty pages
- * in the block device page cache.
- */
- if (fsync(config.fd) < 0)
- MSG(0, "\tError: Could not conduct fsync!!!\n");
-
- if (close(config.fd) < 0)
- MSG(0, "\tError: Failed to close device file!!!\n");
-
-}
+#ifdef HAVE_LINUX_FS_H
+#include <linux/fs.h>
+#endif
int f2fs_trim_device()
{
@@ -48,14 +39,20 @@ int f2fs_trim_device()
return -1;
}
+#if defined(WITH_BLKDISCARD) && defined(BLKDISCARD)
MSG(0, "Info: Discarding device\n");
if (S_ISREG(stat_buf.st_mode))
return 0;
else if (S_ISBLK(stat_buf.st_mode)) {
- if (ioctl(config.fd, BLKDISCARD, &range) < 0)
+ if (ioctl(config.fd, BLKDISCARD, &range) < 0) {
MSG(0, "Info: This device doesn't support TRIM\n");
+ } else {
+ MSG(0, "Info: Discarded %lu sectors\n",
+ config.total_sectors);
+ }
} else
return -1;
+#endif
return 0;
}
diff --git a/mkfs/f2fs_format_utils.h b/mkfs/f2fs_format_utils.h
index 3ba0fd6..9f531ee 100644
--- a/mkfs/f2fs_format_utils.h
+++ b/mkfs/f2fs_format_utils.h
@@ -4,16 +4,17 @@
* Copyright (c) 2014 Samsung Electronics Co., Ltd.
* http://www.samsung.com/
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
+ * Dual licensed under the GPL or LGPL version 2 licenses.
*/
#define _LARGEFILE64_SOURCE
+#ifndef ANDROID
+#include "f2fs_fs.h"
+#else
#include "include/f2fs_fs.h"
-#include "include/f2fs_version.h"
+#endif
extern struct f2fs_configuration config;
-void f2fs_finalize_device();
-int f2fs_trim_device();
+int f2fs_trim_device(void);
+int f2fs_format_device(void);
diff --git a/scripts/dumpf2fs.sh b/scripts/dumpf2fs.sh
new file mode 100755
index 0000000..2c2a273
--- /dev/null
+++ b/scripts/dumpf2fs.sh
@@ -0,0 +1,61 @@
+#!/system/bin/sh
+DEV=/dev/block/mmcblk0p16
+
+CMD=$1
+BASE=0x200000
+BASE_MAIN=0xac00000
+
+case $CMD in
+cp1)
+ echo dump cp1
+ let addr=$BASE
+ echo $addr
+ hexdump -s $addr -n 4096 $DEV;;
+cp2)
+ echo dump cp2
+ let addr=$BASE+0x200000
+ hexdump -s $addr -n 4096 $DEV;;
+cp)
+ echo dump cp1 and cp2
+ let addr=$BASE
+ hexdump -s $addr -n 409 $DEV
+ let addr=$BASE+0x200000
+ hexdump -s $addr -n 4096 $DEV;;
+cp1_all)
+ echo dump cp1 all
+ let addr=$BASE
+ hexdump -s $addr -n 20480 $DEV;;
+cp2_all)
+ echo dump cp2 all
+ let addr=$BASE+0x200000
+ hexdump -s $addr -n 20480 $DEV;;
+cp_all)
+ echo dump cp1 and cp2 all
+ let addr=$BASE
+ hexdump -s $addr -n 20480 $DEV
+ let addr=$BASE+0x200000
+ hexdump -s $addr -n 20480 $DEV;;
+blk)
+ let addr=$BASE_MAIN+$2*0x200000+$3*0x1000
+ hexdump -s $addr -n 4096 $DEV
+ echo ;;
+inode)
+ let addr=$BASE_MAIN+$2*0x200000+$3*0x1000
+ for i in `seq $3 511`
+ do
+ hexdump -s $addr -n 8 $DEV
+ let end=$addr+0x0ff0
+ hexdump -s $end -n 16 $DEV
+ let addr=$addr+0x1000
+ done
+ echo ;;
+*)
+ let addr=$1*0x1000
+ let segno=$addr-$BASE_MAIN
+ let segno=$segno/0x200000
+ let off=$addr-$BASE_MAIN
+ let off=$off%0x200000/0x1000
+ echo $segno, $off
+ hexdump -s $addr -n 4096 $DEV
+ echo ;;
+esac
diff --git a/scripts/spo_test.sh b/scripts/spo_test.sh
new file mode 100755
index 0000000..2191214
--- /dev/null
+++ b/scripts/spo_test.sh
@@ -0,0 +1,70 @@
+#!/bin/bash
+
+MNT=/mnt/f2fs
+DEV=/dev/sdb1
+USER_DIR=/home/zeus
+F2FS_DIR=$USER_DIR/f2fs_test
+
+check_stop() {
+ stop=`cat /tmp/stop`
+ if [ $stop -eq 1 ]; then
+ exit
+ fi
+}
+
+case $1 in
+start)
+ echo 0 > /tmp/stop
+ umount /mnt/*
+ echo 3 > /proc/sys/vm/drop_caches
+ echo 8 > /proc/sys/kernel/printk
+
+ date >> $USER_DIR/por_result
+ sync
+
+ insmod $F2FS_DIR/src/fs/f2fs/f2fs.ko || exit
+
+ echo Start checking F2FS without fsync
+ check_stop
+ fsck.f2fs $DEV -d 0 || exit
+ mount -t f2fs -o disable_roll_forward $DEV $MNT || exit
+ umount $MNT
+ echo 3 > /proc/sys/vm/drop_caches
+
+ echo Start checking F2FS with fsync
+ check_stop
+ fsck.f2fs $DEV -d 0 || exit
+ mount -t f2fs $DEV $MNT || exit
+ umount $MNT
+
+ check_stop
+ fsck.f2fs $DEV -d 0 || exit
+ mount -t f2fs $DEV $MNT || exit
+
+ count=`cat $USER_DIR/por_time`
+ if [ $count -eq 20 ]; then
+ echo Start rm all
+ time rm -rf $MNT/* || exit
+ echo 0 > $USER_DIR/por_time
+ sync
+ else
+ echo $((count+1)) > $USER_DIR/por_time
+ fi
+ echo 8 > /proc/sys/kernel/printk
+ echo Start fsstress
+ date
+ $F2FS_DIR/stress_test/fsstress/fsstress -z -f link=0 -f mkdir=3 -f mknod=3 -f rmdir=2 -f symlink=3 -f truncate=4 -f write=10 -f creat=10 -f unlink=5 -f rename=5 -f fsync=10 -p 10 -n 10000 -l 0 -d $MNT &
+ RANDOM=`date '+%s'`
+ rand=$[($RANDOM % 540) + 60]
+ echo Start sleep: $rand seconds
+ sleep $rand
+
+ echo Reboot now
+ check_stop
+ echo b > /proc/sysrq-trigger
+ ;;
+stop)
+ killall -9 fsstress
+ echo 1 > /tmp/stop
+ ;;
+esac
diff --git a/scripts/tracepoint.sh b/scripts/tracepoint.sh
new file mode 100755
index 0000000..7f5a9b8
--- /dev/null
+++ b/scripts/tracepoint.sh
@@ -0,0 +1,65 @@
+#!/system/bin/sh
+
+TRACE=/sys/kernel/debug/tracing/
+dev=$(((8<<20) + 17)) # sdb1 (8,17)
+
+echo 1 > $TRACE/tracing_on
+
+# block tracepoints
+#echo "dev == $dev" > $TRACE/events/block/block_rq_complete/filter
+echo 0 > $TRACE/events/block/block_rq_complete/enable
+echo 0 > $TRACE/events/block/block_bio_complete/enable
+
+# GC
+G=0
+echo $G > $TRACE/events/f2fs/f2fs_get_victim/enable
+
+# block allocation
+A=0
+echo $A > $TRACE/events/f2fs/f2fs_reserve_new_block/enable
+
+# block truncation
+T=0
+echo $T > $TRACE/events/f2fs/f2fs_truncate/enable
+echo $T > $TRACE/events/f2fs/f2fs_truncate_inode_blocks_enter/enable
+echo $T > $TRACE/events/f2fs/f2fs_truncate_inode_blocks_exit/enable
+echo $T > $TRACE/events/f2fs/f2fs_truncate_blocks_enter/enable
+echo $T > $TRACE/events/f2fs/f2fs_truncate_blocks_exit/enable
+echo $T > $TRACE/events/f2fs/f2fs_truncate_nodes_enter/enable
+echo $T > $TRACE/events/f2fs/f2fs_truncate_nodes_exit/enable
+echo $T > $TRACE/events/f2fs/f2fs_truncate_data_blocks_range/enable
+echo $T > $TRACE/events/f2fs/f2fs_truncate_node/enable
+echo $T > $TRACE/events/f2fs/f2fs_truncate_partial_nodes/enable
+
+# syscalls
+S=0
+echo $S > $TRACE/events/f2fs/f2fs_unlink_enter/enable
+echo $S > $TRACE/events/f2fs/f2fs_unlink_exit/enable
+echo $S > $TRACE/events/f2fs/f2fs_fallocate/enable
+echo $S > $TRACE/events/f2fs/f2fs_get_data_block/enable
+
+# IOs
+R=0
+W=0
+echo $R > $TRACE/events/f2fs/f2fs_readpage/enable
+echo $W > $TRACE/events/f2fs/f2fs_writepage/enable
+echo $W > $TRACE/events/f2fs/f2fs_submit_write_bio/enable
+echo $R > $TRACE/events/f2fs/f2fs_submit_read_bio/enable
+
+echo 0 > $TRACE/events/f2fs/f2fs_submit_page_bio/enable
+echo 0 > $TRACE/events/f2fs/f2fs_submit_page_mbio/enable
+echo 0 > $TRACE/events/f2fs/f2fs_issue_discard/enable
+echo 0 > $TRACE/events/f2fs/f2fs_issue_flush/enable
+
+# VFS interfaces
+V=0
+echo $V > $TRACE/events/f2fs/f2fs_iget/enable
+echo $V > $TRACE/events/f2fs/f2fs_iget_exit/enable
+echo $V > $TRACE/events/f2fs/f2fs_new_inode/enable
+echo $V > $TRACE/events/f2fs/f2fs_evict_inode/enable
+echo $V > $TRACE/events/f2fs/f2fs_sync_file_enter/enable
+echo $V > $TRACE/events/f2fs/f2fs_sync_file_exit/enable
+echo $V > $TRACE/events/f2fs/f2fs_write_checkpoint/enable
+echo $V > $TRACE/events/f2fs/f2fs_sync_fs/enable
+
+cat $TRACE/trace_pipe
diff --git a/tools/f2fstat.c b/tools/f2fstat.c
index dffbd4c..89dd7ff 100644
--- a/tools/f2fstat.c
+++ b/tools/f2fstat.c
@@ -5,7 +5,9 @@
#include <fcntl.h>
#include <libgen.h>
+#ifdef ANDROID
#include "include/f2fs_version.h"
+#endif
#ifdef DEBUG
#define dbg(fmt, args...) printf(fmt, __VA_ARGS__);
@@ -18,6 +20,9 @@
*/
#define F2FS_STATUS "/sys/kernel/debug/f2fs/status"
+#define KEY_NODE 0x00000001
+#define KEY_META 0x00000010
+
unsigned long util;
unsigned long used_node_blks;
unsigned long used_data_blks;
@@ -28,16 +33,16 @@ unsigned long valid_segs;
unsigned long dirty_segs;
unsigned long prefree_segs;
-unsigned long gc;
-unsigned long bg_gc;
+unsigned long gc, bg_gc;
+unsigned long cp;
unsigned long gc_data_blks;
unsigned long gc_node_blks;
//unsigned long extent_hit_ratio;
-unsigned long dirty_node;
+unsigned long dirty_node, node_kb;
unsigned long dirty_dents;
-unsigned long dirty_meta;
+unsigned long dirty_meta, meta_kb;
unsigned long nat_caches;
unsigned long dirty_sit;
@@ -45,7 +50,7 @@ unsigned long free_nids;
unsigned long ssr_blks;
unsigned long lfs_blks;
-
+unsigned long memory_kb;
struct options {
int delay;
@@ -56,6 +61,7 @@ struct options {
struct mm_table {
const char *name;
unsigned long *val;
+ int flag;
};
static int compare_mm_table(const void *a, const void *b)
@@ -86,21 +92,24 @@ void f2fstat(struct options *opt)
int found_cnt = 0;
static struct mm_table f2fstat_table[] = {
- { " - Data", &used_data_blks },
- { " - Dirty", &dirty_segs },
- { " - Free", &free_segs },
- { " - NATs", &nat_caches },
- { " - Node", &used_node_blks },
- { " - Prefree", &prefree_segs },
- { " - SITs", &dirty_sit },
- { " - Valid", &valid_segs },
- { " - dents", &dirty_dents },
- { " - meta", &dirty_meta },
- { " - nodes", &dirty_node },
- { "GC calls", &gc },
- { "LFS", &lfs_blks },
- { "SSR", &ssr_blks },
- { "Utilization", &util },
+ { " - Data", &used_data_blks, 0 },
+ { " - Dirty", &dirty_segs, 0 },
+ { " - Free", &free_segs, 0 },
+ { " - NATs", &nat_caches, 0 },
+ { " - Node", &used_node_blks, 0 },
+ { " - Prefree", &prefree_segs, 0 },
+ { " - SITs", &dirty_sit, 0 },
+ { " - Valid", &valid_segs, 0 },
+ { " - dents", &dirty_dents, 0 },
+ { " - free_nids", &free_nids, 0 },
+ { " - meta", &dirty_meta, KEY_META },
+ { " - nodes", &dirty_node, KEY_NODE },
+ { "CP calls", &cp, 0 },
+ { "GC calls", &gc, 0 },
+ { "LFS", &lfs_blks, 0 },
+ { "Memory", &memory_kb, 0 },
+ { "SSR", &ssr_blks, 0 },
+ { "Utilization", &util, 0 },
};
f2fstat_table_cnt = sizeof(f2fstat_table)/sizeof(struct mm_table);
@@ -149,6 +158,20 @@ void f2fstat(struct options *opt)
goto nextline;
*(found->val) = strtoul(head, &tail, 10);
+ if (found->flag) {
+ int npages;
+ tail = strstr(head, "in");
+ head = tail + 2;
+ npages = strtoul(head, &tail, 10);
+ switch (found->flag & (KEY_NODE | KEY_META)) {
+ case KEY_NODE:
+ node_kb = npages * 4;
+ break;
+ case KEY_META:
+ meta_kb = npages * 4;
+ break;
+ }
+ }
if (++found_cnt == f2fstat_table_cnt)
break;
nextline:
@@ -172,8 +195,13 @@ void usage(void)
void parse_option(int argc, char *argv[], struct options *opt)
{
+#ifndef ANDROID
+ char option;
+ const char *option_string = "d:i:p:h";
+#else
int option;
const char *option_string = "d:i:p:";
+#endif
while ((option = getopt(argc, argv, option_string)) != EOF) {
switch (option) {
@@ -195,13 +223,17 @@ void parse_option(int argc, char *argv[], struct options *opt)
void print_head(void)
{
- printf("---utilization--- -----------main area-------- ---balancing async-- -gc- ---alloc---\n");
- printf("util node data free valid dirty prefree node dent meta sit gc ssr lfs\n");
+ fprintf(stderr, "---utilization--- -----------main area-------- ---------balancing async------- ---gc--- ---alloc--- -----memory-----\n");
+ fprintf(stderr, "util node data free valid dirty prefree node dent meta sit nat fnid cp gc ssr lfs total node meta\n");
}
+#ifndef ANDROID
+int main(int argc, char *argv[])
+#else
int f2fstat_main(int argc, char *argv[])
+#endif
{
- char format[] = "%3ld %6ld %6ld %6ld %6ld %6ld %6ld %5ld %5ld %3ld %3ld %5ld %6ld %6ld\n";
+ char format[] = "%3ld %6ld %6ld %6ld %6ld %6ld %6ld %5ld %5ld %3ld %5ld %5ld %3ld %3ld %3ld %6ld %6ld %6ld %6ld %6ld\n";
int head_interval;
struct options opt = {
.delay = 1,
@@ -210,8 +242,8 @@ int f2fstat_main(int argc, char *argv[])
};
printf("\n\tF2FS-tools: f2fstat Ver: %s (%s)\n\n",
- F2FS_TOOLS_VERSION,
- F2FS_TOOLS_DATE);
+ F2FS_TOOLS_VERSION, F2FS_TOOLS_DATE);
+
parse_option(argc, argv, &opt);
head_interval = opt.interval;
@@ -224,10 +256,10 @@ int f2fstat_main(int argc, char *argv[])
f2fstat(&opt);
- printf(format, util, used_node_blks, used_data_blks,
- free_segs, valid_segs, dirty_segs, prefree_segs,
- dirty_node, dirty_dents, dirty_meta, dirty_sit,
- gc, ssr_blks, lfs_blks);
+ fprintf(stderr, format, util, used_node_blks, used_data_blks,
+ free_segs, valid_segs, dirty_segs, prefree_segs,
+ dirty_node, dirty_dents, dirty_meta, dirty_sit, nat_caches, free_nids,
+ cp, gc, ssr_blks, lfs_blks, memory_kb, node_kb, meta_kb);
sleep(opt.delay);
}
diff --git a/tools/fibmap.c b/tools/fibmap.c
index 8790145..ce30850 100644
--- a/tools/fibmap.c
+++ b/tools/fibmap.c
@@ -5,6 +5,7 @@
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
+#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <libgen.h>
@@ -12,7 +13,9 @@
#include <linux/types.h>
#include <linux/fs.h>
+#ifdef ANDROID
#include "include/f2fs_version.h"
+#endif
struct file_ext {
__u32 f_pos;
@@ -30,18 +33,22 @@ void print_ext(struct file_ext *ext)
ext->end_blk, ext->blk_count);
}
+#ifndef ANDROID
+void print_stat(struct stat64 *st)
+#else
void fibmap_print_stat(struct stat64 *st)
+#endif
{
printf("--------------------------------------------\n");
printf("dev [%d:%d]\n", major(st->st_dev), minor(st->st_dev));
- printf("ino [0x%8llx : %lld]\n", st->st_ino, st->st_ino);
+ printf("ino [0x%8lx : %ld]\n", st->st_ino, st->st_ino);
printf("mode [0x%8x : %d]\n", st->st_mode, st->st_mode);
- printf("nlink [0x%8x : %d]\n", st->st_nlink, st->st_nlink);
- printf("uid [0x%8lx : %ld]\n", st->st_uid, st->st_uid);
- printf("gid [0x%8lx : %ld]\n", st->st_gid, st->st_gid);
- printf("size [0x%8llx : %lld]\n", st->st_size, st->st_size);
+ printf("nlink [0x%8lx : %ld]\n", st->st_nlink, st->st_nlink);
+ printf("uid [0x%8x : %d]\n", st->st_uid, st->st_uid);
+ printf("gid [0x%8x : %d]\n", st->st_gid, st->st_gid);
+ printf("size [0x%8lx : %ld]\n", st->st_size, st->st_size);
printf("blksize [0x%8lx : %ld]\n", st->st_blksize, st->st_blksize);
- printf("blocks [0x%8llx : %lld]\n", st->st_blocks, st->st_blocks);
+ printf("blocks [0x%8lx : %ld]\n", st->st_blocks, st->st_blocks);
printf("--------------------------------------------\n\n");
}
@@ -81,7 +88,11 @@ out:
}
+#ifndef ANDROID
+int main(int argc, char *argv[])
+#else
int fibmap_main(int argc, char *argv[])
+#endif
{
int fd;
int ret = 0;
@@ -94,8 +105,8 @@ int fibmap_main(int argc, char *argv[])
__u32 blknum;
printf("\n\tF2FS-tools: fibmap.f2fs Ver: %s (%s)\n\n",
- F2FS_TOOLS_VERSION,
- F2FS_TOOLS_DATE);
+ F2FS_TOOLS_VERSION, F2FS_TOOLS_DATE);
+
if (argc != 2) {
fprintf(stderr, "No filename\n");
exit(-1);
@@ -123,7 +134,11 @@ int fibmap_main(int argc, char *argv[])
printf("\n----------------file info-------------------\n");
printf("%s :\n", filename);
+#ifndef ANDROID
+ print_stat(&st);
+#else
fibmap_print_stat(&st);
+#endif
printf("file_pos start_blk end_blk blks\n");
blknum = 0;