summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDimitri John Ledkov <xnox@ubuntu.com>2016-09-08 12:29:10 +0100
committerDimitri John Ledkov <xnox@ubuntu.com>2016-09-08 12:29:10 +0100
commit249a3592d5dfdec0e52b5e9e712339364ea758ed (patch)
tree54a81f37cfdccbb5ba1d3c925e6fd9261311550e
parentca0dc13dd212ef8ca19fa6128115fe933b055437 (diff)
New upstream release. (Closes: #836778)debian/4.7.2-1
-rw-r--r--CHANGES14
-rw-r--r--Documentation/btrfs-man5.asciidoc92
-rw-r--r--Documentation/btrfstune.asciidoc24
-rw-r--r--Documentation/mkfs.btrfs.asciidoc13
-rw-r--r--Makefile.in5
-rw-r--r--btrfs-corrupt-block.c44
-rw-r--r--btrfs-image.c36
-rw-r--r--btrfs-map-logical.c10
-rw-r--r--btrfs-select-super.c4
-rw-r--r--btrfs-zero-log.c2
-rw-r--r--btrfstune.c16
-rw-r--r--cmds-check.c448
-rw-r--r--cmds-inspect-dump-super.c28
-rwxr-xr-xconfigure26
-rw-r--r--configure.ac8
-rw-r--r--debian/changelog6
-rw-r--r--disk-io.c18
-rw-r--r--print-tree.c145
-rw-r--r--print-tree.h2
-rw-r--r--super-recover.c2
-rw-r--r--tests/README.md11
-rw-r--r--tests/fuzz-tests/images/bko-153641-unaligned-tree-block-bytenr.raw.txt33
-rw-r--r--tests/fuzz-tests/images/bko-153641-unaligned-tree-block-bytenr.raw.xzbin0 -> 3852 bytes
-rw-r--r--tests/fuzz-tests/images/bko-154021-invalid-drop-level.raw.txt30
-rw-r--r--tests/fuzz-tests/images/bko-154021-invalid-drop-level.raw.xzbin0 -> 3788 bytes
-rw-r--r--tests/fuzz-tests/images/bko-154961-heap-overflow-chunk-items.raw.txt21
-rw-r--r--tests/fuzz-tests/images/bko-154961-heap-overflow-chunk-items.raw.xzbin0 -> 3692 bytes
-rw-r--r--tests/fuzz-tests/images/bko-155181-unaligned-extent-item.raw.txt8
-rw-r--r--tests/fuzz-tests/images/bko-155181-unaligned-extent-item.raw.xzbin0 -> 3684 bytes
-rw-r--r--tests/fuzz-tests/images/bko-155201-wrong-chunk-item-in-root-tree.raw.txt35
-rw-r--r--tests/fuzz-tests/images/bko-155201-wrong-chunk-item-in-root-tree.raw.xzbin0 -> 3696 bytes
-rw-r--r--tests/fuzz-tests/images/bko-97021-invalid-chunk-sectorsize.raw.txt41
-rw-r--r--tests/fuzz-tests/images/bko-97021-invalid-chunk-sectorsize.raw.xzbin0 -> 6472 bytes
-rw-r--r--tests/fuzz-tests/images/bko-97031-invalid-stripe-len-sys-array.raw.txt58
-rw-r--r--tests/fuzz-tests/images/bko-97031-invalid-stripe-len-sys-array.raw.xzbin0 -> 7128 bytes
-rw-r--r--tests/fuzz-tests/images/bko-97041-invalid-sub-stripes-zero-FPE.raw.txt50
-rw-r--r--tests/fuzz-tests/images/bko-97041-invalid-sub-stripes-zero-FPE.raw.xzbin0 -> 6476 bytes
-rwxr-xr-xtests/misc-tests/015-dump-super-garbage/test.sh17
-rwxr-xr-xversion.sh2
-rw-r--r--volumes.c8
-rw-r--r--volumes.h4
41 files changed, 898 insertions, 363 deletions
diff --git a/CHANGES b/CHANGES
index c19ed2c5..03168517 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,17 @@
+btrfs-progs-4.7.2 (2016-09-05)
+ * check:
+ * urgent fix: false report of backref mismatches; do not --repair
+ last unaffected version 4.6.1 (code reverted to that state)
+ * fuzzing and fixes
+ * added more sanity checks for various structures
+ * testing images added
+ * build: udev compatibility: do not install .rules on version < 190
+ * other:
+ * dump-super: do not crash on garbage value in csum_type
+ * minor improvements in messages and help strings
+ * documentation:
+ * filesystem features
+
btrfs-progs-4.7.1 (2016-08-25)
* check:
* new optional mode: optimized for low memory usage (memory/io tradeoff)
diff --git a/Documentation/btrfs-man5.asciidoc b/Documentation/btrfs-man5.asciidoc
index 467f11bf..a1f364e0 100644
--- a/Documentation/btrfs-man5.asciidoc
+++ b/Documentation/btrfs-man5.asciidoc
@@ -12,9 +12,12 @@ tools. Currently covers:
1. mount options
-2. file attributes
+2. filesystem features
+
+3. file attributes
+
+4. control device
-3. control device
MOUNT OPTIONS
-------------
@@ -406,6 +409,91 @@ NOTE: This option has replaced 'recovery'.
Allow subvolumes to be deleted by their respective owner. Otherwise, only the
root user can do that.
+FILESYSTEM FEATURES
+-------------------
+
+The basic set of filesystem features gets extended over time. The backward
+compatibility is maintained and the features are optional, need to be
+explicitly asked for so accidental use will not create incompatibilities.
+
+There are several classes and the respective tools to manage the features:
+
+at mkfs time only::
+This is namely for core structures, like the b-tree nodesize, see
+`mkfs.btrfs`(8) for more details.
+
+after mkfs, on an unmounted filesystem::
+Features that may optimize internal structures or add new structures to support
+new functionality, see `btrfstune`(8). The command *btrfs inspect-internal
+dump-super device* will dump a superblock, you can map the value of
+'incompat_flags' to the features listed below
+
+after mkfs, on a mounted filesystem::
+The features of a filesystem (with a given UUID) are listed in
+`/sys/fs/btrfs/UUID/features/`, one file per feature. The status of is stored
+insid the file. The value '1' is for enabled, '0' means the feature was had
+been enabled at the mount time and turned off afterwards.
++
+Whether a particular feature can be turned on a mounted filesystem can be found
+in the directory `/sys/fs/btrfs/features/`, one file per feature. The value '1'
+means the feature can be enabled.
+
+List of features (see also `mkfs.btrfs`(8) section 'FILESYSTEM FEATURES'):
+
+big_metadata::
+(since: 3.4)
++
+the filesystem uses 'nodesize' bigger than the page size
+compress_lzo::
+(since: 2.6.38)
++
+the 'lzo' compression has been used on the filesystem, either as a mount option
+or via *btrfs filesystem defrag*.
+
+default_subvol::
+(since: 2.6.34)
++
+the default subvolume has been set on the filesystem
+
+extended_iref::
+(since: 3.7)
++
+increased hardlink limit per file in a directory to 65536, older kernels
+supported a varying number of hardlinks depending on the sum of all file name
+sizes that can be stored into one metadata block
+
+mixed_backref::
+(since: 2.6.31)
++
+the last major disk format change, improved backreferences
+
+mixed_groups::
+(since: 2.6.37)
++
+mixed data and metadata block groups, ie. the data and metadata are not
+separated and occupy the same block groups, this mode is suitable for small
+volumes as there are no constraints how the remaining space should be used
+(compared to the split mode, where empty metadata space cannot be used for data
+and vice versa)
++
+on the other hand, the final layout is quite unpredictable and possibly highly
+fragmented, which means worse performance
+
+no_holes::
+(since: 3.14)
+improved representation of file extents where holes are not explicitly
+stored as an extent, saves a few percent of metadata if sparse files are used
+
+raid56::
+(since: 3.9)
++
+the filesystem contains or contained a raid56 profile of block groups
++
+skinny_metadata::
+(since: 3.10)
++
+reduced-size metadata for extent references, saves a few percent of metadata
+
FILE ATTRIBUTES
---------------
The btrfs filesystem supports setting the following file attributes using the
diff --git a/Documentation/btrfstune.asciidoc b/Documentation/btrfstune.asciidoc
index 68fec4c9..1e9aa703 100644
--- a/Documentation/btrfstune.asciidoc
+++ b/Documentation/btrfstune.asciidoc
@@ -17,7 +17,11 @@ parameters. The filesystem must be unmounted.
The common usecase is to enable features that were not enabled at mkfs time.
Please make sure that you have kernel support for the features. You can find a
complete list of features and kernel version of their introduction at
-https://btrfs.wiki.kernel.org/index.php/Changelog#By_feature .
+https://btrfs.wiki.kernel.org/index.php/Changelog#By_feature . Also, the
+manual page `mkfs.btrfs`(8) contains more details about the features.
+
+Some of the features could be enabled on a mounted filesytem. Please refer to
+the respective section in `btrfs`(5).
OPTIONS
-------
@@ -26,14 +30,24 @@ Enable seeding on a given device. Value 1 will enable seeding, 0 will disable it
A seeding filesystem is forced to be mounted read-only. A new device can be added
to the filesystem and will capture all writes keeping the seeding device intact.
-r::
+(since kernel: 3.7)
++
Enable extended inode refs (hardlink limit per file in a directory is 65536),
-enabled by mkfs feature 'extref'. Since kernel 3.7.
+enabled by mkfs feature 'extref'.
-x::
+(since kernel: 3.10)
++
Enable skinny metadata extent refs (more efficient representation of extents),
-enabled by mkfs feature 'skinny-metadata'. Since kernel 3.10.
+enabled by mkfs feature 'skinny-metadata'.
++
+All newly created extents will use the new representation. To completely switch
+the entire filesystem, run a full balance of the metadata. Please refer to
+`btrfs-balance`(8).
-n::
+(since kernel: 3.14)
++
Enable no-holes feature (more efficient representation of file holes), enabled
-by mkfs feature 'no-holes'. Since kernel 3.14.
+by mkfs feature 'no-holes'.
-f::
Allow dangerous changes, e.g. clear the seeding flag or change fsid. Make sure
that you are aware of the dangers.
@@ -72,4 +86,6 @@ will become deprecated and removed afterwards.
SEE ALSO
--------
+`btrfs`(5),
+`btrfs-balance`(8),
`mkfs.btrfs`(8)
diff --git a/Documentation/mkfs.btrfs.asciidoc b/Documentation/mkfs.btrfs.asciidoc
index 5d79e24f..98fe694b 100644
--- a/Documentation/mkfs.btrfs.asciidoc
+++ b/Documentation/mkfs.btrfs.asciidoc
@@ -185,7 +185,12 @@ initramfs/initrd systems.
FILESYSTEM FEATURES
-------------------
+Features that can be enabled during creation time. See also `btrfs`(5) section
+'FILESYSTEM FEATURES'.
+
*mixed-bg*::
+(kernel support since 2.6.37)
++
mixed data and metadata block groups, also set by option '--mixed'
*extref*::
@@ -196,6 +201,8 @@ supported a varying number of hardlinks depending on the sum of all file name
sizes that can be stored into one metadata block
*raid56*::
+(kernel support since 3.9)
++
extended format for RAID5/6, also enabled if raid5 or raid6 block groups
are selected
@@ -205,6 +212,8 @@ are selected
reduced-size metadata for extent references, saves a few percent of metadata
*no-holes*::
+(kernel support since 3.14)
++
improved representation of file extents where holes are not explicitly
stored as an extent, saves a few percent of metadata if sparse files are used
@@ -351,4 +360,6 @@ further details.
SEE ALSO
--------
-`btrfs`(8), `wipefs`(8)
+`btrfs`(5),
+`btrfs`(8),
+`wipefs`(8)
diff --git a/Makefile.in b/Makefile.in
index 5c0c0d06..fd68b3ee 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -17,6 +17,7 @@
# trace - print trace before the error/warning messages
# abort - call abort() on first error (dumps core)
# all - shortcut for all of the above
+# asan - enable address sanitizer compiler feature
# W=123 build with warnings (default: off)
# DEBUG_CFLAGS additional compiler flags for debugging build
# EXTRA_CFLAGS additional compiler flags
@@ -145,6 +146,10 @@ ifneq (,$(findstring all,$(D)))
DEBUG_CFLAGS_INTERNAL += -DDEBUG_ABORT_ON_ERROR=1
endif
+ifneq (,$(findstring asan,$(D)))
+ DEBUG_CFLAGS_INTERNAL += -fsanitize=address
+endif
+
MAKEOPTS = --no-print-directory Q=$(Q)
# build all by default
diff --git a/btrfs-corrupt-block.c b/btrfs-corrupt-block.c
index a488e479..789cbc70 100644
--- a/btrfs-corrupt-block.c
+++ b/btrfs-corrupt-block.c
@@ -103,32 +103,24 @@ static int debug_corrupt_block(struct extent_buffer *eb,
static void print_usage(int ret)
{
- fprintf(stderr, "usage: btrfs-corrupt-block [options] device\n");
- fprintf(stderr, "\t-l Logical extent to be corrupted\n");
- fprintf(stderr, "\t-c Copy of the extent to be corrupted"
- " (usually 1 or 2, default: 0)\n");
- fprintf(stderr, "\t-b Number of bytes to be corrupted\n");
- fprintf(stderr, "\t-e Extent to be corrupted\n");
- fprintf(stderr, "\t-E The whole extent tree to be corrupted\n");
- fprintf(stderr, "\t-u Given chunk item to be corrupted\n");
- fprintf(stderr, "\t-U The whole chunk tree to be corrupted\n");
- fprintf(stderr, "\t-i The inode item to corrupt (must also specify "
- "the field to corrupt)\n");
- fprintf(stderr, "\t-x The file extent item to corrupt (must also "
- "specify -i for the inode and -f for the field to corrupt)\n");
- fprintf(stderr, "\t-m The metadata block to corrupt (must also "
- "specify -f for the field to corrupt)\n");
- fprintf(stderr, "\t-K The key to corrupt in the format "
- "<num>,<num>,<num> (must also specify -f for the field)\n");
- fprintf(stderr, "\t-f The field in the item to corrupt\n");
- fprintf(stderr, "\t-I An item to corrupt (must also specify the field "
- "to corrupt and a root+key for the item)\n");
- fprintf(stderr, "\t-D Corrupt a dir item, must specify key and field\n");
- fprintf(stderr, "\t-d Delete this item (must specify -K)\n");
- fprintf(stderr, "\t-r Operate on this root (only works with -d)\n");
- fprintf(stderr, "\t-C Delete a csum for the specified bytenr. When "
- "used with -b it'll delete that many bytes, otherwise it's "
- "just sectorsize\n");
+ printf("usage: btrfs-corrupt-block [options] device\n");
+ printf("\t-l Logical extent to be corrupted\n");
+ printf("\t-c Copy of the extent to be corrupted (usually 1 or 2, default: 0)\n");
+ printf("\t-b Number of bytes to be corrupted\n");
+ printf("\t-e Extent to be corrupted\n");
+ printf("\t-E The whole extent tree to be corrupted\n");
+ printf("\t-u Given chunk item to be corrupted\n");
+ printf("\t-U The whole chunk tree to be corrupted\n");
+ printf("\t-i The inode item to corrupt (must also specify the field to corrupt)\n");
+ printf("\t-x The file extent item to corrupt (must also specify -i for the inode and -f for the field to corrupt)\n");
+ printf("\t-m The metadata block to corrupt (must also specify -f for the field to corrupt)\n");
+ printf("\t-K The key to corrupt in the format <num>,<num>,<num> (must also specify -f for the field)\n");
+ printf("\t-f The field in the item to corrupt\n");
+ printf("\t-I An item to corrupt (must also specify the field to corrupt and a root+key for the item)\n");
+ printf("\t-D Corrupt a dir item, must specify key and field\n");
+ printf("\t-d Delete this item (must specify -K)\n");
+ printf("\t-r Operate on this root (only works with -d)\n");
+ printf("\t-C Delete a csum for the specified bytenr. When used with -b it'll delete that many bytes, otherwise it's just sectorsize\n");
exit(ret);
}
diff --git a/btrfs-image.c b/btrfs-image.c
index af5437b4..953d368d 100644
--- a/btrfs-image.c
+++ b/btrfs-image.c
@@ -2716,17 +2716,17 @@ out:
static void print_usage(int ret)
{
- fprintf(stderr, "usage: btrfs-image [options] source target\n");
- fprintf(stderr, "\t-r \trestore metadump image\n");
- fprintf(stderr, "\t-c value\tcompression level (0 ~ 9)\n");
- fprintf(stderr, "\t-t value\tnumber of threads (1 ~ 32)\n");
- fprintf(stderr, "\t-o \tdon't mess with the chunk tree when restoring\n");
- fprintf(stderr, "\t-s \tsanitize file names, use once to just use garbage, use twice if you want crc collisions\n");
- fprintf(stderr, "\t-w \twalk all trees instead of using extent tree, do this if your extent tree is broken\n");
- fprintf(stderr, "\t-m \trestore for multiple devices\n");
- fprintf(stderr, "\n");
- fprintf(stderr, "\tIn the dump mode, source is the btrfs device and target is the output file (use '-' for stdout).\n");
- fprintf(stderr, "\tIn the restore mode, source is the dumped image and target is the btrfs device/file.\n");
+ printf("usage: btrfs-image [options] source target\n");
+ printf("\t-r \trestore metadump image\n");
+ printf("\t-c value\tcompression level (0 ~ 9)\n");
+ printf("\t-t value\tnumber of threads (1 ~ 32)\n");
+ printf("\t-o \tdon't mess with the chunk tree when restoring\n");
+ printf("\t-s \tsanitize file names, use once to just use garbage, use twice if you want crc collisions\n");
+ printf("\t-w \twalk all trees instead of using extent tree, do this if your extent tree is broken\n");
+ printf("\t-m \trestore for multiple devices\n");
+ printf("\n");
+ printf("\tIn the dump mode, source is the btrfs device and target is the output file (use '-' for stdout).\n");
+ printf("\tIn the restore mode, source is the dumped image and target is the btrfs device/file.\n");
exit(ret);
}
@@ -2760,13 +2760,19 @@ int main(int argc, char *argv[])
break;
case 't':
num_threads = arg_strtou64(optarg);
- if (num_threads > 32)
- print_usage(1);
+ if (num_threads > 32) {
+ error("number of threads out of range: %llu",
+ (unsigned long long)num_threads);
+ return 1;
+ }
break;
case 'c':
compress_level = arg_strtou64(optarg);
- if (compress_level > 9)
- print_usage(1);
+ if (compress_level > 9) {
+ error("compression level out of range: %llu",
+ (unsigned long long)compress_level);
+ return 1;
+ }
break;
case 'o':
old_restore = 1;
diff --git a/btrfs-map-logical.c b/btrfs-map-logical.c
index f421a50f..f3be1ea8 100644
--- a/btrfs-map-logical.c
+++ b/btrfs-map-logical.c
@@ -193,11 +193,11 @@ static int write_extent_content(struct btrfs_fs_info *fs_info, int out_fd,
static void print_usage(void) __attribute__((noreturn));
static void print_usage(void)
{
- fprintf(stderr, "usage: btrfs-map-logical [options] device\n");
- fprintf(stderr, "\t-l Logical extent to map\n");
- fprintf(stderr, "\t-c Copy of the extent to read (usually 1 or 2)\n");
- fprintf(stderr, "\t-o Output file to hold the extent\n");
- fprintf(stderr, "\t-b Number of bytes to read\n");
+ printf("usage: btrfs-map-logical [options] device\n");
+ printf("\t-l Logical extent to map\n");
+ printf("\t-c Copy of the extent to read (usually 1 or 2)\n");
+ printf("\t-o Output file to hold the extent\n");
+ printf("\t-b Number of bytes to read\n");
exit(1);
}
diff --git a/btrfs-select-super.c b/btrfs-select-super.c
index 4f4ec0b6..7e96dc0b 100644
--- a/btrfs-select-super.c
+++ b/btrfs-select-super.c
@@ -32,8 +32,8 @@
static void print_usage(void)
{
- fprintf(stderr, "usage: btrfs-select-super -s number dev\n");
- fprintf(stderr, "%s\n", PACKAGE_STRING);
+ printf("usage: btrfs-select-super -s number dev\n");
+ printf("\t-s super copy of superbloc to overwrite the primary one (values: 1, 2)\n");
exit(1);
}
diff --git a/btrfs-zero-log.c b/btrfs-zero-log.c
index f5ca9fcf..44293998 100644
--- a/btrfs-zero-log.c
+++ b/btrfs-zero-log.c
@@ -27,7 +27,7 @@
__attribute__((noreturn)) static void print_usage(void)
{
- fprintf(stderr, "usage: btrfs-zero-log dev\n");
+ printf("usage: btrfs-zero-log dev\n");
exit(1);
}
diff --git a/btrfstune.c b/btrfstune.c
index 93b25e8c..b824f2b8 100644
--- a/btrfstune.c
+++ b/btrfstune.c
@@ -376,14 +376,14 @@ out:
static void print_usage(void)
{
- fprintf(stderr, "usage: btrfstune [options] device\n");
- fprintf(stderr, "\t-S value\tpositive value will enable seeding, zero to disable, negative is not allowed\n");
- fprintf(stderr, "\t-r \t\tenable extended inode refs\n");
- fprintf(stderr, "\t-x \t\tenable skinny metadata extent refs\n");
- fprintf(stderr, "\t-n \t\tenable no-holes feature (more efficient sparse file representation)\n");
- fprintf(stderr, "\t-f \t\tforce to do dangerous operation, make sure that you are aware of the dangers\n");
- fprintf(stderr, "\t-u \t\tchange fsid, use a random one\n");
- fprintf(stderr, "\t-U UUID\t\tchange fsid to UUID\n");
+ printf("usage: btrfstune [options] device\n");
+ printf("\t-S value\tpositive value will enable seeding, zero to disable, negative is not allowed\n");
+ printf("\t-r \t\tenable extended inode refs\n");
+ printf("\t-x \t\tenable skinny metadata extent refs\n");
+ printf("\t-n \t\tenable no-holes feature (more efficient sparse file representation)\n");
+ printf("\t-f \t\tforce to do dangerous operation, make sure that you are aware of the dangers\n");
+ printf("\t-u \t\tchange fsid, use a random one\n");
+ printf("\t-U UUID\t\tchange fsid to UUID\n");
}
int main(int argc, char *argv[])
diff --git a/cmds-check.c b/cmds-check.c
index 0ddfd24a..a453696e 100644
--- a/cmds-check.c
+++ b/cmds-check.c
@@ -84,7 +84,7 @@ enum btrfs_check_mode {
static enum btrfs_check_mode check_mode = CHECK_MODE_DEFAULT;
struct extent_backref {
- struct rb_node node;
+ struct list_head list;
unsigned int is_data:1;
unsigned int found_extent_tree:1;
unsigned int full_backref:1;
@@ -92,9 +92,9 @@ struct extent_backref {
unsigned int broken:1;
};
-static inline struct extent_backref* rb_node_to_extent_backref(struct rb_node *node)
+static inline struct extent_backref* to_extent_backref(struct list_head *entry)
{
- return rb_entry(node, struct extent_backref, node);
+ return list_entry(entry, struct extent_backref, list);
}
struct data_backref {
@@ -117,56 +117,6 @@ static inline struct data_backref* to_data_backref(struct extent_backref *back)
return container_of(back, struct data_backref, node);
}
-static int compare_data_backref(struct rb_node *node1, struct rb_node *node2)
-{
- struct extent_backref *ext1 = rb_node_to_extent_backref(node1);
- struct extent_backref *ext2 = rb_node_to_extent_backref(node2);
- struct data_backref *back1 = to_data_backref(ext1);
- struct data_backref *back2 = to_data_backref(ext2);
-
- WARN_ON(!ext1->is_data);
- WARN_ON(!ext2->is_data);
-
- /* parent and root are a union, so this covers both */
- if (back1->parent > back2->parent)
- return 1;
- if (back1->parent < back2->parent)
- return -1;
-
- /* This is a full backref and the parents match. */
- if (back1->node.full_backref)
- return 0;
-
- if (back1->owner > back2->owner)
- return 1;
- if (back1->owner < back2->owner)
- return -1;
-
- if (back1->offset > back2->offset)
- return 1;
- if (back1->offset < back2->offset)
- return -1;
-
- if (back1->bytes > back2->bytes)
- return 1;
- if (back1->bytes < back2->bytes)
- return -1;
-
- if (back1->found_ref && back2->found_ref) {
- if (back1->disk_bytenr > back2->disk_bytenr)
- return 1;
- if (back1->disk_bytenr < back2->disk_bytenr)
- return -1;
-
- if (back1->found_ref > back2->found_ref)
- return 1;
- if (back1->found_ref < back2->found_ref)
- return -1;
- }
-
- return 0;
-}
-
/*
* Much like data_backref, just removed the undetermined members
* and change it to use list_head.
@@ -195,54 +145,12 @@ static inline struct tree_backref* to_tree_backref(struct extent_backref *back)
return container_of(back, struct tree_backref, node);
}
-static int compare_tree_backref(struct rb_node *node1, struct rb_node *node2)
-{
- struct extent_backref *ext1 = rb_node_to_extent_backref(node1);
- struct extent_backref *ext2 = rb_node_to_extent_backref(node2);
- struct tree_backref *back1 = to_tree_backref(ext1);
- struct tree_backref *back2 = to_tree_backref(ext2);
-
- WARN_ON(ext1->is_data);
- WARN_ON(ext2->is_data);
-
- /* parent and root are a union, so this covers both */
- if (back1->parent > back2->parent)
- return 1;
- if (back1->parent < back2->parent)
- return -1;
-
- return 0;
-}
-
-static int compare_extent_backref(struct rb_node *node1, struct rb_node *node2)
-{
- struct extent_backref *ext1 = rb_node_to_extent_backref(node1);
- struct extent_backref *ext2 = rb_node_to_extent_backref(node2);
-
- if (ext1->is_data > ext2->is_data)
- return 1;
-
- if (ext1->is_data < ext2->is_data)
- return -1;
-
- if (ext1->full_backref > ext2->full_backref)
- return 1;
- if (ext1->full_backref < ext2->full_backref)
- return -1;
-
- if (ext1->is_data)
- return compare_data_backref(node1, node2);
- else
- return compare_tree_backref(node1, node2);
-}
-
/* Explicit initialization for extent_record::flag_block_full_backref */
enum { FLAG_UNSET = 2 };
struct extent_record {
struct list_head backrefs;
struct list_head dups;
- struct rb_root backref_tree;
struct list_head list;
struct cache_extent cache;
struct btrfs_disk_key parent_key;
@@ -3742,6 +3650,11 @@ static int check_fs_root(struct btrfs_root *root,
btrfs_disk_key_to_cpu(&key, &root_item->drop_progress);
level = root_item->drop_level;
path.lowest_level = level;
+ if (level > btrfs_header_level(root->node) ||
+ level >= BTRFS_MAX_LEVEL) {
+ error("ignoring invalid drop level: %u", level);
+ goto skip_walking;
+ }
wret = btrfs_search_slot(NULL, root, &key, &path, 0, 0);
if (wret < 0)
goto skip_walking;
@@ -3925,15 +3838,16 @@ out:
static int all_backpointers_checked(struct extent_record *rec, int print_errs)
{
- struct rb_node *n;
+ struct list_head *cur = rec->backrefs.next;
struct extent_backref *back;
struct tree_backref *tback;
struct data_backref *dback;
u64 found = 0;
int err = 0;
- for (n = rb_first(&rec->backref_tree); n; n = rb_next(n)) {
- back = rb_node_to_extent_backref(n);
+ while(cur != &rec->backrefs) {
+ back = to_extent_backref(cur);
+ cur = cur->next;
if (!back->found_extent_tree) {
err = 1;
if (!print_errs)
@@ -4036,16 +3950,17 @@ out:
return err;
}
-static void __free_one_backref(struct rb_node *node)
-{
- struct extent_backref *back = rb_node_to_extent_backref(node);
-
- free(back);
-}
-
-static void free_all_extent_backrefs(struct extent_record *rec)
+static int free_all_extent_backrefs(struct extent_record *rec)
{
- rb_free_nodes(&rec->backref_tree, __free_one_backref);
+ struct extent_backref *back;
+ struct list_head *cur;
+ while (!list_empty(&rec->backrefs)) {
+ cur = rec->backrefs.next;
+ back = to_extent_backref(cur);
+ list_del(cur);
+ free(back);
+ }
+ return 0;
}
static void free_extent_record_cache(struct btrfs_fs_info *fs_info,
@@ -4085,7 +4000,7 @@ static int check_owner_ref(struct btrfs_root *root,
struct extent_record *rec,
struct extent_buffer *buf)
{
- struct extent_backref *node, *tmp;
+ struct extent_backref *node;
struct tree_backref *back;
struct btrfs_root *ref_root;
struct btrfs_key key;
@@ -4095,8 +4010,7 @@ static int check_owner_ref(struct btrfs_root *root,
int found = 0;
int ret;
- rbtree_postorder_for_each_entry_safe(node, tmp,
- &rec->backref_tree, node) {
+ list_for_each_entry(node, &rec->backrefs, list) {
if (node->is_data)
continue;
if (!node->found_ref)
@@ -4141,16 +4055,18 @@ static int check_owner_ref(struct btrfs_root *root,
static int is_extent_tree_record(struct extent_record *rec)
{
- struct extent_backref *ref, *tmp;
+ struct list_head *cur = rec->backrefs.next;
+ struct extent_backref *node;
struct tree_backref *back;
int is_extent = 0;
- rbtree_postorder_for_each_entry_safe(ref, tmp,
- &rec->backref_tree, node) {
- if (ref->is_data)
+ while(cur != &rec->backrefs) {
+ node = to_extent_backref(cur);
+ cur = cur->next;
+ if (node->is_data)
return 0;
- back = to_tree_backref(ref);
- if (ref->full_backref)
+ back = to_tree_backref(node);
+ if (node->full_backref)
return 0;
if (back->root == BTRFS_EXTENT_TREE_OBJECTID)
is_extent = 1;
@@ -4524,31 +4440,32 @@ static int check_block(struct btrfs_root *root,
return ret;
}
-
static struct tree_backref *find_tree_backref(struct extent_record *rec,
u64 parent, u64 root)
{
- struct rb_node *node;
- struct tree_backref *back = NULL;
- struct tree_backref match = {
- .node = {
- .is_data = 0,
- },
- };
+ struct list_head *cur = rec->backrefs.next;
+ struct extent_backref *node;
+ struct tree_backref *back;
- if (parent) {
- match.parent = parent;
- match.node.full_backref = 1;
- } else {
- match.root = root;
+ while(cur != &rec->backrefs) {
+ node = to_extent_backref(cur);
+ cur = cur->next;
+ if (node->is_data)
+ continue;
+ back = to_tree_backref(node);
+ if (parent > 0) {
+ if (!node->full_backref)
+ continue;
+ if (parent == back->parent)
+ return back;
+ } else {
+ if (node->full_backref)
+ continue;
+ if (back->root == root)
+ return back;
+ }
}
-
- node = rb_search(&rec->backref_tree, &match.node.node,
- (rb_compare_keys)compare_extent_backref, NULL);
- if (node)
- back = to_tree_backref(rb_node_to_extent_backref(node));
-
- return back;
+ return NULL;
}
static struct tree_backref *alloc_tree_backref(struct extent_record *rec,
@@ -4566,7 +4483,7 @@ static struct tree_backref *alloc_tree_backref(struct extent_record *rec,
ref->root = root;
ref->node.full_backref = 0;
}
- rb_insert(&rec->backref_tree, &ref->node.node, compare_extent_backref);
+ list_add_tail(&ref->node.list, &rec->backrefs);
return ref;
}
@@ -4577,32 +4494,35 @@ static struct data_backref *find_data_backref(struct extent_record *rec,
int found_ref,
u64 disk_bytenr, u64 bytes)
{
- struct rb_node *node;
- struct data_backref *back = NULL;
- struct data_backref match = {
- .node = {
- .is_data = 1,
- },
- .owner = owner,
- .offset = offset,
- .bytes = bytes,
- .found_ref = found_ref,
- .disk_bytenr = disk_bytenr,
- };
+ struct list_head *cur = rec->backrefs.next;
+ struct extent_backref *node;
+ struct data_backref *back;
- if (parent) {
- match.parent = parent;
- match.node.full_backref = 1;
- } else {
- match.root = root;
+ while(cur != &rec->backrefs) {
+ node = to_extent_backref(cur);
+ cur = cur->next;
+ if (!node->is_data)
+ continue;
+ back = to_data_backref(node);
+ if (parent > 0) {
+ if (!node->full_backref)
+ continue;
+ if (parent == back->parent)
+ return back;
+ } else {
+ if (node->full_backref)
+ continue;
+ if (back->root == root && back->owner == owner &&
+ back->offset == offset) {
+ if (found_ref && node->found_ref &&
+ (back->bytes != bytes ||
+ back->disk_bytenr != disk_bytenr))
+ continue;
+ return back;
+ }
+ }
}
-
- node = rb_search(&rec->backref_tree, &match.node.node,
- (rb_compare_keys)compare_extent_backref, NULL);
- if (node)
- back = to_data_backref(rb_node_to_extent_backref(node));
-
- return back;
+ return NULL;
}
static struct data_backref *alloc_data_backref(struct extent_record *rec,
@@ -4631,7 +4551,7 @@ static struct data_backref *alloc_data_backref(struct extent_record *rec,
ref->bytes = max_size;
ref->found_ref = 0;
ref->num_refs = 0;
- rb_insert(&rec->backref_tree, &ref->node.node, compare_extent_backref);
+ list_add_tail(&ref->node.list, &rec->backrefs);
if (max_size > rec->max_size)
rec->max_size = max_size;
return ref;
@@ -4664,12 +4584,12 @@ static void check_extent_type(struct extent_record *rec)
* Check SYSTEM extent, as it's also marked as metadata, we can only
* make sure it's a SYSTEM extent by its backref
*/
- if (!RB_EMPTY_ROOT(&rec->backref_tree)) {
+ if (!list_empty(&rec->backrefs)) {
struct extent_backref *node;
struct tree_backref *tback;
u64 bg_type;
- node = rb_node_to_extent_backref(rb_first(&rec->backref_tree));
+ node = to_extent_backref(rec->backrefs.next);
if (node->is_data) {
/* tree block shouldn't have data backref */
rec->wrong_chunk_type = 1;
@@ -4719,7 +4639,6 @@ static int add_extent_rec_nolookup(struct cache_tree *extent_cache,
INIT_LIST_HEAD(&rec->backrefs);
INIT_LIST_HEAD(&rec->dups);
INIT_LIST_HEAD(&rec->list);
- rec->backref_tree = RB_ROOT;
memcpy(&rec->parent_key, &tmpl->parent_key, sizeof(tmpl->parent_key));
rec->cache.start = tmpl->start;
rec->cache.size = tmpl->nr;
@@ -4859,20 +4778,25 @@ static int add_tree_backref(struct cache_tree *extent_cache, u64 bytenr,
add_extent_rec_nolookup(extent_cache, &tmpl);
+ /* really a bug in cache_extent implement now */
cache = lookup_cache_extent(extent_cache, bytenr, 1);
if (!cache)
- abort();
+ return -ENOENT;
}
rec = container_of(cache, struct extent_record, cache);
if (rec->start != bytenr) {
- abort();
+ /*
+ * Several cause, from unaligned bytenr to over lapping extents
+ */
+ return -EEXIST;
}
back = find_tree_backref(rec, parent, root);
if (!back) {
back = alloc_tree_backref(rec, parent, root);
- BUG_ON(!back);
+ if (!back)
+ return -ENOMEM;
}
if (found_ref) {
@@ -5149,16 +5073,18 @@ static int process_extent_ref_v0(struct cache_tree *extent_cache,
{
struct btrfs_extent_ref_v0 *ref0;
struct btrfs_key key;
+ int ret;
btrfs_item_key_to_cpu(leaf, &key, slot);
ref0 = btrfs_item_ptr(leaf, slot, struct btrfs_extent_ref_v0);
if (btrfs_ref_objectid_v0(leaf, ref0) < BTRFS_FIRST_FREE_OBJECTID) {
- add_tree_backref(extent_cache, key.objectid, key.offset, 0, 0);
+ ret = add_tree_backref(extent_cache, key.objectid, key.offset,
+ 0, 0);
} else {
- add_data_backref(extent_cache, key.objectid, key.offset, 0,
- 0, 0, btrfs_ref_count_v0(leaf, ref0), 0, 0);
+ ret = add_data_backref(extent_cache, key.objectid, key.offset,
+ 0, 0, 0, btrfs_ref_count_v0(leaf, ref0), 0, 0);
}
- return 0;
+ return ret;
}
#endif
@@ -5220,8 +5146,24 @@ static int process_chunk_item(struct cache_tree *chunk_cache,
int slot)
{
struct chunk_record *rec;
+ struct btrfs_chunk *chunk;
int ret = 0;
+ chunk = btrfs_item_ptr(eb, slot, struct btrfs_chunk);
+ /*
+ * Do extra check for this chunk item,
+ *
+ * It's still possible one can craft a leaf with CHUNK_ITEM, with
+ * wrong onwer(3) out of chunk tree, to pass both chunk tree check
+ * and owner<->key_type check.
+ */
+ ret = btrfs_check_chunk_valid(global_info->tree_root, eb, chunk, slot,
+ key->offset);
+ if (ret < 0) {
+ error("chunk(%llu, %llu) is not valid, ignore it",
+ key->offset, btrfs_chunk_length(eb, chunk));
+ return 0;
+ }
rec = btrfs_new_chunk_record(eb, key, slot);
ret = insert_cache_extent(chunk_cache, &rec->cache);
if (ret) {
@@ -5385,6 +5327,7 @@ static int process_extent_item(struct btrfs_root *root,
struct extent_record tmpl;
unsigned long end;
unsigned long ptr;
+ int ret;
int type;
u32 item_size = btrfs_item_size_nr(eb, slot);
u64 refs = 0;
@@ -5401,6 +5344,11 @@ static int process_extent_item(struct btrfs_root *root,
num_bytes = key.offset;
}
+ if (!IS_ALIGNED(key.objectid, root->sectorsize)) {
+ error("ignoring invalid extent, bytenr %llu is not aligned to %u",
+ key.objectid, root->sectorsize);
+ return -EIO;
+ }
if (item_size < sizeof(*ei)) {
#ifdef BTRFS_COMPAT_EXTENT_TREE_V0
struct btrfs_extent_item_v0 *ei0;
@@ -5427,6 +5375,16 @@ static int process_extent_item(struct btrfs_root *root,
metadata = 1;
else
metadata = 0;
+ if (metadata && num_bytes != root->nodesize) {
+ error("ignore invalid metadata extent, length %llu does not equal to %u",
+ num_bytes, root->nodesize);
+ return -EIO;
+ }
+ if (!metadata && !IS_ALIGNED(num_bytes, root->sectorsize)) {
+ error("ignore invalid data extent, length %llu is not aligned to %u",
+ num_bytes, root->sectorsize);
+ return -EIO;
+ }
memset(&tmpl, 0, sizeof(tmpl));
tmpl.start = key.objectid;
@@ -5449,12 +5407,18 @@ static int process_extent_item(struct btrfs_root *root,
offset = btrfs_extent_inline_ref_offset(eb, iref);
switch (type) {
case BTRFS_TREE_BLOCK_REF_KEY:
- add_tree_backref(extent_cache, key.objectid,
- 0, offset, 0);
+ ret = add_tree_backref(extent_cache, key.objectid,
+ 0, offset, 0);
+ if (ret < 0)
+ error("add_tree_backref failed: %s",
+ strerror(-ret));
break;
case BTRFS_SHARED_BLOCK_REF_KEY:
- add_tree_backref(extent_cache, key.objectid,
- offset, 0, 0);
+ ret = add_tree_backref(extent_cache, key.objectid,
+ offset, 0, 0);
+ if (ret < 0)
+ error("add_tree_backref failed: %s",
+ strerror(-ret));
break;
case BTRFS_EXTENT_DATA_REF_KEY:
dref = (struct btrfs_extent_data_ref *)(&iref->offset);
@@ -6122,6 +6086,58 @@ full_backref:
return 0;
}
+static void report_mismatch_key_root(u8 key_type, u64 rootid)
+{
+ fprintf(stderr, "Invalid key type(");
+ print_key_type(stderr, 0, key_type);
+ fprintf(stderr, ") found in root(");
+ print_objectid(stderr, rootid, 0);
+ fprintf(stderr, ")\n");
+}
+
+/*
+ * Check if the key is valid with its extent buffer.
+ *
+ * This is a early check in case invalid key exists in a extent buffer
+ * This is not comprehensive yet, but should prevent wrong key/item passed
+ * further
+ */
+static int check_type_with_root(u64 rootid, u8 key_type)
+{
+ switch (key_type) {
+ /* Only valid in chunk tree */
+ case BTRFS_DEV_ITEM_KEY:
+ case BTRFS_CHUNK_ITEM_KEY:
+ if (rootid != BTRFS_CHUNK_TREE_OBJECTID)
+ goto err;
+ break;
+ /* valid in csum and log tree */
+ case BTRFS_CSUM_TREE_OBJECTID:
+ if (!(rootid == BTRFS_TREE_LOG_OBJECTID ||
+ is_fstree(rootid)))
+ goto err;
+ break;
+ case BTRFS_EXTENT_ITEM_KEY:
+ case BTRFS_METADATA_ITEM_KEY:
+ case BTRFS_BLOCK_GROUP_ITEM_KEY:
+ if (rootid != BTRFS_EXTENT_TREE_OBJECTID)
+ goto err;
+ break;
+ case BTRFS_ROOT_ITEM_KEY:
+ if (rootid != BTRFS_ROOT_TREE_OBJECTID)
+ goto err;
+ break;
+ case BTRFS_DEV_EXTENT_KEY:
+ if (rootid != BTRFS_DEV_TREE_OBJECTID)
+ goto err;
+ break;
+ }
+ return 0;
+err:
+ report_mismatch_key_root(key_type, rootid);
+ return -EINVAL;
+}
+
static int run_next_block(struct btrfs_root *root,
struct block_info *bits,
int bits_nr,
@@ -6271,6 +6287,16 @@ static int run_next_block(struct btrfs_root *root,
for (i = 0; i < nritems; i++) {
struct btrfs_file_extent_item *fi;
btrfs_item_key_to_cpu(buf, &key, i);
+ /*
+ * Check key type against the leaf owner.
+ * Could filter quite a lot of early error if
+ * owner is correct
+ */
+ if (check_type_with_root(btrfs_header_owner(buf),
+ key.type)) {
+ fprintf(stderr, "ignoring invalid key\n");
+ continue;
+ }
if (key.type == BTRFS_EXTENT_ITEM_KEY) {
process_extent_item(root, extent_cache, buf,
i);
@@ -6315,13 +6341,19 @@ static int run_next_block(struct btrfs_root *root,
}
if (key.type == BTRFS_TREE_BLOCK_REF_KEY) {
- add_tree_backref(extent_cache, key.objectid, 0,
- key.offset, 0);
+ ret = add_tree_backref(extent_cache,
+ key.objectid, 0, key.offset, 0);
+ if (ret < 0)
+ error("add_tree_backref failed: %s",
+ strerror(-ret));
continue;
}
if (key.type == BTRFS_SHARED_BLOCK_REF_KEY) {
- add_tree_backref(extent_cache, key.objectid,
- key.offset, 0, 0);
+ ret = add_tree_backref(extent_cache,
+ key.objectid, key.offset, 0, 0);
+ if (ret < 0)
+ error("add_tree_backref failed: %s",
+ strerror(-ret));
continue;
}
if (key.type == BTRFS_EXTENT_DATA_REF_KEY) {
@@ -6419,9 +6451,16 @@ static int run_next_block(struct btrfs_root *root,
tmpl.metadata = 1;
tmpl.max_size = size;
ret = add_extent_rec(extent_cache, &tmpl);
- BUG_ON(ret);
+ if (ret < 0)
+ goto out;
- add_tree_backref(extent_cache, ptr, parent, owner, 1);
+ ret = add_tree_backref(extent_cache, ptr, parent,
+ owner, 1);
+ if (ret < 0) {
+ error("add_tree_backref failed: %s",
+ strerror(-ret));
+ continue;
+ }
if (level > 1) {
add_pending(nodes, seen, ptr, size);
@@ -6455,6 +6494,7 @@ static int add_root_to_pending(struct extent_buffer *buf,
u64 objectid)
{
struct extent_record tmpl;
+ int ret;
if (btrfs_header_level(buf) > 0)
add_pending(nodes, seen, buf->start, buf->len);
@@ -6472,11 +6512,12 @@ static int add_root_to_pending(struct extent_buffer *buf,
if (objectid == BTRFS_TREE_RELOC_OBJECTID ||
btrfs_header_backref_rev(buf) < BTRFS_MIXED_BACKREF_REV)
- add_tree_backref(extent_cache, buf->start, buf->start,
- 0, 1);
+ ret = add_tree_backref(extent_cache, buf->start, buf->start,
+ 0, 1);
else
- add_tree_backref(extent_cache, buf->start, 0, objectid, 1);
- return 0;
+ ret = add_tree_backref(extent_cache, buf->start, 0, objectid,
+ 1);
+ return ret;
}
/* as we fix the tree, we might be deleting blocks that
@@ -6522,7 +6563,7 @@ static int free_extent_hook(struct btrfs_trans_handle *trans,
back->node.found_extent_tree = 0;
if (!back->node.found_extent_tree && back->node.found_ref) {
- rb_erase(&back->node.node, &rec->backref_tree);
+ list_del(&back->node.list);
free(back);
}
} else {
@@ -6541,7 +6582,7 @@ static int free_extent_hook(struct btrfs_trans_handle *trans,
back->node.found_extent_tree = 0;
}
if (!back->node.found_extent_tree && back->node.found_ref) {
- rb_erase(&back->node.node, &rec->backref_tree);
+ list_del(&back->node.list);
free(back);
}
}
@@ -6978,7 +7019,7 @@ out:
static int verify_backrefs(struct btrfs_fs_info *info, struct btrfs_path *path,
struct extent_record *rec)
{
- struct extent_backref *back, *tmp;
+ struct extent_backref *back;
struct data_backref *dback;
struct extent_entry *entry, *best = NULL;
LIST_HEAD(entries);
@@ -6994,8 +7035,7 @@ static int verify_backrefs(struct btrfs_fs_info *info, struct btrfs_path *path,
if (rec->metadata)
return 0;
- rbtree_postorder_for_each_entry_safe(back, tmp,
- &rec->backref_tree, node) {
+ list_for_each_entry(back, &rec->backrefs, list) {
if (back->full_backref || !back->is_data)
continue;
@@ -7121,8 +7161,7 @@ static int verify_backrefs(struct btrfs_fs_info *info, struct btrfs_path *path,
* Ok great we all agreed on an extent record, let's go find the real
* references and fix up the ones that don't match.
*/
- rbtree_postorder_for_each_entry_safe(back, tmp,
- &rec->backref_tree, node) {
+ list_for_each_entry(back, &rec->backrefs, list) {
if (back->full_backref || !back->is_data)
continue;
@@ -7351,7 +7390,7 @@ static int find_possible_backrefs(struct btrfs_fs_info *info,
struct extent_record *rec)
{
struct btrfs_root *root;
- struct extent_backref *back, *tmp;
+ struct extent_backref *back;
struct data_backref *dback;
struct cache_extent *cache;
struct btrfs_file_extent_item *fi;
@@ -7359,8 +7398,7 @@ static int find_possible_backrefs(struct btrfs_fs_info *info,
u64 bytenr, bytes;
int ret;
- rbtree_postorder_for_each_entry_safe(back, tmp,
- &rec->backref_tree, node) {
+ list_for_each_entry(back, &rec->backrefs, list) {
/* Don't care about full backrefs (poor unloved backrefs) */
if (back->full_backref || !back->is_data)
continue;
@@ -7448,7 +7486,7 @@ static int record_orphan_data_extents(struct btrfs_fs_info *fs_info,
{
struct btrfs_key key;
struct btrfs_root *dest_root;
- struct extent_backref *back, *tmp;
+ struct extent_backref *back;
struct data_backref *dback;
struct orphan_data_extent *orphan;
struct btrfs_path *path;
@@ -7460,8 +7498,7 @@ static int record_orphan_data_extents(struct btrfs_fs_info *fs_info,
path = btrfs_alloc_path();
if (!path)
return -ENOMEM;
- rbtree_postorder_for_each_entry_safe(back, tmp,
- &rec->backref_tree, node) {
+ list_for_each_entry(back, &rec->backrefs, list) {
if (back->full_backref || !back->is_data ||
!back->found_extent_tree)
continue;
@@ -7528,8 +7565,9 @@ static int fixup_extent_refs(struct btrfs_fs_info *info,
struct btrfs_trans_handle *trans = NULL;
int ret;
struct btrfs_path *path;
+ struct list_head *cur = rec->backrefs.next;
struct cache_extent *cache;
- struct extent_backref *back, *tmp;
+ struct extent_backref *back;
int allocated = 0;
u64 flags = 0;
@@ -7580,8 +7618,10 @@ static int fixup_extent_refs(struct btrfs_fs_info *info,
}
/* step three, recreate all the refs we did find */
- rbtree_postorder_for_each_entry_safe(back, tmp,
- &rec->backref_tree, node) {
+ while(cur != &rec->backrefs) {
+ back = to_extent_backref(cur);
+ cur = cur->next;
+
/*
* if we didn't find any references, don't create a
* new extent record
@@ -8327,8 +8367,10 @@ static int deal_root_from_list(struct list_head *list,
ret = -EIO;
break;
}
- add_root_to_pending(buf, extent_cache, pending,
+ ret = add_root_to_pending(buf, extent_cache, pending,
seen, nodes, rec->objectid);
+ if (ret < 0)
+ break;
/*
* To rebuild extent tree, we need deal with snapshot
* one by one, otherwise we deal with node firstly which
diff --git a/cmds-inspect-dump-super.c b/cmds-inspect-dump-super.c
index 3e09ee8c..aab50752 100644
--- a/cmds-inspect-dump-super.c
+++ b/cmds-inspect-dump-super.c
@@ -287,11 +287,29 @@ static void dump_superblock(struct btrfs_super_block *sb, int full)
int i;
char *s, buf[BTRFS_UUID_UNPARSED_SIZE];
u8 *p;
+ u32 csum_size;
+ u16 csum_type;
+
+ csum_type = btrfs_super_csum_type(sb);
+ csum_size = BTRFS_CSUM_SIZE;
+ printf("csum_type\t\t%hu (", csum_type);
+ if (csum_type >= ARRAY_SIZE(btrfs_csum_sizes)) {
+ printf("INVALID");
+ } else {
+ if (csum_type == BTRFS_CSUM_TYPE_CRC32) {
+ printf("crc32c");
+ csum_size = btrfs_csum_sizes[csum_type];
+ } else {
+ printf("unknown");
+ }
+ }
+ printf(")\n");
+ printf("csum_size\t\t%llu\n", (unsigned long long)csum_size);
printf("csum\t\t\t0x");
- for (i = 0, p = sb->csum; i < btrfs_super_csum_size(sb); i++)
+ for (i = 0, p = sb->csum; i < csum_size; i++)
printf("%02x", p[i]);
- if (check_csum_sblock(sb, btrfs_super_csum_size(sb)))
+ if (check_csum_sblock(sb, csum_size))
printf(" [match]");
else
printf(" [DON'T MATCH]");
@@ -363,10 +381,6 @@ static void dump_superblock(struct btrfs_super_block *sb, int full)
printf("incompat_flags\t\t0x%llx\n",
(unsigned long long)btrfs_super_incompat_flags(sb));
print_readable_incompat_flag(btrfs_super_incompat_flags(sb));
- printf("csum_type\t\t%llu\n",
- (unsigned long long)btrfs_super_csum_type(sb));
- printf("csum_size\t\t%llu\n",
- (unsigned long long)btrfs_super_csum_size(sb));
printf("cache_generation\t%llu\n",
(unsigned long long)btrfs_super_cache_generation(sb));
printf("uuid_tree_generation\t%llu\n",
@@ -511,7 +525,7 @@ int cmd_inspect_dump_super(int argc, char **argv)
for (i = optind; i < argc; i++) {
filename = argv[i];
- fd = open(filename, O_RDONLY, 0666);
+ fd = open(filename, O_RDONLY);
if (fd < 0) {
error("cannot open %s: %s", filename, strerror(errno));
ret = 1;
diff --git a/configure b/configure
index fc572408..d23f5b1b 100755
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for btrfs-progs v4.7.1.
+# Generated by GNU Autoconf 2.69 for btrfs-progs v4.7.2.
#
# Report bugs to <linux-btrfs@vger.kernel.org>.
#
@@ -580,8 +580,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='btrfs-progs'
PACKAGE_TARNAME='btrfs-progs'
-PACKAGE_VERSION='v4.7.1'
-PACKAGE_STRING='btrfs-progs v4.7.1'
+PACKAGE_VERSION='v4.7.2'
+PACKAGE_STRING='btrfs-progs v4.7.2'
PACKAGE_BUGREPORT='linux-btrfs@vger.kernel.org'
PACKAGE_URL='http://btrfs.wiki.kernel.org'
@@ -1290,7 +1290,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
-\`configure' configures btrfs-progs v4.7.1 to adapt to many kinds of systems.
+\`configure' configures btrfs-progs v4.7.2 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1355,7 +1355,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of btrfs-progs v4.7.1:";;
+ short | recursive ) echo "Configuration of btrfs-progs v4.7.2:";;
esac
cat <<\_ACEOF
@@ -1471,7 +1471,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-btrfs-progs configure v4.7.1
+btrfs-progs configure v4.7.2
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
@@ -1840,7 +1840,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by btrfs-progs $as_me v4.7.1, which was
+It was created by btrfs-progs $as_me v4.7.2, which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
@@ -6106,7 +6106,13 @@ fi
fi
-UDEVDIR="$(pkg-config udev --variable=udevdir)"
+# udev v190 introduced the btrfs builtin and a udev rule to use it.
+# Our udev rule gives us the friendly dm names but isn't required (or valid)
+# on earlier releases.
+UDEVDIR=
+if pkg-config udev --atleast-version 190; then
+ UDEVDIR="$(pkg-config udev --variable=udevdir)"
+fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for lzo_version in -llzo2" >&5
@@ -6678,7 +6684,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
-This file was extended by btrfs-progs $as_me v4.7.1, which was
+This file was extended by btrfs-progs $as_me v4.7.2, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -6741,7 +6747,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
-btrfs-progs config.status v4.7.1
+btrfs-progs config.status v4.7.2
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"
diff --git a/configure.ac b/configure.ac
index 97e89f23..8fd8f425 100644
--- a/configure.ac
+++ b/configure.ac
@@ -161,7 +161,13 @@ PKG_STATIC(UUID_LIBS_STATIC, [uuid])
PKG_CHECK_MODULES(ZLIB, [zlib])
PKG_STATIC(ZLIB_LIBS_STATIC, [zlib])
-UDEVDIR="$(pkg-config udev --variable=udevdir)"
+# udev v190 introduced the btrfs builtin and a udev rule to use it.
+# Our udev rule gives us the friendly dm names but isn't required (or valid)
+# on earlier releases.
+UDEVDIR=
+if pkg-config udev --atleast-version 190; then
+ UDEVDIR="$(pkg-config udev --variable=udevdir)"
+fi
AC_SUBST(UDEVDIR)
dnl lzo library does not provide pkg-config, let use classic way
diff --git a/debian/changelog b/debian/changelog
index b5ebd567..70c7d983 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+btrfs-progs (4.7.2-1) unstable; urgency=medium
+
+ * New upstream release. (Closes: #836778)
+
+ -- Dimitri John Ledkov <xnox@ubuntu.com> Thu, 08 Sep 2016 12:27:38 +0100
+
btrfs-progs (4.7.1-1) unstable; urgency=medium
* New upstream release.
diff --git a/disk-io.c b/disk-io.c
index ca4578f7..f5340c31 100644
--- a/disk-io.c
+++ b/disk-io.c
@@ -313,11 +313,29 @@ struct extent_buffer* read_tree_block_fs_info(
int ret;
struct extent_buffer *eb;
u64 best_transid = 0;
+ u32 sectorsize = btrfs_super_sectorsize(fs_info->super_copy);
+ u32 nodesize = btrfs_super_nodesize(fs_info->super_copy);
int mirror_num = 0;
int good_mirror = 0;
int num_copies;
int ignore = 0;
+ /*
+ * Don't even try to create tree block for unaligned tree block
+ * bytenr.
+ * Such unaligned tree block will free overlapping extent buffer,
+ * causing use-after-free bugs for fuzzed images.
+ */
+ if (!IS_ALIGNED(bytenr, sectorsize)) {
+ error("tree block bytenr %llu is not aligned to sectorsize %u",
+ bytenr, sectorsize);
+ return ERR_PTR(-EIO);
+ }
+ if (!IS_ALIGNED(blocksize, nodesize)) {
+ error("tree block size %u is not aligned to nodesize %u",
+ blocksize, nodesize);
+ return ERR_PTR(-EIO);
+ }
eb = btrfs_find_create_tree_block(fs_info, bytenr, blocksize);
if (!eb)
return ERR_PTR(-ENOMEM);
diff --git a/print-tree.c b/print-tree.c
index 81ab81fe..f97482f3 100644
--- a/print-tree.c
+++ b/print-tree.c
@@ -577,227 +577,228 @@ static void print_free_space_header(struct extent_buffer *leaf, int slot)
(unsigned long long)btrfs_free_space_bitmaps(leaf, header));
}
-static void print_key_type(u64 objectid, u8 type)
+void print_key_type(FILE *stream, u64 objectid, u8 type)
{
if (type == 0 && objectid == BTRFS_FREE_SPACE_OBJECTID) {
- printf("UNTYPED");
+ fprintf(stream, "UNTYPED");
return;
}
switch (type) {
case BTRFS_INODE_ITEM_KEY:
- printf("INODE_ITEM");
+ fprintf(stream, "INODE_ITEM");
break;
case BTRFS_INODE_REF_KEY:
- printf("INODE_REF");
+ fprintf(stream, "INODE_REF");
break;
case BTRFS_INODE_EXTREF_KEY:
- printf("INODE_EXTREF");
+ fprintf(stream, "INODE_EXTREF");
break;
case BTRFS_DIR_ITEM_KEY:
- printf("DIR_ITEM");
+ fprintf(stream, "DIR_ITEM");
break;
case BTRFS_DIR_INDEX_KEY:
- printf("DIR_INDEX");
+ fprintf(stream, "DIR_INDEX");
break;
case BTRFS_DIR_LOG_ITEM_KEY:
- printf("DIR_LOG_ITEM");
+ fprintf(stream, "DIR_LOG_ITEM");
break;
case BTRFS_DIR_LOG_INDEX_KEY:
- printf("DIR_LOG_INDEX");
+ fprintf(stream, "DIR_LOG_INDEX");
break;
case BTRFS_XATTR_ITEM_KEY:
- printf("XATTR_ITEM");
+ fprintf(stream, "XATTR_ITEM");
break;
case BTRFS_ORPHAN_ITEM_KEY:
- printf("ORPHAN_ITEM");
+ fprintf(stream, "ORPHAN_ITEM");
break;
case BTRFS_ROOT_ITEM_KEY:
- printf("ROOT_ITEM");
+ fprintf(stream, "ROOT_ITEM");
break;
case BTRFS_ROOT_REF_KEY:
- printf("ROOT_REF");
+ fprintf(stream, "ROOT_REF");
break;
case BTRFS_ROOT_BACKREF_KEY:
- printf("ROOT_BACKREF");
+ fprintf(stream, "ROOT_BACKREF");
break;
case BTRFS_EXTENT_ITEM_KEY:
- printf("EXTENT_ITEM");
+ fprintf(stream, "EXTENT_ITEM");
break;
case BTRFS_METADATA_ITEM_KEY:
- printf("METADATA_ITEM");
+ fprintf(stream, "METADATA_ITEM");
break;
case BTRFS_TREE_BLOCK_REF_KEY:
- printf("TREE_BLOCK_REF");
+ fprintf(stream, "TREE_BLOCK_REF");
break;
case BTRFS_SHARED_BLOCK_REF_KEY:
- printf("SHARED_BLOCK_REF");
+ fprintf(stream, "SHARED_BLOCK_REF");
break;
case BTRFS_EXTENT_DATA_REF_KEY:
- printf("EXTENT_DATA_REF");
+ fprintf(stream, "EXTENT_DATA_REF");
break;
case BTRFS_SHARED_DATA_REF_KEY:
- printf("SHARED_DATA_REF");
+ fprintf(stream, "SHARED_DATA_REF");
break;
case BTRFS_EXTENT_REF_V0_KEY:
- printf("EXTENT_REF_V0");
+ fprintf(stream, "EXTENT_REF_V0");
break;
case BTRFS_CSUM_ITEM_KEY:
- printf("CSUM_ITEM");
+ fprintf(stream, "CSUM_ITEM");
break;
case BTRFS_EXTENT_CSUM_KEY:
- printf("EXTENT_CSUM");
+ fprintf(stream, "EXTENT_CSUM");
break;
case BTRFS_EXTENT_DATA_KEY:
- printf("EXTENT_DATA");
+ fprintf(stream, "EXTENT_DATA");
break;
case BTRFS_BLOCK_GROUP_ITEM_KEY:
- printf("BLOCK_GROUP_ITEM");
+ fprintf(stream, "BLOCK_GROUP_ITEM");
break;
case BTRFS_FREE_SPACE_INFO_KEY:
- printf("FREE_SPACE_INFO");
+ fprintf(stream, "FREE_SPACE_INFO");
break;
case BTRFS_FREE_SPACE_EXTENT_KEY:
- printf("FREE_SPACE_EXTENT");
+ fprintf(stream, "FREE_SPACE_EXTENT");
break;
case BTRFS_FREE_SPACE_BITMAP_KEY:
- printf("FREE_SPACE_BITMAP");
+ fprintf(stream, "FREE_SPACE_BITMAP");
break;
case BTRFS_CHUNK_ITEM_KEY:
- printf("CHUNK_ITEM");
+ fprintf(stream, "CHUNK_ITEM");
break;
case BTRFS_DEV_ITEM_KEY:
- printf("DEV_ITEM");
+ fprintf(stream, "DEV_ITEM");
break;
case BTRFS_DEV_EXTENT_KEY:
- printf("DEV_EXTENT");
+ fprintf(stream, "DEV_EXTENT");
break;
case BTRFS_BALANCE_ITEM_KEY:
- printf("BALANCE_ITEM");
+ fprintf(stream, "BALANCE_ITEM");
break;
case BTRFS_DEV_REPLACE_KEY:
- printf("DEV_REPLACE");
+ fprintf(stream, "DEV_REPLACE");
break;
case BTRFS_STRING_ITEM_KEY:
- printf("STRING_ITEM");
+ fprintf(stream, "STRING_ITEM");
break;
case BTRFS_QGROUP_STATUS_KEY:
- printf("QGROUP_STATUS");
+ fprintf(stream, "QGROUP_STATUS");
break;
case BTRFS_QGROUP_RELATION_KEY:
- printf("QGROUP_RELATION");
+ fprintf(stream, "QGROUP_RELATION");
break;
case BTRFS_QGROUP_INFO_KEY:
- printf("QGROUP_INFO");
+ fprintf(stream, "QGROUP_INFO");
break;
case BTRFS_QGROUP_LIMIT_KEY:
- printf("QGROUP_LIMIT");
+ fprintf(stream, "QGROUP_LIMIT");
break;
case BTRFS_DEV_STATS_KEY:
- printf("DEV_STATS");
+ fprintf(stream, "DEV_STATS");
break;
case BTRFS_UUID_KEY_SUBVOL:
- printf("UUID_KEY_SUBVOL");
+ fprintf(stream, "UUID_KEY_SUBVOL");
break;
case BTRFS_UUID_KEY_RECEIVED_SUBVOL:
- printf("UUID_KEY_RECEIVED_SUBVOL");
+ fprintf(stream, "UUID_KEY_RECEIVED_SUBVOL");
break;
default:
- printf("UNKNOWN.%d", type);
+ fprintf(stream, "UNKNOWN.%d", type);
};
}
-static void print_objectid(u64 objectid, u8 type)
+void print_objectid(FILE *stream, u64 objectid, u8 type)
{
switch (type) {
case BTRFS_DEV_EXTENT_KEY:
- printf("%llu", (unsigned long long)objectid); /* device id */
+ /* device id */
+ fprintf(stream, "%llu", (unsigned long long)objectid);
return;
case BTRFS_QGROUP_RELATION_KEY:
- printf("%llu/%llu", btrfs_qgroup_level(objectid),
+ fprintf(stream, "%llu/%llu", btrfs_qgroup_level(objectid),
btrfs_qgroup_subvid(objectid));
return;
case BTRFS_UUID_KEY_SUBVOL:
case BTRFS_UUID_KEY_RECEIVED_SUBVOL:
- printf("0x%016llx", (unsigned long long)objectid);
+ fprintf(stream, "0x%016llx", (unsigned long long)objectid);
return;
}
switch (objectid) {
case BTRFS_ROOT_TREE_OBJECTID:
if (type == BTRFS_DEV_ITEM_KEY)
- printf("DEV_ITEMS");
+ fprintf(stream, "DEV_ITEMS");
else
- printf("ROOT_TREE");
+ fprintf(stream, "ROOT_TREE");
break;
case BTRFS_EXTENT_TREE_OBJECTID:
- printf("EXTENT_TREE");
+ fprintf(stream, "EXTENT_TREE");
break;
case BTRFS_CHUNK_TREE_OBJECTID:
- printf("CHUNK_TREE");
+ fprintf(stream, "CHUNK_TREE");
break;
case BTRFS_DEV_TREE_OBJECTID:
- printf("DEV_TREE");
+ fprintf(stream, "DEV_TREE");
break;
case BTRFS_FS_TREE_OBJECTID:
- printf("FS_TREE");
+ fprintf(stream, "FS_TREE");
break;
case BTRFS_ROOT_TREE_DIR_OBJECTID:
- printf("ROOT_TREE_DIR");
+ fprintf(stream, "ROOT_TREE_DIR");
break;
case BTRFS_CSUM_TREE_OBJECTID:
- printf("CSUM_TREE");
+ fprintf(stream, "CSUM_TREE");
break;
case BTRFS_BALANCE_OBJECTID:
- printf("BALANCE");
+ fprintf(stream, "BALANCE");
break;
case BTRFS_ORPHAN_OBJECTID:
- printf("ORPHAN");
+ fprintf(stream, "ORPHAN");
break;
case BTRFS_TREE_LOG_OBJECTID:
- printf("TREE_LOG");
+ fprintf(stream, "TREE_LOG");
break;
case BTRFS_TREE_LOG_FIXUP_OBJECTID:
- printf("LOG_FIXUP");
+ fprintf(stream, "LOG_FIXUP");
break;
case BTRFS_TREE_RELOC_OBJECTID:
- printf("TREE_RELOC");
+ fprintf(stream, "TREE_RELOC");
break;
case BTRFS_DATA_RELOC_TREE_OBJECTID:
- printf("DATA_RELOC_TREE");
+ fprintf(stream, "DATA_RELOC_TREE");
break;
case BTRFS_EXTENT_CSUM_OBJECTID:
- printf("EXTENT_CSUM");
+ fprintf(stream, "EXTENT_CSUM");
break;
case BTRFS_FREE_SPACE_OBJECTID:
- printf("FREE_SPACE");
+ fprintf(stream, "FREE_SPACE");
break;
case BTRFS_FREE_INO_OBJECTID:
- printf("FREE_INO");
+ fprintf(stream, "FREE_INO");
break;
case BTRFS_QUOTA_TREE_OBJECTID:
- printf("QUOTA_TREE");
+ fprintf(stream, "QUOTA_TREE");
break;
case BTRFS_UUID_TREE_OBJECTID:
- printf("UUID_TREE");
+ fprintf(stream, "UUID_TREE");
break;
case BTRFS_FREE_SPACE_TREE_OBJECTID:
- printf("FREE_SPACE_TREE");
+ fprintf(stream, "FREE_SPACE_TREE");
break;
case BTRFS_MULTIPLE_OBJECTIDS:
- printf("MULTIPLE");
+ fprintf(stream, "MULTIPLE");
break;
case (u64)-1:
- printf("-1");
+ fprintf(stream, "-1");
break;
case BTRFS_FIRST_CHUNK_TREE_OBJECTID:
if (type == BTRFS_CHUNK_ITEM_KEY) {
- printf("FIRST_CHUNK_TREE");
+ fprintf(stream, "FIRST_CHUNK_TREE");
break;
}
/* fall-thru */
default:
- printf("%llu", (unsigned long long)objectid);
+ fprintf(stream, "%llu", (unsigned long long)objectid);
}
}
@@ -808,9 +809,9 @@ void btrfs_print_key(struct btrfs_disk_key *disk_key)
u64 offset = btrfs_disk_key_offset(disk_key);
printf("key (");
- print_objectid(objectid, type);
+ print_objectid(stdout, objectid, type);
printf(" ");
- print_key_type(objectid, type);
+ print_key_type(stdout, objectid, type);
switch (type) {
case BTRFS_QGROUP_RELATION_KEY:
case BTRFS_QGROUP_INFO_KEY:
diff --git a/print-tree.h b/print-tree.h
index f0153c18..9865500b 100644
--- a/print-tree.h
+++ b/print-tree.h
@@ -24,4 +24,6 @@ void btrfs_print_tree(struct btrfs_root *root, struct extent_buffer *t, int foll
void btrfs_print_key(struct btrfs_disk_key *disk_key);
void print_chunk(struct extent_buffer *eb, struct btrfs_chunk *chunk);
void print_extent_item(struct extent_buffer *eb, int slot, int metadata);
+void print_objectid(FILE *stream, u64 objectid, u8 type);
+void print_key_type(FILE *stream, u64 objectid, u8 type);
#endif
diff --git a/super-recover.c b/super-recover.c
index 1dc3fc7d..635e804b 100644
--- a/super-recover.c
+++ b/super-recover.c
@@ -138,7 +138,7 @@ read_dev_supers(char *filename, struct btrfs_recover_superblock *recover)
struct btrfs_super_block *sb = (struct btrfs_super_block *)buf;
- fd = open(filename, O_RDONLY, 0666);
+ fd = open(filename, O_RDONLY);
if (fd < 0)
return -errno;
diff --git a/tests/README.md b/tests/README.md
index 6bb3de49..ca45cf6f 100644
--- a/tests/README.md
+++ b/tests/README.md
@@ -159,3 +159,14 @@ $ TEST=012\* ./misc-tests.sh # from tests/
6. The commit changelog should reference a commit that either introduced or
fixed the bug (or both). Subject line of the shall mention the name of the
new directory for ease of search, eg. `btrfs-progs: tests: add 012-subvolume-sync-must-wait`
+
+### Crafted/fuzzed images
+
+Images that are create by fuzzing or specially crafted to trigger some error
+conditions should be added to the directory *fuzz-tests/images*, accompanied by
+a textual description of the source (bugzilla, mail), the reporter, brief
+description of the problem or the stack trace.
+
+If you have a fix for the problem, please submit it prior to the test image, so
+the fuzz tests always succeed when run on random checked out. This helps
+bisectability.
diff --git a/tests/fuzz-tests/images/bko-153641-unaligned-tree-block-bytenr.raw.txt b/tests/fuzz-tests/images/bko-153641-unaligned-tree-block-bytenr.raw.txt
new file mode 100644
index 00000000..05cf3928
--- /dev/null
+++ b/tests/fuzz-tests/images/bko-153641-unaligned-tree-block-bytenr.raw.txt
@@ -0,0 +1,33 @@
+URL: https://bugzilla.kernel.org/show_bug.cgi?id=153641
+Lukas Lueg 2016-08-23 19:54:45 UTC
+
+Created attachment 229941 [details]
+Image triggering btrfsck into asan error
+
+The filesystem-image attached to this bug drives btrfsck from btrfs-progs
+v4.7-42-g56e9586 into a heap-use-after-free. The src was from kdave's mirror,
+devel branch. CFLAGS='-DNDEBUG -O1 -g -fsanitize=address
+-fno-omit-frame-pointer -fno-optimize-sibling-calls'
+
+
+The juicy parts:
+==32639==ERROR: AddressSanitizer: heap-use-after-free on address
+0x621000019170 at pc 0x0000005c046e bp 0x7fff631e48d0 sp 0x7fff631e48c8
+READ of size 4 at 0x621000019170 thread T0
+ #0 0x5c046d in free_extent_buffer
+/home/lukas/dev/btrfsprogs_fuzz/src/extent_io.c:579:10
+ #1 0x59356c in btrfs_release_all_roots
+/home/lukas/dev/btrfsprogs_fuzz/src/disk-io.c:1084:3
+ #2 0x5949a7 in __open_ctree_fd
+/home/lukas/dev/btrfsprogs_fuzz/src/disk-io.c:1325:2
+ #3 0x594325 in open_ctree_fs_info
+/home/lukas/dev/btrfsprogs_fuzz/src/disk-io.c:1363:9
+ #4 0x51e717 in cmd_check
+/home/lukas/dev/btrfsprogs_fuzz/src/cmds-check.c:11320:9
+ #5 0x4f0f81 in main /home/lukas/dev/btrfsprogs_fuzz/src/btrfs.c:243:8
+ #6 0x7f5ce75ee730 in __libc_start_main (/lib64/libc.so.6+0x20730)
+ #7 0x4213f8 in _start (/home/lukas/dev/btrfsfuzz/bin/bin/btrfs+0x4213f8)
+
+
+Note that the bug happens within core itself. The kernel may be vulnerable as
+well, I didn't check, though.
diff --git a/tests/fuzz-tests/images/bko-153641-unaligned-tree-block-bytenr.raw.xz b/tests/fuzz-tests/images/bko-153641-unaligned-tree-block-bytenr.raw.xz
new file mode 100644
index 00000000..d37b1a2d
--- /dev/null
+++ b/tests/fuzz-tests/images/bko-153641-unaligned-tree-block-bytenr.raw.xz
Binary files differ
diff --git a/tests/fuzz-tests/images/bko-154021-invalid-drop-level.raw.txt b/tests/fuzz-tests/images/bko-154021-invalid-drop-level.raw.txt
new file mode 100644
index 00000000..dab91dcc
--- /dev/null
+++ b/tests/fuzz-tests/images/bko-154021-invalid-drop-level.raw.txt
@@ -0,0 +1,30 @@
+URL: https://bugzilla.kernel.org/show_bug.cgi?id=154021
+Lukas Lueg 2016-08-26 22:53:42 UTC
+
+Created attachment 230361 [details]
+Image triggering btrfsck to segv
+
+The fuzzer hit again:
+
+==32522==ERROR: AddressSanitizer: SEGV on unknown address 0x00027fff801c (pc
+0x0000004a952e bp 0x7fff5222ce70 sp 0x7fff5222c600 T0)
+ #0 0x4a952d in __asan_memcpy
+(/home/lukas/dev/btrfsfuzz/bin-asan/bin/btrfs+0x4a952d)
+ #1 0x66a323 in read_extent_buffer
+/home/lukas/dev/btrfsfuzz/src-asan/extent_io.c:867:2
+ #2 0x55ad25 in btrfs_node_key
+/home/lukas/dev/btrfsfuzz/src-asan/./ctree.h:1668:2
+ #3 0x58573b in check_fs_root
+/home/lukas/dev/btrfsfuzz/src-asan/cmds-check.c:3748:3
+ #4 0x544136 in check_fs_roots
+/home/lukas/dev/btrfsfuzz/src-asan/cmds-check.c:3896:10
+ #5 0x53d8c5 in cmd_check
+/home/lukas/dev/btrfsfuzz/src-asan/cmds-check.c:11470:8
+ #6 0x4f105f in main /home/lukas/dev/btrfsfuzz/src-asan/btrfs.c:243:8
+ #7 0x7fea1bcb7730 in __libc_start_main (/lib64/libc.so.6+0x20730)
+ #8 0x421238 in _start
+(/home/lukas/dev/btrfsfuzz/bin-asan/bin/btrfs+0x421238)
+
+
+See the attached image to reproduce using btrfs-progs btrfs-progs
+v4.7-42-g56e9586.
diff --git a/tests/fuzz-tests/images/bko-154021-invalid-drop-level.raw.xz b/tests/fuzz-tests/images/bko-154021-invalid-drop-level.raw.xz
new file mode 100644
index 00000000..76c58dce
--- /dev/null
+++ b/tests/fuzz-tests/images/bko-154021-invalid-drop-level.raw.xz
Binary files differ
diff --git a/tests/fuzz-tests/images/bko-154961-heap-overflow-chunk-items.raw.txt b/tests/fuzz-tests/images/bko-154961-heap-overflow-chunk-items.raw.txt
new file mode 100644
index 00000000..f41eac60
--- /dev/null
+++ b/tests/fuzz-tests/images/bko-154961-heap-overflow-chunk-items.raw.txt
@@ -0,0 +1,21 @@
+URL: https://bugzilla.kernel.org/show_bug.cgi?id=154961
+Lukas Lueg 2016-08-27 17:29:35 UTC
+
+More news from the fuzzer. See the attached image to reproduce using
+btrfs-progs btrfs-progs v4.7-42-g56e9586. You may need to compile with ASAN,
+could not reproduce without...
+
+
+==2572==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x621000018d86 at pc 0x000000547c3c bp 0x7ffd60ec5ef0 sp 0x7ffd60ec5ee8
+READ of size 8 at 0x621000018d86 thread T0
+ #0 0x547c3b in btrfs_stripe_offset /home/lukas/dev/btrfsfuzz/src-asan/./ctree.h:1357:1
+ #1 0x5391f7 in btrfs_stripe_offset_nr /home/lukas/dev/btrfsfuzz/src-asan/./ctree.h:1399:9
+ #2 0x538790 in btrfs_new_chunk_record /home/lukas/dev/btrfsfuzz/src-asan/cmds-check.c:5209:4
+ #3 0x56c55d in process_chunk_item /home/lukas/dev/btrfsfuzz/src-asan/cmds-check.c:5225:8
+ #4 0x5634e7 in run_next_block /home/lukas/dev/btrfsfuzz/src-asan/cmds-check.c:6290:5
+ #5 0x55c489 in deal_root_from_list /home/lukas/dev/btrfsfuzz/src-asan/cmds-check.c:8338:10
+ #6 0x541d53 in check_chunks_and_extents /home/lukas/dev/btrfsfuzz/src-asan/cmds-check.c:8505:8
+ #7 0x53d565 in cmd_check /home/lukas/dev/btrfsfuzz/src-asan/cmds-check.c:11430:9
+ #8 0x4f105f in main /home/lukas/dev/btrfsfuzz/src-asan/btrfs.c:243:8
+ #9 0x7f40dcd8b730 in __libc_start_main (/lib64/libc.so.6+0x20730)
+ #10 0x421238 in _start (/home/lukas/dev/btrfsfuzz/bin-asan/bin/btrfs+0x421238)
diff --git a/tests/fuzz-tests/images/bko-154961-heap-overflow-chunk-items.raw.xz b/tests/fuzz-tests/images/bko-154961-heap-overflow-chunk-items.raw.xz
new file mode 100644
index 00000000..dfd01ca2
--- /dev/null
+++ b/tests/fuzz-tests/images/bko-154961-heap-overflow-chunk-items.raw.xz
Binary files differ
diff --git a/tests/fuzz-tests/images/bko-155181-unaligned-extent-item.raw.txt b/tests/fuzz-tests/images/bko-155181-unaligned-extent-item.raw.txt
new file mode 100644
index 00000000..7f0b8045
--- /dev/null
+++ b/tests/fuzz-tests/images/bko-155181-unaligned-extent-item.raw.txt
@@ -0,0 +1,8 @@
+URL: https://bugzilla.kernel.org/show_bug.cgi?id=155181
+Lukas Lueg 2016-08-28 10:52:32 UTC
+
+Created attachment 230891 [details]
+BTRFS-image that reaches abort() in btrfsck
+
+More news from the fuzzer. The attached image causes btrfsck to reach abort()
+in in cmds-check.c:add_tree_backref(); using btrfs-progs v4.7-42-g56e9586.
diff --git a/tests/fuzz-tests/images/bko-155181-unaligned-extent-item.raw.xz b/tests/fuzz-tests/images/bko-155181-unaligned-extent-item.raw.xz
new file mode 100644
index 00000000..c401f2e5
--- /dev/null
+++ b/tests/fuzz-tests/images/bko-155181-unaligned-extent-item.raw.xz
Binary files differ
diff --git a/tests/fuzz-tests/images/bko-155201-wrong-chunk-item-in-root-tree.raw.txt b/tests/fuzz-tests/images/bko-155201-wrong-chunk-item-in-root-tree.raw.txt
new file mode 100644
index 00000000..9097e49d
--- /dev/null
+++ b/tests/fuzz-tests/images/bko-155201-wrong-chunk-item-in-root-tree.raw.txt
@@ -0,0 +1,35 @@
+URL: https://bugzilla.kernel.org/show_bug.cgi?id=155201
+Lukas Lueg 2016-08-28 19:15:53 UTC
+
+Created attachment 230921 [details]
+Image causing SIGFPE in btrfsck
+
+News from the fuzzer. See the attached image to reproduce using btrfs-progs
+v4.7-42-g56e9586.
+
+
+[Thread debugging using libthread_db enabled]
+Using host libthread_db library "/lib64/libthread_db.so.1".
+checking extents
+Chunk[0, 4194304] existed.
+Chunk[18446744073709551607, 228, 0]: length(1), offset(0), type(4160) mismatch
+with block group[0, 192, 4194304]: offset(4194304), objectid(0), flags(2)
+
+Program received signal SIGFPE, Arithmetic exception.
+0x000000000042b178 in calc_stripe_length (type=4160, length=1, num_stripes=0)
+at cmds-check.c:8018
+8018 stripe_size /= num_stripes;
+#0 0x000000000042b178 in calc_stripe_length (type=4160, length=1,
+num_stripes=0) at cmds-check.c:8018
+#1 0x000000000042b56d in check_chunk_refs (silent=0,
+dev_extent_cache=0x7fffffffdd30, block_group_cache=0x7fffffffdd60,
+chunk_rec=0x6b92c0) at cmds-check.c:8101
+#2 check_chunks (chunk_cache=chunk_cache@entry=0x7fffffffdd80,
+block_group_cache=block_group_cache@entry=0x7fffffffdd60,
+dev_extent_cache=dev_extent_cache@entry=0x7fffffffdd30, good=good@entry=0x0,
+bad=bad@entry=0x0, rebuild=rebuild@entry=0x0, silent=0) at cmds-check.c:8165
+#3 0x000000000042bbdd in check_chunks_and_extents (root=root@entry=0x6b2cf0)
+at cmds-check.c:8524
+#4 0x000000000042e3cb in cmd_check (argc=<optimized out>, argv=<optimized
+out>) at cmds-check.c:11430
+#5 0x000000000040a416 in main (argc=2, argv=0x7fffffffe218) at btrfs.c:243
diff --git a/tests/fuzz-tests/images/bko-155201-wrong-chunk-item-in-root-tree.raw.xz b/tests/fuzz-tests/images/bko-155201-wrong-chunk-item-in-root-tree.raw.xz
new file mode 100644
index 00000000..5bc2d3b9
--- /dev/null
+++ b/tests/fuzz-tests/images/bko-155201-wrong-chunk-item-in-root-tree.raw.xz
Binary files differ
diff --git a/tests/fuzz-tests/images/bko-97021-invalid-chunk-sectorsize.raw.txt b/tests/fuzz-tests/images/bko-97021-invalid-chunk-sectorsize.raw.txt
new file mode 100644
index 00000000..fb098411
--- /dev/null
+++ b/tests/fuzz-tests/images/bko-97021-invalid-chunk-sectorsize.raw.txt
@@ -0,0 +1,41 @@
+URL: https://bugzilla.kernel.org/show_bug.cgi?id=97021
+Lukas Lueg 2015-04-21 21:36:31 UTC
+
+The btrfs-image attached to this bug causes the userland tools v3.19.1 to crash
+by reaching a call to abort().
+
+(gdb) run check btrfs_fukked_abort_cmds-check:5919.bin
+Starting program: /usr/sbin/btrfs check btrfs_fukked_abort_cmds-check:5919.bin
+[Thread debugging using libthread_db enabled]
+Using host libthread_db library "/lib64/libthread_db.so.1".
+Checking filesystem on btrfs_fukked_abort_cmds-check:5919.bin
+UUID: cdd8684f-9eb1-40a4-91ec-1ed7c3cb444c
+checking extents
+
+Program received signal SIGABRT, Aborted.
+0x00000032626348d7 in __GI_raise (sig=sig@entry=6)
+ at ../sysdeps/unix/sysv/linux/raise.c:55
+55 return INLINE_SYSCALL (tgkill, 3, pid, selftid, sig);
+(gdb) bt
+#0 0x00000032626348d7 in __GI_raise (sig=sig@entry=6)
+ at ../sysdeps/unix/sysv/linux/raise.c:55
+#1 0x000000326263653a in __GI_abort () at abort.c:89
+#2 0x0000000000425038 in run_next_block (root=root@entry=0x894b20,
+ bits=bits@entry=0x896960, last=last@entry=0x7fffffffd470,
+ pending=pending@entry=0x7fffffffd5f0, seen=seen@entry=0x7fffffffd5e0,
+ reada=reada@entry=0x7fffffffd600, nodes=0x7fffffffd610,
+ extent_cache=0x7fffffffd5d0, chunk_cache=0x7fffffffd5c0, dev_cache=0x7fffffffd5b0,
+ block_group_cache=0x7fffffffd6a0, dev_extent_cache=0x7fffffffd6c0, ri=0x894e20,
+ bits_nr=1024) at cmds-check.c:5908
+#3 0x000000000042523d in deal_root_from_list (list=list@entry=0x7fffffffd640,
+ root=root@entry=0x894b20, bits=bits@entry=0x896960,
+ pending=pending@entry=0x7fffffffd5f0, seen=seen@entry=0x7fffffffd5e0,
+ reada=reada@entry=0x7fffffffd600, nodes=0x7fffffffd610,
+ extent_cache=0x7fffffffd5d0, chunk_cache=0x7fffffffd5c0, dev_cache=0x7fffffffd5b0,
+ block_group_cache=0x7fffffffd6a0, dev_extent_cache=0x7fffffffd6c0, bits_nr=1024)
+ at cmds-check.c:7838
+#4 0x0000000000425f3d in check_chunks_and_extents (root=root@entry=0x894b20)
+ at cmds-check.c:8000
+#5 0x0000000000428144 in cmd_check (argc=<optimized out>, argv=<optimized out>)
+ at cmds-check.c:9431
+#6 0x000000000040e5a2 in main (argc=2, argv=0x7fffffffde90) at btrfs.c:245
diff --git a/tests/fuzz-tests/images/bko-97021-invalid-chunk-sectorsize.raw.xz b/tests/fuzz-tests/images/bko-97021-invalid-chunk-sectorsize.raw.xz
new file mode 100644
index 00000000..4e9ff538
--- /dev/null
+++ b/tests/fuzz-tests/images/bko-97021-invalid-chunk-sectorsize.raw.xz
Binary files differ
diff --git a/tests/fuzz-tests/images/bko-97031-invalid-stripe-len-sys-array.raw.txt b/tests/fuzz-tests/images/bko-97031-invalid-stripe-len-sys-array.raw.txt
new file mode 100644
index 00000000..2dc51b21
--- /dev/null
+++ b/tests/fuzz-tests/images/bko-97031-invalid-stripe-len-sys-array.raw.txt
@@ -0,0 +1,58 @@
+URL: https://bugzilla.kernel.org/show_bug.cgi?id=97031
+Lukas Lueg 2015-04-21 21:47:18 UTC
+
+The btrfs-image attached to this bug causes the userland tools v3.19.1 to crash
+with a SIGFPE. The problem is that map->stripe_len in __btrfs_map_block() is
+allowed to be 0 before entering a division.
+
+The userland tool crashes.
+The kernel fails to mount with
+> BTRFS: failed to read the system array on loop0
+> BTRFS: open_ctree_failed
+
+
+
+(gdb) run check btrfs_fukked_sigfpe_volumes:1372.bin
+....
+warning, device 0 is missing
+warning, device 4294967295 is missing
+warning, device 0 is missing
+warning, device 0 is missing
+warning, device 0 is missing
+warning, device 0 is missing
+warning, device 4294967295 is missing
+
+Program received signal SIGFPE, Arithmetic exception.
+0x000000000044d56f in __btrfs_map_block (map_tree=map_tree@entry=0x88c170,
+ rw=rw@entry=0, logical=<optimized out>, length=length@entry=0x7fffffffd8f0,
+ type=type@entry=0x0, multi_ret=multi_ret@entry=0x7fffffffd8e8, mirror_num=0,
+ raid_map_ret=0x0) at volumes.c:1372
+1372 stripe_nr = stripe_nr / map->stripe_len;
+(gdb) bt
+#0 0x000000000044d56f in __btrfs_map_block (map_tree=map_tree@entry=0x88c170,
+ rw=rw@entry=0, logical=<optimized out>, length=length@entry=0x7fffffffd8f0,
+ type=type@entry=0x0, multi_ret=multi_ret@entry=0x7fffffffd8e8, mirror_num=0,
+ raid_map_ret=0x0) at volumes.c:1372
+#1 0x000000000044db45 in btrfs_map_block (map_tree=map_tree@entry=0x88c170,
+ rw=rw@entry=0, logical=<optimized out>, length=length@entry=0x7fffffffd8f0,
+ multi_ret=multi_ret@entry=0x7fffffffd8e8, mirror_num=mirror_num@entry=0,
+ raid_map_ret=0x0) at volumes.c:1291
+#2 0x000000000043b22d in read_whole_eb (info=0x88c010, eb=eb@entry=0x88f400,
+ mirror=mirror@entry=0) at disk-io.c:232
+#3 0x000000000043caa2 in read_tree_block (root=root@entry=0x88c710,
+ bytenr=<optimized out>, blocksize=<optimized out>, parent_transid=5)
+ at disk-io.c:295
+#4 0x000000000043d5df in btrfs_setup_chunk_tree_and_device_map (
+ fs_info=fs_info@entry=0x88c010) at disk-io.c:1106
+#5 0x000000000043d7d1 in __open_ctree_fd (fp=fp@entry=3,
+ path=path@entry=0x7fffffffe1fa "btrfs_fukked_sigfpe_volumes:1372.bin",
+ sb_bytenr=65536, sb_bytenr@entry=0, root_tree_bytenr=root_tree_bytenr@entry=0,
+ flags=flags@entry=OPEN_CTREE_EXCLUSIVE) at disk-io.c:1190
+#6 0x000000000043d965 in open_ctree_fs_info (
+ filename=0x7fffffffe1fa "btrfs_fukked_sigfpe_volumes:1372.bin",
+ sb_bytenr=sb_bytenr@entry=0, root_tree_bytenr=root_tree_bytenr@entry=0,
+ flags=flags@entry=OPEN_CTREE_EXCLUSIVE) at disk-io.c:1231
+#7 0x0000000000427bf5 in cmd_check (argc=1, argv=0x7fffffffde90) at cmds-check.c:9326
+#8 0x000000000040e5a2 in main (argc=2, argv=0x7fffffffde90) at btrfs.c:245
+(gdb) p map->stripe_len
+$1 = 0
diff --git a/tests/fuzz-tests/images/bko-97031-invalid-stripe-len-sys-array.raw.xz b/tests/fuzz-tests/images/bko-97031-invalid-stripe-len-sys-array.raw.xz
new file mode 100644
index 00000000..8680fa34
--- /dev/null
+++ b/tests/fuzz-tests/images/bko-97031-invalid-stripe-len-sys-array.raw.xz
Binary files differ
diff --git a/tests/fuzz-tests/images/bko-97041-invalid-sub-stripes-zero-FPE.raw.txt b/tests/fuzz-tests/images/bko-97041-invalid-sub-stripes-zero-FPE.raw.txt
new file mode 100644
index 00000000..5f631646
--- /dev/null
+++ b/tests/fuzz-tests/images/bko-97041-invalid-sub-stripes-zero-FPE.raw.txt
@@ -0,0 +1,50 @@
+URL: https://bugzilla.kernel.org/show_bug.cgi?id=97041
+ Lukas Lueg 2015-04-21 21:53:14 UTC
+
+The btrfs-image attached to this bug causes the userland tools v3.19.1 to
+crash with a SIGFPE. The problem is that map->sub_stripes in
+__btrfs_map_block() is allowed to be 0 before entering a division.
+
+The userland tool crashes. The kernel reports a "divide error: 0000 ..."
+with a traceback from __btrfs_map_block()
+
+
+(gdb) run check btrfs_fukked_sigfpe_volumes:1404.bin
+Starting program: /usr/sbin/btrfs check btrfs_fukked_sigfpe_volumes:1404.bin
+[Thread debugging using libthread_db enabled]
+Using host libthread_db library "/lib64/libthread_db.so.1".
+
+Program received signal SIGFPE, Arithmetic exception.
+0x000000000044d7b6 in __btrfs_map_block (map_tree=map_tree@entry=0x88c170,
+ rw=rw@entry=0, logical=<optimized out>, length=length@entry=0x7fffffffd8f0,
+ type=type@entry=0x0, multi_ret=multi_ret@entry=0x7fffffffd8e8, mirror_num=0,
+ raid_map_ret=0x0) at volumes.c:1404
+1404 int factor = map->num_stripes / map->sub_stripes;
+(gdb) bt
+#0 0x000000000044d7b6 in __btrfs_map_block (map_tree=map_tree@entry=0x88c170,
+ rw=rw@entry=0, logical=<optimized out>, length=length@entry=0x7fffffffd8f0,
+ type=type@entry=0x0, multi_ret=multi_ret@entry=0x7fffffffd8e8, mirror_num=0,
+ raid_map_ret=0x0) at volumes.c:1404
+#1 0x000000000044db45 in btrfs_map_block (map_tree=map_tree@entry=0x88c170,
+ rw=rw@entry=0, logical=<optimized out>, length=length@entry=0x7fffffffd8f0,
+ multi_ret=multi_ret@entry=0x7fffffffd8e8, mirror_num=mirror_num@entry=0,
+ raid_map_ret=0x0) at volumes.c:1291
+#2 0x000000000043b22d in read_whole_eb (info=0x88c010, eb=eb@entry=0x88f400,
+ mirror=mirror@entry=0) at disk-io.c:232
+#3 0x000000000043caa2 in read_tree_block (root=root@entry=0x88c710,
+ bytenr=<optimized out>, blocksize=<optimized out>, parent_transid=5)
+ at disk-io.c:295
+#4 0x000000000043d5df in btrfs_setup_chunk_tree_and_device_map (
+ fs_info=fs_info@entry=0x88c010) at disk-io.c:1106
+#5 0x000000000043d7d1 in __open_ctree_fd (fp=fp@entry=3,
+ path=path@entry=0x7fffffffe1fa "btrfs_fukked_sigfpe_volumes:1404.bin",
+ sb_bytenr=65536, sb_bytenr@entry=0, root_tree_bytenr=root_tree_bytenr@entry=0,
+ flags=flags@entry=OPEN_CTREE_EXCLUSIVE) at disk-io.c:1190
+#6 0x000000000043d965 in open_ctree_fs_info (
+ filename=0x7fffffffe1fa "btrfs_fukked_sigfpe_volumes:1404.bin",
+ sb_bytenr=sb_bytenr@entry=0, root_tree_bytenr=root_tree_bytenr@entry=0,
+ flags=flags@entry=OPEN_CTREE_EXCLUSIVE) at disk-io.c:1231
+#7 0x0000000000427bf5 in cmd_check (argc=1, argv=0x7fffffffde90) at cmds-check.c:9326
+#8 0x000000000040e5a2 in main (argc=2, argv=0x7fffffffde90) at btrfs.c:245
+(gdb) p map->sub_stripes
+$1 = 0
diff --git a/tests/fuzz-tests/images/bko-97041-invalid-sub-stripes-zero-FPE.raw.xz b/tests/fuzz-tests/images/bko-97041-invalid-sub-stripes-zero-FPE.raw.xz
new file mode 100644
index 00000000..b8e23eb7
--- /dev/null
+++ b/tests/fuzz-tests/images/bko-97041-invalid-sub-stripes-zero-FPE.raw.xz
Binary files differ
diff --git a/tests/misc-tests/015-dump-super-garbage/test.sh b/tests/misc-tests/015-dump-super-garbage/test.sh
new file mode 100755
index 00000000..33fc8332
--- /dev/null
+++ b/tests/misc-tests/015-dump-super-garbage/test.sh
@@ -0,0 +1,17 @@
+#!/bin/bash
+#
+# let dump-super dump random data, must not crash
+
+source $TOP/tests/common
+
+check_prereq btrfs
+
+run_check $TOP/btrfs inspect-internal dump-super /dev/urandom
+run_check $TOP/btrfs inspect-internal dump-super -a /dev/urandom
+run_check $TOP/btrfs inspect-internal dump-super -fa /dev/urandom
+run_check $TOP/btrfs inspect-internal dump-super -Ffa /dev/urandom
+run_check $TOP/btrfs inspect-internal dump-super -Ffa /dev/urandom
+run_check $TOP/btrfs inspect-internal dump-super -Ffa /dev/urandom
+run_check $TOP/btrfs inspect-internal dump-super -Ffa /dev/urandom
+run_check $TOP/btrfs inspect-internal dump-super -Ffa /dev/urandom
+run_check $TOP/btrfs inspect-internal dump-super -Ffa /dev/urandom
diff --git a/version.sh b/version.sh
index 96fa8812..caf5dddc 100755
--- a/version.sh
+++ b/version.sh
@@ -6,7 +6,7 @@
# Copyright 2008, Oracle
# Released under the GNU GPLv2
-v="v4.7.1"
+v="v4.7.2"
opt=$1
diff --git a/volumes.c b/volumes.c
index 9a5580ae..2d07e66a 100644
--- a/volumes.c
+++ b/volumes.c
@@ -1614,10 +1614,10 @@ static struct btrfs_device *fill_missing_device(u64 devid)
* slot == -1: SYSTEM chunk
* return -EIO on error, otherwise return 0
*/
-static int btrfs_check_chunk_valid(struct btrfs_root *root,
- struct extent_buffer *leaf,
- struct btrfs_chunk *chunk,
- int slot, u64 logical)
+int btrfs_check_chunk_valid(struct btrfs_root *root,
+ struct extent_buffer *leaf,
+ struct btrfs_chunk *chunk,
+ int slot, u64 logical)
{
u64 length;
u64 stripe_len;
diff --git a/volumes.h b/volumes.h
index af7182b8..d7b7d3cc 100644
--- a/volumes.h
+++ b/volumes.h
@@ -226,4 +226,8 @@ int write_raid56_with_parity(struct btrfs_fs_info *info,
struct extent_buffer *eb,
struct btrfs_multi_bio *multi,
u64 stripe_len, u64 *raid_map);
+int btrfs_check_chunk_valid(struct btrfs_root *root,
+ struct extent_buffer *leaf,
+ struct btrfs_chunk *chunk,
+ int slot, u64 logical);
#endif