Project import
diff --git a/f2fs-tools/AUTHORS b/f2fs-tools/AUTHORS
new file mode 100644
index 0000000..6ec1861
--- /dev/null
+++ b/f2fs-tools/AUTHORS
@@ -0,0 +1 @@
+This package has been developed by Praesto Team at Samsung Electronics Co., Ltd.
diff --git a/f2fs-tools/Android.mk b/f2fs-tools/Android.mk
new file mode 100644
index 0000000..55f4a4e
--- /dev/null
+++ b/f2fs-tools/Android.mk
@@ -0,0 +1,128 @@
+LOCAL_PATH:= $(call my-dir)
+
+# f2fs-tools depends on Linux kernel headers being in the system include path.
+ifeq ($(HOST_OS),linux)
+
+# The versions depend on $(LOCAL_PATH)/VERSION
+version_CFLAGS := -DF2FS_MAJOR_VERSION=1 -DF2FS_MINOR_VERSION=4 -DF2FS_TOOLS_VERSION=\"1.4.0\" -DF2FS_TOOLS_DATE=\"2014-10-18\"
+
+# external/e2fsprogs/lib is needed for uuid/uuid.h
+common_C_INCLUDES := $(LOCAL_PATH)/include external/e2fsprogs/lib/
+
+#----------------------------------------------------------
+include $(CLEAR_VARS)
+LOCAL_MODULE := libf2fs_fmt
+LOCAL_SRC_FILES := \
+ lib/libf2fs.c \
+ mkfs/f2fs_format.c \
+ mkfs/f2fs_format_utils.c \
+
+LOCAL_C_INCLUDES := $(common_C_INCLUDES)
+LOCAL_CFLAGS := $(version_CFLAGS)
+LOCAL_EXPORT_CFLAGS := $(version_CFLAGS)
+LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include $(LOCAL_PATH)/mkfs
+include $(BUILD_STATIC_LIBRARY)
+
+#----------------------------------------------------------
+include $(CLEAR_VARS)
+LOCAL_MODULE := libf2fs_fmt_host
+LOCAL_SRC_FILES := \
+ lib/libf2fs.c \
+ mkfs/f2fs_format.c \
+ mkfs/f2fs_format_utils.c \
+
+LOCAL_C_INCLUDES := $(common_C_INCLUDES)
+LOCAL_CFLAGS := $(version_CFLAGS)
+LOCAL_EXPORT_CFLAGS := $(version_CFLAGS)
+LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include $(LOCAL_PATH)/mkfs
+include $(BUILD_HOST_STATIC_LIBRARY)
+
+#----------------------------------------------------------
+include $(CLEAR_VARS)
+LOCAL_MODULE := libf2fs_fmt_host_dyn
+LOCAL_SRC_FILES := \
+ lib/libf2fs.c \
+ mkfs/f2fs_format.c \
+
+LOCAL_C_INCLUDES := $(common_C_INCLUDES)
+LOCAL_CFLAGS := $(version_CFLAGS)
+LOCAL_EXPORT_CFLAGS := $(version_CFLAGS)
+LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include $(LOCAL_PATH)/mkfs
+LOCAL_STATIC_LIBRARIES := \
+ libf2fs_ioutils_host \
+ libext2_uuid-host \
+ libsparse_host \
+ libz
+# LOCAL_LDLIBS := -ldl
+include $(BUILD_HOST_SHARED_LIBRARY)
+
+#----------------------------------------------------------
+include $(CLEAR_VARS)
+# The LOCAL_MODULE name is referenced by the code. Don't change it.
+LOCAL_MODULE := mkfs.f2fs
+
+# mkfs.f2fs is used in recovery: must be static.
+LOCAL_FORCE_STATIC_EXECUTABLE := true
+
+LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/sbin
+
+LOCAL_SRC_FILES := \
+ lib/libf2fs_io.c \
+ mkfs/f2fs_format_main.c
+LOCAL_C_INCLUDES := $(common_C_INCLUDES)
+LOCAL_CFLAGS := $(version_CFLAGS)
+LOCAL_STATIC_LIBRARIES := libc libf2fs_fmt libext2_uuid_static
+LOCAL_MODULE_TAGS := optional
+include $(BUILD_EXECUTABLE)
+
+#----------------------------------------------------------
+include $(CLEAR_VARS)
+LOCAL_MODULE := make_f2fs
+
+LOCAL_SRC_FILES := \
+ lib/libf2fs_io.c \
+ mkfs/f2fs_format_main.c
+LOCAL_C_INCLUDES := $(common_C_INCLUDES)
+LOCAL_CFLAGS := $(version_CFLAGS)
+LOCAL_STATIC_LIBRARIES := libf2fs_fmt
+LOCAL_SHARED_LIBRARIES := libext2_uuid
+LOCAL_SYSTEM_SHARED_LIBRARIES := libc
+LOCAL_MODULE_TAGS := optional
+include $(BUILD_EXECUTABLE)
+
+#----------------------------------------------------------
+include $(CLEAR_VARS)
+# The LOCAL_MODULE name is referenced by the code. Don't change it.
+LOCAL_MODULE := fsck.f2fs
+LOCAL_SRC_FILES := \
+ fsck/dump.c \
+ fsck/fsck.c \
+ fsck/main.c \
+ fsck/mount.c \
+ lib/libf2fs.c \
+ lib/libf2fs_io.c \
+
+LOCAL_C_INCLUDES := $(common_C_INCLUDES)
+LOCAL_CFLAGS := $(version_CFLAGS)
+LOCAL_SHARED_LIBRARIES := libext2_uuid
+LOCAL_SYSTEM_SHARED_LIBRARIES := libc
+LOCAL_MODULE_TAGS := optional
+include $(BUILD_EXECUTABLE)
+
+#----------------------------------------------------------
+include $(CLEAR_VARS)
+LOCAL_MODULE := fsck.f2fs
+LOCAL_SRC_FILES := \
+ fsck/dump.c \
+ fsck/fsck.c \
+ fsck/main.c \
+ fsck/mount.c \
+ lib/libf2fs.c \
+ lib/libf2fs_io.c \
+
+LOCAL_C_INCLUDES := $(common_C_INCLUDES)
+LOCAL_CFLAGS := $(version_CFLAGS)
+LOCAL_HOST_SHARED_LIBRARIES := libext2_uuid_host
+include $(BUILD_HOST_EXECUTABLE)
+
+endif
diff --git a/f2fs-tools/COPYING b/f2fs-tools/COPYING
new file mode 100644
index 0000000..52f956d
--- /dev/null
+++ b/f2fs-tools/COPYING
@@ -0,0 +1,864 @@
+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/
+
+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.
+
+================================================================================
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 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.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
+
+================================================================================
+ 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/f2fs-tools/ChangeLog b/f2fs-tools/ChangeLog
new file mode 100644
index 0000000..9739e99
--- /dev/null
+++ b/f2fs-tools/ChangeLog
@@ -0,0 +1,4 @@
+f2fs-tools-1.0.0 Tue Aug 14, 2012 KST
+ * The first release of f2fs-tools.
+f2fs-tools-1.0.1 Tue Jun 04, 2013 KST
+ * Added fsck and dump for f2fs-tools.
diff --git a/f2fs-tools/MODULE_LICENSE_LGPL b/f2fs-tools/MODULE_LICENSE_LGPL
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/f2fs-tools/MODULE_LICENSE_LGPL
diff --git a/f2fs-tools/Makefile.am b/f2fs-tools/Makefile.am
new file mode 100644
index 0000000..d2921d6
--- /dev/null
+++ b/f2fs-tools/Makefile.am
@@ -0,0 +1,5 @@
+## Makefile.am
+
+ACLOCAL_AMFLAGS = -I m4
+
+SUBDIRS = man lib mkfs fsck tools
diff --git a/f2fs-tools/NOTICE b/f2fs-tools/NOTICE
new file mode 100644
index 0000000..52f956d
--- /dev/null
+++ b/f2fs-tools/NOTICE
@@ -0,0 +1,864 @@
+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/
+
+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.
+
+================================================================================
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 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.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
+
+================================================================================
+ 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/f2fs-tools/README b/f2fs-tools/README
new file mode 100644
index 0000000..222cbc3
--- /dev/null
+++ b/f2fs-tools/README
@@ -0,0 +1,48 @@
+F2FS format utilility
+---------------------
+
+To use f2fs filesystem, you should format the storage partition
+with this utilility. Otherwise, you cannot mount f2fs.
+
+Before compilation
+------------------
+
+Your should install the following packages.
+ - libuuid-devel or uuid-dev
+ - pkg-config
+ - autoconf
+ - libtool
+
+Initial compilation
+-------------------
+
+Before compilation initially, autoconf/automake tools should be run.
+
+ # autoreconf --install
+
+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
+---------------------
+
+ $ ./mkfs.f2fs -l [LABEL] $DEV
+
+For more mkfs options, see man page.
diff --git a/f2fs-tools/VERSION b/f2fs-tools/VERSION
new file mode 100644
index 0000000..0e58c09
--- /dev/null
+++ b/f2fs-tools/VERSION
@@ -0,0 +1,2 @@
+1.4.1
+2015-03-04
diff --git a/f2fs-tools/configure.ac b/f2fs-tools/configure.ac
new file mode 100644
index 0000000..ae451b8
--- /dev/null
+++ b/f2fs-tools/configure.ac
@@ -0,0 +1,92 @@
+# -*- Autoconf -*-
+# Process this file with autoconf to produce a configure script.
+
+AC_PREREQ([2.68])
+
+# Get version from file VERSION
+m4_define([f2fs_tools_version], m4_esyscmd([sed -n '1p' VERSION | tr -d '\n']))
+m4_define([f2fs_tools_date], m4_esyscmd([sed -n '2p' VERSION | tr -d '\n']))
+m4_define([f2fs_tools_gitdate],
+ m4_esyscmd([git log -1 --pretty=format:%ci 2> /dev/null]))
+
+AC_INIT([F2FS tools], [f2fs_tools_version],
+ [linux-f2fs-devel@lists.sourceforge.net])
+
+AC_DEFINE([F2FS_TOOLS_VERSION], "f2fs_tools_version", [f2fs-tools version])
+AC_DEFINE([F2FS_MAJOR_VERSION], m4_bpatsubst(f2fs_tools_version,
+ [\([0-9]*\)\(\w\|\W\)*], [\1]),
+ [Major version for f2fs-tools])
+AC_DEFINE([F2FS_MINOR_VERSION], m4_bpatsubst(f2fs_tools_version,
+ [\([0-9]*\).\([0-9]*\)\(\w\|\W\)*], [\2]),
+ [Minor version for f2fs-tools])
+
+AC_CHECK_FILE(.git,
+ AC_DEFINE([F2FS_TOOLS_DATE],
+ "m4_bpatsubst(f2fs_tools_gitdate,
+ [\([0-9-]*\)\(\w\|\W\)*], [\1])",
+ [f2fs-tools date based on Git commits]),
+ AC_DEFINE([F2FS_TOOLS_DATE],
+ "f2fs_tools_date",
+ [f2fs-tools date based on Source releases]))
+
+AC_CONFIG_SRCDIR([config.h.in])
+AC_CONFIG_HEADER([config.h])
+AC_CONFIG_MACRO_DIR([m4])
+AC_CONFIG_AUX_DIR([build-aux])
+AM_INIT_AUTOMAKE([foreign tar-pax dist-xz])
+
+AC_CHECK_HEADERS_ONCE([
+ fcntl.h
+ mntent.h
+ stdlib.h
+ string.h
+ unistd.h
+ sys/ioctl.h
+ sys/mount.h
+])
+
+# Checks for programs.
+AC_PROG_CC
+AC_PROG_LIBTOOL
+AC_PATH_PROG([LDCONFIG], [ldconfig],
+ [AC_MSG_ERROR([ldconfig not found])],
+ [$PATH:/sbin])
+
+# Checks for libraries.
+PKG_CHECK_MODULES([libuuid], [uuid])
+
+# Checks for header files.
+AC_CHECK_HEADERS([linux/fs.h fcntl.h mntent.h stdlib.h string.h \
+ sys/ioctl.h sys/mount.h unistd.h linux/falloc.h byteswap.h])
+
+# Checks for typedefs, structures, and compiler characteristics.
+AC_C_INLINE
+AC_TYPE_INT32_T
+AC_TYPE_INT8_T
+AC_TYPE_SIZE_T
+
+# Checks for library functions.
+AC_FUNC_GETMNTENT
+AC_CHECK_FUNCS_ONCE([
+ getmntent
+ memset
+])
+
+AS_IF([test "$ac_cv_header_byteswap_h" = "yes"],
+ [AC_CHECK_DECLS([bswap_64],,,[#include <byteswap.h>])])
+
+# Install directories
+AC_PREFIX_DEFAULT([/usr])
+AC_SUBST([sbindir], [/sbin])
+AC_SUBST([sysconfdir], [/etc])
+AC_SUBST([localstatedir], [/var])
+AC_CONFIG_FILES([
+ Makefile
+ man/Makefile
+ lib/Makefile
+ mkfs/Makefile
+ fsck/Makefile
+ tools/Makefile
+])
+
+AC_OUTPUT
diff --git a/f2fs-tools/fsck/Makefile.am b/f2fs-tools/fsck/Makefile.am
new file mode 100644
index 0000000..3258e47
--- /dev/null
+++ b/f2fs-tools/fsck/Makefile.am
@@ -0,0 +1,10 @@
+## Makefile.am
+
+AM_CPPFLAGS = ${libuuid_CFLAGS} -I$(top_srcdir)/include
+AM_CFLAGS = -Wall
+sbin_PROGRAMS = fsck.f2fs
+fsck_f2fs_SOURCES = main.c fsck.c dump.c mount.c
+fsck_f2fs_LDADD = ${libuuid_LIBS} $(top_builddir)/lib/libf2fs.la
+
+install-data-hook:
+ ln -sf fsck.f2fs $(DESTDIR)/$(sbindir)/dump.f2fs
diff --git a/f2fs-tools/fsck/dump.c b/f2fs-tools/fsck/dump.c
new file mode 100644
index 0000000..3c4a8d1
--- /dev/null
+++ b/f2fs-tools/fsck/dump.c
@@ -0,0 +1,466 @@
+/**
+ * dump.c
+ *
+ * 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.
+ */
+#include <inttypes.h>
+
+#include "fsck.h"
+#include <locale.h>
+
+#define BUF_SZ 80
+
+const char *seg_type_name[SEG_TYPE_MAX] = {
+ "SEG_TYPE_DATA",
+ "SEG_TYPE_CUR_DATA",
+ "SEG_TYPE_NODE",
+ "SEG_TYPE_CUR_NODE",
+};
+
+void sit_dump(struct f2fs_sb_info *sbi, int start_sit, int end_sit)
+{
+ struct seg_entry *se;
+ int segno;
+ char buf[BUF_SZ];
+ u32 free_segs = 0;;
+ u64 valid_blocks = 0;
+ int ret;
+ int fd;
+
+ fd = open("dump_sit", O_CREAT|O_WRONLY|O_TRUNC, 0666);
+ ASSERT(fd >= 0);
+
+ for (segno = start_sit; segno < end_sit; segno++) {
+ se = get_seg_entry(sbi, segno);
+
+ memset(buf, 0, BUF_SZ);
+ snprintf(buf, BUF_SZ, "%5d %8d\n", segno, se->valid_blocks);
+
+ ret = write(fd, buf, strlen(buf));
+ ASSERT(ret >= 0);
+
+ DBG(4, "SIT[0x%3x] : 0x%x\n", segno, se->valid_blocks);
+ if (se->valid_blocks == 0x0) {
+ free_segs++;
+ } else {
+ ASSERT(se->valid_blocks <= 512);
+ valid_blocks += se->valid_blocks;
+ }
+ }
+
+ memset(buf, 0, BUF_SZ);
+ snprintf(buf, BUF_SZ, "valid_segs:%d\t free_segs:%d\n",
+ SM_I(sbi)->main_segments - free_segs, free_segs);
+ ret = write(fd, buf, strlen(buf));
+ ASSERT(ret >= 0);
+
+ close(fd);
+ 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)
+{
+ struct f2fs_summary_block sum_blk;
+ char buf[BUF_SZ];
+ int segno, i, ret;
+ int fd;
+
+ fd = open("dump_ssa", O_CREAT|O_WRONLY|O_TRUNC, 0666);
+ ASSERT(fd >= 0);
+
+ snprintf(buf, BUF_SZ, "Note: dump.f2fs -b blkaddr = 0x%x + segno * "
+ " 0x200 + offset\n",
+ sbi->sm_info->main_blkaddr);
+ ret = write(fd, buf, strlen(buf));
+ ASSERT(ret >= 0);
+
+ for (segno = start_ssa; segno < end_ssa; segno++) {
+ ret = get_sum_block(sbi, segno, &sum_blk);
+
+ memset(buf, 0, BUF_SZ);
+ switch (ret) {
+ case SEG_TYPE_CUR_NODE:
+ snprintf(buf, BUF_SZ, "\n\nsegno: %x, Current Node\n", segno);
+ break;
+ case SEG_TYPE_CUR_DATA:
+ snprintf(buf, BUF_SZ, "\n\nsegno: %x, Current Data\n", segno);
+ break;
+ case SEG_TYPE_NODE:
+ snprintf(buf, BUF_SZ, "\n\nsegno: %x, Node\n", segno);
+ break;
+ case SEG_TYPE_DATA:
+ snprintf(buf, BUF_SZ, "\n\nsegno: %x, Data\n", segno);
+ break;
+ }
+ ret = write(fd, buf, strlen(buf));
+ ASSERT(ret >= 0);
+
+ for (i = 0; i < ENTRIES_IN_SUM; i++) {
+ memset(buf, 0, BUF_SZ);
+ if (i % 10 == 0) {
+ buf[0] = '\n';
+ ret = write(fd, buf, strlen(buf));
+ ASSERT(ret >= 0);
+ }
+ snprintf(buf, BUF_SZ, "[%3d: %6x]", i,
+ le32_to_cpu(sum_blk.entries[i].nid));
+ ret = write(fd, buf, strlen(buf));
+ ASSERT(ret >= 0);
+ }
+ }
+ close(fd);
+}
+
+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;
+
+ 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);
+
+ DBG(1, "Node ID [0x%x]\n", nid);
+ DBG(1, "nat_entry.block_addr [0x%x]\n", ni.blk_addr);
+ 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)
+ 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));
+
+ 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);
+}
+
+static void dump_node_from_blkaddr(u32 blk_addr)
+{
+ struct f2fs_node *node_blk;
+ int ret;
+
+ node_blk = calloc(BLOCK_SZ, 1);
+ ASSERT(node_blk);
+
+ ret = dev_read_block(node_blk, blk_addr);
+ ASSERT(ret >= 0);
+
+ if (config.dbg_lv > 0)
+ print_node_info(node_blk);
+ else
+ print_inode_info(&node_blk->i, 1);
+
+ free(node_blk);
+}
+
+static void dump_data_offset(u32 blk_addr, int ofs_in_node)
+{
+ struct f2fs_node *node_blk;
+ unsigned int indirect_blks = 2 * NIDS_PER_BLOCK + 4;
+ unsigned int bidx = 0;
+ unsigned int node_ofs;
+ int ret;
+
+ node_blk = calloc(BLOCK_SZ, 1);
+ ASSERT(node_blk);
+
+ ret = dev_read_block(node_blk, blk_addr);
+ ASSERT(ret >= 0);
+
+ node_ofs = ofs_of_node(node_blk);
+
+ if (node_ofs == 0)
+ goto got_it;
+
+ if (node_ofs > 0 && node_ofs <= 2) {
+ bidx = node_ofs - 1;
+ } else if (node_ofs <= indirect_blks) {
+ int dec = (node_ofs - 4) / (NIDS_PER_BLOCK + 1);
+ bidx = node_ofs - 2 - dec;
+ } else {
+ int dec = (node_ofs - indirect_blks - 3) / (NIDS_PER_BLOCK + 1);
+ bidx = node_ofs - 5 - dec;
+ }
+ bidx = bidx * ADDRS_PER_BLOCK + ADDRS_PER_INODE(&node_blk->i);
+got_it:
+ bidx += ofs_in_node;
+
+ setlocale(LC_ALL, "");
+ MSG(0, " - Data offset : 0x%x (4KB), %'u (bytes)\n",
+ bidx, bidx * 4096);
+ free(node_blk);
+}
+
+static void dump_node_offset(u32 blk_addr)
+{
+ struct f2fs_node *node_blk;
+ int ret;
+
+ node_blk = calloc(BLOCK_SZ, 1);
+ ASSERT(node_blk);
+
+ ret = dev_read_block(node_blk, blk_addr);
+ ASSERT(ret >= 0);
+
+ MSG(0, " - Node offset : 0x%x\n", ofs_of_node(node_blk));
+ free(node_blk);
+}
+
+int dump_info_from_blkaddr(struct f2fs_sb_info *sbi, u32 blk_addr)
+{
+ nid_t nid;
+ int type;
+ struct f2fs_summary sum_entry;
+ struct node_info ni, ino_ni;
+ int ret = 0;
+
+ MSG(0, "\n== Dump data from block address ==\n\n");
+
+ if (blk_addr < SM_I(sbi)->seg0_blkaddr) {
+ MSG(0, "\nFS Reserved Area for SEG #0: ");
+ ret = -EINVAL;
+ } else if (blk_addr < SIT_I(sbi)->sit_base_addr) {
+ MSG(0, "\nFS Metadata Area: ");
+ ret = -EINVAL;
+ } else if (blk_addr < NM_I(sbi)->nat_blkaddr) {
+ MSG(0, "\nFS SIT Area: ");
+ ret = -EINVAL;
+ } else if (blk_addr < SM_I(sbi)->ssa_blkaddr) {
+ MSG(0, "\nFS NAT Area: ");
+ ret = -EINVAL;
+ } else if (blk_addr < SM_I(sbi)->main_blkaddr) {
+ MSG(0, "\nFS SSA Area: ");
+ ret = -EINVAL;
+ } else if (blk_addr > __end_block_addr(sbi)) {
+ MSG(0, "\nOut of address space: ");
+ ret = -EINVAL;
+ }
+
+ if (ret) {
+ MSG(0, "User data is from 0x%x to 0x%x\n\n",
+ SM_I(sbi)->main_blkaddr,
+ __end_block_addr(sbi));
+ return ret;
+ }
+
+ type = get_sum_entry(sbi, blk_addr, &sum_entry);
+ nid = le32_to_cpu(sum_entry.nid);
+
+ 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);
+ DBG(1, " - Segno [0x%x]\n", GET_SEGNO(sbi, blk_addr));
+ DBG(1, " - Offset [0x%x]\n", OFFSET_IN_SEG(sbi, blk_addr));
+ DBG(1, "SUM.nid [0x%x]\n", nid);
+ DBG(1, "SUM.type [%s]\n", seg_type_name[type]);
+ DBG(1, "SUM.version [%d]\n", sum_entry.version);
+ DBG(1, "SUM.ofs_in_node [0x%x]\n", sum_entry.ofs_in_node);
+ DBG(1, "NAT.blkaddr [0x%x]\n", ni.blk_addr);
+ DBG(1, "NAT.ino [0x%x]\n", ni.ino);
+
+ get_node_info(sbi, ni.ino, &ino_ni);
+
+ /* inode block address */
+ if (ni.blk_addr == NULL_ADDR || ino_ni.blk_addr == NULL_ADDR) {
+ MSG(0, "FS Userdata Area: Obsolete block from 0x%x\n",
+ blk_addr);
+ return -EINVAL;
+ }
+
+ /* print inode */
+ if (config.dbg_lv > 0)
+ dump_node_from_blkaddr(ino_ni.blk_addr);
+
+ if (type == SEG_TYPE_CUR_DATA || type == SEG_TYPE_DATA) {
+ MSG(0, "FS Userdata Area: Data block from 0x%x\n", blk_addr);
+ MSG(0, " - Direct node block : id = 0x%x from 0x%x\n",
+ nid, ni.blk_addr);
+ MSG(0, " - Inode block : id = 0x%x from 0x%x\n",
+ ni.ino, ino_ni.blk_addr);
+ dump_node_from_blkaddr(ino_ni.blk_addr);
+ dump_data_offset(ni.blk_addr,
+ le16_to_cpu(sum_entry.ofs_in_node));
+ } else {
+ MSG(0, "FS Userdata Area: Node block from 0x%x\n", blk_addr);
+ if (ni.ino == ni.nid) {
+ MSG(0, " - Inode block : id = 0x%x from 0x%x\n",
+ ni.ino, ino_ni.blk_addr);
+ dump_node_from_blkaddr(ino_ni.blk_addr);
+ } else {
+ MSG(0, " - Node block : id = 0x%x from 0x%x\n",
+ nid, ni.blk_addr);
+ MSG(0, " - Inode block : id = 0x%x from 0x%x\n",
+ ni.ino, ino_ni.blk_addr);
+ dump_node_from_blkaddr(ino_ni.blk_addr);
+ dump_node_offset(ni.blk_addr);
+ }
+ }
+
+ return 0;
+}
diff --git a/f2fs-tools/fsck/f2fs.h b/f2fs-tools/fsck/f2fs.h
new file mode 100644
index 0000000..c268f15
--- /dev/null
+++ b/f2fs-tools/fsck/f2fs.h
@@ -0,0 +1,387 @@
+/**
+ * f2fs.h
+ *
+ * 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.
+ */
+#ifndef _F2FS_H_
+#define _F2FS_H_
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include <mntent.h>
+#include <linux/types.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <assert.h>
+
+#include <f2fs_fs.h>
+
+#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
+};
+
+struct node_info {
+ nid_t nid;
+ nid_t ino;
+ u32 blk_addr;
+ unsigned char version;
+};
+
+struct f2fs_nm_info {
+ block_t nat_blkaddr;
+ nid_t max_nid;
+ nid_t init_scan_nid;
+ nid_t next_scan_nid;
+
+ unsigned int nat_cnt;
+ unsigned int fcnt;
+
+ char *nat_bitmap;
+ int bitmap_size;
+};
+
+struct seg_entry {
+ unsigned short valid_blocks; /* # of valid blocks */
+ unsigned char *cur_valid_map; /* validity bitmap of blocks */
+ /*
+ * # of valid blocks and the validity bitmap stored in the the last
+ * checkpoint pack. This information is used by the SSR mode.
+ */
+ unsigned short ckpt_valid_blocks;
+ unsigned char *ckpt_valid_map;
+ unsigned char type; /* segment type like CURSEG_XXX_TYPE */
+ unsigned char orig_type; /* segment type like CURSEG_XXX_TYPE */
+ unsigned long long mtime; /* modification time of the segment */
+};
+
+struct sec_entry {
+ unsigned int valid_blocks; /* # of valid blocks in a section */
+};
+
+struct sit_info {
+
+ block_t sit_base_addr; /* start block address of SIT area */
+ block_t sit_blocks; /* # of blocks used by SIT area */
+ block_t written_valid_blocks; /* # of valid blocks in main area */
+ char *sit_bitmap; /* SIT bitmap pointer */
+ unsigned int bitmap_size; /* SIT bitmap size */
+
+ unsigned long *dirty_sentries_bitmap; /* bitmap for dirty sentries */
+ unsigned int dirty_sentries; /* # of dirty sentries */
+ unsigned int sents_per_block; /* # of SIT entries per block */
+ struct seg_entry *sentries; /* SIT segment-level cache */
+ struct sec_entry *sec_entries; /* SIT section-level cache */
+
+ unsigned long long elapsed_time; /* elapsed time after mount */
+ unsigned long long mounted_time; /* mount time */
+ unsigned long long min_mtime; /* min. modification time */
+ unsigned long long max_mtime; /* max. modification time */
+};
+
+struct curseg_info {
+ struct f2fs_summary_block *sum_blk; /* cached summary block */
+ unsigned char alloc_type; /* current allocation type */
+ unsigned int segno; /* current segment number */
+ unsigned short next_blkoff; /* next block offset to write */
+ unsigned int zone; /* current zone number */
+ unsigned int next_segno; /* preallocated segment */
+};
+
+struct f2fs_sm_info {
+ struct sit_info *sit_info;
+ struct curseg_info *curseg_array;
+
+ block_t seg0_blkaddr;
+ block_t main_blkaddr;
+ block_t ssa_blkaddr;
+
+ unsigned int segment_count;
+ unsigned int main_segments;
+ unsigned int reserved_segments;
+ unsigned int ovp_segments;
+};
+
+struct f2fs_sb_info {
+ struct f2fs_fsck *fsck;
+
+ struct f2fs_super_block *raw_super;
+ 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;
+
+ /* basic file system units */
+ unsigned int log_sectors_per_block; /* log2 sectors per block */
+ unsigned int log_blocksize; /* log2 block size */
+ unsigned int blocksize; /* block size */
+ unsigned int root_ino_num; /* root inode number*/
+ unsigned int node_ino_num; /* node inode number*/
+ unsigned int meta_ino_num; /* meta inode number*/
+ unsigned int log_blocks_per_seg; /* log2 blocks per segment */
+ unsigned int blocks_per_seg; /* blocks per segment */
+ unsigned int segs_per_sec; /* segments per section */
+ unsigned int secs_per_zone; /* sections per zone */
+ unsigned int total_sections; /* total section count */
+ unsigned int total_node_count; /* total node block count */
+ unsigned int total_valid_node_count; /* valid node block count */
+ unsigned int total_valid_inode_count; /* valid inode count */
+ int active_logs; /* # of active logs */
+
+ block_t user_block_count; /* # of user blocks */
+ block_t total_valid_block_count; /* # of valid blocks */
+ block_t alloc_valid_block_count; /* # of allocated blocks */
+ block_t last_valid_block_count; /* for recovery */
+ u32 s_next_generation; /* for NFS support */
+
+ unsigned int cur_victim_sec; /* current victim section num */
+
+};
+
+static inline struct f2fs_super_block *F2FS_RAW_SUPER(struct f2fs_sb_info *sbi)
+{
+ return (struct f2fs_super_block *)(sbi->raw_super);
+}
+
+static inline struct f2fs_checkpoint *F2FS_CKPT(struct f2fs_sb_info *sbi)
+{
+ return (struct f2fs_checkpoint *)(sbi->ckpt);
+}
+
+static inline struct f2fs_fsck *F2FS_FSCK(struct f2fs_sb_info *sbi)
+{
+ return (struct f2fs_fsck *)(sbi->fsck);
+}
+
+static inline struct f2fs_nm_info *NM_I(struct f2fs_sb_info *sbi)
+{
+ return (struct f2fs_nm_info *)(sbi->nm_info);
+}
+
+static inline struct f2fs_sm_info *SM_I(struct f2fs_sb_info *sbi)
+{
+ return (struct f2fs_sm_info *)(sbi->sm_info);
+}
+
+static inline struct sit_info *SIT_I(struct f2fs_sb_info *sbi)
+{
+ return (struct sit_info *)(SM_I(sbi)->sit_info);
+}
+
+static inline void *inline_data_addr(struct f2fs_node *node_blk)
+{
+ return (void *)&(node_blk->i.i_addr[1]);
+}
+
+static inline unsigned int ofs_of_node(struct f2fs_node *node_blk)
+{
+ unsigned flag = le32_to_cpu(node_blk->footer.flag);
+ return flag >> OFFSET_BIT_SHIFT;
+}
+
+static inline unsigned long __bitmap_size(struct f2fs_sb_info *sbi, int flag)
+{
+ struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
+
+ /* return NAT or SIT bitmap */
+ if (flag == NAT_BITMAP)
+ return le32_to_cpu(ckpt->nat_ver_bitmap_bytesize);
+ else if (flag == SIT_BITMAP)
+ return le32_to_cpu(ckpt->sit_ver_bitmap_bytesize);
+
+ return 0;
+}
+
+static inline void *__bitmap_ptr(struct f2fs_sb_info *sbi, int flag)
+{
+ struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
+ 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)
+{
+ unsigned int ckpt_flags = le32_to_cpu(cp->ckpt_flags);
+ return ckpt_flags & f;
+}
+
+static inline block_t __start_cp_addr(struct f2fs_sb_info *sbi)
+{
+ block_t start_addr;
+ struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
+ unsigned long long ckpt_version = le64_to_cpu(ckpt->checkpoint_ver);
+
+ start_addr = le32_to_cpu(F2FS_RAW_SUPER(sbi)->cp_blkaddr);
+
+ /*
+ * odd numbered checkpoint should at cp segment 0
+ * and even segent must be at cp segment 1
+ */
+ if (!(ckpt_version & 1))
+ start_addr += sbi->blocks_per_seg;
+
+ return start_addr;
+}
+
+static inline block_t __start_sum_addr(struct f2fs_sb_info *sbi)
+{
+ return le32_to_cpu(F2FS_CKPT(sbi)->cp_pack_start_sum);
+}
+
+static inline block_t __end_block_addr(struct f2fs_sb_info *sbi)
+{
+ block_t end = SM_I(sbi)->main_blkaddr;
+ return end + le64_to_cpu(F2FS_RAW_SUPER(sbi)->block_count);
+}
+
+#define GET_ZONENO_FROM_SEGNO(sbi, segno) \
+ ((segno / sbi->segs_per_sec) / sbi->secs_per_zone)
+
+#define IS_DATASEG(t) \
+ ((t == CURSEG_HOT_DATA) || (t == CURSEG_COLD_DATA) || \
+ (t == CURSEG_WARM_DATA))
+
+#define IS_NODESEG(t) \
+ ((t == CURSEG_HOT_NODE) || (t == CURSEG_COLD_NODE) || \
+ (t == CURSEG_WARM_NODE))
+
+#define GET_SUM_BLKADDR(sbi, segno) \
+ ((sbi->sm_info->ssa_blkaddr) + segno)
+
+#define GET_SEGOFF_FROM_SEG0(sbi, blk_addr) \
+ ((blk_addr) - SM_I(sbi)->seg0_blkaddr)
+
+#define GET_SEGNO_FROM_SEG0(sbi, blk_addr) \
+ (GET_SEGOFF_FROM_SEG0(sbi, blk_addr) >> sbi->log_blocks_per_seg)
+
+#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))
+
+static inline struct curseg_info *CURSEG_I(struct f2fs_sb_info *sbi, int type)
+{
+ return (struct curseg_info *)(SM_I(sbi)->curseg_array + type);
+}
+
+static inline block_t start_sum_block(struct f2fs_sb_info *sbi)
+{
+ return __start_cp_addr(sbi) + le32_to_cpu(F2FS_CKPT(sbi)->cp_pack_start_sum);
+}
+
+static inline block_t sum_blk_addr(struct f2fs_sb_info *sbi, int base, int type)
+{
+ return __start_cp_addr(sbi) + le32_to_cpu(F2FS_CKPT(sbi)->cp_pack_total_block_count)
+ - (base + 1) + type;
+}
+
+
+#define nats_in_cursum(sum) (le16_to_cpu(sum->n_nats))
+#define sits_in_cursum(sum) (le16_to_cpu(sum->n_sits))
+
+#define nat_in_journal(sum, i) (sum->nat_j.entries[i].ne)
+#define nid_in_journal(sum, i) (sum->nat_j.entries[i].nid)
+#define sit_in_journal(sum, i) (sum->sit_j.entries[i].se)
+#define segno_in_journal(sum, i) (sum->sit_j.entries[i].segno)
+
+#define SIT_ENTRY_OFFSET(sit_i, segno) \
+ (segno % sit_i->sents_per_block)
+#define SIT_BLOCK_OFFSET(sit_i, segno) \
+ (segno / SIT_ENTRY_PER_BLOCK)
+#define TOTAL_SEGS(sbi) (SM_I(sbi)->main_segments)
+
+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) {
+ ASSERT_MSG("block addr [0x%x]\n", addr);
+ 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)
+{
+ ASSERT(blk_addr >= SM_I(sbi)->main_blkaddr);
+ return blk_addr - SM_I(sbi)->main_blkaddr;
+}
+
+static inline u32 GET_SEGNO(struct f2fs_sb_info *sbi, u64 blk_addr)
+{
+ return (u32)(BLKOFF_FROM_MAIN(sbi, blk_addr)
+ >> sbi->log_blocks_per_seg);
+}
+
+static inline u32 OFFSET_IN_SEG(struct f2fs_sb_info *sbi, u64 blk_addr)
+{
+ return (u32)(BLKOFF_FROM_MAIN(sbi, blk_addr)
+ % (1 << sbi->log_blocks_per_seg));
+}
+
+static inline void node_info_from_raw_nat(struct node_info *ni,
+ struct f2fs_nat_entry *raw_nat)
+{
+ ni->ino = le32_to_cpu(raw_nat->ino);
+ ni->blk_addr = le32_to_cpu(raw_nat->block_addr);
+ ni->version = raw_nat->version;
+}
+
+extern int lookup_nat_in_journal(struct f2fs_sb_info *sbi, u32 nid, struct f2fs_nat_entry *ne);
+#define IS_SUM_NODE_SEG(footer) (footer.entry_type == SUM_TYPE_NODE)
+
+#endif /* _F2FS_H_ */
diff --git a/f2fs-tools/fsck/fsck.c b/f2fs-tools/fsck/fsck.c
new file mode 100644
index 0000000..1b27ae0
--- /dev/null
+++ b/f2fs-tools/fsck/fsck.c
@@ -0,0 +1,1210 @@
+/**
+ * fsck.c
+ *
+ * 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.
+ */
+#include "fsck.h"
+
+char *tree_mark;
+uint32_t tree_mark_size = 256;
+
+static inline int f2fs_set_main_bitmap(struct f2fs_sb_info *sbi, u32 blk,
+ int type)
+{
+ struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
+ struct seg_entry *se;
+
+ se = get_seg_entry(sbi, GET_SEGNO(sbi, blk));
+ if (se->type != type) {
+ if (type == CURSEG_WARM_DATA) {
+ if (se->type != CURSEG_COLD_DATA) {
+ DBG(1, "Wrong segment type [0x%x] %x -> %x",
+ GET_SEGNO(sbi, blk), se->type,
+ CURSEG_WARM_DATA);
+ se->type = CURSEG_WARM_DATA;
+ }
+ } else {
+ DBG(1, "Wrong segment type [0x%x] %x -> %x",
+ GET_SEGNO(sbi, blk), se->type, type);
+ se->type = type;
+ }
+ }
+ 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;
+
+ node = calloc(sizeof(struct hard_link_node), 1);
+ ASSERT(node != NULL);
+
+ node->nid = nid;
+ node->links = link_cnt;
+ node->next = NULL;
+
+ if (fsck->hard_link_list_head == NULL) {
+ fsck->hard_link_list_head = node;
+ goto out;
+ }
+
+ tmp = fsck->hard_link_list_head;
+
+ /* Find insertion position */
+ while (tmp && (nid < tmp->nid)) {
+ ASSERT(tmp->nid != nid);
+ prev = tmp;
+ tmp = tmp->next;
+ }
+
+ if (tmp == fsck->hard_link_list_head) {
+ node->next = tmp;
+ fsck->hard_link_list_head = node;
+ } else {
+ prev->next = node;
+ node->next = tmp;
+ }
+
+out:
+ DBG(2, "ino[0x%x] has hard links [0x%x]\n", nid, link_cnt);
+ return 0;
+}
+
+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)
+ return -EINVAL;
+
+ node = fsck->hard_link_list_head;
+
+ while (node && (nid < node->nid)) {
+ prev = node;
+ node = node->next;
+ }
+
+ if (node == NULL || (nid != node->nid))
+ return -EINVAL;
+
+ /* Decrease link count */
+ node->links = node->links - 1;
+
+ /* if link count becomes one, remove the node */
+ if (node->links == 1) {
+ if (fsck->hard_link_list_head == node)
+ fsck->hard_link_list_head = node->next;
+ else
+ 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)
+{
+ int ret = 0;
+ struct f2fs_summary sum_entry;
+
+ ret = get_sum_entry(sbi, blk_addr, &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 0;
+}
+
+static int is_valid_ssa_data_blk(struct f2fs_sb_info *sbi, u32 blk_addr,
+ u32 parent_nid, u16 idx_in_node, u8 version)
+{
+ int ret = 0;
+ struct f2fs_summary sum_entry;
+
+ ret = get_sum_entry(sbi, blk_addr, &sum_entry);
+
+ 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, "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("Invalid data seg summary\n");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+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);
+ int ret;
+
+ if (!IS_VALID_NID(sbi, nid)) {
+ ASSERT_MSG("nid is not valid. [0x%x]", nid);
+ return -EINVAL;
+ }
+
+ get_node_info(sbi, nid, ni);
+ if (ni->blk_addr == NEW_ADDR) {
+ ASSERT_MSG("nid is NEW_ADDR. [0x%x]", nid);
+ return -EINVAL;
+ }
+
+ if (!IS_VALID_BLK_ADDR(sbi, ni->blk_addr)) {
+ ASSERT_MSG("blkaddres is not valid. [0x%x]", ni->blk_addr);
+ return -EINVAL;
+ }
+
+ 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);
+
+ 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;
+ }
+
+ 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;
+ }
+
+ if (ntype == TYPE_XATTR) {
+ u32 flag = le32_to_cpu(node_blk->footer.flag);
+
+ 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;
+ }
+ }
+
+ /* 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);
+
+ /* 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, CURSEG_COLD_NODE);
+ DBG(2, "ino[0x%x] x_nid[0x%x]\n", ino, x_nid);
+out:
+ free(node_blk);
+ return ret;
+}
+
+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) {
+ fsck_chk_inode_blk(sbi, nid, ftype, node_blk, blk_cnt, &ni);
+ } else {
+ switch (ntype) {
+ case TYPE_DIRECT_NODE:
+ f2fs_set_main_bitmap(sbi, ni.blk_addr,
+ CURSEG_WARM_NODE);
+ fsck_chk_dnode_blk(sbi, inode, nid, ftype, node_blk,
+ blk_cnt, &ni);
+ break;
+ case TYPE_INDIRECT_NODE:
+ f2fs_set_main_bitmap(sbi, ni.blk_addr,
+ CURSEG_COLD_NODE);
+ fsck_chk_idnode_blk(sbi, inode, ftype, node_blk,
+ blk_cnt);
+ break;
+ case TYPE_DOUBLE_INDIRECT_NODE:
+ f2fs_set_main_bitmap(sbi, ni.blk_addr,
+ CURSEG_COLD_NODE);
+ fsck_chk_didnode_blk(sbi, inode, ftype, node_blk,
+ blk_cnt);
+ break;
+ default:
+ ASSERT(0);
+ }
+ }
+ free(node_blk);
+ return 0;
+err:
+ free(node_blk);
+ return -EINVAL;
+}
+
+/* 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);
+ unsigned int idx = 0;
+ int need_fix = 0;
+ int ret;
+
+ if (f2fs_test_main_bitmap(sbi, ni->blk_addr) == 0)
+ fsck->chk.valid_inode_cnt++;
+
+ if (ftype == F2FS_FT_DIR) {
+ f2fs_set_main_bitmap(sbi, ni->blk_addr, CURSEG_HOT_NODE);
+ } else {
+ if (f2fs_test_main_bitmap(sbi, ni->blk_addr) == 0) {
+ f2fs_set_main_bitmap(sbi, ni->blk_addr,
+ CURSEG_WARM_NODE);
+ 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 {
+ 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);
+ 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);
+ }
+ goto check;
+ }
+ /* No need to go deep into the node */
+ return;
+ }
+ }
+
+ 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)
+ goto check;
+
+ if((node_blk->i.i_inline & F2FS_INLINE_DATA)) {
+ if (le32_to_cpu(node_blk->i.i_addr[0]) != 0) {
+ /* should fix this bug all the time */
+ FIX_MSG("inline_data has wrong 0'th block = %x",
+ le32_to_cpu(node_blk->i.i_addr[0]));
+ node_blk->i.i_addr[0] = 0;
+ node_blk->i.i_blocks = cpu_to_le64(*blk_cnt);
+ need_fix = 1;
+ }
+ if (!(node_blk->i.i_inline & F2FS_DATA_EXIST)) {
+ char buf[MAX_INLINE_DATA];
+ memset(buf, 0, MAX_INLINE_DATA);
+
+ if (memcmp(buf, &node_blk->i.i_addr[1],
+ MAX_INLINE_DATA)) {
+ FIX_MSG("inline_data has DATA_EXIST");
+ node_blk->i.i_inline |= F2FS_DATA_EXIST;
+ need_fix = 1;
+ }
+ }
+ DBG(3, "ino[0x%x] has inline data!\n", nid);
+ goto check;
+ }
+ if((node_blk->i.i_inline & F2FS_INLINE_DENTRY)) {
+ DBG(3, "ino[0x%x] has inline dentry!\n", nid);
+ ret = fsck_chk_inline_dentries(sbi, node_blk,
+ &child_cnt, &child_files);
+ if (ret < 0) {
+ /* should fix this bug all the time */
+ need_fix = 1;
+ }
+ goto check;
+ }
+
+ /* readahead node blocks */
+ for (idx = 0; idx < 5; idx++) {
+ u32 nid = le32_to_cpu(node_blk->i.i_nid[idx]);
+
+ if (nid != 0) {
+ struct node_info ni;
+
+ get_node_info(sbi, nid, &ni);
+ if (IS_VALID_BLK_ADDR(sbi, ni.blk_addr))
+ dev_reada_block(ni.blk_addr);
+ }
+ }
+
+ /* 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) {
+ ret = fsck_chk_data_blk(sbi,
+ le32_to_cpu(node_blk->i.i_addr[idx]),
+ &child_cnt, &child_files,
+ (i_blocks == *blk_cnt),
+ 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);
+ }
+ }
+ }
+
+ /* check node blocks in inode */
+ for (idx = 0; idx < 5; idx++) {
+ if (idx == 0 || idx == 1)
+ ntype = TYPE_DIRECT_NODE;
+ else if (idx == 2 || idx == 3)
+ ntype = TYPE_INDIRECT_NODE;
+ else if (idx == 4)
+ ntype = TYPE_DOUBLE_INDIRECT_NODE;
+ else
+ ASSERT(0);
+
+ if (le32_to_cpu(node_blk->i.i_nid[idx]) != 0) {
+ ret = fsck_chk_node_blk(sbi, &node_blk->i,
+ le32_to_cpu(node_blk->i.i_nid[idx]),
+ 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: 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: 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);
+ }
+ }
+
+ 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 idx, ret;
+ u32 child_cnt = 0, child_files = 0;
+ int need_fix = 0;
+
+ for (idx = 0; idx < ADDRS_PER_BLOCK; idx++) {
+ if (le32_to_cpu(node_blk->dn.addr[idx]) == 0x0)
+ continue;
+ 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;
+ } else if (config.fix_on) {
+ node_blk->dn.addr[idx] = 0;
+ need_fix = 1;
+ FIX_MSG("[0x%x] dn.addr[%d] = 0", nid, idx);
+ }
+ }
+ if (need_fix) {
+ ret = dev_write_block(node_blk, ni->blk_addr);
+ ASSERT(ret >= 0);
+ }
+ return 0;
+}
+
+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;
+ ret = fsck_chk_node_blk(sbi, inode,
+ le32_to_cpu(node_blk->in.nid[i]),
+ 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,
+ 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;
+ ret = fsck_chk_node_blk(sbi, inode,
+ le32_to_cpu(node_blk->in.nid[i]),
+ 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;
+}
+
+static void print_dentry(__u32 depth, __u8 *name,
+ unsigned long *bitmap,
+ struct f2fs_dir_entry *dentry,
+ int max, int idx, int last_blk)
+{
+ int last_de = 0;
+ int next_idx = 0;
+ int name_len;
+ unsigned int i;
+ int bit_offset;
+
+ if (config.dbg_lv != -1)
+ return;
+
+ name_len = le16_to_cpu(dentry[idx].name_len);
+ next_idx = idx + (name_len + F2FS_SLOT_LEN - 1) / F2FS_SLOT_LEN;
+
+ bit_offset = find_next_bit(bitmap, max, next_idx);
+ if (bit_offset >= max && last_blk)
+ last_de = 1;
+
+ if (tree_mark_size <= depth) {
+ tree_mark_size *= 2;
+ tree_mark = realloc(tree_mark, tree_mark_size);
+ }
+
+ if (last_de)
+ tree_mark[depth] = '`';
+ else
+ tree_mark[depth] = '|';
+
+ if (tree_mark[depth - 1] == '`')
+ tree_mark[depth - 1] = ' ';
+
+
+ for (i = 1; i < depth; i++)
+ printf("%c ", tree_mark[i]);
+ printf("%c-- %s 0x%x\n", last_de ? '`' : '|',
+ name, le32_to_cpu(dentry[idx].ino));
+}
+
+static int __chk_dentries(struct f2fs_sb_info *sbi, u32 *child_cnt,
+ u32* child_files,
+ unsigned long *bitmap,
+ struct f2fs_dir_entry *dentry,
+ __u8 (*filenames)[F2FS_SLOT_LEN],
+ int max, int last_blk)
+{
+ struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
+ enum FILE_TYPE ftype;
+ int dentries = 0;
+ u32 blk_cnt;
+ u8 *name;
+ u32 hash_code, ino;
+ u16 name_len;;
+ int ret = 0;
+ int fixed = 0;
+ int i;
+
+ /* readahead inode blocks */
+ for (i = 0; i < max;) {
+ if (test_bit(i, bitmap) == 0) {
+ i++;
+ continue;
+ }
+ ino = le32_to_cpu(dentry[i].ino);
+
+ if (IS_VALID_NID(sbi, ino)) {
+ struct node_info ni;
+
+ get_node_info(sbi, ino, &ni);
+ if (IS_VALID_BLK_ADDR(sbi, ni.blk_addr))
+ dev_reada_block(ni.blk_addr);
+ }
+ name_len = le16_to_cpu(dentry[i].name_len);
+ i += (name_len + F2FS_SLOT_LEN - 1) / F2FS_SLOT_LEN;
+ }
+
+ for (i = 0; i < max;) {
+ if (test_bit(i, bitmap) == 0) {
+ i++;
+ continue;
+ }
+ if (!IS_VALID_NID(sbi, le32_to_cpu(dentry[i].ino))) {
+ DBG(1, "Bad dentry 0x%x with invalid NID/ino 0x%x",
+ i, le32_to_cpu(dentry[i].ino));
+ if (config.fix_on) {
+ FIX_MSG("Clear bad dentry 0x%x with bad ino 0x%x",
+ i, le32_to_cpu(dentry[i].ino));
+ clear_bit(i, bitmap);
+ i++;
+ fixed = 1;
+ continue;
+ }
+ }
+ ftype = dentry[i].file_type;
+ if ((ftype <= F2FS_FT_UNKNOWN || ftype > F2FS_FT_LAST_FILE_TYPE) && config.fix_on) {
+ DBG(1, "Bad dentry 0x%x with unexpected ftype 0x%x",
+ i, ftype);
+ if (config.fix_on) {
+ FIX_MSG("Clear bad dentry 0x%x with bad ftype 0x%x",
+ i, ftype);
+ clear_bit(i, bitmap);
+ i++;
+ fixed = 1;
+ continue;
+ }
+ }
+ name_len = le16_to_cpu(dentry[i].name_len);
+ name = calloc(name_len + 1, 1);
+ memcpy(name, filenames[i], name_len);
+ hash_code = f2fs_dentry_hash((const unsigned char *)name,
+ name_len);
+
+ /* fix hash_code made by old buggy code */
+ if (le32_to_cpu(dentry[i].hash_code) != hash_code) {
+ dentry[i].hash_code = hash_code;
+ fixed = 1;
+ FIX_MSG("hash_code[%d] of %s", i, name);
+ }
+
+ /* Becareful. 'dentry.file_type' is not imode. */
+ if (ftype == F2FS_FT_DIR) {
+ *child_cnt = *child_cnt + 1;
+ if ((name[0] == '.' && name_len == 1) ||
+ (name[0] == '.' && name[1] == '.' &&
+ name_len == 2)) {
+ i++;
+ free(name);
+ continue;
+ }
+ }
+
+ 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(dentry[i].ino),
+ dentry[i].file_type);
+
+ print_dentry(fsck->dentry_depth, name, bitmap,
+ dentry, max, i, last_blk);
+
+ blk_cnt = 1;
+ ret = fsck_chk_node_blk(sbi,
+ NULL, le32_to_cpu(dentry[i].ino),
+ ftype, TYPE_INODE, &blk_cnt);
+
+ 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, bitmap);
+ FIX_MSG("Unlink [0x%x] - %s len[0x%x], type[0x%x]",
+ le32_to_cpu(dentry[i].ino),
+ name, name_len,
+ dentry[i].file_type);
+ i += slots;
+ free(name);
+ fixed = 1;
+ continue;
+ }
+
+ i += (name_len + F2FS_SLOT_LEN - 1) / F2FS_SLOT_LEN;
+ dentries++;
+ *child_files = *child_files + 1;
+ free(name);
+ }
+ return fixed ? -1 : dentries;
+}
+
+int fsck_chk_inline_dentries(struct f2fs_sb_info *sbi,
+ struct f2fs_node *node_blk, u32 *child_cnt, u32 *child_files)
+{
+ struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
+ struct f2fs_inline_dentry *de_blk;
+ int dentries;
+
+ de_blk = inline_data_addr(node_blk);
+ ASSERT(de_blk != NULL);
+
+ fsck->dentry_depth++;
+ dentries = __chk_dentries(sbi, child_cnt, child_files,
+ (unsigned long *)de_blk->dentry_bitmap,
+ de_blk->dentry, de_blk->filename,
+ NR_INLINE_DENTRY, 1);
+ if (dentries < 0) {
+ DBG(1, "[%3d] Inline Dentry Block Fixed hash_codes\n\n",
+ fsck->dentry_depth);
+ } else {
+ DBG(1, "[%3d] Inline Dentry Block Done : "
+ "dentries:%d in %d slots (len:%d)\n\n",
+ fsck->dentry_depth, dentries,
+ (int)NR_INLINE_DENTRY, F2FS_NAME_LEN);
+ }
+ fsck->dentry_depth--;
+ return dentries;
+}
+
+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);
+ struct f2fs_dentry_block *de_blk;
+ int dentries, ret;
+
+ de_blk = (struct f2fs_dentry_block *)calloc(BLOCK_SZ, 1);
+ ASSERT(de_blk != NULL);
+
+ ret = dev_read_block(de_blk, blk_addr);
+ ASSERT(ret >= 0);
+
+ fsck->dentry_depth++;
+ dentries = __chk_dentries(sbi, child_cnt, child_files,
+ (unsigned long *)de_blk->dentry_bitmap,
+ de_blk->dentry, de_blk->filename,
+ NR_DENTRY_IN_BLOCK, last_blk);
+
+ if (dentries < 0) {
+ ret = dev_write_block(de_blk, blk_addr);
+ ASSERT(ret >= 0);
+ DBG(1, "[%3d] Dentry Block [0x%x] Fixed hash_codes\n\n",
+ fsck->dentry_depth, blk_addr);
+ } else {
+ 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, 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);
+
+ /* Is it reserved block? */
+ if (blk_addr == NEW_ADDR) {
+ fsck->chk.valid_blk_cnt++;
+ return 0;
+ }
+
+ if (!IS_VALID_BLK_ADDR(sbi, blk_addr)) {
+ ASSERT_MSG("blkaddres is not valid. [0x%x]", blk_addr);
+ return -EINVAL;
+ }
+
+ 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;
+ }
+
+ if (f2fs_test_sit_bitmap(sbi, blk_addr) == 0)
+ ASSERT_MSG("SIT bitmap is 0x0. blk_addr[0x%x]", blk_addr);
+
+ 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);
+
+
+ fsck->chk.valid_blk_cnt++;
+
+ if (ftype == F2FS_FT_DIR) {
+ f2fs_set_main_bitmap(sbi, blk_addr, CURSEG_HOT_DATA);
+ return fsck_chk_dentry_blk(sbi, blk_addr, child_cnt,
+ child_files, last_blk);
+ } else {
+ f2fs_set_main_bitmap(sbi, blk_addr, CURSEG_WARM_DATA);
+ }
+ return 0;
+}
+
+void fsck_chk_orphan_node(struct f2fs_sb_info *sbi)
+{
+ 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(ckpt, CP_ORPHAN_PRESENT_FLAG))
+ 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++) {
+ 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);
+ if (config.fix_on) {
+ FIX_MSG("Discard orphan inodes: ino [0x%x]",
+ ino);
+ continue;
+ }
+ blk_cnt = 1;
+ fsck_chk_node_blk(sbi, NULL, ino,
+ F2FS_FT_ORPHAN, TYPE_INODE, &blk_cnt);
+ }
+ memset(orphan_blk, 0, BLOCK_SZ);
+ }
+ free(orphan_blk);
+}
+
+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.
+ * 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.
+ */
+ fsck->nr_main_blks = sm_i->main_segments << sbi->log_blocks_per_seg;
+ fsck->main_area_bitmap_sz = (fsck->nr_main_blks + 7) / 8;
+ fsck->main_area_bitmap = calloc(fsck->main_area_bitmap_sz, 1);
+ ASSERT(fsck->main_area_bitmap != NULL);
+
+ build_nat_area_bitmap(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 check_sit_types(struct f2fs_sb_info *sbi)
+{
+ unsigned int i;
+ int err = 0;
+
+ for (i = 0; i < TOTAL_SEGS(sbi); i++) {
+ struct seg_entry *se;
+
+ se = get_seg_entry(sbi, i);
+ if (se->orig_type != se->type) {
+ if (se->orig_type == CURSEG_COLD_DATA) {
+ se->type = se->orig_type;
+ } else {
+ FIX_MSG("Wrong segment type [0x%x] %x -> %x",
+ i, se->orig_type, se->type);
+ err = -EINVAL;
+ }
+ }
+ }
+ return err;
+}
+
+int fsck_verify(struct f2fs_sb_info *sbi)
+{
+ unsigned int i = 0;
+ int ret = 0;
+ int force = 0;
+ u32 nr_unref_nid = 0;
+ struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
+ struct hard_link_node *node = NULL;
+
+ printf("\n");
+
+ for (i = 0; i < fsck->nr_nat_entries; i++) {
+ if (f2fs_test_bit(i, fsck->nat_area_bitmap) != 0) {
+ printf("NID[0x%x] is unreachable\n", i);
+ nr_unref_nid++;
+ }
+ }
+
+ if (fsck->hard_link_list_head != NULL) {
+ node = fsck->hard_link_list_head;
+ while (node) {
+ printf("NID[0x%x] has [0x%x] more unreachable links\n",
+ node->nid, node->links);
+ node = node->next;
+ }
+ config.bug_on = 1;
+ }
+
+ printf("[FSCK] Unreachable nat entries ");
+ if (nr_unref_nid == 0x0) {
+ printf(" [Ok..] [0x%x]\n", nr_unref_nid);
+ } 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) {
+ printf("[Ok..]\n");
+ } else {
+ printf("[Fail]\n");
+ ret = EXIT_ERR_CODE;
+ config.bug_on = 1;
+ }
+
+ printf("[FSCK] Hard link checking for regular file ");
+ if (fsck->hard_link_list_head == NULL) {
+ printf(" [Ok..] [0x%x]\n", fsck->chk.multi_hard_link_files);
+ } 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%x]\n", (u32)fsck->chk.valid_blk_cnt);
+ } else {
+ 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) ");
+ if (sbi->total_valid_node_count == fsck->chk.valid_node_cnt) {
+ printf(" [Ok..] [0x%x]\n", fsck->chk.valid_node_cnt);
+ } 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) ");
+ if (sbi->total_valid_node_count == fsck->chk.valid_nat_entry_cnt) {
+ printf(" [Ok..] [0x%x]\n", fsck->chk.valid_nat_entry_cnt);
+ } 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 ");
+ if (sbi->total_valid_inode_count == fsck->chk.valid_inode_cnt) {
+ printf(" [Ok..] [0x%x]\n", fsck->chk.valid_inode_cnt);
+ } 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] fixing SIT types\n");
+ if (check_sit_types(sbi) != 0)
+ force = 1;
+
+ printf("[FSCK] other corrupted bugs ");
+ if (config.bug_on == 0) {
+ printf(" [Ok..]\n");
+ } else {
+ printf(" [Fail]\n");
+ ret = EXIT_ERR_CODE;
+ }
+
+ /* fix global metadata */
+ if (force || (config.bug_on && config.fix_on)) {
+ fix_nat_entries(sbi);
+ rewrite_sit_area_bitmap(sbi);
+ fix_checkpoint(sbi);
+ }
+ return ret;
+}
+
+void fsck_free(struct f2fs_sb_info *sbi)
+{
+ struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
+ if (fsck->main_area_bitmap)
+ free(fsck->main_area_bitmap);
+
+ if (fsck->nat_area_bitmap)
+ free(fsck->nat_area_bitmap);
+
+ if (fsck->sit_area_bitmap)
+ free(fsck->sit_area_bitmap);
+
+ if (tree_mark)
+ free(tree_mark);
+}
diff --git a/f2fs-tools/fsck/fsck.h b/f2fs-tools/fsck/fsck.h
new file mode 100644
index 0000000..9cad013
--- /dev/null
+++ b/f2fs-tools/fsck/fsck.h
@@ -0,0 +1,131 @@
+/**
+ * fsck.h
+ *
+ * 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.
+ */
+#ifndef _FSCK_H_
+#define _FSCK_H_
+
+#include "f2fs.h"
+
+/* fsck.c */
+struct orphan_info {
+ u32 nr_inodes;
+ u32 *ino_list;
+};
+
+struct f2fs_fsck {
+ struct f2fs_sb_info sbi;
+
+ struct orphan_info orphani;
+ struct chk_result {
+ u64 valid_blk_cnt;
+ u32 valid_nat_entry_cnt;
+ u32 valid_node_cnt;
+ u32 valid_inode_cnt;
+ 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;
+
+ char *main_seg_usage;
+ char *main_area_bitmap;
+ char *nat_area_bitmap;
+ char *sit_area_bitmap;
+
+ u64 main_area_bitmap_sz;
+ u32 nat_area_bitmap_sz;
+ u32 sit_area_bitmap_sz;
+
+ u64 nr_main_blks;
+ u32 nr_nat_entries;
+
+ u32 dentry_depth;
+};
+
+#define BLOCK_SZ 4096
+struct block {
+ unsigned char buf[BLOCK_SZ];
+};
+
+enum NODE_TYPE {
+ TYPE_INODE = 37,
+ TYPE_DIRECT_NODE = 43,
+ TYPE_INDIRECT_NODE = 53,
+ TYPE_DOUBLE_INDIRECT_NODE = 67,
+ TYPE_XATTR = 77
+};
+
+struct hard_link_node {
+ u32 nid;
+ u32 links;
+ struct hard_link_node *next;
+};
+
+enum seg_type {
+ SEG_TYPE_DATA,
+ SEG_TYPE_CUR_DATA,
+ SEG_TYPE_NODE,
+ SEG_TYPE_CUR_NODE,
+ SEG_TYPE_MAX,
+};
+
+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);
+int fsck_chk_inline_dentries(struct f2fs_sb_info *, struct f2fs_node *,
+ u32 *, u32 *);
+
+extern void print_node_info(struct f2fs_node *);
+extern void print_inode_info(struct f2fs_inode *, int);
+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 {
+ nid_t nid;
+ int start_sit;
+ int end_sit;
+ int start_ssa;
+ int end_ssa;
+ int32_t 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_info_from_blkaddr(struct f2fs_sb_info *, u32);
+
+#endif /* _FSCK_H_ */
diff --git a/f2fs-tools/fsck/main.c b/f2fs-tools/fsck/main.c
new file mode 100644
index 0000000..3606f62
--- /dev/null
+++ b/f2fs-tools/fsck/main.c
@@ -0,0 +1,261 @@
+/**
+ * main.c
+ *
+ * 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.
+ */
+#include "fsck.h"
+#include <libgen.h>
+
+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);
+}
+
+void dump_usage()
+{
+ MSG(0, "\nUsage: dump.f2fs [options] device\n");
+ MSG(0, "[options]:\n");
+ MSG(0, " -d debug level [default:0]\n");
+ MSG(0, " -i inode no (hex)\n");
+ MSG(0, " -s [SIT dump segno from #1~#2 (decimal), for all 0~-1]\n");
+ MSG(0, " -a [SSA dump segno from #1~#2 (decimal), for all 0~-1]\n");
+ MSG(0, " -b blk_addr (in 4KB)\n");
+
+ exit(1);
+}
+
+void f2fs_parse_options(int argc, char *argv[])
+{
+ int option = 0;
+ char *prog = basename(argv[0]);
+
+ if (!strcmp("fsck.f2fs", prog)) {
+ const char *option_string = "ad:ft";
+
+ config.func = FSCK;
+ while ((option = getopt(argc, argv, option_string)) != EOF) {
+ switch (option) {
+ 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:
+ MSG(0, "\tError: Unknown option %c\n", option);
+ fsck_usage();
+ break;
+ }
+ }
+ } else if (!strcmp("dump.f2fs", prog)) {
+ const char *option_string = "d:i:s:a:b:";
+ static struct dump_option dump_opt = {
+ .nid = 3, /* default root ino */
+ .start_sit = -1,
+ .end_sit = -1,
+ .start_ssa = -1,
+ .end_ssa = -1,
+ .blk_addr = -1,
+ };
+
+ 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))
+ 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:
+ MSG(0, "\tError: Unknown option %c\n", option);
+ dump_usage();
+ break;
+ }
+ ASSERT(ret >= 0);
+ }
+
+ config.private = &dump_opt;
+ }
+
+ if ((optind + 1) != argc) {
+ MSG(0, "\tError: Device not specified\n");
+ if (config.func == FSCK)
+ fsck_usage();
+ else if (config.func == DUMP)
+ dump_usage();
+ }
+ config.device_name = argv[optind];
+}
+
+static void do_fsck(struct f2fs_sb_info *sbi)
+{
+ u32 blk_cnt;
+
+ fsck_init(sbi);
+
+ fsck_chk_orphan_node(sbi);
+
+ /* Traverse all block recursively from root inode */
+ blk_cnt = 1;
+ fsck_chk_node_blk(sbi, NULL, sbi->root_ino_num,
+ F2FS_FT_DIR, TYPE_INODE, &blk_cnt);
+ fsck_verify(sbi);
+ fsck_free(sbi);
+}
+
+static void do_dump(struct f2fs_sb_info *sbi)
+{
+ struct dump_option *opt = (struct dump_option *)config.private;
+ struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
+ u32 flag = le32_to_cpu(ckpt->ckpt_flags);
+
+ fsck_init(sbi);
+
+ if (opt->end_sit == -1)
+ opt->end_sit = SM_I(sbi)->main_segments;
+ if (opt->end_ssa == -1)
+ opt->end_ssa = SM_I(sbi)->main_segments;
+ if (opt->start_sit != -1)
+ sit_dump(sbi, opt->start_sit, opt->end_sit);
+ if (opt->start_ssa != -1)
+ ssa_dump(sbi, opt->start_ssa, opt->end_ssa);
+ if (opt->blk_addr != -1) {
+ dump_info_from_blkaddr(sbi, opt->blk_addr);
+ goto cleanup;
+ }
+
+ MSG(0, "Info: checkpoint state = %x : ", flag);
+ if (flag & CP_FSCK_FLAG)
+ MSG(0, "%s", " fsck");
+ if (flag & CP_ERROR_FLAG)
+ MSG(0, "%s", " error");
+ if (flag & CP_COMPACT_SUM_FLAG)
+ MSG(0, "%s", " compacted_summary");
+ if (flag & CP_ORPHAN_PRESENT_FLAG)
+ MSG(0, "%s", " orphan_inodes");
+ if (flag & CP_FASTBOOT_FLAG)
+ MSG(0, "%s", " fastboot");
+ if (flag & CP_UMOUNT_FLAG)
+ MSG(0, "%s", " unmount");
+ else
+ MSG(0, "%s", " sudden-power-off");
+ MSG(0, "\n");
+
+ dump_node(sbi, opt->nid);
+cleanup:
+ fsck_free(sbi);
+}
+
+int main(int argc, char **argv)
+{
+ struct f2fs_sb_info *sbi;
+ int ret = 0;
+
+ f2fs_init_configuration(&config);
+
+ f2fs_parse_options(argc, argv);
+
+ if (f2fs_dev_is_umounted(&config) < 0)
+ return -1;
+
+ /* Get device */
+ if (f2fs_get_device_info(&config) < 0)
+ return -1;
+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:
+ 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 0;
+}
diff --git a/f2fs-tools/fsck/mount.c b/f2fs-tools/fsck/mount.c
new file mode 100644
index 0000000..6d96db8
--- /dev/null
+++ b/f2fs-tools/fsck/mount.c
@@ -0,0 +1,1326 @@
+/**
+ * mount.c
+ *
+ * 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.
+ */
+#include "fsck.h"
+#include <locale.h>
+
+void print_inode_info(struct f2fs_inode *inode, int name)
+{
+ unsigned int i = 0;
+ int namelen = le32_to_cpu(inode->i_namelen);
+
+ if (name && namelen) {
+ inode->i_name[namelen] = '\0';
+ MSG(0, " - File name : %s\n", inode->i_name);
+ setlocale(LC_ALL, "");
+ MSG(0, " - File size : %'llu (bytes)\n",
+ le64_to_cpu(inode->i_size));
+ return;
+ }
+
+ DISP_u32(inode, i_mode);
+ DISP_u32(inode, i_uid);
+ DISP_u32(inode, i_gid);
+ DISP_u32(inode, i_links);
+ DISP_u64(inode, i_size);
+ DISP_u64(inode, i_blocks);
+
+ DISP_u64(inode, i_atime);
+ DISP_u32(inode, i_atime_nsec);
+ DISP_u64(inode, i_ctime);
+ DISP_u32(inode, i_ctime_nsec);
+ DISP_u64(inode, i_mtime);
+ DISP_u32(inode, i_mtime_nsec);
+
+ DISP_u32(inode, i_generation);
+ DISP_u32(inode, i_current_depth);
+ DISP_u32(inode, i_xattr_nid);
+ DISP_u32(inode, i_flags);
+ DISP_u32(inode, i_inline);
+ DISP_u32(inode, i_pino);
+
+ if (namelen) {
+ DISP_u32(inode, i_namelen);
+ inode->i_name[namelen] = '\0';
+ DISP_utf(inode, i_name);
+ }
+
+ printf("i_ext: fofs:%x blkaddr:%x len:%x\n",
+ inode->i_ext.fofs,
+ inode->i_ext.blk_addr,
+ inode->i_ext.len);
+
+ DISP_u32(inode, i_addr[0]); /* Pointers to data blocks */
+ DISP_u32(inode, i_addr[1]); /* Pointers to data blocks */
+ DISP_u32(inode, i_addr[2]); /* Pointers to data blocks */
+ DISP_u32(inode, i_addr[3]); /* Pointers to data blocks */
+
+ 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[0x%4x]\n",
+ i, inode->i_addr[i]);
+ break;
+ }
+ }
+
+ DISP_u32(inode, i_nid[0]); /* direct */
+ DISP_u32(inode, i_nid[1]); /* direct */
+ DISP_u32(inode, i_nid[2]); /* indirect */
+ DISP_u32(inode, i_nid[3]); /* indirect */
+ DISP_u32(inode, i_nid[4]); /* double indirect */
+
+ printf("\n");
+}
+
+void print_node_info(struct f2fs_node *node_block)
+{
+ nid_t ino = le32_to_cpu(node_block->footer.ino);
+ nid_t nid = le32_to_cpu(node_block->footer.nid);
+ /* Is this inode? */
+ if (ino == nid) {
+ DBG(0, "Node ID [0x%x:%u] is inode\n", nid, nid);
+ print_inode_info(&node_block->i, 0);
+ } 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);
+ for (i = 0; i <= 10; i++)
+ MSG(0, "[%d]\t\t\t[0x%8x : %d]\n",
+ i, dump_blk[i], dump_blk[i]);
+ }
+}
+
+void print_raw_sb_info(struct f2fs_sb_info *sbi)
+{
+ struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi);
+
+ if (!config.dbg_lv)
+ return;
+
+ printf("\n");
+ printf("+--------------------------------------------------------+\n");
+ printf("| Super block |\n");
+ printf("+--------------------------------------------------------+\n");
+
+ DISP_u32(sb, magic);
+ DISP_u32(sb, major_ver);
+ DISP_u32(sb, minor_ver);
+ DISP_u32(sb, log_sectorsize);
+ DISP_u32(sb, log_sectors_per_block);
+
+ DISP_u32(sb, log_blocksize);
+ DISP_u32(sb, log_blocks_per_seg);
+ DISP_u32(sb, segs_per_sec);
+ DISP_u32(sb, secs_per_zone);
+ DISP_u32(sb, checksum_offset);
+ DISP_u64(sb, block_count);
+
+ DISP_u32(sb, section_count);
+ DISP_u32(sb, segment_count);
+ DISP_u32(sb, segment_count_ckpt);
+ DISP_u32(sb, segment_count_sit);
+ DISP_u32(sb, segment_count_nat);
+
+ DISP_u32(sb, segment_count_ssa);
+ DISP_u32(sb, segment_count_main);
+ DISP_u32(sb, segment0_blkaddr);
+
+ DISP_u32(sb, cp_blkaddr);
+ DISP_u32(sb, sit_blkaddr);
+ DISP_u32(sb, nat_blkaddr);
+ DISP_u32(sb, ssa_blkaddr);
+ DISP_u32(sb, main_blkaddr);
+
+ DISP_u32(sb, root_ino);
+ DISP_u32(sb, node_ino);
+ DISP_u32(sb, meta_ino);
+ DISP_u32(sb, cp_payload);
+ DISP("%s", sb, version);
+ printf("\n");
+}
+
+void print_ckpt_info(struct f2fs_sb_info *sbi)
+{
+ struct f2fs_checkpoint *cp = F2FS_CKPT(sbi);
+
+ if (!config.dbg_lv)
+ return;
+
+ printf("\n");
+ printf("+--------------------------------------------------------+\n");
+ printf("| Checkpoint |\n");
+ printf("+--------------------------------------------------------+\n");
+
+ DISP_u64(cp, checkpoint_ver);
+ DISP_u64(cp, user_block_count);
+ DISP_u64(cp, valid_block_count);
+ DISP_u32(cp, rsvd_segment_count);
+ DISP_u32(cp, overprov_segment_count);
+ DISP_u32(cp, free_segment_count);
+
+ DISP_u32(cp, alloc_type[CURSEG_HOT_NODE]);
+ DISP_u32(cp, alloc_type[CURSEG_WARM_NODE]);
+ DISP_u32(cp, alloc_type[CURSEG_COLD_NODE]);
+ DISP_u32(cp, cur_node_segno[0]);
+ DISP_u32(cp, cur_node_segno[1]);
+ DISP_u32(cp, cur_node_segno[2]);
+
+ DISP_u32(cp, cur_node_blkoff[0]);
+ DISP_u32(cp, cur_node_blkoff[1]);
+ DISP_u32(cp, cur_node_blkoff[2]);
+
+
+ DISP_u32(cp, alloc_type[CURSEG_HOT_DATA]);
+ DISP_u32(cp, alloc_type[CURSEG_WARM_DATA]);
+ DISP_u32(cp, alloc_type[CURSEG_COLD_DATA]);
+ DISP_u32(cp, cur_data_segno[0]);
+ DISP_u32(cp, cur_data_segno[1]);
+ DISP_u32(cp, cur_data_segno[2]);
+
+ DISP_u32(cp, cur_data_blkoff[0]);
+ DISP_u32(cp, cur_data_blkoff[1]);
+ DISP_u32(cp, cur_data_blkoff[2]);
+
+ DISP_u32(cp, ckpt_flags);
+ DISP_u32(cp, cp_pack_total_block_count);
+ DISP_u32(cp, cp_pack_start_sum);
+ DISP_u32(cp, valid_node_count);
+ DISP_u32(cp, valid_inode_count);
+ DISP_u32(cp, next_free_nid);
+ DISP_u32(cp, sit_ver_bitmap_bytesize);
+ DISP_u32(cp, nat_ver_bitmap_bytesize);
+ DISP_u32(cp, checksum_offset);
+ DISP_u64(cp, elapsed_time);
+
+ DISP_u32(cp, sit_nat_version_bitmap[0]);
+ printf("\n\n");
+}
+
+int sanity_check_raw_super(struct f2fs_super_block *raw_super)
+{
+ unsigned int blocksize;
+
+ if (F2FS_SUPER_MAGIC != le32_to_cpu(raw_super->magic)) {
+ return -1;
+ }
+
+ if (F2FS_BLKSIZE != PAGE_CACHE_SIZE) {
+ return -1;
+ }
+
+ blocksize = 1 << le32_to_cpu(raw_super->log_blocksize);
+ if (F2FS_BLKSIZE != blocksize) {
+ return -1;
+ }
+
+ if (le32_to_cpu(raw_super->log_sectorsize) > F2FS_MAX_LOG_SECTOR_SIZE ||
+ le32_to_cpu(raw_super->log_sectorsize) <
+ F2FS_MIN_LOG_SECTOR_SIZE) {
+ return -1;
+ }
+
+ if (le32_to_cpu(raw_super->log_sectors_per_block) +
+ le32_to_cpu(raw_super->log_sectorsize) !=
+ F2FS_MAX_LOG_SECTOR_SIZE) {
+ return -1;
+ }
+
+ return 0;
+}
+
+int validate_super_block(struct f2fs_sb_info *sbi, int block)
+{
+ u64 offset;
+
+ sbi->raw_super = malloc(sizeof(struct f2fs_super_block));
+
+ if (block == 0)
+ offset = F2FS_SUPER_OFFSET;
+ else
+ offset = F2FS_BLKSIZE + F2FS_SUPER_OFFSET;
+
+ if (dev_read(sbi->raw_super, offset, sizeof(struct f2fs_super_block)))
+ return -1;
+
+ if (!sanity_check_raw_super(sbi->raw_super)) {
+ /* get kernel version */
+ if (config.kd >= 0) {
+ dev_read_version(config.version, 0, VERSION_LEN);
+ get_kernel_version(config.version);
+ } else {
+ memset(config.version, 0, VERSION_LEN);
+ }
+
+ /* build sb version */
+ memcpy(config.sb_version, sbi->raw_super->version, VERSION_LEN);
+ get_kernel_version(config.sb_version);
+ memcpy(config.init_version, sbi->raw_super->init_version, VERSION_LEN);
+ get_kernel_version(config.init_version);
+
+ MSG(0, "Info: MKFS version\n \"%s\"\n", config.init_version);
+ MSG(0, "Info: FSCK version\n from \"%s\"\n to \"%s\"\n",
+ config.sb_version, config.version);
+ if (memcmp(config.sb_version, config.version, VERSION_LEN)) {
+ int ret;
+
+ memcpy(sbi->raw_super->version,
+ config.version, VERSION_LEN);
+ ret = dev_write(sbi->raw_super, offset,
+ sizeof(struct f2fs_super_block));
+ ASSERT(ret >= 0);
+
+ config.auto_fix = 0;
+ config.fix_on = 1;
+ }
+ return 0;
+ }
+
+ free(sbi->raw_super);
+ MSG(0, "\tCan't find a valid F2FS superblock at 0x%x\n", block);
+
+ return -EINVAL;
+}
+
+int init_sb_info(struct f2fs_sb_info *sbi)
+{
+ struct f2fs_super_block *raw_super = sbi->raw_super;
+
+ sbi->log_sectors_per_block =
+ le32_to_cpu(raw_super->log_sectors_per_block);
+ sbi->log_blocksize = le32_to_cpu(raw_super->log_blocksize);
+ sbi->blocksize = 1 << sbi->log_blocksize;
+ sbi->log_blocks_per_seg = le32_to_cpu(raw_super->log_blocks_per_seg);
+ sbi->blocks_per_seg = 1 << sbi->log_blocks_per_seg;
+ sbi->segs_per_sec = le32_to_cpu(raw_super->segs_per_sec);
+ sbi->secs_per_zone = le32_to_cpu(raw_super->secs_per_zone);
+ sbi->total_sections = le32_to_cpu(raw_super->section_count);
+ sbi->total_node_count =
+ (le32_to_cpu(raw_super->segment_count_nat) / 2)
+ * sbi->blocks_per_seg * NAT_ENTRY_PER_BLOCK;
+ sbi->root_ino_num = le32_to_cpu(raw_super->root_ino);
+ sbi->node_ino_num = le32_to_cpu(raw_super->node_ino);
+ sbi->meta_ino_num = le32_to_cpu(raw_super->meta_ino);
+ sbi->cur_victim_sec = NULL_SEGNO;
+ return 0;
+}
+
+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;
+ unsigned long blk_size = sbi->blocksize;
+ unsigned long long cur_version = 0, pre_version = 0;
+ unsigned int crc = 0;
+ size_t crc_offset;
+
+ /* Read the 1st cp block in this CP pack */
+ cp_page_1 = malloc(PAGE_SIZE);
+ if (dev_read_block(cp_page_1, cp_addr) < 0)
+ return NULL;
+
+ cp_block = (struct f2fs_checkpoint *)cp_page_1;
+ crc_offset = le32_to_cpu(cp_block->checksum_offset);
+ if (crc_offset >= blk_size)
+ goto invalid_cp1;
+
+ crc = *(unsigned int *)((unsigned char *)cp_block + crc_offset);
+ if (f2fs_crc_valid(crc, cp_block, crc_offset))
+ goto invalid_cp1;
+
+ pre_version = le64_to_cpu(cp_block->checkpoint_ver);
+
+ /* 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;
+
+ cp_block = (struct f2fs_checkpoint *)cp_page_2;
+ crc_offset = le32_to_cpu(cp_block->checksum_offset);
+ if (crc_offset >= blk_size)
+ goto invalid_cp2;
+
+ crc = *(unsigned int *)((unsigned char *)cp_block + crc_offset);
+ if (f2fs_crc_valid(crc, cp_block, crc_offset))
+ goto invalid_cp2;
+
+ cur_version = le64_to_cpu(cp_block->checkpoint_ver);
+
+ if (cur_version == pre_version) {
+ *version = cur_version;
+ free(cp_page_2);
+ return cp_page_1;
+ }
+
+invalid_cp2:
+ free(cp_page_2);
+invalid_cp1:
+ free(cp_page_1);
+ return NULL;
+}
+
+int get_valid_checkpoint(struct f2fs_sb_info *sbi)
+{
+ struct f2fs_super_block *raw_sb = sbi->raw_super;
+ void *cp1, *cp2, *cur_page;
+ 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(cp_blks * blk_size);
+ if (!sbi->ckpt)
+ return -ENOMEM;
+ /*
+ * Finding out valid cp block involves read both
+ * sets( cp pack1 and cp pack 2)
+ */
+ cp_start_blk_no = le32_to_cpu(raw_sb->cp_blkaddr);
+ cp1 = validate_checkpoint(sbi, cp_start_blk_no, &cp1_version);
+
+ /* The second checkpoint pack should start at the next segment */
+ cp_start_blk_no += 1 << le32_to_cpu(raw_sb->log_blocks_per_seg);
+ cp2 = validate_checkpoint(sbi, cp_start_blk_no, &cp2_version);
+
+ if (cp1 && cp2) {
+ if (ver_after(cp2_version, cp1_version)) {
+ cur_page = cp2;
+ 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);
+ goto fail_no_cp;
+ }
+
+ 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;
+
+fail_no_cp:
+ free(sbi->ckpt);
+ return -EINVAL;
+}
+
+int sanity_check_ckpt(struct f2fs_sb_info *sbi)
+{
+ unsigned int total, fsmeta;
+ struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi);
+ struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
+
+ total = le32_to_cpu(raw_super->segment_count);
+ fsmeta = le32_to_cpu(raw_super->segment_count_ckpt);
+ fsmeta += le32_to_cpu(raw_super->segment_count_sit);
+ fsmeta += le32_to_cpu(raw_super->segment_count_nat);
+ fsmeta += le32_to_cpu(ckpt->rsvd_segment_count);
+ fsmeta += le32_to_cpu(raw_super->segment_count_ssa);
+
+ if (fsmeta >= total)
+ return 1;
+
+ return 0;
+}
+
+int init_node_manager(struct f2fs_sb_info *sbi)
+{
+ struct f2fs_super_block *sb_raw = F2FS_RAW_SUPER(sbi);
+ struct f2fs_nm_info *nm_i = NM_I(sbi);
+ unsigned char *version_bitmap;
+ unsigned int nat_segs, nat_blocks;
+
+ nm_i->nat_blkaddr = le32_to_cpu(sb_raw->nat_blkaddr);
+
+ /* segment_count_nat includes pair segment so divide to 2. */
+ nat_segs = le32_to_cpu(sb_raw->segment_count_nat) >> 1;
+ nat_blocks = nat_segs << le32_to_cpu(sb_raw->log_blocks_per_seg);
+ nm_i->max_nid = NAT_ENTRY_PER_BLOCK * nat_blocks;
+ nm_i->fcnt = 0;
+ nm_i->nat_cnt = 0;
+ nm_i->init_scan_nid = le32_to_cpu(sbi->ckpt->next_free_nid);
+ nm_i->next_scan_nid = le32_to_cpu(sbi->ckpt->next_free_nid);
+
+ nm_i->bitmap_size = __bitmap_size(sbi, NAT_BITMAP);
+
+ nm_i->nat_bitmap = malloc(nm_i->bitmap_size);
+ if (!nm_i->nat_bitmap)
+ return -ENOMEM;
+ version_bitmap = __bitmap_ptr(sbi, NAT_BITMAP);
+ if (!version_bitmap)
+ return -EFAULT;
+
+ /* copy version bitmap */
+ memcpy(nm_i->nat_bitmap, version_bitmap, nm_i->bitmap_size);
+ return 0;
+}
+
+int build_node_manager(struct f2fs_sb_info *sbi)
+{
+ int err;
+ sbi->nm_info = malloc(sizeof(struct f2fs_nm_info));
+ if (!sbi->nm_info)
+ return -ENOMEM;
+
+ err = init_node_manager(sbi);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+int build_sit_info(struct f2fs_sb_info *sbi)
+{
+ struct f2fs_super_block *raw_sb = F2FS_RAW_SUPER(sbi);
+ struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
+ struct sit_info *sit_i;
+ unsigned int sit_segs, start;
+ char *src_bitmap, *dst_bitmap;
+ unsigned int bitmap_size;
+
+ sit_i = malloc(sizeof(struct sit_info));
+ if (!sit_i)
+ return -ENOMEM;
+
+ SM_I(sbi)->sit_info = sit_i;
+
+ sit_i->sentries = calloc(TOTAL_SEGS(sbi) * sizeof(struct seg_entry), 1);
+
+ for (start = 0; start < TOTAL_SEGS(sbi); start++) {
+ sit_i->sentries[start].cur_valid_map
+ = calloc(SIT_VBLOCK_MAP_SIZE, 1);
+ sit_i->sentries[start].ckpt_valid_map
+ = calloc(SIT_VBLOCK_MAP_SIZE, 1);
+ if (!sit_i->sentries[start].cur_valid_map
+ || !sit_i->sentries[start].ckpt_valid_map)
+ return -ENOMEM;
+ }
+
+ sit_segs = le32_to_cpu(raw_sb->segment_count_sit) >> 1;
+ bitmap_size = __bitmap_size(sbi, SIT_BITMAP);
+ src_bitmap = __bitmap_ptr(sbi, SIT_BITMAP);
+
+ dst_bitmap = malloc(bitmap_size);
+ memcpy(dst_bitmap, src_bitmap, bitmap_size);
+
+ sit_i->sit_base_addr = le32_to_cpu(raw_sb->sit_blkaddr);
+ sit_i->sit_blocks = sit_segs << sbi->log_blocks_per_seg;
+ sit_i->written_valid_blocks = le64_to_cpu(ckpt->valid_block_count);
+ sit_i->sit_bitmap = dst_bitmap;
+ sit_i->bitmap_size = bitmap_size;
+ sit_i->dirty_sentries = 0;
+ sit_i->sents_per_block = SIT_ENTRY_PER_BLOCK;
+ sit_i->elapsed_time = le64_to_cpu(ckpt->elapsed_time);
+ return 0;
+}
+
+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;
+
+ 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;
+}
+
+static void read_compacted_summaries(struct f2fs_sb_info *sbi)
+{
+ struct curseg_info *curseg;
+ unsigned int i, j, offset;
+ block_t start;
+ char *kaddr;
+ int ret;
+
+ start = start_sum_block(sbi);
+
+ kaddr = (char *)malloc(PAGE_SIZE);
+ 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);
+
+ offset = 2 * SUM_JOURNAL_SIZE;
+ for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_DATA; i++) {
+ unsigned short blk_off;
+ struct curseg_info *curseg = CURSEG_I(sbi, i);
+
+ 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)
+ continue;
+ memset(kaddr, 0, PAGE_SIZE);
+ ret = dev_read_block(kaddr, start++);
+ ASSERT(ret >= 0);
+ offset = 0;
+ }
+ }
+ free(kaddr);
+}
+
+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;
+ block_t addr;
+ unsigned int i;
+ int ret;
+
+ 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++) {
+ ret = dev_read_block(node_blk, addr);
+ ASSERT(ret >= 0);
+ sum_entry->nid = node_blk->footer.nid;
+ addr++;
+ }
+ free(node_blk);
+}
+
+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 int segno = 0;
+ block_t blk_addr = 0;
+ int ret;
+
+ if (IS_DATASEG(type)) {
+ segno = le32_to_cpu(ckpt->cur_data_segno[type]);
+ 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]);
+ if (is_set_ckpt_flags(ckpt, CP_UMOUNT_FLAG))
+ 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);
+ 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);
+ reset_curseg(sbi, type);
+ free(sum_blk);
+}
+
+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)) {
+ read_compacted_summaries(sbi);
+ type = CURSEG_HOT_NODE;
+ }
+
+ for (; type <= CURSEG_COLD_NODE; type++)
+ read_normal_summaries(sbi, type);
+}
+
+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);
+ 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];
+ }
+ restore_curseg_summaries(sbi);
+}
+
+inline void check_seg_range(struct f2fs_sb_info *sbi, unsigned int segno)
+{
+ unsigned int end_segno = SM_I(sbi)->segment_count - 1;
+ ASSERT(segno <= end_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);
+
+ /* calculate sit block address */
+ if (f2fs_test_bit(offset, sit_i->sit_bitmap))
+ blk_addr += sit_i->sit_blocks;
+
+ 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,
+ 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;
+ unsigned int i;
+
+ /* check segment usage */
+ 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 */
+ if (segno > end_segno)
+ ASSERT_MSG("Invalid SEGNO: 0x%x", segno);
+
+ /* check bitmap with valid block count */
+ 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,
+ struct f2fs_sit_entry *raw_sit)
+{
+ se->valid_blocks = GET_SIT_VBLOCKS(raw_sit);
+ se->ckpt_valid_blocks = GET_SIT_VBLOCKS(raw_sit);
+ memcpy(se->cur_valid_map, raw_sit->valid_map, SIT_VBLOCK_MAP_SIZE);
+ memcpy(se->ckpt_valid_map, raw_sit->valid_map, SIT_VBLOCK_MAP_SIZE);
+ se->type = GET_SIT_TYPE(raw_sit);
+ se->orig_type = GET_SIT_TYPE(raw_sit);
+ se->mtime = le64_to_cpu(raw_sit->mtime);
+}
+
+struct seg_entry *get_seg_entry(struct f2fs_sb_info *sbi,
+ unsigned int segno)
+{
+ struct sit_info *sit_i = SIT_I(sbi);
+ return &sit_i->sentries[segno];
+}
+
+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;
+ int type, ret;
+ u64 ssa_blk;
+
+ ssa_blk = GET_SUM_BLKADDR(sbi, segno);
+ 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;
+ }
+ }
+
+ 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);
+ return SEG_TYPE_CUR_DATA;
+ }
+ }
+
+ ret = dev_read_block(sum_blk, ssa_blk);
+ ASSERT(ret >= 0);
+
+ if (IS_SUM_NODE_SEG(sum_blk->footer))
+ return SEG_TYPE_NODE;
+ else
+ return SEG_TYPE_DATA;
+
+}
+
+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;
+ int ret;
+
+ segno = GET_SEGNO(sbi, blk_addr);
+ offset = OFFSET_IN_SEG(sbi, blk_addr);
+
+ 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));
+ free(sum_blk);
+ return ret;
+}
+
+static void get_nat_entry(struct f2fs_sb_info *sbi, nid_t nid,
+ struct f2fs_nat_entry *raw_nat)
+{
+ 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;
+
+ if (lookup_nat_in_journal(sbi, nid, raw_nat) >= 0)
+ 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);
+
+ memcpy(raw_nat, &nat_block->entries[entry_off],
+ sizeof(struct f2fs_nat_entry));
+ free(nat_block);
+}
+
+void get_node_info(struct f2fs_sb_info *sbi, nid_t nid, struct node_info *ni)
+{
+ struct f2fs_nat_entry raw_nat;
+ get_nat_entry(sbi, nid, &raw_nat);
+ ni->nid = nid;
+ node_info_from_raw_nat(ni, &raw_nat);
+}
+
+void build_sit_entries(struct f2fs_sb_info *sbi)
+{
+ struct sit_info *sit_i = SIT_I(sbi);
+ struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_COLD_DATA);
+ struct f2fs_summary_block *sum = curseg->sum_blk;
+ unsigned int segno;
+
+ for (segno = 0; segno < TOTAL_SEGS(sbi); segno++) {
+ struct seg_entry *se = &sit_i->sentries[segno];
+ struct f2fs_sit_block *sit_blk;
+ struct f2fs_sit_entry sit;
+ int i;
+
+ for (i = 0; i < sits_in_cursum(sum); i++) {
+ if (le32_to_cpu(segno_in_journal(sum, i)) == segno) {
+ sit = sit_in_journal(sum, i);
+ goto got_it;
+ }
+ }
+ sit_blk = get_current_sit_page(sbi, segno);
+ sit = sit_blk->entries[SIT_ENTRY_OFFSET(sit_i, segno)];
+ free(sit_blk);
+got_it:
+ check_block_count(sbi, segno, &sit);
+ seg_info_from_raw_sit(se, &sit);
+ }
+
+}
+
+int build_segment_manager(struct f2fs_sb_info *sbi)
+{
+ struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi);
+ struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
+ struct f2fs_sm_info *sm_info;
+
+ sm_info = malloc(sizeof(struct f2fs_sm_info));
+ if (!sm_info)
+ return -ENOMEM;
+
+ /* init sm info */
+ sbi->sm_info = sm_info;
+ sm_info->seg0_blkaddr = le32_to_cpu(raw_super->segment0_blkaddr);
+ sm_info->main_blkaddr = le32_to_cpu(raw_super->main_blkaddr);
+ sm_info->segment_count = le32_to_cpu(raw_super->segment_count);
+ sm_info->reserved_segments = le32_to_cpu(ckpt->rsvd_segment_count);
+ sm_info->ovp_segments = le32_to_cpu(ckpt->overprov_segment_count);
+ sm_info->main_segments = le32_to_cpu(raw_super->segment_count_main);
+ sm_info->ssa_blkaddr = le32_to_cpu(raw_super->ssa_blkaddr);
+
+ build_sit_info(sbi);
+
+ build_curseg(sbi);
+
+ build_sit_entries(sbi);
+
+ return 0;
+}
+
+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);
+ unsigned int segno = 0;
+ char *ptr = NULL;
+ u32 sum_vblocks = 0;
+ u32 free_segs = 0;
+ struct seg_entry *se;
+
+ fsck->sit_area_bitmap_sz = sm_i->main_segments * SIT_VBLOCK_MAP_SIZE;
+ fsck->sit_area_bitmap = calloc(1, fsck->sit_area_bitmap_sz);
+ ptr = fsck->sit_area_bitmap;
+
+ ASSERT(fsck->sit_area_bitmap_sz == fsck->main_area_bitmap_sz);
+
+ 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;
+
+ 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 ||
+ sbi->ckpt->cur_data_segno[1] == segno ||
+ sbi->ckpt->cur_node_segno[2] == segno ||
+ sbi->ckpt->cur_data_segno[2] == segno) {
+ continue;
+ } else {
+ free_segs++;
+ }
+ } else {
+ 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,
+ free_segs, free_segs);
+}
+
+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_MSG("Invalide type and valid blocks=%x,%x",
+ segno, 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;
+ int i = 0;
+
+ 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));
+ DBG(3, "==> Found nid [0x%x] in nat cache\n", nid);
+ return i;
+ }
+ }
+ 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);
+ struct f2fs_super_block *raw_sb = F2FS_RAW_SUPER(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;
+ 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;
+
+ fsck->nr_nat_entries = nr_nat_blks * NAT_ENTRY_PER_BLOCK;
+ fsck->nat_area_bitmap_sz = (fsck->nr_nat_entries + 7) / 8;
+ fsck->nat_area_bitmap = calloc(fsck->nat_area_bitmap_sz, 1);
+ ASSERT(fsck->nat_area_bitmap != NULL);
+
+ for (block_off = 0; block_off < nr_nat_blks; block_off++) {
+
+ 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);
+
+ nid = block_off * NAT_ENTRY_PER_BLOCK;
+ for (i = 0; i < NAT_ENTRY_PER_BLOCK; i++) {
+ struct f2fs_nat_entry raw_nat;
+ struct node_info ni;
+ ni.nid = nid + i;
+
+ 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) {
+ node_info_from_raw_nat(&ni, &raw_nat);
+ if (ni.blk_addr != 0x0) {
+ 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);
+ }
+ } else {
+ 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);
+}
+
+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) {
+ ret = validate_super_block(sbi, 1);
+ if (ret)
+ return -1;
+ }
+
+ print_raw_sb_info(sbi);
+
+ init_sb_info(sbi);
+
+ ret = get_valid_checkpoint(sbi);
+ if (ret) {
+ ERR_MSG("Can't find valid checkpoint\n");
+ return -1;
+ }
+
+ if (sanity_check_ckpt(sbi)) {
+ ERR_MSG("Checkpoint is polluted\n");
+ return -1;
+ }
+
+ 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->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->last_valid_block_count = sbi->total_valid_block_count;
+ sbi->alloc_valid_block_count = 0;
+
+ if (build_segment_manager(sbi)) {
+ ERR_MSG("build_segment_manager failed\n");
+ return -1;
+ }
+
+ if (build_node_manager(sbi)) {
+ ERR_MSG("build_segment_manager failed\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+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);
+ unsigned int i;
+
+ /* free nm_info */
+ free(nm_i->nat_bitmap);
+ free(sbi->nm_info);
+
+ /* free sit_info */
+ for (i = 0; i < TOTAL_SEGS(sbi); i++) {
+ free(sit_i->sentries[i].cur_valid_map);
+ free(sit_i->sentries[i].ckpt_valid_map);
+ }
+ free(sit_i->sit_bitmap);
+ free(sm_i->sit_info);
+
+ /* free sm_info */
+ for (i = 0; i < NR_CURSEG_TYPE; i++)
+ free(sm_i->curseg_array[i].sum_blk);
+
+ free(sm_i->curseg_array);
+ free(sbi->sm_info);
+
+ free(sbi->ckpt);
+ free(sbi->raw_super);
+}
diff --git a/f2fs-tools/include/f2fs_fs.h b/f2fs-tools/include/f2fs_fs.h
new file mode 100644
index 0000000..6ce58c2
--- /dev/null
+++ b/f2fs-tools/include/f2fs_fs.h
@@ -0,0 +1,797 @@
+/**
+ * f2fs_fs.h
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * Dual licensed under the GPL or LGPL version 2 licenses.
+ *
+ * The byteswap codes are copied from:
+ * samba_3_master/lib/ccan/endian/endian.h under LGPL 2.1
+ */
+#ifndef __F2FS_FS_H__
+#define __F2FS_FS_H__
+
+#include <inttypes.h>
+#include <linux/types.h>
+#include <sys/types.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+typedef u_int64_t u64;
+typedef u_int32_t u32;
+typedef u_int16_t u16;
+typedef u_int8_t u8;
+typedef u32 block_t;
+typedef u32 nid_t;
+typedef u8 bool;
+typedef unsigned long pgoff_t;
+
+#if HAVE_BYTESWAP_H
+#include <byteswap.h>
+#else
+/**
+ * bswap_16 - reverse bytes in a uint16_t value.
+ * @val: value whose bytes to swap.
+ *
+ * Example:
+ * // Output contains "1024 is 4 as two bytes reversed"
+ * printf("1024 is %u as two bytes reversed\n", bswap_16(1024));
+ */
+static inline uint16_t bswap_16(uint16_t val)
+{
+ return ((val & (uint16_t)0x00ffU) << 8)
+ | ((val & (uint16_t)0xff00U) >> 8);
+}
+
+/**
+ * bswap_32 - reverse bytes in a uint32_t value.
+ * @val: value whose bytes to swap.
+ *
+ * Example:
+ * // Output contains "1024 is 262144 as four bytes reversed"
+ * printf("1024 is %u as four bytes reversed\n", bswap_32(1024));
+ */
+static inline uint32_t bswap_32(uint32_t val)
+{
+ return ((val & (uint32_t)0x000000ffUL) << 24)
+ | ((val & (uint32_t)0x0000ff00UL) << 8)
+ | ((val & (uint32_t)0x00ff0000UL) >> 8)
+ | ((val & (uint32_t)0xff000000UL) >> 24);
+}
+#endif /* !HAVE_BYTESWAP_H */
+
+#if defined HAVE_DECL_BSWAP_64 && !HAVE_DECL_BSWAP_64
+/**
+ * bswap_64 - reverse bytes in a uint64_t value.
+ * @val: value whose bytes to swap.
+ *
+ * Example:
+ * // Output contains "1024 is 1125899906842624 as eight bytes reversed"
+ * printf("1024 is %llu as eight bytes reversed\n",
+ * (unsigned long long)bswap_64(1024));
+ */
+static inline uint64_t bswap_64(uint64_t val)
+{
+ return ((val & (uint64_t)0x00000000000000ffULL) << 56)
+ | ((val & (uint64_t)0x000000000000ff00ULL) << 40)
+ | ((val & (uint64_t)0x0000000000ff0000ULL) << 24)
+ | ((val & (uint64_t)0x00000000ff000000ULL) << 8)
+ | ((val & (uint64_t)0x000000ff00000000ULL) >> 8)
+ | ((val & (uint64_t)0x0000ff0000000000ULL) >> 24)
+ | ((val & (uint64_t)0x00ff000000000000ULL) >> 40)
+ | ((val & (uint64_t)0xff00000000000000ULL) >> 56);
+}
+#endif
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define le16_to_cpu(x) ((__u16)(x))
+#define le32_to_cpu(x) ((__u32)(x))
+#define le64_to_cpu(x) ((__u64)(x))
+#define cpu_to_le16(x) ((__u16)(x))
+#define cpu_to_le32(x) ((__u32)(x))
+#define cpu_to_le64(x) ((__u64)(x))
+#elif __BYTE_ORDER == __BIG_ENDIAN
+#define le16_to_cpu(x) bswap_16(x)
+#define le32_to_cpu(x) bswap_32(x)
+#define le64_to_cpu(x) bswap_64(x)
+#define cpu_to_le16(x) bswap_16(x)
+#define cpu_to_le32(x) bswap_32(x)
+#define cpu_to_le64(x) bswap_64(x)
+#endif
+
+#define typecheck(type,x) \
+ ({ type __dummy; \
+ typeof(x) __dummy2; \
+ (void)(&__dummy == &__dummy2); \
+ 1; \
+ })
+
+#define NULL_SEGNO ((unsigned int)~0)
+
+/*
+ * Debugging interfaces
+ */
+#define FIX_MSG(fmt, ...) \
+ do { \
+ 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("[ASSERT] (%s:%4d) " #exp"\n", \
+ __func__, __LINE__); \
+ exit(-1); \
+ } \
+ } while (0)
+
+#define ERR_MSG(fmt, ...) \
+ do { \
+ 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)
+
+#define DBG(n, fmt, ...) \
+ do { \
+ if (config.dbg_lv >= n) { \
+ printf("[%s:%4d] " fmt, \
+ __func__, __LINE__, ##__VA_ARGS__); \
+ } \
+ } while (0)
+
+/* Display on console */
+#define DISP(fmt, ptr, member) \
+ do { \
+ printf("%-30s" fmt, #member, ((ptr)->member)); \
+ } 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)
+
+#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)
+
+#define DISP_utf(ptr, member) \
+ do { \
+ 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) \
+ snprintf(buf, len, #member)
+
+/* these are defined in kernel */
+#define PAGE_SIZE 4096
+#define PAGE_CACHE_SIZE 4096
+#define BITS_PER_BYTE 8
+#define F2FS_SUPER_MAGIC 0xF2F52010 /* F2FS Magic Number */
+#define CHECKSUM_OFFSET 4092
+
+/* for mkfs */
+#define F2FS_MIN_VOLUME_SIZE 104857600
+#define F2FS_NUMBER_OF_CHECKPOINT_PACK 2
+#define DEFAULT_SECTOR_SIZE 512
+#define DEFAULT_SECTORS_PER_BLOCK 8
+#define DEFAULT_BLOCKS_PER_SEGMENT 512
+#define DEFAULT_SEGMENTS_PER_SECTION 1
+
+#define VERSION_LEN 256
+
+enum f2fs_config_func {
+ FSCK,
+ DUMP,
+};
+
+struct f2fs_configuration {
+ u_int32_t sector_size;
+ u_int32_t reserved_segments;
+ u_int32_t overprovision;
+ u_int32_t cur_seg[6];
+ u_int32_t segs_per_sec;
+ u_int32_t secs_per_zone;
+ u_int32_t segs_per_zone;
+ u_int32_t start_sector;
+ u_int64_t total_sectors;
+ u_int32_t sectors_per_blk;
+ u_int32_t blks_per_seg;
+ __u8 init_version[VERSION_LEN + 1];
+ __u8 sb_version[VERSION_LEN + 1];
+ __u8 version[VERSION_LEN + 1];
+ char *vol_label;
+ int heap;
+ int32_t fd, kd;
+ 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
+#define BITS_PER_LONG 64
+#else
+#define BITS_PER_LONG 32
+#endif
+
+#define BIT_MASK(nr) (1 << (nr % BITS_PER_LONG))
+#define BIT_WORD(nr) (nr / BITS_PER_LONG)
+
+/*
+ * Copied from fs/f2fs/f2fs.h
+ */
+#define NR_CURSEG_DATA_TYPE (3)
+#define NR_CURSEG_NODE_TYPE (3)
+#define NR_CURSEG_TYPE (NR_CURSEG_DATA_TYPE + NR_CURSEG_NODE_TYPE)
+
+enum {
+ CURSEG_HOT_DATA = 0, /* directory entry blocks */
+ CURSEG_WARM_DATA, /* data blocks */
+ CURSEG_COLD_DATA, /* multimedia or GCed data blocks */
+ CURSEG_HOT_NODE, /* direct node blocks of directory files */
+ CURSEG_WARM_NODE, /* direct node blocks of normal files */
+ CURSEG_COLD_NODE, /* indirect node blocks */
+ NO_CHECK_TYPE
+};
+
+/*
+ * Copied from fs/f2fs/segment.h
+ */
+#define GET_SUM_TYPE(footer) ((footer)->entry_type)
+#define SET_SUM_TYPE(footer, type) ((footer)->entry_type = type)
+
+/*
+ * Copied from include/linux/f2fs_sb.h
+ */
+#define F2FS_SUPER_OFFSET 1024 /* byte-size offset */
+#define F2FS_MIN_LOG_SECTOR_SIZE 9 /* 9 bits for 512 bytes */
+#define F2FS_MAX_LOG_SECTOR_SIZE 12 /* 12 bits for 4096 bytes */
+#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
+
+#define F2FS_ROOT_INO(sbi) (sbi->root_ino_num)
+#define F2FS_NODE_INO(sbi) (sbi->node_ino_num)
+#define F2FS_META_INO(sbi) (sbi->meta_ino_num)
+
+/* This flag is used by node and meta inodes, and by recovery */
+#define GFP_F2FS_ZERO (GFP_NOFS | __GFP_ZERO)
+
+/*
+ * For further optimization on multi-head logs, on-disk layout supports maximum
+ * 16 logs by default. The number, 16, is expected to cover all the cases
+ * enoughly. The implementaion currently uses no more than 6 logs.
+ * Half the logs are used for nodes, and the other half are used for data.
+ */
+#define MAX_ACTIVE_LOGS 16
+#define MAX_ACTIVE_NODE_LOGS 8
+#define MAX_ACTIVE_DATA_LOGS 8
+
+/*
+ * For superblock
+ */
+struct f2fs_super_block {
+ __le32 magic; /* Magic Number */
+ __le16 major_ver; /* Major Version */
+ __le16 minor_ver; /* Minor Version */
+ __le32 log_sectorsize; /* log2 sector size in bytes */
+ __le32 log_sectors_per_block; /* log2 # of sectors per block */
+ __le32 log_blocksize; /* log2 block size in bytes */
+ __le32 log_blocks_per_seg; /* log2 # of blocks per segment */
+ __le32 segs_per_sec; /* # of segments per section */
+ __le32 secs_per_zone; /* # of sections per zone */
+ __le32 checksum_offset; /* checksum offset inside super block */
+ __le64 block_count; /* total # of user blocks */
+ __le32 section_count; /* total # of sections */
+ __le32 segment_count; /* total # of segments */
+ __le32 segment_count_ckpt; /* # of segments for checkpoint */
+ __le32 segment_count_sit; /* # of segments for SIT */
+ __le32 segment_count_nat; /* # of segments for NAT */
+ __le32 segment_count_ssa; /* # of segments for SSA */
+ __le32 segment_count_main; /* # of segments for main area */
+ __le32 segment0_blkaddr; /* start block address of segment 0 */
+ __le32 cp_blkaddr; /* start block address of checkpoint */
+ __le32 sit_blkaddr; /* start block address of SIT */
+ __le32 nat_blkaddr; /* start block address of NAT */
+ __le32 ssa_blkaddr; /* start block address of SSA */
+ __le32 main_blkaddr; /* start block address of main area */
+ __le32 root_ino; /* root inode number */
+ __le32 node_ino; /* node inode number */
+ __le32 meta_ino; /* meta inode number */
+ __u8 uuid[16]; /* 128-bit uuid for volume */
+ __le16 volume_name[512]; /* volume name */
+ __le32 extension_count; /* # of extensions below */
+ __u8 extension_list[F2FS_MAX_EXTENSION][8]; /* extension array */
+ __le32 cp_payload;
+ __u8 version[VERSION_LEN]; /* the kernel version */
+ __u8 init_version[VERSION_LEN]; /* the initial kernel version */
+} __attribute__((packed));
+
+/*
+ * For checkpoint
+ */
+#define CP_FASTBOOT_FLAG 0x00000020
+#define CP_FSCK_FLAG 0x00000010
+#define CP_ERROR_FLAG 0x00000008
+#define CP_COMPACT_SUM_FLAG 0x00000004
+#define CP_ORPHAN_PRESENT_FLAG 0x00000002
+#define CP_UMOUNT_FLAG 0x00000001
+
+struct f2fs_checkpoint {
+ __le64 checkpoint_ver; /* checkpoint block version number */
+ __le64 user_block_count; /* # of user blocks */
+ __le64 valid_block_count; /* # of valid blocks in main area */
+ __le32 rsvd_segment_count; /* # of reserved segments for gc */
+ __le32 overprov_segment_count; /* # of overprovision segments */
+ __le32 free_segment_count; /* # of free segments in main area */
+
+ /* information of current node segments */
+ __le32 cur_node_segno[MAX_ACTIVE_NODE_LOGS];
+ __le16 cur_node_blkoff[MAX_ACTIVE_NODE_LOGS];
+ /* information of current data segments */
+ __le32 cur_data_segno[MAX_ACTIVE_DATA_LOGS];
+ __le16 cur_data_blkoff[MAX_ACTIVE_DATA_LOGS];
+ __le32 ckpt_flags; /* Flags : umount and journal_present */
+ __le32 cp_pack_total_block_count; /* total # of one cp pack */
+ __le32 cp_pack_start_sum; /* start block number of data summary */
+ __le32 valid_node_count; /* Total number of valid nodes */
+ __le32 valid_inode_count; /* Total number of valid inodes */
+ __le32 next_free_nid; /* Next free node number */
+ __le32 sit_ver_bitmap_bytesize; /* Default value 64 */
+ __le32 nat_ver_bitmap_bytesize; /* Default value 256 */
+ __le32 checksum_offset; /* checksum offset inside cp block */
+ __le64 elapsed_time; /* mounted time */
+ /* allocation type of current segment */
+ unsigned char alloc_type[MAX_ACTIVE_LOGS];
+
+ /* SIT and NAT version bitmap */
+ unsigned char sit_nat_version_bitmap[1];
+} __attribute__((packed));
+
+/*
+ * For orphan inode management
+ */
+#define F2FS_ORPHANS_PER_BLOCK 1020
+
+struct f2fs_orphan_block {
+ __le32 ino[F2FS_ORPHANS_PER_BLOCK]; /* inode numbers */
+ __le32 reserved; /* reserved */
+ __le16 blk_addr; /* block index in current CP */
+ __le16 blk_count; /* Number of orphan inode blocks in CP */
+ __le32 entry_count; /* Total number of orphan nodes in current CP */
+ __le32 check_sum; /* CRC32 for orphan inode block */
+} __attribute__((packed));
+
+/*
+ * For NODE structure
+ */
+struct f2fs_extent {
+ __le32 fofs; /* start file offset of the extent */
+ __le32 blk_addr; /* start block address of the extent */
+ __le32 len; /* lengh of the extent */
+} __attribute__((packed));
+
+#define F2FS_NAME_LEN 255
+#define F2FS_INLINE_XATTR_ADDRS 50 /* 200 bytes for inline xattrs */
+#define DEF_ADDRS_PER_INODE 923 /* Address Pointers in an Inode */
+#define ADDRS_PER_INODE(fi) addrs_per_inode(fi)
+#define ADDRS_PER_BLOCK 1018 /* Address Pointers in a Direct Block */
+#define NIDS_PER_BLOCK 1018 /* Node IDs in an Indirect Block */
+
+#define NODE_DIR1_BLOCK (DEF_ADDRS_PER_INODE + 1)
+#define NODE_DIR2_BLOCK (DEF_ADDRS_PER_INODE + 2)
+#define NODE_IND1_BLOCK (DEF_ADDRS_PER_INODE + 3)
+#define NODE_IND2_BLOCK (DEF_ADDRS_PER_INODE + 4)
+#define NODE_DIND_BLOCK (DEF_ADDRS_PER_INODE + 5)
+
+#define F2FS_INLINE_XATTR 0x01 /* file inline xattr flag */
+#define F2FS_INLINE_DATA 0x02 /* file inline data flag */
+#define F2FS_INLINE_DENTRY 0x04 /* file inline dentry flag */
+#define F2FS_DATA_EXIST 0x08 /* file inline data exist flag */
+
+#define MAX_INLINE_DATA (sizeof(__le32) * (DEF_ADDRS_PER_INODE - \
+ F2FS_INLINE_XATTR_ADDRS - 1))
+
+#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 */
+ __u8 i_inline; /* file inline flags */
+ __le32 i_uid; /* user ID */
+ __le32 i_gid; /* group ID */
+ __le32 i_links; /* links count */
+ __le64 i_size; /* file size in bytes */
+ __le64 i_blocks; /* file size in blocks */
+ __le64 i_atime; /* access time */
+ __le64 i_ctime; /* change time */
+ __le64 i_mtime; /* modification time */
+ __le32 i_atime_nsec; /* access time in nano scale */
+ __le32 i_ctime_nsec; /* change time in nano scale */
+ __le32 i_mtime_nsec; /* modification time in nano scale */
+ __le32 i_generation; /* file version (for NFS) */
+ __le32 i_current_depth; /* only for directory depth */
+ __le32 i_xattr_nid; /* nid to save xattr */
+ __le32 i_flags; /* file attributes */
+ __le32 i_pino; /* parent inode number */
+ __le32 i_namelen; /* file name length */
+ __u8 i_name[F2FS_NAME_LEN]; /* file name for SPOR */
+ __u8 i_dir_level; /* dentry_level for large dir */
+
+ struct f2fs_extent i_ext; /* caching a largest extent */
+
+ __le32 i_addr[DEF_ADDRS_PER_INODE]; /* Pointers to data blocks */
+
+ __le32 i_nid[5]; /* direct(2), indirect(2),
+ double_indirect(1) node id */
+} __attribute__((packed));
+
+struct direct_node {
+ __le32 addr[ADDRS_PER_BLOCK]; /* array of data block address */
+} __attribute__((packed));
+
+struct indirect_node {
+ __le32 nid[NIDS_PER_BLOCK]; /* array of data block address */
+} __attribute__((packed));
+
+enum {
+ COLD_BIT_SHIFT = 0,
+ FSYNC_BIT_SHIFT,
+ DENT_BIT_SHIFT,
+ 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 */
+ __le32 flag; /* include cold/fsync/dentry marks and offset */
+ __le64 cp_ver; /* checkpoint version */
+ __le32 next_blkaddr; /* next node page block address */
+} __attribute__((packed));
+
+struct f2fs_node {
+ /* can be one of three types: inode, direct, and indirect types */
+ union {
+ struct f2fs_inode i;
+ struct direct_node dn;
+ struct indirect_node in;
+ };
+ struct node_footer footer;
+} __attribute__((packed));
+
+/*
+ * For NAT entries
+ */
+#define NAT_ENTRY_PER_BLOCK (PAGE_CACHE_SIZE / sizeof(struct f2fs_nat_entry))
+
+struct f2fs_nat_entry {
+ __u8 version; /* latest version of cached nat entry */
+ __le32 ino; /* inode number */
+ __le32 block_addr; /* block address */
+} __attribute__((packed));
+
+struct f2fs_nat_block {
+ struct f2fs_nat_entry entries[NAT_ENTRY_PER_BLOCK];
+} __attribute__((packed));
+
+/*
+ * For SIT entries
+ *
+ * Each segment is 2MB in size by default so that a bitmap for validity of
+ * there-in blocks should occupy 64 bytes, 512 bits.
+ * Not allow to change this.
+ */
+#define SIT_VBLOCK_MAP_SIZE 64
+#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
+ */
+#define SIT_VBLOCKS_SHIFT 10
+#define SIT_VBLOCKS_MASK ((1 << SIT_VBLOCKS_SHIFT) - 1)
+#define GET_SIT_VBLOCKS(raw_sit) \
+ (le16_to_cpu((raw_sit)->vblocks) & SIT_VBLOCKS_MASK)
+#define GET_SIT_TYPE(raw_sit) \
+ ((le16_to_cpu((raw_sit)->vblocks) & ~SIT_VBLOCKS_MASK) \
+ >> SIT_VBLOCKS_SHIFT)
+
+struct f2fs_sit_entry {
+ __le16 vblocks; /* reference above */
+ __u8 valid_map[SIT_VBLOCK_MAP_SIZE]; /* bitmap for valid blocks */
+ __le64 mtime; /* segment age for cleaning */
+} __attribute__((packed));
+
+struct f2fs_sit_block {
+ struct f2fs_sit_entry entries[SIT_ENTRY_PER_BLOCK];
+} __attribute__((packed));
+
+/*
+ * For segment summary
+ *
+ * One summary block contains exactly 512 summary entries, which represents
+ * exactly 2MB segment by default. Not allow to change the basic units.
+ *
+ * NOTE: For initializing fields, you must use set_summary
+ *
+ * - If data page, nid represents dnode's nid
+ * - If node page, nid represents the node page's nid.
+ *
+ * The ofs_in_node is used by only data page. It represents offset
+ * from node's page's beginning to get a data block address.
+ * ex) data_blkaddr = (block_t)(nodepage_start_address + ofs_in_node)
+ */
+#define ENTRIES_IN_SUM 512
+#define SUMMARY_SIZE (7) /* sizeof(struct summary) */
+#define SUM_FOOTER_SIZE (5) /* sizeof(struct summary_footer) */
+#define SUM_ENTRIES_SIZE (SUMMARY_SIZE * ENTRIES_IN_SUM)
+
+/* a summary entry for a 4KB-sized block in a segment */
+struct f2fs_summary {
+ __le32 nid; /* parent node id */
+ union {
+ __u8 reserved[3];
+ struct {
+ __u8 version; /* node version number */
+ __le16 ofs_in_node; /* block index in parent node */
+ } __attribute__((packed));
+ };
+} __attribute__((packed));
+
+/* summary block type, node or data, is stored to the summary_footer */
+#define SUM_TYPE_NODE (1)
+#define SUM_TYPE_DATA (0)
+
+struct summary_footer {
+ unsigned char entry_type; /* SUM_TYPE_XXX */
+ __u32 check_sum; /* summary checksum */
+} __attribute__((packed));
+
+#define SUM_JOURNAL_SIZE (F2FS_BLKSIZE - SUM_FOOTER_SIZE -\
+ SUM_ENTRIES_SIZE)
+#define NAT_JOURNAL_ENTRIES ((SUM_JOURNAL_SIZE - 2) /\
+ sizeof(struct nat_journal_entry))
+#define NAT_JOURNAL_RESERVED ((SUM_JOURNAL_SIZE - 2) %\
+ sizeof(struct nat_journal_entry))
+#define SIT_JOURNAL_ENTRIES ((SUM_JOURNAL_SIZE - 2) /\
+ sizeof(struct sit_journal_entry))
+#define SIT_JOURNAL_RESERVED ((SUM_JOURNAL_SIZE - 2) %\
+ sizeof(struct sit_journal_entry))
+/*
+ * frequently updated NAT/SIT entries can be stored in the spare area in
+ * summary blocks
+ */
+enum {
+ NAT_JOURNAL = 0,
+ SIT_JOURNAL
+};
+
+struct nat_journal_entry {
+ __le32 nid;
+ struct f2fs_nat_entry ne;
+} __attribute__((packed));
+
+struct nat_journal {
+ struct nat_journal_entry entries[NAT_JOURNAL_ENTRIES];
+ __u8 reserved[NAT_JOURNAL_RESERVED];
+} __attribute__((packed));
+
+struct sit_journal_entry {
+ __le32 segno;
+ struct f2fs_sit_entry se;
+} __attribute__((packed));
+
+struct sit_journal {
+ struct sit_journal_entry entries[SIT_JOURNAL_ENTRIES];
+ __u8 reserved[SIT_JOURNAL_RESERVED];
+} __attribute__((packed));
+
+/* 4KB-sized summary block structure */
+struct f2fs_summary_block {
+ struct f2fs_summary entries[ENTRIES_IN_SUM];
+ union {
+ __le16 n_nats;
+ __le16 n_sits;
+ };
+ /* spare area is used by NAT or SIT journals */
+ union {
+ struct nat_journal nat_j;
+ struct sit_journal sit_j;
+ };
+ struct summary_footer footer;
+} __attribute__((packed));
+
+/*
+ * For directory operations
+ */
+#define F2FS_DOT_HASH 0
+#define F2FS_DDOT_HASH F2FS_DOT_HASH
+#define F2FS_MAX_HASH (~((0x3ULL) << 62))
+#define F2FS_HASH_COL_BIT ((0x1ULL) << 63)
+
+typedef __le32 f2fs_hash_t;
+
+/* One directory entry slot covers 8bytes-long file name */
+#define F2FS_SLOT_LEN 8
+#define F2FS_SLOT_LEN_BITS 3
+
+#define GET_DENTRY_SLOTS(x) ((x + F2FS_SLOT_LEN - 1) >> F2FS_SLOT_LEN_BITS)
+
+/* the number of dentry in a block */
+#define NR_DENTRY_IN_BLOCK 214
+
+/* MAX level for dir lookup */
+#define MAX_DIR_HASH_DEPTH 63
+
+#define SIZE_OF_DIR_ENTRY 11 /* by byte */
+#define SIZE_OF_DENTRY_BITMAP ((NR_DENTRY_IN_BLOCK + BITS_PER_BYTE - 1) / \
+ BITS_PER_BYTE)
+#define SIZE_OF_RESERVED (PAGE_SIZE - ((SIZE_OF_DIR_ENTRY + \
+ F2FS_SLOT_LEN) * \
+ NR_DENTRY_IN_BLOCK + SIZE_OF_DENTRY_BITMAP))
+
+/* One directory entry slot representing F2FS_SLOT_LEN-sized file name */
+struct f2fs_dir_entry {
+ __le32 hash_code; /* hash code of file name */
+ __le32 ino; /* inode number */
+ __le16 name_len; /* lengh of file name */
+ __u8 file_type; /* file type */
+} __attribute__((packed));
+
+/* 4KB-sized directory entry block */
+struct f2fs_dentry_block {
+ /* validity bitmap for directory entries in each block */
+ __u8 dentry_bitmap[SIZE_OF_DENTRY_BITMAP];
+ __u8 reserved[SIZE_OF_RESERVED];
+ struct f2fs_dir_entry dentry[NR_DENTRY_IN_BLOCK];
+ __u8 filename[NR_DENTRY_IN_BLOCK][F2FS_SLOT_LEN];
+} __attribute__((packed));
+
+/* for inline dir */
+#define NR_INLINE_DENTRY (MAX_INLINE_DATA * BITS_PER_BYTE / \
+ ((SIZE_OF_DIR_ENTRY + F2FS_SLOT_LEN) * \
+ BITS_PER_BYTE + 1))
+#define INLINE_DENTRY_BITMAP_SIZE ((NR_INLINE_DENTRY + \
+ BITS_PER_BYTE - 1) / BITS_PER_BYTE)
+#define INLINE_RESERVED_SIZE (MAX_INLINE_DATA - \
+ ((SIZE_OF_DIR_ENTRY + F2FS_SLOT_LEN) * \
+ NR_INLINE_DENTRY + INLINE_DENTRY_BITMAP_SIZE))
+
+/* inline directory entry structure */
+struct f2fs_inline_dentry {
+ __u8 dentry_bitmap[INLINE_DENTRY_BITMAP_SIZE];
+ __u8 reserved[INLINE_RESERVED_SIZE];
+ struct f2fs_dir_entry dentry[NR_INLINE_DENTRY];
+ __u8 filename[NR_INLINE_DENTRY][F2FS_SLOT_LEN];
+} __packed;
+
+/* file types used in inode_info->flags */
+enum FILE_TYPE {
+ F2FS_FT_UNKNOWN,
+ F2FS_FT_REG_FILE,
+ F2FS_FT_DIR,
+ F2FS_FT_CHRDEV,
+ F2FS_FT_BLKDEV,
+ F2FS_FT_FIFO,
+ F2FS_FT_SOCK,
+ F2FS_FT_SYMLINK,
+ F2FS_FT_MAX,
+ /* added for fsck */
+ F2FS_FT_ORPHAN,
+ F2FS_FT_XATTR,
+ F2FS_FT_LAST_FILE_TYPE = F2FS_FT_XATTR,
+};
+
+/* from f2fs/segment.h */
+enum {
+ LFS = 0,
+ SSR
+};
+
+extern void ASCIIToUNICODE(u_int16_t *, u_int8_t *);
+extern int log_base_2(u_int32_t);
+extern unsigned int addrs_per_inode(struct f2fs_inode *);
+
+extern int get_bits_in_byte(unsigned char n);
+extern int set_bit(unsigned int nr,void * addr);
+extern int clear_bit(unsigned int nr, void * addr);
+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 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 *);
+extern int f2fs_dev_is_umounted(struct f2fs_configuration *);
+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 );
+extern int dev_reada_block(__u64);
+
+extern int dev_read_version(void *, __u64, size_t);
+extern void get_kernel_version(__u8 *);
+f2fs_hash_t f2fs_dentry_hash(const unsigned char *, int);
+
+extern struct f2fs_configuration config;
+
+#define ALIGN(val, size) ((val) + (size) - 1) / (size)
+#define SEG_ALIGN(blks) ALIGN(blks, config.blks_per_seg)
+#define ZONE_ALIGN(blks) ALIGN(blks, config.blks_per_seg * \
+ config.segs_per_zone)
+
+#endif /*__F2FS_FS_H */
diff --git a/f2fs-tools/include/list.h b/f2fs-tools/include/list.h
new file mode 100644
index 0000000..571cd5c
--- /dev/null
+++ b/f2fs-tools/include/list.h
@@ -0,0 +1,88 @@
+
+#define POISON_POINTER_DELTA 0
+#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) );})
+
+struct list_head {
+ struct list_head *next, *prev;
+};
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+ struct list_head name = LIST_HEAD_INIT(name)
+
+static inline void INIT_LIST_HEAD(struct list_head *list)
+{
+ list->next = list;
+ list->prev = list;
+}
+
+static inline void __list_add(struct list_head *new,
+ struct list_head *prev,
+ struct list_head *next)
+{
+ next->prev = new;
+ new->next = next;
+ new->prev = prev;
+ prev->next = new;
+}
+
+static inline void list_add(struct list_head *new, struct list_head *head)
+{
+ __list_add(new, head, head->next);
+}
+
+static inline void list_add_tail(struct list_head *new, struct list_head *head)
+{
+ __list_add(new, head->prev, head);
+}
+
+static inline void __list_del(struct list_head * prev, struct list_head * next)
+{
+ next->prev = prev;
+ prev->next = next;
+}
+
+static inline void __list_del_entry(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+}
+
+static inline void list_del(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+ entry->next = LIST_POISON1;
+ entry->prev = LIST_POISON2;
+}
+
+static inline int list_empty(const struct list_head *head)
+{
+ return head->next == head;
+}
+
+#define list_entry(ptr, type, member) \
+ container_of(ptr, type, member)
+
+#define list_for_each(pos, head) \
+ for (pos = (head)->next; pos != (head); pos = pos->next)
+
+#define list_for_each_safe(pos, n, head) \
+ for (pos = (head)->next, n = pos->next; pos != (head); \
+ pos = n, n = pos->next)
+#define list_for_each_entry(pos, head, member) \
+ for (pos = list_entry((head)->next, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = list_entry(pos->member.next, typeof(*pos), member))
+#define list_for_each_entry_safe(pos, n, head, member) \
+ for (pos = list_entry((head)->next, typeof(*pos), member), \
+ n = list_entry(pos->member.next, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = n, n = list_entry(n->member.next, typeof(*n), member))
diff --git a/f2fs-tools/lib/Makefile.am b/f2fs-tools/lib/Makefile.am
new file mode 100644
index 0000000..a6b304c
--- /dev/null
+++ b/f2fs-tools/lib/Makefile.am
@@ -0,0 +1,7 @@
+## Makefile.am
+
+lib_LTLIBRARIES = libf2fs.la
+
+libf2fs_la_SOURCES = libf2fs.c libf2fs_io.c
+libf2fs_la_CFLAGS = -Wall
+libf2fs_la_CPPFLAGS = -I$(top_srcdir)/include
diff --git a/f2fs-tools/lib/libf2fs.c b/f2fs-tools/lib/libf2fs.c
new file mode 100644
index 0000000..9e19e9b
--- /dev/null
+++ b/f2fs-tools/lib/libf2fs.c
@@ -0,0 +1,511 @@
+/**
+ * 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>
+
+#include <f2fs_fs.h>
+
+void ASCIIToUNICODE(u_int16_t *out_buf, u_int8_t *in_buf)
+{
+ u_int8_t *pchTempPtr = in_buf;
+ u_int16_t *pwTempPtr = out_buf;
+
+ while (*pchTempPtr != '\0') {
+ *pwTempPtr = (u_int16_t)*pchTempPtr;
+ pchTempPtr++;
+ pwTempPtr++;
+ }
+ *pwTempPtr = '\0';
+ return;
+}
+
+int log_base_2(u_int32_t num)
+{
+ int ret = 0;
+ if (num <= 0 || (num & (num - 1)) != 0)
+ return -1;
+
+ while (num >>= 1)
+ ret++;
+ return ret;
+}
+
+/*
+ * f2fs bit operations
+ */
+static const int bits_in_byte[256] = {
+ 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
+ 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+ 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+ 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+ 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+ 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8,
+};
+
+int get_bits_in_byte(unsigned char n)
+{
+ return bits_in_byte[n];
+}
+
+int set_bit(unsigned int nr,void * addr)
+{
+ int mask, retval;
+ unsigned char *ADDR = (unsigned char *) addr;
+
+ ADDR += nr >> 3;
+ mask = 1 << ((nr & 0x07));
+ retval = mask & *ADDR;
+ *ADDR |= mask;
+ return retval;
+}
+
+int clear_bit(unsigned int nr, void * addr)
+{
+ int mask, retval;
+ unsigned char *ADDR = (unsigned char *) addr;
+
+ ADDR += nr >> 3;
+ mask = 1 << ((nr & 0x07));
+ retval = mask & *ADDR;
+ *ADDR &= ~mask;
+ return retval;
+}
+
+int test_bit(unsigned int nr, const void * addr)
+{
+ const __u32 *p = (const __u32 *)addr;
+
+ nr = nr ^ 0;
+
+ return ((1 << (nr & 31)) & (p[nr >> 5])) != 0;
+}
+
+int f2fs_test_bit(unsigned int nr, const char *p)
+{
+ int mask;
+ char *addr = (char *)p;
+
+ addr += (nr >> 3);
+ mask = 1 << (7 - (nr & 0x07));
+ return (mask & *addr) != 0;
+}
+
+int f2fs_set_bit(unsigned int nr, char *addr)
+{
+ int mask;
+ int ret;
+
+ addr += (nr >> 3);
+ mask = 1 << (7 - (nr & 0x07));
+ ret = mask & *addr;
+ *addr |= mask;
+ return ret;
+}
+
+int f2fs_clear_bit(unsigned int nr, char *addr)
+{
+ int mask;
+ int ret;
+
+ addr += (nr >> 3);
+ mask = 1 << (7 - (nr & 0x07));
+ ret = mask & *addr;
+ *addr &= ~mask;
+ return ret;
+}
+
+static inline unsigned long __ffs(unsigned long word)
+{
+ int num = 0;
+
+#if BITS_PER_LONG == 64
+ if ((word & 0xffffffff) == 0) {
+ num += 32;
+ word >>= 32;
+ }
+#endif
+ if ((word & 0xffff) == 0) {
+ num += 16;
+ word >>= 16;
+ }
+ if ((word & 0xff) == 0) {
+ num += 8;
+ word >>= 8;
+ }
+ if ((word & 0xf) == 0) {
+ num += 4;
+ word >>= 4;
+ }
+ if ((word & 0x3) == 0) {
+ num += 2;
+ word >>= 2;
+ }
+ if ((word & 0x1) == 0)
+ num += 1;
+ return num;
+}
+
+unsigned long find_next_bit(const unsigned long *addr, unsigned long size,
+ unsigned long offset)
+{
+ const unsigned long *p = addr + BIT_WORD(offset);
+ unsigned long result = offset & ~(BITS_PER_LONG-1);
+ unsigned long tmp;
+
+ if (offset >= size)
+ return size;
+ size -= result;
+ offset %= BITS_PER_LONG;
+ if (offset) {
+ tmp = *(p++);
+ tmp &= (~0UL << offset);
+ if (size < BITS_PER_LONG)
+ goto found_first;
+ if (tmp)
+ goto found_middle;
+ size -= BITS_PER_LONG;
+ result += BITS_PER_LONG;
+ }
+ while (size & ~(BITS_PER_LONG-1)) {
+ if ((tmp = *(p++)))
+ goto found_middle;
+ result += BITS_PER_LONG;
+ size -= BITS_PER_LONG;
+ }
+ if (!size)
+ return result;
+ tmp = *p;
+
+found_first:
+ tmp &= (~0UL >> (BITS_PER_LONG - size));
+ if (tmp == 0UL) /* Are any bits set? */
+ return result + size; /* Nope. */
+found_middle:
+ return result + __ffs(tmp);
+}
+
+/*
+ * Hashing code adapted from ext3
+ */
+#define DELTA 0x9E3779B9
+
+static void TEA_transform(unsigned int buf[4], unsigned int const in[])
+{
+ __u32 sum = 0;
+ __u32 b0 = buf[0], b1 = buf[1];
+ __u32 a = in[0], b = in[1], c = in[2], d = in[3];
+ int n = 16;
+
+ do {
+ sum += DELTA;
+ b0 += ((b1 << 4)+a) ^ (b1+sum) ^ ((b1 >> 5)+b);
+ b1 += ((b0 << 4)+c) ^ (b0+sum) ^ ((b0 >> 5)+d);
+ } while (--n);
+
+ buf[0] += b0;
+ buf[1] += b1;
+
+}
+
+static void str2hashbuf(const unsigned char *msg, int len,
+ unsigned int *buf, int num)
+{
+ unsigned pad, val;
+ int i;
+
+ pad = (__u32)len | ((__u32)len << 8);
+ pad |= pad << 16;
+
+ val = pad;
+ if (len > num * 4)
+ len = num * 4;
+ for (i = 0; i < len; i++) {
+ if ((i % 4) == 0)
+ val = pad;
+ val = msg[i] + (val << 8);
+ if ((i % 4) == 3) {
+ *buf++ = val;
+ val = pad;
+ num--;
+ }
+ }
+ if (--num >= 0)
+ *buf++ = val;
+ while (--num >= 0)
+ *buf++ = pad;
+
+}
+
+/**
+ * Return hash value of directory entry
+ * @param name dentry name
+ * @param len name lenth
+ * @return return on success hash value, errno on failure
+ */
+f2fs_hash_t f2fs_dentry_hash(const unsigned char *name, int len)
+{
+ __u32 hash;
+ f2fs_hash_t f2fs_hash;
+ const unsigned char *p;
+ __u32 in[8], buf[4];
+
+ /* special hash codes for special dentries */
+ if ((len <= 2) && (name[0] == '.') &&
+ (name[1] == '.' || name[1] == '\0'))
+ return 0;
+
+ /* Initialize the default seed for the hash checksum functions */
+ buf[0] = 0x67452301;
+ buf[1] = 0xefcdab89;
+ buf[2] = 0x98badcfe;
+ buf[3] = 0x10325476;
+
+ p = name;
+ while (1) {
+ str2hashbuf(p, len, in, 4);
+ TEA_transform(buf, in);
+ p += 16;
+ if (len <= 16)
+ break;
+ len -= 16;
+ }
+ hash = buf[0];
+
+ f2fs_hash = cpu_to_le32(hash & ~F2FS_HASH_COL_BIT);
+ return f2fs_hash;
+}
+
+unsigned int addrs_per_inode(struct f2fs_inode *i)
+{
+ if (i->i_inline & F2FS_INLINE_XATTR)
+ return DEF_ADDRS_PER_INODE - F2FS_INLINE_XATTR_ADDRS;
+ return DEF_ADDRS_PER_INODE;
+}
+
+/*
+ * CRC32
+ */
+#define CRCPOLY_LE 0xedb88320
+
+u_int32_t f2fs_cal_crc32(u_int32_t crc, void *buf, int len)
+{
+ int i;
+ unsigned char *p = (unsigned char *)buf;
+ while (len--) {
+ crc ^= *p++;
+ for (i = 0; i < 8; i++)
+ crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0);
+ }
+ return crc;
+}
+
+int f2fs_crc_valid(u_int32_t blk_crc, void *buf, int len)
+{
+ u_int32_t cal_crc = 0;
+
+ 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\n",
+ cal_crc, blk_crc, len);
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * device information
+ */
+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;
+
+ /* calculated by overprovision ratio */
+ c->reserved_segments = 48;
+ c->overprovision = 5;
+ c->segs_per_sec = 1;
+ c->secs_per_zone = 1;
+ c->segs_per_zone = 1;
+ c->heap = 1;
+ c->vol_label = "";
+ c->device_name = NULL;
+ c->trim = 1;
+}
+
+static int is_mounted(const char *mpt, const char *device)
+{
+ FILE *file = NULL;
+ struct mntent *mnt = NULL;
+
+ file = setmntent(mpt, "r");
+ if (file == NULL)
+ return 0;
+
+ while ((mnt = getmntent(file)) != NULL) {
+ if (!strcmp(device, mnt->mnt_fsname))
+ break;
+ }
+ endmntent(file);
+ return mnt ? 1 : 0;
+}
+
+int f2fs_dev_is_umounted(struct f2fs_configuration *c)
+{
+ struct stat st_buf;
+ int ret = 0;
+
+ ret = is_mounted(MOUNTED, c->device_name);
+ if (ret) {
+ MSG(0, "\tError: Not available on mounted device!\n");
+ return -1;
+ }
+
+ /*
+ * if failed due to /etc/mtab file not present
+ * try with /proc/mounts.
+ */
+ ret = is_mounted("/proc/mounts", c->device_name);
+ if (ret) {
+ MSG(0, "\tError: Not available on mounted device!\n");
+ return -1;
+ }
+
+ /*
+ * If f2fs is umounted with -l, the process can still use
+ * the file system. In this case, we should not format.
+ */
+ if (stat(c->device_name, &st_buf) == 0 && S_ISBLK(st_buf.st_mode)) {
+ int fd = open(c->device_name, O_RDONLY | O_EXCL);
+
+ if (fd >= 0) {
+ close(fd);
+ } else if (errno == EBUSY) {
+ MSG(0, "\tError: In use by the system!\n");
+ return -1;
+ }
+ }
+ return 0;
+}
+
+void get_kernel_version(__u8 *version)
+{
+ int i;
+ for (i = 0; i < VERSION_LEN; i++) {
+ if (version[i] == '\n')
+ break;
+ }
+ memset(version + i, 0, VERSION_LEN + 1 - i);
+}
+
+int f2fs_get_device_info(struct f2fs_configuration *c)
+{
+ int32_t fd = 0;
+ uint32_t sector_size;
+#ifndef BLKGETSIZE64
+ uint32_t total_sectors;
+#endif
+ 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) {
+ MSG(0, "\tError: Failed to open the device!\n");
+ return -1;
+ }
+ c->fd = fd;
+
+ c->kd = open("/proc/version", O_RDONLY);
+ if (c->kd < 0)
+ MSG(0, "\tInfo: No support kernel version!\n");
+
+ if (fstat(fd, &stat_buf) < 0 ) {
+ MSG(0, "\tError: Failed to get the device stat!\n");
+ return -1;
+ }
+
+ if (S_ISREG(stat_buf.st_mode)) {
+ c->total_sectors = stat_buf.st_size / c->sector_size;
+ } else if (S_ISBLK(stat_buf.st_mode)) {
+ if (ioctl(fd, BLKSSZGET, §or_size) < 0) {
+ MSG(0, "\tError: Using the default sector size\n");
+ } else {
+ if (c->sector_size < sector_size) {
+ c->sector_size = sector_size;
+ c->sectors_per_blk = PAGE_SIZE / sector_size;
+ }
+ }
+
+#ifdef BLKGETSIZE64
+ if (ioctl(fd, BLKGETSIZE64, &c->total_sectors) < 0) {
+ MSG(0, "\tError: Cannot get the device size\n");
+ return -1;
+ }
+ c->total_sectors /= c->sector_size;
+#else
+ if (ioctl(fd, BLKGETSIZE, &total_sectors) < 0) {
+ MSG(0, "\tError: Cannot get the device size\n");
+ return -1;
+ }
+ total_sectors /= c->sector_size;
+ c->total_sectors = total_sectors;
+#endif
+ if (ioctl(fd, HDIO_GETGEO, &geom) < 0)
+ c->start_sector = 0;
+ else
+ c->start_sector = geom.start;
+ } else {
+ 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 %u bytes)\n",
+ c->total_sectors, c->sector_size);
+ c->total_sectors = wanted_total_sectors;
+
+ }
+ MSG(0, "Info: sector size = %u\n", c->sector_size);
+ MSG(0, "Info: total sectors = %"PRIu64" (in %u bytes)\n",
+ c->total_sectors, c->sector_size);
+ if (c->total_sectors <
+ (F2FS_MIN_VOLUME_SIZE / c->sector_size)) {
+ MSG(0, "Error: Min volume size supported is %d\n",
+ F2FS_MIN_VOLUME_SIZE);
+ return -1;
+ }
+
+ return 0;
+}
+
diff --git a/f2fs-tools/lib/libf2fs_io.c b/f2fs-tools/lib/libf2fs_io.c
new file mode 100644
index 0000000..afa345f
--- /dev/null
+++ b/f2fs-tools/lib/libf2fs_io.c
@@ -0,0 +1,121 @@
+/**
+ * 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>
+
+#include <f2fs_fs.h>
+
+struct f2fs_configuration config;
+
+/*
+ * IO interfaces
+ */
+int dev_read_version(void *buf, __u64 offset, size_t len)
+{
+ if (lseek64(config.kd, (off64_t)offset, SEEK_SET) < 0)
+ return -1;
+ if (read(config.kd, buf, len) < 0)
+ return -1;
+ return 0;
+}
+
+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_readahead(__u64 offset, size_t len)
+{
+#ifdef POSIX_FADV_WILLNEED
+ return posix_fadvise(config.fd, offset, len, POSIX_FADV_WILLNEED);
+#else
+ return 0;
+#endif
+}
+
+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);
+}
+
+int dev_reada_block(__u64 blk_addr)
+{
+ return dev_readahead(blk_addr * F2FS_BLKSIZE, 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");
+
+ close(c->kd);
+}
diff --git a/f2fs-tools/man/Makefile.am b/f2fs-tools/man/Makefile.am
new file mode 100644
index 0000000..477d654
--- /dev/null
+++ b/f2fs-tools/man/Makefile.am
@@ -0,0 +1,3 @@
+## Makefile.am
+
+dist_man_MANS = mkfs.f2fs.8
diff --git a/f2fs-tools/man/mkfs.f2fs.8 b/f2fs-tools/man/mkfs.f2fs.8
new file mode 100644
index 0000000..f386ac6
--- /dev/null
+++ b/f2fs-tools/man/mkfs.f2fs.8
@@ -0,0 +1,91 @@
+.\" Copyright (c) 2012 Samsung Electronics Co., Ltd.
+.\" http://www.samsung.com/
+.\" Written by Jaegeuk Kim <jaegeuk.kim@samsung.com>
+.\"
+.TH MKFS.F2FS 8 "January 2013" "f2fs-tools version 1.2.0"
+.SH NAME
+mkfs.f2fs \- create an F2FS file system
+.SH SYNOPSIS
+.B mkfs.f2fs
+[
+.B \-a
+.I heap-based-allocation
+]
+[
+.B \-l
+.I volume-label
+]
+[
+.B \-o
+.I overprovision-ratio-percentage
+]
+[
+.B \-s
+.I log-based-#-of-segments-per-section
+]
+[
+.B \-z
+.I #-of-sections-per-zone
+]
+[
+.B \-e
+.I extenstion-list
+]
+[
+.B \-d
+.I debugging-level
+]
+.I device
+.SH DESCRIPTION
+.B mkfs.f2fs
+is used to create a f2fs file system (usually in a disk partition).
+\fIdevice\fP is the special file corresponding to the device (e.g.
+\fI/dev/sdXX\fP).
+.PP
+The exit code returned by
+.B mkfs.f2fs
+is 0 on success and 1 on failure.
+.SH OPTIONS
+.TP
+.BI \-a " heap-based-allocation"
+Specify 1 or 0 to enable/disable heap based block allocation policy.
+If the value is equal to 1, each of active log areas are initially
+assigned separately according to the whole volume size.
+The default value is 1.
+.TP
+.BI \-l " volume-label"
+Specify the volume label to the partition mounted as F2FS.
+.TP
+.BI \-o " overprovision-ratio-percentage"
+Specify the percentage over the volume size for overprovision area. This area
+is hidden to users, and utilized by F2FS cleaner. The default percentage is 5%.
+.TP
+.BI \-s " log-based-#-of-segments-per-section"
+Specify the log-based number of segments per section. A section consists of
+multiple consecutive segments, and is the unit of garbage collection.
+The default number is 0, which means one segment is assigned to a section.
+.TP
+.BI \-z " #-of-sections-per-zone"
+Specify the number of sections per zone. A zone consists of multiple sections.
+F2FS allocates segments for active logs with separated zones as much as possible.
+The default number is 1, which means a zone consists of one section.
+.TP
+.BI \-e " extension-list"
+Specify a file extension list in order f2fs to treat them as cold files.
+The data of files having those extensions will be stored to the cold log.
+The default list includes most of multimedia file extensions such as jpg, gif,
+mpeg, mkv, and so on.
+.TP
+.BI \-d " debug-level"
+Specify the level of debugging options.
+The default number is 0, which shows basic debugging messages.
+.TP
+.SH AUTHOR
+This version of
+.B mkfs.f2fs
+has been written by Jaegeuk Kim <jaegeuk.kim@samsung.com>.
+.SH AVAILABILITY
+.B mkfs.f2fs
+is available from git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs-tools.git.
+.SH SEE ALSO
+.BR mkfs (8).
diff --git a/f2fs-tools/mkfs/Makefile.am b/f2fs-tools/mkfs/Makefile.am
new file mode 100644
index 0000000..fa48699
--- /dev/null
+++ b/f2fs-tools/mkfs/Makefile.am
@@ -0,0 +1,7 @@
+## Makefile.am
+
+AM_CPPFLAGS = ${libuuid_CFLAGS} -I$(top_srcdir)/include
+AM_CFLAGS = -Wall -DWITH_BLKDISCARD
+sbin_PROGRAMS = mkfs.f2fs
+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/f2fs-tools/mkfs/f2fs_format.c b/f2fs-tools/mkfs/f2fs_format.c
new file mode 100644
index 0000000..094afa3
--- /dev/null
+++ b/f2fs-tools/mkfs/f2fs_format.c
@@ -0,0 +1,963 @@
+/**
+ * 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 <uuid/uuid.h>
+
+#include "f2fs_fs.h"
+#include "f2fs_format_utils.h"
+
+extern struct f2fs_configuration config;
+struct f2fs_super_block sb;
+struct f2fs_checkpoint *cp;
+
+/* Return first segment number of each area */
+#define prev_zone(cur) (config.cur_seg[cur] - config.segs_per_zone)
+#define next_zone(cur) (config.cur_seg[cur] + config.segs_per_zone)
+#define last_zone(cur) ((cur - 1) * config.segs_per_zone)
+#define last_section(cur) (cur + (config.secs_per_zone - 1) * config.segs_per_sec)
+
+#define set_sb_le64(member, val) (sb.member = cpu_to_le64(val))
+#define set_sb_le32(member, val) (sb.member = cpu_to_le32(val))
+#define set_sb_le16(member, val) (sb.member = cpu_to_le16(val))
+#define get_sb_le64(member) le64_to_cpu(sb.member)
+#define get_sb_le32(member) le32_to_cpu(sb.member)
+#define get_sb_le16(member) le16_to_cpu(sb.member)
+
+#define set_sb(member, val) \
+ do { \
+ typeof(sb.member) t; \
+ switch (sizeof(t)) { \
+ case 8: set_sb_le64(member, val); break; \
+ case 4: set_sb_le32(member, val); break; \
+ case 2: set_sb_le16(member, val); break; \
+ } \
+ } while(0)
+
+#define get_sb(member) \
+ ({ \
+ typeof(sb.member) t; \
+ switch (sizeof(t)) { \
+ case 8: t = get_sb_le64(member); break; \
+ case 4: t = get_sb_le32(member); break; \
+ case 2: t = get_sb_le16(member); break; \
+ } \
+ t; \
+ })
+
+#define set_cp_le64(member, val) (cp->member = cpu_to_le64(val))
+#define set_cp_le32(member, val) (cp->member = cpu_to_le32(val))
+#define set_cp_le16(member, val) (cp->member = cpu_to_le16(val))
+#define get_cp_le64(member) le64_to_cpu(cp->member)
+#define get_cp_le32(member) le32_to_cpu(cp->member)
+#define get_cp_le16(member) le16_to_cpu(cp->member)
+
+#define set_cp(member, val) \
+ do { \
+ typeof(cp->member) t; \
+ switch (sizeof(t)) { \
+ case 8: set_cp_le64(member, val); break; \
+ case 4: set_cp_le32(member, val); break; \
+ case 2: set_cp_le16(member, val); break; \
+ } \
+ } while(0)
+
+#define get_cp(member) \
+ ({ \
+ typeof(cp->member) t; \
+ switch (sizeof(t)) { \
+ case 8: t = get_cp_le64(member); break; \
+ case 4: t = get_cp_le32(member); break; \
+ case 2: t = get_cp_le16(member); break; \
+ } \
+ t; \
+ })
+
+
+const char *media_ext_lists[] = {
+ "jpg",
+ "gif",
+ "png",
+ "avi",
+ "divx",
+ "mp4",
+ "mp3",
+ "3gp",
+ "wmv",
+ "wma",
+ "mpeg",
+ "mkv",
+ "mov",
+ "asx",
+ "asf",
+ "wmx",
+ "svi",
+ "wvx",
+ "wm",
+ "mpg",
+ "mpe",
+ "rm",
+ "ogg",
+ "jpeg",
+ "video",
+ "apk", /* for android system */
+ NULL
+};
+
+static void configure_extension_list(void)
+{
+ const char **extlist = media_ext_lists;
+ char *ext_str = config.extension_list;
+ char *ue;
+ int name_len;
+ int i = 0;
+
+ sb.extension_count = 0;
+ memset(sb.extension_list, 0,
+ sizeof(sb.extension_list));
+
+ while (*extlist) {
+ name_len = strlen(*extlist);
+ memcpy(sb.extension_list[i++], *extlist, name_len);
+ extlist++;
+ }
+ set_sb(extension_count, i);
+
+ if (!ext_str)
+ return;
+
+ /* add user ext list */
+ ue = strtok(ext_str, ",");
+ while (ue != NULL) {
+ name_len = strlen(ue);
+ memcpy(sb.extension_list[i++], ue, name_len);
+ ue = strtok(NULL, ",");
+ if (i >= F2FS_MAX_EXTENSION)
+ break;
+ }
+
+ set_sb(extension_count, i);
+
+ free(config.extension_list);
+}
+
+static int f2fs_prepare_super_block(void)
+{
+ u_int32_t blk_size_bytes;
+ u_int32_t log_sectorsize, log_sectors_per_block;
+ u_int32_t log_blocksize, log_blks_per_seg;
+ u_int32_t segment_size_bytes, zone_size_bytes;
+ u_int32_t sit_segments;
+ 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_sit_bitmap_size;
+ u_int32_t max_nat_bitmap_size, max_nat_segments;
+ u_int32_t total_zones;
+
+ set_sb(magic, F2FS_SUPER_MAGIC);
+ set_sb(major_ver, F2FS_MAJOR_VERSION);
+ set_sb(minor_ver, F2FS_MINOR_VERSION);
+
+ log_sectorsize = log_base_2(config.sector_size);
+ log_sectors_per_block = log_base_2(config.sectors_per_blk);
+ log_blocksize = log_sectorsize + log_sectors_per_block;
+ log_blks_per_seg = log_base_2(config.blks_per_seg);
+
+ set_sb(log_sectorsize, log_sectorsize);
+ set_sb(log_sectors_per_block, log_sectors_per_block);
+
+ set_sb(log_blocksize, log_blocksize);
+ set_sb(log_blocks_per_seg, log_blks_per_seg);
+
+ set_sb(segs_per_sec, config.segs_per_sec);
+ set_sb(secs_per_zone, config.secs_per_zone);
+
+ blk_size_bytes = 1 << log_blocksize;
+ segment_size_bytes = blk_size_bytes * config.blks_per_seg;
+ zone_size_bytes =
+ blk_size_bytes * config.secs_per_zone *
+ config.segs_per_sec * config.blks_per_seg;
+
+ sb.checksum_offset = 0;
+
+ set_sb(block_count, config.total_sectors >> log_sectors_per_block);
+
+ zone_align_start_offset =
+ (config.start_sector * config.sector_size +
+ 2 * F2FS_BLKSIZE + zone_size_bytes - 1) /
+ zone_size_bytes * zone_size_bytes -
+ config.start_sector * config.sector_size;
+
+ if (config.start_sector % config.sectors_per_blk) {
+ MSG(1, "\tWARN: Align start sector number to the page unit\n");
+ MSG(1, "\ti.e., start sector: %d, ofs:%d (sects/page: %d)\n",
+ config.start_sector,
+ config.start_sector % config.sectors_per_blk,
+ config.sectors_per_blk);
+ }
+
+ set_sb(segment_count, (config.total_sectors * config.sector_size -
+ zone_align_start_offset) / segment_size_bytes);
+
+ set_sb(segment0_blkaddr, zone_align_start_offset / blk_size_bytes);
+ sb.cp_blkaddr = sb.segment0_blkaddr;
+
+ MSG(0, "Info: zone aligned segment0 blkaddr: %u\n", get_sb(segment0_blkaddr));
+
+ set_sb(segment_count_ckpt, F2FS_NUMBER_OF_CHECKPOINT_PACK);
+
+ set_sb(sit_blkaddr, get_sb(segment0_blkaddr) + get_sb(segment_count_ckpt) *
+ config.blks_per_seg);
+
+ blocks_for_sit = ALIGN(get_sb(segment_count), SIT_ENTRY_PER_BLOCK);
+
+ sit_segments = SEG_ALIGN(blocks_for_sit);
+
+ set_sb(segment_count_sit, sit_segments * 2);
+
+ set_sb(nat_blkaddr, get_sb(sit_blkaddr) + get_sb(segment_count_sit) *
+ config.blks_per_seg);
+
+ total_valid_blks_available = (get_sb(segment_count) -
+ (get_sb(segment_count_ckpt) + get_sb(segment_count_sit))) *
+ config.blks_per_seg;
+
+ blocks_for_nat = ALIGN(total_valid_blks_available, NAT_ENTRY_PER_BLOCK);
+
+ set_sb(segment_count_nat, SEG_ALIGN(blocks_for_nat));
+ /*
+ * The number of node segments should not be exceeded a "Threshold".
+ * This number resizes NAT bitmap area in a CP page.
+ * So the threshold is determined not to overflow one CP page
+ */
+ sit_bitmap_size = ((get_sb(segment_count_sit) / 2) <<
+ log_blks_per_seg) / 8;
+
+ 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;
+ set_sb(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;
+ sb.cp_payload = 0;
+ }
+
+ max_nat_segments = (max_nat_bitmap_size * 8) >> log_blks_per_seg;
+
+ if (get_sb(segment_count_nat) > max_nat_segments)
+ set_sb(segment_count_nat, max_nat_segments);
+
+ set_sb(segment_count_nat, get_sb(segment_count_nat) * 2);
+
+ set_sb(ssa_blkaddr, get_sb(nat_blkaddr) + get_sb(segment_count_nat) *
+ config.blks_per_seg);
+
+ total_valid_blks_available = (get_sb(segment_count) -
+ (get_sb(segment_count_ckpt) +
+ get_sb(segment_count_sit) +
+ get_sb(segment_count_nat))) *
+ config.blks_per_seg;
+
+ blocks_for_ssa = total_valid_blks_available /
+ config.blks_per_seg + 1;
+
+ set_sb(segment_count_ssa, SEG_ALIGN(blocks_for_ssa));
+
+ total_meta_segments = get_sb(segment_count_ckpt) +
+ get_sb(segment_count_sit) +
+ get_sb(segment_count_nat) +
+ get_sb(segment_count_ssa);
+ diff = total_meta_segments % (config.segs_per_zone);
+ if (diff)
+ set_sb(segment_count_ssa, get_sb(segment_count_ssa) +
+ (config.segs_per_zone - diff));
+
+ set_sb(main_blkaddr, get_sb(ssa_blkaddr) + get_sb(segment_count_ssa) *
+ config.blks_per_seg);
+
+ set_sb(segment_count_main, get_sb(segment_count) -
+ (get_sb(segment_count_ckpt) +
+ get_sb(segment_count_sit) +
+ get_sb(segment_count_nat) +
+ get_sb(segment_count_ssa)));
+
+ set_sb(section_count, get_sb(segment_count_main) / config.segs_per_sec);
+
+ set_sb(segment_count_main, get_sb(section_count) * config.segs_per_sec);
+
+ if ((get_sb(segment_count_main) - 2) <
+ config.reserved_segments) {
+ MSG(1, "\tError: Device size is not sufficient for F2FS volume,\
+ more segment needed =%u",
+ config.reserved_segments -
+ (get_sb(segment_count_main) - 2));
+ return -1;
+ }
+
+ uuid_generate(sb.uuid);
+
+ ASCIIToUNICODE(sb.volume_name, (u_int8_t *)config.vol_label);
+
+ set_sb(node_ino, 1);
+ set_sb(meta_ino, 2);
+ set_sb(root_ino, 3);
+
+ total_zones = get_sb(segment_count_main) / (config.segs_per_zone);
+ if (total_zones <= 6) {
+ MSG(1, "\tError: %d zones: Need more zones \
+ by shrinking zone size\n", total_zones);
+ return -1;
+ }
+
+ if (config.heap) {
+ config.cur_seg[CURSEG_HOT_NODE] = last_section(last_zone(total_zones));
+ config.cur_seg[CURSEG_WARM_NODE] = prev_zone(CURSEG_HOT_NODE);
+ config.cur_seg[CURSEG_COLD_NODE] = prev_zone(CURSEG_WARM_NODE);
+ config.cur_seg[CURSEG_HOT_DATA] = prev_zone(CURSEG_COLD_NODE);
+ config.cur_seg[CURSEG_COLD_DATA] = 0;
+ config.cur_seg[CURSEG_WARM_DATA] = next_zone(CURSEG_COLD_DATA);
+ } else {
+ config.cur_seg[CURSEG_HOT_NODE] = 0;
+ config.cur_seg[CURSEG_WARM_NODE] = next_zone(CURSEG_HOT_NODE);
+ config.cur_seg[CURSEG_COLD_NODE] = next_zone(CURSEG_WARM_NODE);
+ config.cur_seg[CURSEG_HOT_DATA] = next_zone(CURSEG_COLD_NODE);
+ config.cur_seg[CURSEG_COLD_DATA] = next_zone(CURSEG_HOT_DATA);
+ config.cur_seg[CURSEG_WARM_DATA] = next_zone(CURSEG_COLD_DATA);
+ }
+
+ configure_extension_list();
+
+ /* get kernel version */
+ if (config.kd >= 0) {
+ dev_read_version(config.version, 0, VERSION_LEN);
+ get_kernel_version(config.version);
+ MSG(0, "Info: format version with\n \"%s\"\n", config.version);
+ } else {
+ memset(config.version, 0, VERSION_LEN);
+ }
+
+ memcpy(sb.version, config.version, VERSION_LEN);
+ memcpy(sb.init_version, config.version, VERSION_LEN);
+
+ return 0;
+}
+
+static int f2fs_init_sit_area(void)
+{
+ u_int32_t blk_size, seg_size;
+ u_int32_t index = 0;
+ u_int64_t sit_seg_addr = 0;
+ u_int8_t *zero_buf = NULL;
+
+ blk_size = 1 << get_sb(log_blocksize);
+ seg_size = (1 << get_sb(log_blocks_per_seg)) * blk_size;
+
+ zero_buf = calloc(sizeof(u_int8_t), seg_size);
+ if(zero_buf == NULL) {
+ MSG(1, "\tError: Calloc Failed for sit_zero_buf!!!\n");
+ return -1;
+ }
+
+ sit_seg_addr = get_sb(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 < (get_sb(segment_count_sit) / 2); index++) {
+ if (dev_fill(zero_buf, sit_seg_addr, seg_size)) {
+ MSG(1, "\tError: While zeroing out the sit area \
+ on disk!!!\n");
+ free(zero_buf);
+ return -1;
+ }
+ sit_seg_addr += seg_size;
+ }
+
+ free(zero_buf);
+ return 0 ;
+}
+
+static int f2fs_init_nat_area(void)
+{
+ u_int32_t blk_size, seg_size;
+ u_int32_t index = 0;
+ u_int64_t nat_seg_addr = 0;
+ u_int8_t *nat_buf = NULL;
+
+ blk_size = 1 << get_sb(log_blocksize);
+ seg_size = (1 << get_sb(log_blocks_per_seg)) * blk_size;
+
+ nat_buf = calloc(sizeof(u_int8_t), seg_size);
+ if (nat_buf == NULL) {
+ MSG(1, "\tError: Calloc Failed for nat_zero_blk!!!\n");
+ return -1;
+ }
+
+ nat_seg_addr = get_sb(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 < get_sb(segment_count_nat) / 2; index++) {
+ if (dev_fill(nat_buf, nat_seg_addr, seg_size)) {
+ MSG(1, "\tError: While zeroing out the nat area \
+ on disk!!!\n");
+ free(nat_buf);
+ return -1;
+ }
+ nat_seg_addr = nat_seg_addr + (2 * seg_size);
+ }
+
+ free(nat_buf);
+ return 0 ;
+}
+
+static int f2fs_write_check_point_pack(void)
+{
+ struct f2fs_summary_block *sum = NULL;
+ u_int32_t blk_size_bytes;
+ u_int64_t cp_seg_blk_offset = 0;
+ u_int32_t crc = 0;
+ unsigned int i;
+ char *cp_payload = NULL;
+ char *sum_compact, *sum_compact_p;
+ struct f2fs_summary *sum_entry;
+ int ret = -1;
+
+ cp = calloc(F2FS_BLKSIZE, 1);
+ if (cp == NULL) {
+ MSG(1, "\tError: Calloc Failed for f2fs_checkpoint!!!\n");
+ return ret;
+ }
+
+ sum = calloc(F2FS_BLKSIZE, 1);
+ if (sum == NULL) {
+ MSG(1, "\tError: Calloc Failed for summay_node!!!\n");
+ goto free_cp;
+ }
+
+ sum_compact = calloc(F2FS_BLKSIZE, 1);
+ if (sum == NULL) {
+ MSG(1, "\tError: Calloc Failed for summay buffer!!!\n");
+ goto free_sum;
+ }
+ sum_compact_p = sum_compact;
+
+ cp_payload = calloc(F2FS_BLKSIZE, 1);
+ if (cp_payload == NULL) {
+ MSG(1, "\tError: Calloc Failed for cp_payload!!!\n");
+ goto free_sum_compact;
+ }
+
+ /* 1. cp page 1 of checkpoint pack 1 */
+ set_cp(checkpoint_ver, 1);
+ set_cp(cur_node_segno[0], config.cur_seg[CURSEG_HOT_NODE]);
+ set_cp(cur_node_segno[1], config.cur_seg[CURSEG_WARM_NODE]);
+ set_cp(cur_node_segno[2], config.cur_seg[CURSEG_COLD_NODE]);
+ set_cp(cur_data_segno[0], config.cur_seg[CURSEG_HOT_DATA]);
+ set_cp(cur_data_segno[1], config.cur_seg[CURSEG_WARM_DATA]);
+ set_cp(cur_data_segno[2], config.cur_seg[CURSEG_COLD_DATA]);
+ for (i = 3; i < MAX_ACTIVE_NODE_LOGS; i++) {
+ set_cp(cur_node_segno[i], 0xffffffff);
+ set_cp(cur_data_segno[i], 0xffffffff);
+ }
+
+ set_cp(cur_node_blkoff[0], 1);
+ set_cp(cur_data_blkoff[0], 1);
+ set_cp(valid_block_count, 2);
+ set_cp(rsvd_segment_count, config.reserved_segments);
+ set_cp(overprov_segment_count, (get_sb(segment_count_main) -
+ get_cp(rsvd_segment_count)) *
+ config.overprovision / 100);
+ set_cp(overprov_segment_count, get_cp(overprov_segment_count) +
+ get_cp(rsvd_segment_count));
+
+ /* main segments - reserved segments - (node + data segments) */
+ set_cp(free_segment_count, get_sb(segment_count_main) - 6);
+ set_cp(user_block_count, ((get_cp(free_segment_count) + 6 -
+ get_cp(overprov_segment_count)) * config.blks_per_seg));
+ /* cp page (2), data summaries (1), node summaries (3) */
+ set_cp(cp_pack_total_block_count, 6 + get_sb(cp_payload));
+ set_cp(ckpt_flags, CP_UMOUNT_FLAG | CP_COMPACT_SUM_FLAG);
+ set_cp(cp_pack_start_sum, 1 + get_sb(cp_payload));
+ set_cp(valid_node_count, 1);
+ set_cp(valid_inode_count, 1);
+ set_cp(next_free_nid, get_sb(root_ino) + 1);
+ set_cp(sit_ver_bitmap_bytesize, ((get_sb(segment_count_sit) / 2) <<
+ get_sb(log_blocks_per_seg)) / 8);
+
+ set_cp(nat_ver_bitmap_bytesize, ((get_sb(segment_count_nat) / 2) <<
+ get_sb(log_blocks_per_seg)) / 8);
+
+ set_cp(checksum_offset, CHECKSUM_OFFSET);
+
+ crc = f2fs_cal_crc32(F2FS_SUPER_MAGIC, cp, CHECKSUM_OFFSET);
+ *((__le32 *)((unsigned char *)cp + CHECKSUM_OFFSET)) =
+ cpu_to_le32(crc);
+
+ blk_size_bytes = 1 << get_sb(log_blocksize);
+ cp_seg_blk_offset = get_sb(segment0_blkaddr);
+ cp_seg_blk_offset *= blk_size_bytes;
+
+ DBG(1, "\tWriting main segments, cp at offset 0x%08"PRIx64"\n", cp_seg_blk_offset);
+ if (dev_write(cp, cp_seg_blk_offset, blk_size_bytes)) {
+ MSG(1, "\tError: While writing the cp to disk!!!\n");
+ goto free_cp_payload;
+ }
+
+ for (i = 0; i < get_sb(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");
+ goto free_cp_payload;
+ }
+ }
+
+ /* Prepare and write Segment summary for HOT/WARM/COLD DATA
+ *
+ * The structure of compact summary
+ * +-------------------+
+ * | nat_journal |
+ * +-------------------+
+ * | sit_journal |
+ * +-------------------+
+ * | hot data summary |
+ * +-------------------+
+ * | warm data summary |
+ * +-------------------+
+ * | cold data summary |
+ * +-------------------+
+ */
+ memset(sum, 0, sizeof(struct f2fs_summary_block));
+ SET_SUM_TYPE((&sum->footer), SUM_TYPE_DATA);
+
+ sum->n_nats = cpu_to_le16(1);
+ sum->nat_j.entries[0].nid = sb.root_ino;
+ sum->nat_j.entries[0].ne.version = 0;
+ sum->nat_j.entries[0].ne.ino = sb.root_ino;
+ sum->nat_j.entries[0].ne.block_addr = cpu_to_le32(
+ get_sb(main_blkaddr) +
+ get_cp(cur_node_segno[0]) * config.blks_per_seg);
+
+ memcpy(sum_compact_p, &sum->n_nats, SUM_JOURNAL_SIZE);
+ sum_compact_p += SUM_JOURNAL_SIZE;
+
+ memset(sum, 0, sizeof(struct f2fs_summary_block));
+ /* inode sit for root */
+ sum->n_sits = cpu_to_le16(6);
+ sum->sit_j.entries[0].segno = cp->cur_node_segno[0];
+ sum->sit_j.entries[0].se.vblocks = cpu_to_le16((CURSEG_HOT_NODE << 10) | 1);
+ f2fs_set_bit(0, (char *)sum->sit_j.entries[0].se.valid_map);
+ sum->sit_j.entries[1].segno = cp->cur_node_segno[1];
+ sum->sit_j.entries[1].se.vblocks = cpu_to_le16((CURSEG_WARM_NODE << 10));
+ sum->sit_j.entries[2].segno = cp->cur_node_segno[2];
+ sum->sit_j.entries[2].se.vblocks = cpu_to_le16((CURSEG_COLD_NODE << 10));
+
+ /* data sit for root */
+ sum->sit_j.entries[3].segno = cp->cur_data_segno[0];
+ sum->sit_j.entries[3].se.vblocks = cpu_to_le16((CURSEG_HOT_DATA << 10) | 1);
+ f2fs_set_bit(0, (char *)sum->sit_j.entries[3].se.valid_map);
+ sum->sit_j.entries[4].segno = cp->cur_data_segno[1];
+ sum->sit_j.entries[4].se.vblocks = cpu_to_le16((CURSEG_WARM_DATA << 10));
+ sum->sit_j.entries[5].segno = cp->cur_data_segno[2];
+ sum->sit_j.entries[5].se.vblocks = cpu_to_le16((CURSEG_COLD_DATA << 10));
+
+ memcpy(sum_compact_p, &sum->n_sits, SUM_JOURNAL_SIZE);
+ sum_compact_p += SUM_JOURNAL_SIZE;
+
+ /* hot data summary */
+ sum_entry = (struct f2fs_summary *)sum_compact_p;
+ sum_entry->nid = sb.root_ino;
+ sum_entry->ofs_in_node = 0;
+ /* warm data summary, nothing to do */
+ /* cold data summary, nothing to do */
+
+ cp_seg_blk_offset += blk_size_bytes;
+ DBG(1, "\tWriting Segment summary for HOT/WARM/COLD_DATA, at offset 0x%08"PRIx64"\n",
+ cp_seg_blk_offset);
+ if (dev_write(sum_compact, cp_seg_blk_offset, blk_size_bytes)) {
+ MSG(1, "\tError: While writing the sum_blk to disk!!!\n");
+ goto free_cp_payload;
+ }
+
+ /* Prepare and write Segment summary for HOT_NODE */
+ memset(sum, 0, sizeof(struct f2fs_summary_block));
+ SET_SUM_TYPE((&sum->footer), SUM_TYPE_NODE);
+
+ sum->entries[0].nid = sb.root_ino;
+ sum->entries[0].ofs_in_node = 0;
+
+ cp_seg_blk_offset += blk_size_bytes;
+ DBG(1, "\tWriting Segment summary for HOT_NODE, 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");
+ goto free_cp_payload;
+ }
+
+ /* Fill segment summary for WARM_NODE to zero. */
+ memset(sum, 0, sizeof(struct f2fs_summary_block));
+ SET_SUM_TYPE((&sum->footer), SUM_TYPE_NODE);
+
+ cp_seg_blk_offset += blk_size_bytes;
+ DBG(1, "\tWriting Segment summary for WARM_NODE, 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");
+ goto free_cp_payload;
+ }
+
+ /* Fill segment summary for COLD_NODE to zero. */
+ memset(sum, 0, sizeof(struct f2fs_summary_block));
+ SET_SUM_TYPE((&sum->footer), SUM_TYPE_NODE);
+ cp_seg_blk_offset += blk_size_bytes;
+ DBG(1, "\tWriting Segment summary for COLD_NODE, 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");
+ goto free_cp_payload;
+ }
+
+ /* cp page2 */
+ cp_seg_blk_offset += blk_size_bytes;
+ DBG(1, "\tWriting cp page2, at offset 0x%08"PRIx64"\n", cp_seg_blk_offset);
+ if (dev_write(cp, cp_seg_blk_offset, blk_size_bytes)) {
+ MSG(1, "\tError: While writing the cp to disk!!!\n");
+ goto free_cp_payload;
+ }
+
+ /* cp page 1 of check point pack 2
+ * Initiatialize other checkpoint pack with version zero
+ */
+ cp->checkpoint_ver = 0;
+
+ crc = f2fs_cal_crc32(F2FS_SUPER_MAGIC, cp, CHECKSUM_OFFSET);
+ *((__le32 *)((unsigned char *)cp + CHECKSUM_OFFSET)) =
+ cpu_to_le32(crc);
+ cp_seg_blk_offset = (get_sb(segment0_blkaddr) +
+ config.blks_per_seg) *
+ blk_size_bytes;
+ DBG(1, "\tWriting cp page 1 of checkpoint pack 2, at offset 0x%08"PRIx64"\n", cp_seg_blk_offset);
+ if (dev_write(cp, cp_seg_blk_offset, blk_size_bytes)) {
+ MSG(1, "\tError: While writing the cp to disk!!!\n");
+ goto free_cp_payload;
+ }
+
+ for (i = 0; i < get_sb(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");
+ goto free_cp_payload;
+ }
+ }
+
+ /* cp page 2 of check point pack 2 */
+ cp_seg_blk_offset += blk_size_bytes * (le32_to_cpu(cp->cp_pack_total_block_count)
+ - get_sb(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(cp, cp_seg_blk_offset, blk_size_bytes)) {
+ MSG(1, "\tError: While writing the cp to disk!!!\n");
+ goto free_cp_payload;
+ }
+
+ ret = 0;
+
+free_cp_payload:
+ free(cp_payload);
+free_sum_compact:
+ free(sum_compact);
+free_sum:
+ free(sum);
+free_cp:
+ free(cp);
+ return ret;
+}
+
+static int f2fs_write_super_block(void)
+{
+ int index;
+ u_int8_t *zero_buff;
+
+ zero_buff = calloc(F2FS_BLKSIZE, 1);
+
+ memcpy(zero_buff + F2FS_SUPER_OFFSET, &sb,
+ sizeof(sb));
+ 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 \
+ on disk!!! index : %d\n", index);
+ free(zero_buff);
+ return -1;
+ }
+ }
+
+ free(zero_buff);
+ return 0;
+}
+
+static int f2fs_write_root_inode(void)
+{
+ struct f2fs_node *raw_node = NULL;
+ u_int64_t blk_size_bytes, data_blk_nor;
+ u_int64_t main_area_node_seg_blk_offset = 0;
+
+ raw_node = calloc(F2FS_BLKSIZE, 1);
+ if (raw_node == NULL) {
+ MSG(1, "\tError: Calloc Failed for raw_node!!!\n");
+ return -1;
+ }
+
+ raw_node->footer.nid = sb.root_ino;
+ raw_node->footer.ino = sb.root_ino;
+ raw_node->footer.cp_ver = cpu_to_le64(1);
+ raw_node->footer.next_blkaddr = cpu_to_le32(
+ get_sb(main_blkaddr) +
+ config.cur_seg[CURSEG_HOT_NODE] *
+ config.blks_per_seg + 1);
+
+ raw_node->i.i_mode = cpu_to_le16(0x41ed);
+ raw_node->i.i_links = cpu_to_le32(2);
+ raw_node->i.i_uid = cpu_to_le32(getuid());
+ raw_node->i.i_gid = cpu_to_le32(getgid());
+
+ blk_size_bytes = 1 << get_sb(log_blocksize);
+ raw_node->i.i_size = cpu_to_le64(1 * blk_size_bytes); /* dentry */
+ raw_node->i.i_blocks = cpu_to_le64(2);
+
+ raw_node->i.i_atime = cpu_to_le32(time(NULL));
+ raw_node->i.i_atime_nsec = 0;
+ raw_node->i.i_ctime = cpu_to_le32(time(NULL));
+ raw_node->i.i_ctime_nsec = 0;
+ raw_node->i.i_mtime = cpu_to_le32(time(NULL));
+ raw_node->i.i_mtime_nsec = 0;
+ raw_node->i.i_generation = 0;
+ 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 = get_sb(main_blkaddr) +
+ config.cur_seg[CURSEG_HOT_DATA] * config.blks_per_seg;
+ raw_node->i.i_addr[0] = cpu_to_le32(data_blk_nor);
+
+ raw_node->i.i_ext.fofs = 0;
+ raw_node->i.i_ext.blk_addr = cpu_to_le32(data_blk_nor);
+ raw_node->i.i_ext.len = cpu_to_le32(1);
+
+ main_area_node_seg_blk_offset = get_sb(main_blkaddr);
+ main_area_node_seg_blk_offset += config.cur_seg[CURSEG_HOT_NODE] *
+ 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");
+ free(raw_node);
+ return -1;
+ }
+
+ memset(raw_node, 0xff, sizeof(struct f2fs_node));
+
+ /* avoid power-off-recovery based on roll-forward policy */
+ main_area_node_seg_blk_offset = get_sb(main_blkaddr);
+ main_area_node_seg_blk_offset += config.cur_seg[CURSEG_WARM_NODE] *
+ 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");
+ free(raw_node);
+ return -1;
+ }
+ free(raw_node);
+ return 0;
+}
+
+static int f2fs_update_nat_root(void)
+{
+ struct f2fs_nat_block *nat_blk = NULL;
+ u_int64_t blk_size_bytes, nat_seg_blk_offset = 0;
+
+ nat_blk = calloc(F2FS_BLKSIZE, 1);
+ if(nat_blk == NULL) {
+ MSG(1, "\tError: Calloc Failed for nat_blk!!!\n");
+ return -1;
+ }
+
+ /* update root */
+ nat_blk->entries[get_sb(root_ino)].block_addr = cpu_to_le32(
+ get_sb(main_blkaddr) +
+ config.cur_seg[CURSEG_HOT_NODE] * config.blks_per_seg);
+ nat_blk->entries[get_sb(root_ino)].ino = sb.root_ino;
+
+ /* update node nat */
+ nat_blk->entries[get_sb(node_ino)].block_addr = cpu_to_le32(1);
+ nat_blk->entries[get_sb(node_ino)].ino = sb.node_ino;
+
+ /* update meta nat */
+ nat_blk->entries[get_sb(meta_ino)].block_addr = cpu_to_le32(1);
+ nat_blk->entries[get_sb(meta_ino)].ino = sb.meta_ino;
+
+ blk_size_bytes = 1 << get_sb(log_blocksize);
+ nat_seg_blk_offset = get_sb(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");
+ free(nat_blk);
+ return -1;
+ }
+
+ free(nat_blk);
+ return 0;
+}
+
+static int f2fs_add_default_dentry_root(void)
+{
+ struct f2fs_dentry_block *dent_blk = NULL;
+ u_int64_t blk_size_bytes, data_blk_offset = 0;
+
+ dent_blk = calloc(F2FS_BLKSIZE, 1);
+ if(dent_blk == NULL) {
+ MSG(1, "\tError: Calloc Failed for dent_blk!!!\n");
+ return -1;
+ }
+
+ dent_blk->dentry[0].hash_code = 0;
+ dent_blk->dentry[0].ino = sb.root_ino;
+ dent_blk->dentry[0].name_len = cpu_to_le16(1);
+ dent_blk->dentry[0].file_type = F2FS_FT_DIR;
+ memcpy(dent_blk->filename[0], ".", 1);
+
+ dent_blk->dentry[1].hash_code = 0;
+ dent_blk->dentry[1].ino = sb.root_ino;
+ dent_blk->dentry[1].name_len = cpu_to_le16(2);
+ dent_blk->dentry[1].file_type = F2FS_FT_DIR;
+ memcpy(dent_blk->filename[1], "..", 2);
+
+ /* bitmap for . and .. */
+ dent_blk->dentry_bitmap[0] = (1 << 1) | (1 << 0);
+ blk_size_bytes = 1 << get_sb(log_blocksize);
+ data_blk_offset = get_sb(main_blkaddr);
+ data_blk_offset += config.cur_seg[CURSEG_HOT_DATA] *
+ 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");
+ free(dent_blk);
+ return -1;
+ }
+
+ free(dent_blk);
+ return 0;
+}
+
+static int f2fs_create_root_dir(void)
+{
+ int err = 0;
+
+ err = f2fs_write_root_inode();
+ if (err < 0) {
+ MSG(1, "\tError: Failed to write root inode!!!\n");
+ goto exit;
+ }
+
+ err = f2fs_update_nat_root();
+ if (err < 0) {
+ MSG(1, "\tError: Failed to update NAT for root!!!\n");
+ goto exit;
+ }
+
+ err = f2fs_add_default_dentry_root();
+ if (err < 0) {
+ MSG(1, "\tError: Failed to add default dentries for root!!!\n");
+ goto exit;
+ }
+exit:
+ if (err)
+ MSG(1, "\tError: Could not create the root directory!!!\n");
+
+ return err;
+}
+
+int f2fs_format_device(void)
+{
+ int err = 0;
+
+ err= f2fs_prepare_super_block();
+ if (err < 0) {
+ MSG(0, "\tError: Failed to prepare a super block!!!\n");
+ goto exit;
+ }
+
+ err = f2fs_trim_device();
+ if (err < 0) {
+ MSG(0, "\tError: Failed to trim whole device!!!\n");
+ goto exit;
+ }
+
+ err = f2fs_init_sit_area();
+ if (err < 0) {
+ MSG(0, "\tError: Failed to Initialise the SIT AREA!!!\n");
+ goto exit;
+ }
+
+ err = f2fs_init_nat_area();
+ if (err < 0) {
+ MSG(0, "\tError: Failed to Initialise the NAT AREA!!!\n");
+ goto exit;
+ }
+
+ err = f2fs_create_root_dir();
+ if (err < 0) {
+ MSG(0, "\tError: Failed to create the root directory!!!\n");
+ goto exit;
+ }
+
+ err = f2fs_write_check_point_pack();
+ if (err < 0) {
+ MSG(0, "\tError: Failed to write the check point pack!!!\n");
+ goto exit;
+ }
+
+ err = f2fs_write_super_block();
+ if (err < 0) {
+ MSG(0, "\tError: Failed to write the Super Block!!!\n");
+ goto exit;
+ }
+exit:
+ if (err)
+ MSG(0, "\tError: Could not format the device!!!\n");
+
+ return err;
+}
diff --git a/f2fs-tools/mkfs/f2fs_format_main.c b/f2fs-tools/mkfs/f2fs_format_main.c
new file mode 100644
index 0000000..bba2085
--- /dev/null
+++ b/f2fs-tools/mkfs/f2fs_format_main.c
@@ -0,0 +1,139 @@
+/**
+ * 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>
+#include <uuid/uuid.h>
+
+#include "f2fs_fs.h"
+#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:
+ MSG(0, "\tError: Unknown option %c\n",option);
+ 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=%08"PRIx64" (%s bytes)\n",
+ config.total_sectors, argv[optind+1]);
+ }
+
+ config.reserved_segments =
+ (2 * (100 / config.overprovision + 1) + 6)
+ * config.segs_per_sec;
+ config.segs_per_zone = config.segs_per_sec * config.secs_per_zone;
+}
+
+int 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;
+
+ f2fs_finalize_device(&config);
+
+ MSG(0, "Info: format successful\n");
+
+ return 0;
+}
diff --git a/f2fs-tools/mkfs/f2fs_format_utils.c b/f2fs-tools/mkfs/f2fs_format_utils.c
new file mode 100644
index 0000000..a0f85f5
--- /dev/null
+++ b/f2fs-tools/mkfs/f2fs_format_utils.c
@@ -0,0 +1,68 @@
+/**
+ * f2fs_format_utils.c
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * Dual licensed under the GPL or LGPL version 2 licenses.
+ */
+#define _LARGEFILE_SOURCE
+#define _LARGEFILE64_SOURCE
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include "f2fs_fs.h"
+
+#ifdef HAVE_LINUX_FS_H
+#include <linux/fs.h>
+#endif
+#ifdef HAVE_LINUX_FALLOC_H
+#include <linux/falloc.h>
+#endif
+
+int f2fs_trim_device()
+{
+ unsigned long long range[2];
+ struct stat stat_buf;
+
+ if (!config.trim)
+ return 0;
+
+ range[0] = 0;
+ range[1] = config.total_sectors * config.sector_size;
+
+ if (fstat(config.fd, &stat_buf) < 0 ) {
+ MSG(1, "\tError: Failed to get the device stat!!!\n");
+ return -1;
+ }
+
+#if defined(WITH_BLKDISCARD) && defined(BLKDISCARD)
+ MSG(0, "Info: Discarding device\n");
+ if (S_ISREG(stat_buf.st_mode)) {
+#ifdef FALLOC_FL_PUNCH_HOLE
+ if (fallocate(config.fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
+ range[0], range[1]) < 0) {
+ MSG(0, "Info: fallocate(PUNCH_HOLE|KEEP_SIZE) is failed\n");
+ }
+#endif
+ return 0;
+ } else if (S_ISBLK(stat_buf.st_mode)) {
+ 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/f2fs-tools/mkfs/f2fs_format_utils.h b/f2fs-tools/mkfs/f2fs_format_utils.h
new file mode 100644
index 0000000..9eb2cea
--- /dev/null
+++ b/f2fs-tools/mkfs/f2fs_format_utils.h
@@ -0,0 +1,16 @@
+/**
+ * f2fs_format_utils.c
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * Dual licensed under the GPL or LGPL version 2 licenses.
+ */
+#define _LARGEFILE64_SOURCE
+
+#include "f2fs_fs.h"
+
+extern struct f2fs_configuration config;
+
+int f2fs_trim_device(void);
+int f2fs_format_device(void);
diff --git a/f2fs-tools/scripts/dumpf2fs.sh b/f2fs-tools/scripts/dumpf2fs.sh
new file mode 100755
index 0000000..2c2a273
--- /dev/null
+++ b/f2fs-tools/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/f2fs-tools/scripts/spo_test.sh b/f2fs-tools/scripts/spo_test.sh
new file mode 100755
index 0000000..2191214
--- /dev/null
+++ b/f2fs-tools/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/f2fs-tools/scripts/tracepoint.sh b/f2fs-tools/scripts/tracepoint.sh
new file mode 100755
index 0000000..15588d7
--- /dev/null
+++ b/f2fs-tools/scripts/tracepoint.sh
@@ -0,0 +1,71 @@
+#!/system/bin/sh
+
+TRACE=/sys/kernel/debug/tracing/
+dev=$(((8<<20) + 17)) # sdb1 (8,17)
+
+echo 1 > $TRACE/tracing_on
+
+# mmc tracepoints
+echo 0 > $TRACE/events/mmc/enable
+
+# 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_write_begin/enable
+echo $W > $TRACE/events/f2fs/f2fs_write_end/enable
+
+echo 0 > $TRACE/events/f2fs/f2fs_submit_page_bio/enable
+echo 0 > $TRACE/events/f2fs/f2fs_submit_page_mbio/enable
+echo $R > $TRACE/events/f2fs/f2fs_submit_read_bio/enable
+echo $W > $TRACE/events/f2fs/f2fs_submit_write_bio/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/f2fs-tools/tools/Makefile.am b/f2fs-tools/tools/Makefile.am
new file mode 100644
index 0000000..69a0bb1
--- /dev/null
+++ b/f2fs-tools/tools/Makefile.am
@@ -0,0 +1,8 @@
+## Makefile.am
+
+AM_CPPFLAGS = ${libuuid_CFLAGS} -I$(top_srcdir)/include
+AM_CFLAGS = -Wall
+sbin_PROGRAMS = f2fstat fibmap.f2fs parse.f2fs
+f2fstat_SOURCES = f2fstat.c
+fibmap_f2fs_SOURCES = fibmap.c
+parse_f2fs_SOURCES = f2fs_io_parse.c
diff --git a/f2fs-tools/tools/f2fs_io_parse.c b/f2fs-tools/tools/f2fs_io_parse.c
new file mode 100644
index 0000000..7f97270
--- /dev/null
+++ b/f2fs-tools/tools/f2fs_io_parse.c
@@ -0,0 +1,322 @@
+/*
+ * f2fs IO tracer
+ *
+ * Copyright (c) 2014 Motorola Mobility
+ * Copyright (c) 2014 Jaegeuk Kim <jaegeuk@kernel.org>
+ *
+ * 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.
+ */
+#define _LARGEFILE64_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/queue.h>
+#include <assert.h>
+#include <locale.h>
+
+#define P_NAMELEN 16
+
+/* For global trace methods */
+enum show_type {
+ SHOW_PID,
+ SHOW_FTYPE,
+ SHOW_ALL,
+};
+
+enum trace_types {
+ TP_PID,
+ TP_IOS,
+ TP_MAX,
+};
+
+struct tps {
+ enum trace_types type;
+ const char *name;
+};
+
+struct tps trace_points[] = {
+ { TP_PID, "f2fs_trace_pid" },
+ { TP_IOS, "f2fs_trace_ios" },
+};
+
+/* For f2fs_trace_pid and f2fs_trace_ios */
+enum rw_type {
+ READ,
+ WRITE,
+ MAX_RW,
+};
+
+enum file_type {
+ __NORMAL_FILE,
+ __DIR_FILE,
+ __NODE_FILE,
+ __META_FILE,
+ __ATOMIC_FILE,
+ __VOLATILE_FILE,
+ __MISC_FILE,
+ __NR_FILES,
+};
+
+char *file_type_string[] = {
+ "User ",
+ "Dir ",
+ "Node ",
+ "Meta ",
+ "Atomic ",
+ "Voltile ",
+ "Misc ",
+};
+
+struct pid_ent {
+ int pid;
+ char name[P_NAMELEN];
+ unsigned long long io[__NR_FILES][MAX_RW];
+ unsigned long long total_io[MAX_RW];
+ LIST_ENTRY(pid_ent) ptr;
+};
+
+/* global variables */
+int major = 0, minor = 0;
+int show_option = SHOW_ALL;
+unsigned long long total_io[__NR_FILES][MAX_RW];
+
+LIST_HEAD(plist, pid_ent) pid_info;
+
+/* Functions */
+static inline int atoh(char *str)
+{
+ int val;
+ sscanf(str, "%x", &val);
+ return val;
+}
+
+static void do_init()
+{
+ struct pid_ent *misc;
+
+ misc = calloc(1, sizeof(struct pid_ent));
+ assert(misc);
+
+ LIST_INIT(&pid_info);
+ LIST_INSERT_HEAD(&pid_info, misc, ptr);
+}
+
+void show_usage()
+{
+ printf("\nUsage: parse.f2fs [options] log_file\n");
+ printf("[options]:\n");
+ printf(" -a RW sorted by pid & file types\n");
+ printf(" -f RW sorted by file types\n");
+ printf(" -p RW sorted by pid\n");
+ printf(" -m major number\n");
+ printf(" -n minor number\n");
+ exit(1);
+}
+
+static int parse_options(int argc, char *argv[])
+{
+ const char *option_string = "fm:n:p";
+ int option = 0;
+
+ while ((option = getopt(argc, argv, option_string)) != EOF) {
+ switch (option) {
+ case 'f':
+ show_option = SHOW_FTYPE;
+ break;
+ case 'm':
+ major = atoh(optarg);
+ break;
+ case 'n':
+ minor = atoh(optarg);
+ break;
+ case 'p':
+ show_option = SHOW_PID;
+ break;
+ default:
+ printf("\tError: Unknown option %c\n", option);
+ show_usage();
+ break;
+ }
+ }
+ if ((optind + 1) != argc) {
+ printf("\tError: Log file is not specified.\n");
+ show_usage();
+ }
+ return optind;
+}
+
+struct pid_ent *get_pid_entry(int pid)
+{
+ struct pid_ent *entry;
+
+ LIST_FOREACH(entry, &pid_info, ptr) {
+ if (entry->pid == pid)
+ return entry;
+ }
+ return LIST_FIRST(&pid_info);
+}
+
+static void handle_tp_pid(char *ptr)
+{
+ struct pid_ent *pent;
+
+ pent = calloc(1, sizeof(struct pid_ent));
+ assert(pent);
+
+ ptr = strtok(NULL, " ");
+ pent->pid = atoh(ptr);
+
+ ptr = strtok(NULL, " ");
+ strcpy(pent->name, ptr);
+
+ LIST_INSERT_HEAD(&pid_info, pent, ptr);
+}
+
+static void handle_tp_ios(char *ptr)
+{
+ int pid, type, rw, len;
+ struct pid_ent *p;
+
+ ptr = strtok(NULL, " ");
+ pid = atoh(ptr);
+
+ ptr = strtok(NULL, " ");
+ ptr = strtok(NULL, " ");
+ type = atoh(ptr);
+
+ ptr = strtok(NULL, " ");
+ rw = atoh(ptr);
+
+ ptr = strtok(NULL, " ");
+ /* unsigned long long blkaddr = atoh(ptr); */
+
+ ptr = strtok(NULL, " ");
+ len = atoh(ptr);
+
+ /* update per-pid stat */
+ p = get_pid_entry(pid);
+ p->io[type][rw & 0x1] += len;
+ p->total_io[rw & 0x1] += len;
+
+ /* update total stat */
+ total_io[type][rw & 0x1] += len;
+}
+
+static void do_parse(FILE *file)
+{
+ char line[300];
+ char *ptr;
+ int i;
+
+ while (fgets(line, sizeof(line), file) != NULL) {
+ ptr = strtok(line, ":");
+
+ ptr = strtok(NULL, " :");
+
+ for (i = 0; i < TP_MAX; i++) {
+ if (!strcmp(ptr, trace_points[i].name))
+ break;
+ }
+ if (i == TP_MAX)
+ continue;
+ ptr = strtok(NULL, " :");
+ if (major && major != atoh(ptr))
+ continue;
+ ptr = strtok(NULL, " :");
+ if (minor && minor != atoh(ptr))
+ continue;
+
+ switch (i) {
+ case TP_PID:
+ handle_tp_pid(ptr);
+ break;
+ case TP_IOS:
+ handle_tp_ios(ptr);
+ break;
+ }
+ }
+}
+
+static void __print_pid()
+{
+ struct pid_ent *entry;
+ int i;
+
+ setlocale(LC_ALL, "");
+ printf("%8s %16s %17s ||", "PID", "NAME", "R/W in 4KB");
+ for (i = 0; i < __NR_FILES; i++)
+ printf(" %17s |", file_type_string[i]);
+ printf("\n");
+
+ LIST_FOREACH(entry, &pid_info, ptr) {
+ printf("%8x %16s %'8lld %'8lld ||",
+ entry->pid, entry->name,
+ entry->total_io[READ],
+ entry->total_io[WRITE]);
+ for (i = 0; i < __NR_FILES; i++)
+ printf(" %'8lld %'8lld |",
+ entry->io[i][READ],
+ entry->io[i][WRITE]);
+ printf("\n");
+ }
+}
+
+static void __print_ftype()
+{
+ int i;
+
+ setlocale(LC_ALL, "");
+ printf("\n===== Data R/W in 4KB accoring to File types =====\n");
+ for (i = 0; i < __NR_FILES; i++)
+ printf(" %17s |", file_type_string[i]);
+ printf("\n");
+
+ for (i = 0; i < __NR_FILES; i++)
+ printf(" %'8lld %'8lld |",
+ total_io[i][READ],
+ total_io[i][WRITE]);
+ printf("\n");
+}
+
+static void do_print()
+{
+ switch (show_option) {
+ case SHOW_PID:
+ __print_pid();
+ break;
+ case SHOW_FTYPE:
+ __print_ftype();
+ break;
+ case SHOW_ALL:
+ __print_pid();
+ printf("\n\n");
+ __print_ftype();
+ break;
+ }
+}
+
+int main(int argc, char **argv)
+{
+ FILE *file;
+ int opt;
+
+ opt = parse_options(argc, argv);
+
+ file = fopen(argv[opt], "r");
+ if (!file) {
+ perror("open log file");
+ exit(EXIT_FAILURE);
+ }
+
+ do_init();
+
+ do_parse(file);
+
+ do_print();
+
+ fclose(file);
+ return 0;
+}
diff --git a/f2fs-tools/tools/f2fstat.c b/f2fs-tools/tools/f2fstat.c
new file mode 100644
index 0000000..7f485b0
--- /dev/null
+++ b/f2fs-tools/tools/f2fstat.c
@@ -0,0 +1,311 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <libgen.h>
+
+#ifdef DEBUG
+#define dbg(fmt, args...) printf(fmt, __VA_ARGS__);
+#else
+#define dbg(fmt, args...)
+#endif
+
+/*
+ * f2fs status
+ */
+#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;
+//unsigned long inline_inode;
+
+unsigned long free_segs;
+unsigned long valid_segs;
+unsigned long dirty_segs;
+unsigned long prefree_segs;
+
+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, node_kb;
+unsigned long dirty_dents;
+unsigned long dirty_meta, meta_kb;
+unsigned long nat_caches;
+unsigned long dirty_sit;
+
+unsigned long free_nids;
+
+unsigned long ssr_blks;
+unsigned long lfs_blks;
+unsigned long memory_kb;
+
+struct options {
+ int delay;
+ int interval;
+ char partname[32];
+};
+
+struct mm_table {
+ const char *name;
+ unsigned long *val;
+ int flag;
+};
+
+static int compare_mm_table(const void *a, const void *b)
+{
+ dbg("[COMPARE] %s, %s\n", ((struct mm_table *)a)->name, ((struct mm_table *)b)->name);
+ return strcmp(((struct mm_table *)a)->name, ((struct mm_table *)b)->name);
+}
+
+static inline void remove_newline(char **head)
+{
+again:
+ if (**head == '\n') {
+ *head = *head + 1;
+ goto again;
+ }
+}
+
+void f2fstat(struct options *opt)
+{
+ int fd;
+ int ret;
+ char keyname[32];
+ char buf[4096];
+ struct mm_table key = { keyname, NULL };
+ struct mm_table *found;
+ int f2fstat_table_cnt;
+ char *head, *tail;
+ int found_cnt = 0;
+
+ static struct mm_table f2fstat_table[] = {
+ { " - 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);
+
+ fd = open(F2FS_STATUS, O_RDONLY);
+ if (fd < 0) {
+ perror("open " F2FS_STATUS);
+ exit(EXIT_FAILURE);
+ }
+
+ ret = read(fd, buf, 4096);
+ if (ret < 0) {
+ perror("read " F2FS_STATUS);
+ exit(EXIT_FAILURE);
+ }
+ buf[ret] = '\0';
+
+ head = buf;
+
+ if (opt->partname[0] != '\0') {
+ head = strstr(buf, opt->partname);
+ if (head == NULL)
+ exit(EXIT_FAILURE);
+ }
+
+ for (;;) {
+ remove_newline(&head);
+ tail = strchr(head, ':');
+ if (!tail)
+ break;
+ *tail = '\0';
+ if (strlen(head) >= sizeof(keyname)) {
+ dbg("[OVER] %s\n", head);
+ *tail = ':';
+ tail = strchr(head, '\n');
+ head = tail + 1;
+ continue;
+ }
+
+ strcpy(keyname, head);
+
+ found = bsearch(&key, f2fstat_table, f2fstat_table_cnt, sizeof(struct mm_table), compare_mm_table);
+ dbg("[RESULT] %s (%s)\n", head, (found) ? "O" : "X");
+ head = tail + 1;
+ if (!found)
+ 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:
+ tail = strchr(head, '\n');
+ if (!tail)
+ break;
+ head = tail + 1;
+ }
+
+ close(fd);
+}
+
+void usage(void)
+{
+ printf("Usage: f2fstat [option]\n"
+ " -d delay (secs)\n"
+ " -i interval of head info\n"
+ " -p partition name (e.g. /dev/sda3)\n");
+ exit(EXIT_FAILURE);
+}
+
+void parse_option(int argc, char *argv[], struct options *opt)
+{
+ int option;
+ const char *option_string = "d:i:p:h";
+
+ while ((option = getopt(argc, argv, option_string)) != EOF) {
+ switch (option) {
+ case 'd':
+ opt->delay = atoi(optarg);
+ break;
+ case 'i':
+ opt->interval = atoi(optarg);
+ break;
+ case 'p':
+ strcpy(opt->partname, basename(optarg));
+ break;
+ default:
+ usage();
+ break;
+ }
+ }
+}
+
+void __make_head(char *head, int index, int i, int len)
+{
+ char name_h[5][20] = {"main segments", "page/slab caches", "cp/gc", "blks", "memory"};
+ int half = (len - strlen(name_h[i])) / 2;
+
+ *(head + index) = '|';
+ index++;
+ memset(head + index, '-', half);
+ index += half;
+ strcpy(head + index, name_h[i]);
+ index += strlen(name_h[i]);
+ memset(head + index, '-', half);
+}
+
+void print_head(char *res)
+{
+ char *ptr, *ptr_buf;
+ char buf[1024], head[1024];
+ char name[20][10] = {"util", "node", "data", "free", "valid", "dirty", "prefree", "node", "dent", "meta",
+ "sit", "nat", "fnid", "cp", "gc", "ssr", "lfs", "total", "node", "meta"};
+ int i, len, prev_index = 0;
+
+ ptr_buf = buf;
+ memset(buf, ' ', 1024);
+ memset(head, ' ', 1024);
+
+ for (i = 0; i < 20; i++) {
+ ptr = (i == 0) ? strtok(res, " ") : strtok(NULL, " ");
+ strncpy(ptr_buf, name[i], strlen(name[i]));
+ if (i == 1) {
+ prev_index = ptr_buf - buf - 1;
+ } else if (i == 7) {
+ len = (ptr_buf - buf) - 1 - prev_index;
+ __make_head(head, prev_index, 0, len);
+ prev_index = ptr_buf - buf - 1;
+ } else if (i == 13) {
+ len = (ptr_buf - buf) - 1 - prev_index;
+ __make_head(head, prev_index, 1, len);
+ prev_index = ptr_buf - buf - 1;
+ } else if (i == 15) {
+ len = (ptr_buf - buf) - 1 - prev_index;
+ __make_head(head, prev_index, 2, len);
+ prev_index = ptr_buf - buf - 1;
+ } else if (i == 17) {
+ len = (ptr_buf - buf) - 1 - prev_index;
+ __make_head(head, prev_index, 3, len);
+ prev_index = ptr_buf - buf - 1;
+ }
+
+ len = strlen(ptr);
+ ptr_buf += (len > strlen(name[i]) ? len : strlen(name[i])) + 1;
+ }
+
+ len = (ptr_buf - buf) - 1 - prev_index;
+ __make_head(head, prev_index, 4, len);
+
+ *ptr_buf = 0;
+ *(head + (ptr_buf - buf - 1)) = '|';
+ *(head + (ptr_buf - buf)) = 0;
+ fprintf(stderr, "%s\n%s\n", head, buf);
+}
+
+int main(int argc, char *argv[])
+{
+ char format[] = "%4ld %4ld %4ld %4ld %5ld %5ld %7ld %4ld %4ld %4ld %3ld %3ld %4ld %2ld %2ld %3ld %3ld %5ld %4ld %4ld";
+ char buf[1024], tmp[1024];
+ int head_interval;
+ struct options opt = {
+ .delay = 1,
+ .interval = 20,
+ .partname = { 0, },
+ };
+
+ parse_option(argc, argv, &opt);
+ head_interval = opt.interval;
+
+ while (1) {
+ memset(buf, 0, 1024);
+ f2fstat(&opt);
+ sprintf(buf, 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);
+
+ strcpy(tmp, buf);
+ if (head_interval == opt.interval)
+ print_head(tmp);
+ if (head_interval-- == 0)
+ head_interval = opt.interval;
+
+ fprintf(stderr, "%s\n", buf);
+
+ sleep(opt.delay);
+ }
+
+ return 0;
+}
diff --git a/f2fs-tools/tools/fibmap.c b/f2fs-tools/tools/fibmap.c
new file mode 100644
index 0000000..224b233
--- /dev/null
+++ b/f2fs-tools/tools/fibmap.c
@@ -0,0 +1,165 @@
+#define _LARGEFILE64_SOURCE
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <libgen.h>
+#include <linux/hdreg.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <inttypes.h>
+
+struct file_ext {
+ __u32 f_pos;
+ __u32 start_blk;
+ __u32 end_blk;
+ __u32 blk_count;
+};
+
+void print_ext(struct file_ext *ext)
+{
+ if (ext->end_blk == 0)
+ printf("%8d %8d %8d %8d\n", ext->f_pos, 0, 0, ext->blk_count);
+ else
+ printf("%8d %8d %8d %8d\n", ext->f_pos, ext->start_blk,
+ ext->end_blk, ext->blk_count);
+}
+
+void print_stat(struct stat64 *st)
+{
+ printf("--------------------------------------------\n");
+ printf("dev [%d:%d]\n", major(st->st_dev), minor(st->st_dev));
+ printf("ino [0x%8"PRIx64" : %"PRIu64"]\n",
+ st->st_ino, st->st_ino);
+ printf("mode [0x%8x : %d]\n", st->st_mode, st->st_mode);
+ 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%8"PRIx64" : %"PRIu64"]\n",
+ st->st_size, st->st_size);
+ printf("blksize [0x%8lx : %ld]\n", st->st_blksize, st->st_blksize);
+ printf("blocks [0x%8"PRIx64" : %"PRIu64"]\n",
+ st->st_blocks, st->st_blocks);
+ printf("--------------------------------------------\n\n");
+}
+
+void stat_bdev(struct stat64 *st, unsigned int *start_lba)
+{
+ struct stat bdev_stat;
+ struct hd_geometry geom;
+ char devname[32] = { 0, };
+ char linkname[32] = { 0, };
+ int fd;
+
+ sprintf(devname, "/dev/block/%d:%d", major(st->st_dev), minor(st->st_dev));
+
+ fd = open(devname, O_RDONLY);
+ if (fd < 0)
+ return;
+
+ if (fstat(fd, &bdev_stat) < 0)
+ goto out;
+
+ if (S_ISBLK(bdev_stat.st_mode)) {
+ if (ioctl(fd, HDIO_GETGEO, &geom) < 0)
+ *start_lba = 0;
+ else
+ *start_lba = geom.start;
+ }
+
+ if (readlink(devname, linkname, sizeof(linkname)) < 0)
+ goto out;
+
+ printf("----------------bdev info-------------------\n");
+ printf("devname = %s\n", basename(linkname));
+ printf("start_lba = %u\n", *start_lba);
+
+out:
+ close(fd);
+
+}
+
+int main(int argc, char *argv[])
+{
+ int fd;
+ int ret = 0;
+ char *filename;
+ struct stat64 st;
+ int total_blks;
+ unsigned int i;
+ struct file_ext ext;
+ __u32 start_lba;
+ __u32 blknum;
+
+ if (argc != 2) {
+ fprintf(stderr, "No filename\n");
+ exit(-1);
+ }
+ filename = argv[1];
+
+ fd = open(filename, O_RDONLY|O_LARGEFILE);
+ if (fd < 0) {
+ ret = errno;
+ perror(filename);
+ exit(-1);
+ }
+
+ fsync(fd);
+
+ if (fstat64(fd, &st) < 0) {
+ ret = errno;
+ perror(filename);
+ goto out;
+ }
+
+ stat_bdev(&st, &start_lba);
+
+ total_blks = (st.st_size + st.st_blksize - 1) / st.st_blksize;
+
+ printf("\n----------------file info-------------------\n");
+ printf("%s :\n", filename);
+ print_stat(&st);
+ printf("file_pos start_blk end_blk blks\n");
+
+ blknum = 0;
+ if (ioctl(fd, FIBMAP, &blknum) < 0) {
+ ret = errno;
+ perror("ioctl(FIBMAP)");
+ goto out;
+ }
+ ext.f_pos = 0;
+ ext.start_blk = blknum;
+ ext.end_blk = blknum;
+ ext.blk_count = 1;
+
+ for (i = 1; i < total_blks; i++) {
+ blknum = i;
+
+ if (ioctl(fd, FIBMAP, &blknum) < 0) {
+ ret = errno;
+ perror("ioctl(FIBMAP)");
+ goto out;
+ }
+
+ if ((blknum == 0 && blknum == ext.end_blk) || (ext.end_blk + 1) == blknum) {
+ ext.end_blk = blknum;
+ ext.blk_count++;
+ } else {
+ print_ext(&ext);
+ ext.f_pos = i * st.st_blksize;
+ ext.start_blk = blknum;
+ ext.end_blk = blknum;
+ ext.blk_count = 1;
+ }
+ }
+
+ print_ext(&ext);
+out:
+ close(fd);
+ return ret;
+}