summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDimitri John Ledkov <xnox@ubuntu.com>2019-01-26 00:37:47 +0000
committerDimitri John Ledkov <xnox@ubuntu.com>2019-01-26 00:37:47 +0000
commit2fd02b1f5f50d499b8f19d0cc5e9bc9ed7e686cd (patch)
tree7557002a8de5892b17c04d1afcd8fdc99a0af4e7
parent03b9f8baf40383f4c2d709c656ca35bd75362dff (diff)
New upstream release
-rw-r--r--.gitignore1
-rw-r--r--.travis.yml1
-rw-r--r--CHANGES24
-rw-r--r--Documentation/btrfs-balance.88
-rw-r--r--Documentation/btrfs-balance.asciidoc2
-rw-r--r--Documentation/btrfs-check.86
-rw-r--r--Documentation/btrfs-convert.86
-rw-r--r--Documentation/btrfs-device.86
-rw-r--r--Documentation/btrfs-filesystem.86
-rw-r--r--Documentation/btrfs-find-root.86
-rw-r--r--Documentation/btrfs-image.86
-rw-r--r--Documentation/btrfs-inspect-internal.86
-rw-r--r--Documentation/btrfs-man5.asciidoc82
-rw-r--r--Documentation/btrfs-map-logical.86
-rw-r--r--Documentation/btrfs-property.86
-rw-r--r--Documentation/btrfs-qgroup.86
-rw-r--r--Documentation/btrfs-quota.86
-rw-r--r--Documentation/btrfs-receive.86
-rw-r--r--Documentation/btrfs-replace.86
-rw-r--r--Documentation/btrfs-rescue.86
-rw-r--r--Documentation/btrfs-restore.86
-rw-r--r--Documentation/btrfs-scrub.88
-rw-r--r--Documentation/btrfs-scrub.asciidoc5
-rw-r--r--Documentation/btrfs-select-super.86
-rw-r--r--Documentation/btrfs-send.86
-rw-r--r--Documentation/btrfs-subvolume.841
-rw-r--r--Documentation/btrfs-subvolume.asciidoc28
-rw-r--r--Documentation/btrfs.568
-rw-r--r--Documentation/btrfs.86
-rw-r--r--Documentation/btrfstune.8104
-rw-r--r--Documentation/btrfstune.asciidoc81
-rw-r--r--Documentation/fsck.btrfs.86
-rw-r--r--Documentation/mkfs.btrfs.86
-rw-r--r--Makefile14
-rw-r--r--Makefile.extrawarn9
-rw-r--r--VERSION2
-rw-r--r--btrfstune.c251
-rw-r--r--check/main.c235
-rw-r--r--check/mode-common.c51
-rw-r--r--check/mode-common.h4
-rw-r--r--check/mode-lowmem.c89
-rw-r--r--check/mode-lowmem.h1
-rw-r--r--check/mode-original.h14
-rw-r--r--chunk-recover.c18
-rw-r--r--cmds-balance.c5
-rw-r--r--cmds-filesystem.c2
-rw-r--r--cmds-inspect-dump-super.c22
-rw-r--r--cmds-rescue.c4
-rw-r--r--cmds-subvolume.c8
-rwxr-xr-xconfigure18
-rw-r--r--convert/common.c2
-rw-r--r--ctree.c150
-rw-r--r--ctree.h23
-rw-r--r--debian/changelog6
-rw-r--r--debian/patches/python3-use-deb-layout.patch8
-rw-r--r--dir-item.c6
-rw-r--r--disk-io.c156
-rw-r--r--disk-io.h4
-rw-r--r--free-space-tree.c102
-rw-r--r--fsfeatures.c23
-rw-r--r--image/main.c279
-rw-r--r--kernel-shared/ulist.c10
-rw-r--r--libbtrfsutil/python/tests/test_subvolume.py10
-rw-r--r--messages.h4
-rw-r--r--mkfs/main.c129
-rw-r--r--rescue.h21
-rw-r--r--send-stream.c3
-rw-r--r--string-table.c1
-rw-r--r--super-recover.c1
-rwxr-xr-xtests/cli-tests/009-btrfstune/test.sh62
-rwxr-xr-xtests/fsck-tests/015-tree-reloc-tree/test.sh16
-rwxr-xr-xtests/fsck-tests/020-extent-ref-cases/test.sh5
-rw-r--r--tests/fsck-tests/020-extent-ref-cases/tree_reloc_for_data_reloc.img.xz (renamed from tests/fsck-tests/015-tree-reloc-tree/tree_reloc_for_data_reloc.img.xz)bin2112 -> 2112 bytes
-rw-r--r--tests/fsck-tests/020-extent-ref-cases/tree_reloc_for_fs_tree.img.xz (renamed from tests/fsck-tests/015-tree-reloc-tree/tree_reloc_for_fs_tree.img.xz)bin2424 -> 2424 bytes
-rw-r--r--tests/fsck-tests/026-bad-dir-item-name/description.txt41
-rwxr-xr-xtests/fsck-tests/026-bad-dir-item-name/test.sh13
-rw-r--r--tests/fsck-tests/036-bad-dev-extents/over_dev_boundary.img.xzbin0 -> 1640 bytes
-rwxr-xr-xtests/fsck-tests/036-bad-dev-extents/test.sh20
-rwxr-xr-xtests/fsck-tests/037-freespacetree-repair/test.sh7
-rwxr-xr-xtests/misc-tests/021-image-multi-devices/test.sh3
-rw-r--r--tests/misc-tests/034-metadata-uuid/disk1.raw.xzbin0 -> 78336 bytes
-rw-r--r--tests/misc-tests/034-metadata-uuid/disk2.raw.xzbin0 -> 77664 bytes
-rw-r--r--tests/misc-tests/034-metadata-uuid/disk3.raw.xzbin0 -> 78328 bytes
-rw-r--r--tests/misc-tests/034-metadata-uuid/disk4.raw.xzbin0 -> 77592 bytes
-rw-r--r--tests/misc-tests/034-metadata-uuid/disk5.raw.xzbin0 -> 78348 bytes
-rw-r--r--tests/misc-tests/034-metadata-uuid/disk6.raw.xzbin0 -> 77552 bytes
-rwxr-xr-xtests/misc-tests/034-metadata-uuid/test.sh225
-rwxr-xr-xtests/misc-tests/035-receive-common-mount-point-prefix/test.sh48
-rw-r--r--utils-lib.c1
-rw-r--r--utils.c64
-rw-r--r--uuid-tree.c12
-rw-r--r--volumes.c85
-rw-r--r--volumes.h4
93 files changed, 2292 insertions, 572 deletions
diff --git a/.gitignore b/.gitignore
index 82620f3c..d9f022c4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -59,6 +59,7 @@
/Makefile.inc
/tags
+/TAGS
/cscope.out
/cscope.files
/cscope.in.out
diff --git a/.travis.yml b/.travis.yml
index a9953bb3..d714816e 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -73,6 +73,7 @@ addons:
script:
# quick build tests
- "if travis/should-run-test; then docker run -it --env CC=$CC kdave/ci-musl-x86_64 ./test-build $TRAVIS_BRANCH --disable-documentation --disable-backtrace; fi"
+ - "if travis/should-run-test; then make TEST_LOG=dump library-test; fi"
# real tests
- "if travis/should-run-test; then make TEST_LOG=dump test-cli; fi"
- "if travis/should-run-test; then make TEST_LOG=dump test-mkfs; fi"
diff --git a/CHANGES b/CHANGES
index f4017f43..6f8ee276 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,27 @@
+btrfs-progs-4.20.1 (2019-01-23)
+ * libbtrfs: fix build of external tools due to missing symbols
+ * ci: enable library test
+
+btrfs-progs-4.20 (2019-01-19)
+ * new feature: metadata uuid
+ * lightweight change of UUID without rewriting all metadata
+ (incompatible change)
+ * done by btrfstune -m/-M
+ * needs kernel support, 5.0+
+ * image:
+ * fix block groups when restoring from multi-device image
+ * only enlarge result image if it's a regular file
+ * check
+ * more device extent checks and fixes
+ * can repair dir item with mismatched hash
+ * mkfs: uuid tree created with proper contents
+ * fix mount point detection due to partial prefix match
+ * other:
+ * new tests
+ * libbtrfsutil: fix tests if kernel lacks support for new subvolume ioctls
+ * build fixes
+ * doc fixes
+
btrfs-progs-4.19.1 (2018-12-05)
* build fixes
* big-endian builds fail due to bswap helper clashes
diff --git a/Documentation/btrfs-balance.8 b/Documentation/btrfs-balance.8
index c686381c..0fe8a9e5 100644
--- a/Documentation/btrfs-balance.8
+++ b/Documentation/btrfs-balance.8
@@ -2,12 +2,12 @@
.\" Title: btrfs-balance
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 12/05/2018
+.\" Date: 01/23/2019
.\" Manual: Btrfs Manual
-.\" Source: Btrfs v4.19.1
+.\" Source: Btrfs v4.20.1
.\" Language: English
.\"
-.TH "BTRFS\-BALANCE" "8" "12/05/2018" "Btrfs v4\&.19\&.1" "Btrfs Manual"
+.TH "BTRFS\-BALANCE" "8" "01/23/2019" "Btrfs v4\&.20\&.1" "Btrfs Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -229,7 +229,7 @@ be verbose and print balance filter arguments
.PP
\-f
.RS 4
-force reducing of metadata integrity, eg\&. when going from
+force a reduction of metadata integrity, eg\&. when going from
\fIraid1\fR
to
\fIsingle\fR
diff --git a/Documentation/btrfs-balance.asciidoc b/Documentation/btrfs-balance.asciidoc
index 536243bc..bfb76742 100644
--- a/Documentation/btrfs-balance.asciidoc
+++ b/Documentation/btrfs-balance.asciidoc
@@ -101,7 +101,7 @@ act on system chunks (requires '-f'), see `FILTERS` section for details about 'f
-v::::
be verbose and print balance filter arguments
-f::::
-force reducing of metadata integrity, eg. when going from 'raid1' to 'single'
+force a reduction of metadata integrity, eg. when going from 'raid1' to 'single'
--background|--bg::::
run the balance operation asynchronously in the background, uses `fork`(2) to
start the process that calls the kernel ioctl
diff --git a/Documentation/btrfs-check.8 b/Documentation/btrfs-check.8
index da562a57..6cd6fb9a 100644
--- a/Documentation/btrfs-check.8
+++ b/Documentation/btrfs-check.8
@@ -2,12 +2,12 @@
.\" Title: btrfs-check
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 12/05/2018
+.\" Date: 01/23/2019
.\" Manual: Btrfs Manual
-.\" Source: Btrfs v4.19.1
+.\" Source: Btrfs v4.20.1
.\" Language: English
.\"
-.TH "BTRFS\-CHECK" "8" "12/05/2018" "Btrfs v4\&.19\&.1" "Btrfs Manual"
+.TH "BTRFS\-CHECK" "8" "01/23/2019" "Btrfs v4\&.20\&.1" "Btrfs Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/btrfs-convert.8 b/Documentation/btrfs-convert.8
index 7b5239ab..c035ac3d 100644
--- a/Documentation/btrfs-convert.8
+++ b/Documentation/btrfs-convert.8
@@ -2,12 +2,12 @@
.\" Title: btrfs-convert
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 12/05/2018
+.\" Date: 01/23/2019
.\" Manual: Btrfs Manual
-.\" Source: Btrfs v4.19.1
+.\" Source: Btrfs v4.20.1
.\" Language: English
.\"
-.TH "BTRFS\-CONVERT" "8" "12/05/2018" "Btrfs v4\&.19\&.1" "Btrfs Manual"
+.TH "BTRFS\-CONVERT" "8" "01/23/2019" "Btrfs v4\&.20\&.1" "Btrfs Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/btrfs-device.8 b/Documentation/btrfs-device.8
index 082e66a5..c8369f3b 100644
--- a/Documentation/btrfs-device.8
+++ b/Documentation/btrfs-device.8
@@ -2,12 +2,12 @@
.\" Title: btrfs-device
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 12/05/2018
+.\" Date: 01/23/2019
.\" Manual: Btrfs Manual
-.\" Source: Btrfs v4.19.1
+.\" Source: Btrfs v4.20.1
.\" Language: English
.\"
-.TH "BTRFS\-DEVICE" "8" "12/05/2018" "Btrfs v4\&.19\&.1" "Btrfs Manual"
+.TH "BTRFS\-DEVICE" "8" "01/23/2019" "Btrfs v4\&.20\&.1" "Btrfs Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/btrfs-filesystem.8 b/Documentation/btrfs-filesystem.8
index 94e4647d..a305be11 100644
--- a/Documentation/btrfs-filesystem.8
+++ b/Documentation/btrfs-filesystem.8
@@ -2,12 +2,12 @@
.\" Title: btrfs-filesystem
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 12/05/2018
+.\" Date: 01/23/2019
.\" Manual: Btrfs Manual
-.\" Source: Btrfs v4.19.1
+.\" Source: Btrfs v4.20.1
.\" Language: English
.\"
-.TH "BTRFS\-FILESYSTEM" "8" "12/05/2018" "Btrfs v4\&.19\&.1" "Btrfs Manual"
+.TH "BTRFS\-FILESYSTEM" "8" "01/23/2019" "Btrfs v4\&.20\&.1" "Btrfs Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/btrfs-find-root.8 b/Documentation/btrfs-find-root.8
index bda5d689..6b805a40 100644
--- a/Documentation/btrfs-find-root.8
+++ b/Documentation/btrfs-find-root.8
@@ -2,12 +2,12 @@
.\" Title: btrfs-find-root
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 12/05/2018
+.\" Date: 01/23/2019
.\" Manual: Btrfs Manual
-.\" Source: Btrfs v4.19.1
+.\" Source: Btrfs v4.20.1
.\" Language: English
.\"
-.TH "BTRFS\-FIND\-ROOT" "8" "12/05/2018" "Btrfs v4\&.19\&.1" "Btrfs Manual"
+.TH "BTRFS\-FIND\-ROOT" "8" "01/23/2019" "Btrfs v4\&.20\&.1" "Btrfs Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/btrfs-image.8 b/Documentation/btrfs-image.8
index b97b846f..1dc9439f 100644
--- a/Documentation/btrfs-image.8
+++ b/Documentation/btrfs-image.8
@@ -2,12 +2,12 @@
.\" Title: btrfs-image
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 12/05/2018
+.\" Date: 01/23/2019
.\" Manual: Btrfs Manual
-.\" Source: Btrfs v4.19.1
+.\" Source: Btrfs v4.20.1
.\" Language: English
.\"
-.TH "BTRFS\-IMAGE" "8" "12/05/2018" "Btrfs v4\&.19\&.1" "Btrfs Manual"
+.TH "BTRFS\-IMAGE" "8" "01/23/2019" "Btrfs v4\&.20\&.1" "Btrfs Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/btrfs-inspect-internal.8 b/Documentation/btrfs-inspect-internal.8
index 3cd467ac..156a96a9 100644
--- a/Documentation/btrfs-inspect-internal.8
+++ b/Documentation/btrfs-inspect-internal.8
@@ -2,12 +2,12 @@
.\" Title: btrfs-inspect-internal
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 12/05/2018
+.\" Date: 01/23/2019
.\" Manual: Btrfs Manual
-.\" Source: Btrfs v4.19.1
+.\" Source: Btrfs v4.20.1
.\" Language: English
.\"
-.TH "BTRFS\-INSPECT\-INTE" "8" "12/05/2018" "Btrfs v4\&.19\&.1" "Btrfs Manual"
+.TH "BTRFS\-INSPECT\-INTE" "8" "01/23/2019" "Btrfs v4\&.20\&.1" "Btrfs Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/btrfs-man5.asciidoc b/Documentation/btrfs-man5.asciidoc
index c358cef1..916311db 100644
--- a/Documentation/btrfs-man5.asciidoc
+++ b/Documentation/btrfs-man5.asciidoc
@@ -16,9 +16,11 @@ tools. Currently covers:
3. filesystem limits
-4. file attributes
+4. bootloader support
-5. control device
+5. file attributes
+
+6. control device
MOUNT OPTIONS
@@ -585,6 +587,13 @@ 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
+*metadata_uuid*::
+(since: 5.0)
++
+the main filesystem UUID is the metadata_uuid, which stores the new UUID only
+in the superblock while all metadata blocks still have the UUID set at mkfs
+time, see `btrfstune`(8) for more
+
*mixed_backref*::
(since: 2.6.31)
+
@@ -624,6 +633,47 @@ ordinary directory. Note that this feature only depends on the kernel version.
+
reduced-size metadata for extent references, saves a few percent of metadata
+SWAPFILE SUPPORT
+~~~~~~~~~~~~~~~~
+
+The swapfile is supported since kernel 5.0. Use `swapon`(8) to activate the
+swapfile. There are some limitations of the implementation in btrfs and linux
+swap subystem:
++
+* filesystem - must be only single device
+* swapfile - the containing subvolume cannot be snapshotted
+* swapfile - must be preallocated
+* swapfile - must be nodatacow (ie. also nodatasum)
+* swapfile - must not be compressed
++
+The limitations come namely from the COW-based design and mapping layer of
+blocks that allows the advanced features like relocation and multi-device
+filesystems. However, the swap subsystem expects simpler mapping and no
+background changes of the file blocks once they've been attached to swap.
++
+With active swapfiles, the following whole-filesystem operations will skip
+swapfile extents or may fail:
+* balance - block groups with swapfile extents are skipped and reported, the rest will be processed normally
+* resize grow - unaffected
+* resize shrink - works as long as the extents are outside of the shrunk range
+* device add - a new device does not interfere with existing swapfile and this operation will work, though no new swapfile can be activated afterwards
+* device delete - if the device has been added as above, it can be also deleted
+* device replace - dtto
++
+When there are no active swapfiles and a whole-filesystem exclusive operation
+is running (ie. balance, device delete, shrink), the swapfiles cannot be
+temporarily activated. The operation must finish first.
++
+--------------------
+# truncate -s 0 swapfile
+# chattr +C swapfile
+# fallocate -l 2G swapfile
+# chmod 0600 swapfile
+# mkswap swapfile
+# swapon swapfile
+--------------------
+
+
FILESYSTEM LIMITS
-----------------
@@ -632,10 +682,11 @@ maximum file name length::
maximum symlink target length::
depends on the 'nodesize' value, for 4k it's 3949 bytes, for larger nodesize
-it's 4095
+it's 4095 due to the system limit PATH_MAX
+
-The symlink target may not be a valid path, ie the path name components
-can exceed the limits, there's no content validation at `symlink`(3) creation.
+The symlink target may not be a valid path, ie. the path name components
+can exceed the limits (NAME_MAX), there's no content validation at `symlink`(3)
+creation.
maximum number of inodes::
2^64^ but depends on the available metadata space as the inodes are created
@@ -648,15 +699,25 @@ maximum file length::
inherent limit of btrfs is 2^64^ (16 EiB) but the linux VFS limit is 2^63^ (8 EiB)
maximum number of subvolumes::
-2^64^ but depends on the available metadata space, the space consumed by all
-subvolume metadata includes bookkeeping of the shared extents can be large (MiB,
-GiB)
+the subvolume ids can go up to 2^64^ but the number of actual subvolumes
+depends on the available metadata space, the space consumed by all subvolume
+metadata includes bookkeeping of shared extents can be large (MiB, GiB)
maximum number of hardlinks of a file in a directory::
65536 when the `extref` feature is turned on during mkfs (default), roughly
100 otherwise
+BOOTLOADER SUPPORT
+------------------
+
+GRUB2 (https://www.gnu.org/software/grub) has the most advanced support of
+booting from BTRFS with respect to features.
+
+EXTLINUX (from the https://syslinux.org project) can boot but does not support
+all features. Please check the upstream documentation before you use it.
+
+
FILE ATTRIBUTES
---------------
The btrfs filesystem supports setting the following file attributes using the
@@ -708,6 +769,7 @@ When set on a directory, all newly created files will inherit this attribute.
No other attributes are supported. For the complete list please refer to the
`chattr`(1) manual page.
+
CONTROL DEVICE
--------------
@@ -739,6 +801,7 @@ The control device is not strictly required but the device scanning will not
work and a workaround would need to be used to mount a multi-device filesystem.
The mount option 'device' can trigger the device scanning during mount.
+
SEE ALSO
--------
`acl`(5),
@@ -747,4 +810,5 @@ SEE ALSO
`fstrim`(8),
`ioctl`(2),
`mkfs.btrfs`(8),
-`mount`(8)
+`mount`(8),
+`swapon`(8)
diff --git a/Documentation/btrfs-map-logical.8 b/Documentation/btrfs-map-logical.8
index 75f7fd3a..8788ca4c 100644
--- a/Documentation/btrfs-map-logical.8
+++ b/Documentation/btrfs-map-logical.8
@@ -2,12 +2,12 @@
.\" Title: btrfs-map-logical
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 12/05/2018
+.\" Date: 01/23/2019
.\" Manual: Btrfs Manual
-.\" Source: Btrfs v4.19.1
+.\" Source: Btrfs v4.20.1
.\" Language: English
.\"
-.TH "BTRFS\-MAP\-LOGICAL" "8" "12/05/2018" "Btrfs v4\&.19\&.1" "Btrfs Manual"
+.TH "BTRFS\-MAP\-LOGICAL" "8" "01/23/2019" "Btrfs v4\&.20\&.1" "Btrfs Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/btrfs-property.8 b/Documentation/btrfs-property.8
index b8df629e..d43355e1 100644
--- a/Documentation/btrfs-property.8
+++ b/Documentation/btrfs-property.8
@@ -2,12 +2,12 @@
.\" Title: btrfs-property
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 12/05/2018
+.\" Date: 01/23/2019
.\" Manual: Btrfs Manual
-.\" Source: Btrfs v4.19.1
+.\" Source: Btrfs v4.20.1
.\" Language: English
.\"
-.TH "BTRFS\-PROPERTY" "8" "12/05/2018" "Btrfs v4\&.19\&.1" "Btrfs Manual"
+.TH "BTRFS\-PROPERTY" "8" "01/23/2019" "Btrfs v4\&.20\&.1" "Btrfs Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/btrfs-qgroup.8 b/Documentation/btrfs-qgroup.8
index ed01649e..fff31c8d 100644
--- a/Documentation/btrfs-qgroup.8
+++ b/Documentation/btrfs-qgroup.8
@@ -2,12 +2,12 @@
.\" Title: btrfs-qgroup
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 12/05/2018
+.\" Date: 01/23/2019
.\" Manual: Btrfs Manual
-.\" Source: Btrfs v4.19.1
+.\" Source: Btrfs v4.20.1
.\" Language: English
.\"
-.TH "BTRFS\-QGROUP" "8" "12/05/2018" "Btrfs v4\&.19\&.1" "Btrfs Manual"
+.TH "BTRFS\-QGROUP" "8" "01/23/2019" "Btrfs v4\&.20\&.1" "Btrfs Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/btrfs-quota.8 b/Documentation/btrfs-quota.8
index bc2dc239..5854f038 100644
--- a/Documentation/btrfs-quota.8
+++ b/Documentation/btrfs-quota.8
@@ -2,12 +2,12 @@
.\" Title: btrfs-quota
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 12/05/2018
+.\" Date: 01/23/2019
.\" Manual: Btrfs Manual
-.\" Source: Btrfs v4.19.1
+.\" Source: Btrfs v4.20.1
.\" Language: English
.\"
-.TH "BTRFS\-QUOTA" "8" "12/05/2018" "Btrfs v4\&.19\&.1" "Btrfs Manual"
+.TH "BTRFS\-QUOTA" "8" "01/23/2019" "Btrfs v4\&.20\&.1" "Btrfs Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/btrfs-receive.8 b/Documentation/btrfs-receive.8
index acc0dd52..13771d33 100644
--- a/Documentation/btrfs-receive.8
+++ b/Documentation/btrfs-receive.8
@@ -2,12 +2,12 @@
.\" Title: btrfs-receive
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 12/05/2018
+.\" Date: 01/23/2019
.\" Manual: Btrfs Manual
-.\" Source: Btrfs v4.19.1
+.\" Source: Btrfs v4.20.1
.\" Language: English
.\"
-.TH "BTRFS\-RECEIVE" "8" "12/05/2018" "Btrfs v4\&.19\&.1" "Btrfs Manual"
+.TH "BTRFS\-RECEIVE" "8" "01/23/2019" "Btrfs v4\&.20\&.1" "Btrfs Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/btrfs-replace.8 b/Documentation/btrfs-replace.8
index 95baf9c6..a9f639b5 100644
--- a/Documentation/btrfs-replace.8
+++ b/Documentation/btrfs-replace.8
@@ -2,12 +2,12 @@
.\" Title: btrfs-replace
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 12/05/2018
+.\" Date: 01/23/2019
.\" Manual: Btrfs Manual
-.\" Source: Btrfs v4.19.1
+.\" Source: Btrfs v4.20.1
.\" Language: English
.\"
-.TH "BTRFS\-REPLACE" "8" "12/05/2018" "Btrfs v4\&.19\&.1" "Btrfs Manual"
+.TH "BTRFS\-REPLACE" "8" "01/23/2019" "Btrfs v4\&.20\&.1" "Btrfs Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/btrfs-rescue.8 b/Documentation/btrfs-rescue.8
index ccf542a7..87125552 100644
--- a/Documentation/btrfs-rescue.8
+++ b/Documentation/btrfs-rescue.8
@@ -2,12 +2,12 @@
.\" Title: btrfs-rescue
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 12/05/2018
+.\" Date: 01/23/2019
.\" Manual: Btrfs Manual
-.\" Source: Btrfs v4.19.1
+.\" Source: Btrfs v4.20.1
.\" Language: English
.\"
-.TH "BTRFS\-RESCUE" "8" "12/05/2018" "Btrfs v4\&.19\&.1" "Btrfs Manual"
+.TH "BTRFS\-RESCUE" "8" "01/23/2019" "Btrfs v4\&.20\&.1" "Btrfs Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/btrfs-restore.8 b/Documentation/btrfs-restore.8
index db635693..d3bb754b 100644
--- a/Documentation/btrfs-restore.8
+++ b/Documentation/btrfs-restore.8
@@ -2,12 +2,12 @@
.\" Title: btrfs-restore
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 12/05/2018
+.\" Date: 01/23/2019
.\" Manual: Btrfs Manual
-.\" Source: Btrfs v4.19.1
+.\" Source: Btrfs v4.20.1
.\" Language: English
.\"
-.TH "BTRFS\-RESTORE" "8" "12/05/2018" "Btrfs v4\&.19\&.1" "Btrfs Manual"
+.TH "BTRFS\-RESTORE" "8" "01/23/2019" "Btrfs v4\&.20\&.1" "Btrfs Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/btrfs-scrub.8 b/Documentation/btrfs-scrub.8
index a393a553..ce49476b 100644
--- a/Documentation/btrfs-scrub.8
+++ b/Documentation/btrfs-scrub.8
@@ -2,12 +2,12 @@
.\" Title: btrfs-scrub
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 12/05/2018
+.\" Date: 01/23/2019
.\" Manual: Btrfs Manual
-.\" Source: Btrfs v4.19.1
+.\" Source: Btrfs v4.20.1
.\" Language: English
.\"
-.TH "BTRFS\-SCRUB" "8" "12/05/2018" "Btrfs v4\&.19\&.1" "Btrfs Manual"
+.TH "BTRFS\-SCRUB" "8" "01/23/2019" "Btrfs v4\&.20\&.1" "Btrfs Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -48,7 +48,7 @@ btrfs-scrub \- scrub btrfs filesystem, verify block checksums
.ps -1
.br
.sp
-Scrub is not a filesystem checker (fsck) and does not verify nor repair structural damage in the filesystem\&.
+Scrub is not a filesystem checker (fsck) and does not verify nor repair structural damage in the filesystem\&. It really only checks checksums of of data and tree blocks, it doesn\(cqt ensure the content of tree blocks is valid and consistent\&. There\(cqs some validation performed when metadata blocks are read from disk but it\(cqs not extensive and cannot substitute full \fIbtrfs check\fR run\&.
.sp .5v
.RE
.sp
diff --git a/Documentation/btrfs-scrub.asciidoc b/Documentation/btrfs-scrub.asciidoc
index 4c49269e..44022657 100644
--- a/Documentation/btrfs-scrub.asciidoc
+++ b/Documentation/btrfs-scrub.asciidoc
@@ -16,7 +16,10 @@ and metadata blocks from all devices and verify checksums. Automatically repair
corrupted blocks if there's a correct copy available.
NOTE: Scrub is not a filesystem checker (fsck) and does not verify nor repair
-structural damage in the filesystem.
+structural damage in the filesystem. It really only checks checksums of of data
+and tree blocks, it doesn't ensure the content of tree blocks is valid and
+consistent. There's some validation performed when metadata blocks are read
+from disk but it's not extensive and cannot substitute full 'btrfs check' run.
The user is supposed to run it manually or via a periodic system service. The
recommended period is a month but could be less. The estimated device bandwidth
diff --git a/Documentation/btrfs-select-super.8 b/Documentation/btrfs-select-super.8
index e56b290a..7c9a9282 100644
--- a/Documentation/btrfs-select-super.8
+++ b/Documentation/btrfs-select-super.8
@@ -2,12 +2,12 @@
.\" Title: btrfs-select-super
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 12/05/2018
+.\" Date: 01/23/2019
.\" Manual: Btrfs Manual
-.\" Source: Btrfs v4.19.1
+.\" Source: Btrfs v4.20.1
.\" Language: English
.\"
-.TH "BTRFS\-SELECT\-SUPER" "8" "12/05/2018" "Btrfs v4\&.19\&.1" "Btrfs Manual"
+.TH "BTRFS\-SELECT\-SUPER" "8" "01/23/2019" "Btrfs v4\&.20\&.1" "Btrfs Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/btrfs-send.8 b/Documentation/btrfs-send.8
index 1a29bfa0..a720409a 100644
--- a/Documentation/btrfs-send.8
+++ b/Documentation/btrfs-send.8
@@ -2,12 +2,12 @@
.\" Title: btrfs-send
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 12/05/2018
+.\" Date: 01/23/2019
.\" Manual: Btrfs Manual
-.\" Source: Btrfs v4.19.1
+.\" Source: Btrfs v4.20.1
.\" Language: English
.\"
-.TH "BTRFS\-SEND" "8" "12/05/2018" "Btrfs v4\&.19\&.1" "Btrfs Manual"
+.TH "BTRFS\-SEND" "8" "01/23/2019" "Btrfs v4\&.20\&.1" "Btrfs Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/btrfs-subvolume.8 b/Documentation/btrfs-subvolume.8
index 76688bd2..0b0012dd 100644
--- a/Documentation/btrfs-subvolume.8
+++ b/Documentation/btrfs-subvolume.8
@@ -2,12 +2,12 @@
.\" Title: btrfs-subvolume
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 12/05/2018
+.\" Date: 01/23/2019
.\" Manual: Btrfs Manual
-.\" Source: Btrfs v4.19.1
+.\" Source: Btrfs v4.20.1
.\" Language: English
.\"
-.TH "BTRFS\-SUBVOLUME" "8" "12/05/2018" "Btrfs v4\&.19\&.1" "Btrfs Manual"
+.TH "BTRFS\-SUBVOLUME" "8" "01/23/2019" "Btrfs v4\&.20\&.1" "Btrfs Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -308,26 +308,45 @@ or
\fBbtrfs inspect\-internal rootid\fR\&.
.RE
.PP
-\fBshow\fR [options] \fI<path>\fR|\fI<mnt>\fR
+\fBshow\fR [options] \fI<path>\fR
.RS 4
-Show information of a given subvolume in the
-\fI<path>\fR\&.
+Show more information about subvolume
+\fI<path>\fR
+regarding UUIDs, times, generations, flags and related snapshots\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+/mnt/btrfs/subvolume
+ Name: subvolume
+ UUID: 5e076a14\-4e42\-254d\-ac8e\-55bebea982d1
+ Parent UUID: \-
+ Received UUID: \-
+ Creation time: 2018\-01\-01 12:34:56 +0000
+ Subvolume ID: 79
+ Generation: 2844
+ Gen at creation: 2844
+ Parent ID: 5
+ Top level ID: 5
+ Flags: \-
+ Snapshot(s):
+.fi
+.if n \{\
+.RE
+.\}
.sp
\fBOptions\fR
.PP
\-r|\-\-rootid
.RS 4
rootid of the subvolume\&.
+.RE
.PP
\-u|\-\-uuid
.RS 4
UUID of the subvolume\&.
.RE
-.sp
-If no option is specified, subvolume information of
-\fI<path>\fR
-is shown, otherwise the subvolume information of rootid or UUID in the filesystem is shown\&.
-.RE
.RE
.PP
\fBsnapshot\fR [\-r|\-i \fI<qgroupid>\fR] \fI<source>\fR \fI<dest>\fR|[<dest>/]\fI<name>\fR
diff --git a/Documentation/btrfs-subvolume.asciidoc b/Documentation/btrfs-subvolume.asciidoc
index f3eb4e26..49c72e89 100644
--- a/Documentation/btrfs-subvolume.asciidoc
+++ b/Documentation/btrfs-subvolume.asciidoc
@@ -171,21 +171,33 @@ path.
The id can be obtained from *btrfs subvolume list*, *btrfs subvolume show* or
*btrfs inspect-internal rootid*.
-*show* [options] <path>|<mnt>::
-Show information of a given subvolume in the <path>.
+*show* [options] <path>::
+Show more information about subvolume <path> regarding UUIDs, times,
+generations, flags and related snapshots.
++
+----------
+/mnt/btrfs/subvolume
+ Name: subvolume
+ UUID: 5e076a14-4e42-254d-ac8e-55bebea982d1
+ Parent UUID: -
+ Received UUID: -
+ Creation time: 2018-01-01 12:34:56 +0000
+ Subvolume ID: 79
+ Generation: 2844
+ Gen at creation: 2844
+ Parent ID: 5
+ Top level ID: 5
+ Flags: -
+ Snapshot(s):
+----------
+
`Options`
+
-r|--rootid::::
rootid of the subvolume.
--u|--uuid:::
+-u|--uuid::::
UUID of the subvolume.
-+
-If no option is specified, subvolume information of <path> is shown,
-otherwise the subvolume information of rootid or UUID in the filesystem
-is shown.
-
*snapshot* [-r|-i <qgroupid>] <source> <dest>|[<dest>/]<name>::
Create a snapshot of the subvolume <source> with the
name <name> in the <dest> directory.
diff --git a/Documentation/btrfs.5 b/Documentation/btrfs.5
index 433e6dd6..ea2b18ce 100644
--- a/Documentation/btrfs.5
+++ b/Documentation/btrfs.5
@@ -2,12 +2,12 @@
.\" Title: btrfs-man5
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 12/05/2018
+.\" Date: 01/23/2019
.\" Manual: Btrfs Manual
-.\" Source: Btrfs v4.19.1
+.\" Source: Btrfs v4.20.1
.\" Language: English
.\"
-.TH "BTRFS\-MAN5" "5" "12/05/2018" "Btrfs v4\&.19\&.1" "Btrfs Manual"
+.TH "BTRFS\-MAN5" "5" "01/23/2019" "Btrfs v4\&.20\&.1" "Btrfs Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -74,7 +74,7 @@ filesystem limits
.sp -1
.IP " 4." 4.2
.\}
-file attributes
+bootloader support
.RE
.sp
.RS 4
@@ -85,6 +85,17 @@ file attributes
.sp -1
.IP " 5." 4.2
.\}
+file attributes
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 6.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP " 6." 4.2
+.\}
control device
.RE
.SH "MOUNT OPTIONS"
@@ -895,6 +906,14 @@ the default subvolume has been set on the filesystem
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
.RE
.PP
+\fBmetadata_uuid\fR
+.RS 4
+(since: 5\&.0)
+.sp
+the main filesystem UUID is the metadata_uuid, which stores the new UUID only in the superblock while all metadata blocks still have the UUID set at mkfs time, see
+\fBbtrfstune\fR(8) for more
+.RE
+.PP
\fBmixed_backref\fR
.RS 4
(since: 2\&.6\&.31)
@@ -939,6 +958,34 @@ indicate that
.sp
reduced\-size metadata for extent references, saves a few percent of metadata
.RE
+.SS "SWAPFILE SUPPORT"
+.sp
+The swapfile is supported since kernel 5\&.0\&. Use \fBswapon\fR(8) to activate the swapfile\&. There are some limitations of the implementation in btrfs and linux swap subystem:
+.sp
++ * filesystem \- must be only single device * swapfile \- the containing subvolume cannot be snapshotted * swapfile \- must be preallocated * swapfile \- must be nodatacow (ie\&. also nodatasum) * swapfile \- must not be compressed
+.sp
++ The limitations come namely from the COW\-based design and mapping layer of blocks that allows the advanced features like relocation and multi\-device filesystems\&. However, the swap subsystem expects simpler mapping and no background changes of the file blocks once they\(cqve been attached to swap\&.
+.sp
++ With active swapfiles, the following whole\-filesystem operations will skip swapfile extents or may fail: * balance \- block groups with swapfile extents are skipped and reported, the rest will be processed normally * resize grow \- unaffected * resize shrink \- works as long as the extents are outside of the shrunk range * device add \- a new device does not interfere with existing swapfile and this operation will work, though no new swapfile can be activated afterwards * device delete \- if the device has been added as above, it can be also deleted * device replace \- dtto
+.sp
++ When there are no active swapfiles and a whole\-filesystem exclusive operation is running (ie\&. balance, device delete, shrink), the swapfiles cannot be temporarily activated\&. The operation must finish first\&.
+.sp
++
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# truncate \-s 0 swapfile
+# chattr +C swapfile
+# fallocate \-l 2G swapfile
+# chmod 0600 swapfile
+# mkswap swapfile
+# swapon swapfile
+.fi
+.if n \{\
+.RE
+.\}
.SH "FILESYSTEM LIMITS"
.PP
maximum file name length
@@ -950,9 +997,9 @@ maximum symlink target length
.RS 4
depends on the
\fInodesize\fR
-value, for 4k it\(cqs 3949 bytes, for larger nodesize it\(cqs 4095
+value, for 4k it\(cqs 3949 bytes, for larger nodesize it\(cqs 4095 due to the system limit PATH_MAX
.sp
-The symlink target may not be a valid path, ie the path name components can exceed the limits, there\(cqs no content validation at
+The symlink target may not be a valid path, ie\&. the path name components can exceed the limits (NAME_MAX), there\(cqs no content validation at
\fBsymlink\fR(3) creation\&.
.RE
.PP
@@ -973,7 +1020,7 @@ inherent limit of btrfs is 2^64 (16 EiB) but the linux VFS limit is 2^63 (8 EiB)
.PP
maximum number of subvolumes
.RS 4
-2^64 but depends on the available metadata space, the space consumed by all subvolume metadata includes bookkeeping of the shared extents can be large (MiB, GiB)
+the subvolume ids can go up to 2^64 but the number of actual subvolumes depends on the available metadata space, the space consumed by all subvolume metadata includes bookkeeping of shared extents can be large (MiB, GiB)
.RE
.PP
maximum number of hardlinks of a file in a directory
@@ -982,6 +1029,11 @@ maximum number of hardlinks of a file in a directory
\fBextref\fR
feature is turned on during mkfs (default), roughly 100 otherwise
.RE
+.SH "BOOTLOADER SUPPORT"
+.sp
+GRUB2 (\m[blue]\fBhttps://www\&.gnu\&.org/software/grub\fR\m[]) has the most advanced support of booting from BTRFS with respect to features\&.
+.sp
+EXTLINUX (from the \m[blue]\fBhttps://syslinux\&.org\fR\m[] project) can boot but does not support all features\&. Please check the upstream documentation before you use it\&.
.SH "FILE ATTRIBUTES"
.sp
The btrfs filesystem supports setting the following file attributes using the \fBchattr\fR(1) utility:
@@ -1128,4 +1180,4 @@ The device is usually created by a system device node manager (eg\&. udev), but
The control device is not strictly required but the device scanning will not work and a workaround would need to be used to mount a multi\-device filesystem\&. The mount option \fIdevice\fR can trigger the device scanning during mount\&.
.SH "SEE ALSO"
.sp
-\fBacl\fR(5), \fBbtrfs\fR(8), \fBchattr\fR(1), \fBfstrim\fR(8), \fBioctl\fR(2), \fBmkfs\&.btrfs\fR(8), \fBmount\fR(8)
+\fBacl\fR(5), \fBbtrfs\fR(8), \fBchattr\fR(1), \fBfstrim\fR(8), \fBioctl\fR(2), \fBmkfs\&.btrfs\fR(8), \fBmount\fR(8), \fBswapon\fR(8)
diff --git a/Documentation/btrfs.8 b/Documentation/btrfs.8
index 3fc6b0e2..21e7858d 100644
--- a/Documentation/btrfs.8
+++ b/Documentation/btrfs.8
@@ -2,12 +2,12 @@
.\" Title: btrfs
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 12/05/2018
+.\" Date: 01/23/2019
.\" Manual: Btrfs Manual
-.\" Source: Btrfs v4.19.1
+.\" Source: Btrfs v4.20.1
.\" Language: English
.\"
-.TH "BTRFS" "8" "12/05/2018" "Btrfs v4\&.19\&.1" "Btrfs Manual"
+.TH "BTRFS" "8" "01/23/2019" "Btrfs v4\&.20\&.1" "Btrfs Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/btrfstune.8 b/Documentation/btrfstune.8
index b83d9e9d..77351c0a 100644
--- a/Documentation/btrfstune.8
+++ b/Documentation/btrfstune.8
@@ -2,12 +2,12 @@
.\" Title: btrfstune
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 12/05/2018
+.\" Date: 01/23/2019
.\" Manual: Btrfs Manual
-.\" Source: Btrfs v4.19.1
+.\" Source: Btrfs v4.20.1
.\" Language: English
.\"
-.TH "BTRFSTUNE" "8" "12/05/2018" "Btrfs v4\&.19\&.1" "Btrfs Manual"
+.TH "BTRFSTUNE" "8" "01/23/2019" "Btrfs v4\&.20\&.1" "Btrfs Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -41,30 +41,34 @@ The common usecase is to enable features that were not enabled at mkfs time\&. P
Some of the features could be also enabled on a mounted filesystem by other means\&. Please refer to the \fIFILESYSTEM FEATURES\fR in \fBbtrfs\fR(5)\&.
.SH "OPTIONS"
.PP
-\-S \fI<0|1>\fR
+\-f
.RS 4
-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\&.
+Allow dangerous changes, e\&.g\&. clear the seeding flag or change fsid\&. Make sure that you are aware of the dangers\&.
.RE
.PP
-\-r
+\-m
.RS 4
-(since kernel: 3\&.7)
+(since kernel: 5\&.0)
.sp
-Enable extended inode refs (hardlink limit per file in a directory is 65536), enabled by mkfs feature
-\fIextref\fR\&.
+change fsid stored as
+\fImetadata_uuid\fR
+to a randomly generated UUID, see also
+\fI\-U\fR
.RE
.PP
-\-x
+\-M \fI<UUID>\fR
.RS 4
-(since kernel: 3\&.10)
+(since kernel: 5\&.0)
.sp
-Enable skinny metadata extent refs (more efficient representation of extents), enabled by mkfs feature
-\fIskinny\-metadata\fR\&.
+change fsid stored as
+\fImetadata_uuid\fR
+to a given UUID, see also
+\fI\-U\fR
.sp
-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
-\fBbtrfs\-balance\fR(8)\&.
+The metadata_uuid is stored only in the superblock and is a backward incompatible change\&. The fsid in metadata blocks remains unchanged and is not overwritten, thus the whole operation is significantly faster than
+\fI\-U\fR\&.
+.sp
+The new metadata_uuid can be used for mount by UUID and is also used to identify devices of a multi\-device filesystem\&.
.RE
.PP
\-n
@@ -75,9 +79,37 @@ Enable no\-holes feature (more efficient representation of file holes), enabled
\fIno\-holes\fR\&.
.RE
.PP
-\-f
+\-r
.RS 4
-Allow dangerous changes, e\&.g\&. clear the seeding flag or change fsid\&. Make sure that you are aware of the dangers\&.
+(since kernel: 3\&.7)
+.sp
+Enable extended inode refs (hardlink limit per file in a directory is 65536), enabled by mkfs feature
+\fIextref\fR\&.
+.RE
+.PP
+\-S \fI<0|1>\fR
+.RS 4
+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\&.
+.if n \{\
+.sp
+.\}
+.RS 4
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.ps +1
+\fBWarning\fR
+.ps -1
+.br
+Clearing the seeding flag on a device may be dangerous\&. If a previously\-seeding device is changed, all filesystems that used that device will become unmountable\&. Setting the seeding flag back will not fix that\&.
+
+A valid usecase is
+\fIseeding device as a base image\fR\&. Clear the seeding flag, update the filesystem and make it seeding again, provided that it\(cqs OK to throw away all filesystems built on top of the previous base\&.
+.sp .5v
+.RE
.RE
.PP
\-u
@@ -88,7 +120,8 @@ Change fsid to a randomly generated UUID or continue previous fsid change operat
\-U \fI<UUID>\fR
.RS 4
Change fsid to
-\fIUUID\fR\&.
+\fIUUID\fR
+in all metadata blocks\&.
.sp
The
\fIUUID\fR
@@ -98,7 +131,9 @@ should be a 36 bytes string in
\fIUUID\fR
matches the unfinished one or if you use the option
\fI\-u\fR\&.
-.RE
+.sp
+All metadata blocks are rewritten, this may take some time, but the final filesystem compatibility is unaffected, unlike
+\fI\-M\fR\&.
.if n \{\
.sp
.\}
@@ -111,25 +146,22 @@ matches the unfinished one or if you use the option
\fBWarning\fR
.ps -1
.br
-.sp
-Cancelling or interrupting a UUID change operation will make the filesystem temporarily unmountable\&. To fix it, rerun \fIbtrfstune \-u\fR to restore the UUID and let it complete\&.
+Cancelling or interrupting a UUID change operation will make the filesystem temporarily unmountable\&. To fix it, rerun
+\fIbtrfstune \-u\fR
+and let it complete\&.
.sp .5v
.RE
-.if n \{\
-.sp
-.\}
+.RE
+.PP
+\-x
.RS 4
-.it 1 an-trap
-.nr an-no-space-flag 1
-.nr an-break-flag 1
-.br
-.ps +1
-\fBWarning\fR
-.ps -1
-.br
+(since kernel: 3\&.10)
.sp
-Clearing the seeding flag on a device may be dangerous\&. If a previously\-seeding device is changed, all filesystems that used that device will become unmountable\&. Setting the seeding flag back will not fix that\&. A valid usecase is \fIseeding device as a base image\fR\&. Clear the seeding flag, update the filesystem and make it seeding again, provided that it\(cqs OK to throw away all filesystems built on top of the previous base\&.
-.sp .5v
+Enable skinny metadata extent refs (more efficient representation of extents), enabled by mkfs feature
+\fIskinny\-metadata\fR\&.
+.sp
+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
+\fBbtrfs\-balance\fR(8)\&.
.RE
.SH "EXIT STATUS"
.sp
diff --git a/Documentation/btrfstune.asciidoc b/Documentation/btrfstune.asciidoc
index 27100964..1d6bc98d 100644
--- a/Documentation/btrfstune.asciidoc
+++ b/Documentation/btrfstune.asciidoc
@@ -25,26 +25,29 @@ means. Please refer to the 'FILESYSTEM FEATURES' in `btrfs`(5).
OPTIONS
-------
--S <0|1>::
-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)
+-f::
+Allow dangerous changes, e.g. clear the seeding flag or change fsid. Make sure
+that you are aware of the dangers.
+
+-m::
+(since kernel: 5.0)
+
-Enable extended inode refs (hardlink limit per file in a directory is 65536),
-enabled by mkfs feature 'extref'.
+change fsid stored as 'metadata_uuid' to a randomly generated UUID,
+see also '-U'
--x::
-(since kernel: 3.10)
+-M <UUID>::
+(since kernel: 5.0)
+
-Enable skinny metadata extent refs (more efficient representation of extents),
-enabled by mkfs feature 'skinny-metadata'.
+change fsid stored as 'metadata_uuid' to a given UUID, see also '-U'
+
-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).
+The metadata_uuid is stored only in the superblock and is a backward
+incompatible change. The fsid in metadata blocks remains unchanged and
+is not overwritten, thus the whole operation is significantly faster than
+'-U'.
++
+The new metadata_uuid can be used for mount by UUID and is also used to
+identify devices of a multi-device filesystem.
-n::
(since kernel: 3.14)
@@ -52,33 +55,53 @@ the entire filesystem, run a full balance of the metadata. Please refer to
Enable no-holes feature (more efficient representation of file holes), enabled
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.
+-r::
+(since kernel: 3.7)
++
+Enable extended inode refs (hardlink limit per file in a directory is 65536),
+enabled by mkfs feature 'extref'.
+
+-S <0|1>::
+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.
++
+WARNING: Clearing the seeding flag on a device may be dangerous.
+If a previously-seeding device is changed, all filesystems that used that
+device will become unmountable. Setting the seeding flag back will not fix
+that. +
+A valid usecase is 'seeding device as a base image'. Clear the seeding
+flag, update the filesystem and make it seeding again, provided that it's OK
+to throw away all filesystems built on top of the previous base.
-u::
Change fsid to a randomly generated UUID or continue previous fsid change
operation in case it was interrupted.
-U <UUID>::
-Change fsid to 'UUID'.
+Change fsid to 'UUID' in all metadata blocks.
+
The 'UUID' should be a 36 bytes string in `printf`(3) format
'"%08x-%04x-%04x-%04x-%012x"'.
If there is a previous unfinished fsid change, it will continue only if the
'UUID' matches the unfinished one or if you use the option '-u'.
-
++
+All metadata blocks are rewritten, this may take some time, but the final
+filesystem compatibility is unaffected, unlike '-M'.
++
WARNING: Cancelling or interrupting a UUID change operation will make the
-filesystem temporarily unmountable. To fix it, rerun 'btrfstune -u' to restore
-the UUID and let it complete.
+filesystem temporarily unmountable. To fix it, rerun 'btrfstune -u' and let
+it complete.
-WARNING: Clearing the seeding flag on a device may be dangerous.
-If a previously-seeding device is changed, all filesystems that used that
-device will become unmountable. Setting the seeding flag back will not fix
-that. +
-A valid usecase is 'seeding device as a base image'. Clear the seeding
-flag, update the filesystem and make it seeding again, provided that it's OK
-to throw away all filesystems built on top of the previous base.
+-x::
+(since kernel: 3.10)
++
+Enable skinny metadata extent refs (more efficient representation of extents),
+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).
EXIT STATUS
-----------
diff --git a/Documentation/fsck.btrfs.8 b/Documentation/fsck.btrfs.8
index c5bbcc23..32e5a451 100644
--- a/Documentation/fsck.btrfs.8
+++ b/Documentation/fsck.btrfs.8
@@ -2,12 +2,12 @@
.\" Title: fsck.btrfs
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 12/05/2018
+.\" Date: 01/23/2019
.\" Manual: Btrfs Manual
-.\" Source: Btrfs v4.19.1
+.\" Source: Btrfs v4.20.1
.\" Language: English
.\"
-.TH "FSCK\&.BTRFS" "8" "12/05/2018" "Btrfs v4\&.19\&.1" "Btrfs Manual"
+.TH "FSCK\&.BTRFS" "8" "01/23/2019" "Btrfs v4\&.20\&.1" "Btrfs Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/mkfs.btrfs.8 b/Documentation/mkfs.btrfs.8
index fbcd1203..7bc55d11 100644
--- a/Documentation/mkfs.btrfs.8
+++ b/Documentation/mkfs.btrfs.8
@@ -2,12 +2,12 @@
.\" Title: mkfs.btrfs
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 12/05/2018
+.\" Date: 01/23/2019
.\" Manual: Btrfs Manual
-.\" Source: Btrfs v4.19.1
+.\" Source: Btrfs v4.20.1
.\" Language: English
.\"
-.TH "MKFS\&.BTRFS" "8" "12/05/2018" "Btrfs v4\&.19\&.1" "Btrfs Manual"
+.TH "MKFS\&.BTRFS" "8" "01/23/2019" "Btrfs v4\&.20\&.1" "Btrfs Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Makefile b/Makefile
index 8edfb8ad..7100329b 100644
--- a/Makefile
+++ b/Makefile
@@ -44,6 +44,7 @@ $(error Makefile.inc not generated, please configure first)
endif
TAGS_CMD := ctags
+ETAGS_CMD := etags
CSCOPE_CMD := cscope -u -b -c -q
include Makefile.extrawarn
@@ -62,6 +63,10 @@ DEBUG_LDFLAGS :=
ABSTOPDIR = $(shell pwd)
TOPDIR := .
+# Disable certain GCC 8 + glibc 2.28 warning for snprintf()
+# where string truncation for snprintf() is expected.
+DISABLE_WARNING_FLAGS := $(call cc-disable-warning, format-truncation)
+
# Common build flags
CFLAGS = $(SUBST_CFLAGS) \
$(CSTD) \
@@ -73,6 +78,7 @@ CFLAGS = $(SUBST_CFLAGS) \
-I$(TOPDIR) \
-I$(TOPDIR)/kernel-lib \
-I$(TOPDIR)/libbtrfsutil \
+ $(DISABLE_WARNING_FLAGS) \
$(EXTRAWARN_CFLAGS) \
$(DEBUG_CFLAGS_INTERNAL) \
$(EXTRA_CFLAGS)
@@ -597,6 +603,12 @@ tags: FORCE
check/*.[ch] kernel-lib/*.[ch] kernel-shared/*.[ch] \
libbtrfsutil/*.[ch]
+etags: FORCE
+ @echo " [ETAGS] $(ETAGS_CMD)"
+ $(Q)$(ETAGS_CMD) *.[ch] image/*.[ch] convert/*.[ch] mkfs/*.[ch] \
+ check/*.[ch] kernel-lib/*.[ch] kernel-shared/*.[ch] \
+ libbtrfsutil/*.[ch]
+
cscope: FORCE
@echo " [CSCOPE] $(CSCOPE_CMD)"
$(Q)ls -1 *.[ch] image/*.[ch] convert/*.[ch] mkfs/*.[ch] check/*.[ch] \
@@ -633,7 +645,7 @@ clean-gen:
@echo "Cleaning Generated Files"
$(Q)$(RM) -rf -- version.h config.status config.cache config.log \
configure.lineno config.status.lineno Makefile.inc \
- Documentation/Makefile tags \
+ Documentation/Makefile tags TAGS \
cscope.files cscope.out cscope.in.out cscope.po.out \
config.log config.h config.h.in~ aclocal.m4 \
configure autom4te.cache/ config/
diff --git a/Makefile.extrawarn b/Makefile.extrawarn
index 1f4bda94..0c483785 100644
--- a/Makefile.extrawarn
+++ b/Makefile.extrawarn
@@ -19,6 +19,11 @@ try-run = $(shell set -e; \
cc-option = $(call try-run,\
$(CC) $(CFLAGS) $(1) -c -x c /dev/null -o "$$TMP",$(1),$(2))
+# cc-disable-warning
+# Usage: cflags-y += $(call cc-disable-warning,unused-but-set-variable)
+cc-disable-warning = $(call try-run, \
+ $(CC) -Werror $(CFLAGS) -W$(strip $(1)) -c -x c /dev/null -o "$$TMP",-Wno-$(strip $(1)))
+
# From linux.git/scripts/Makefile.extrawarn
# ==========================================================================
#
@@ -47,6 +52,8 @@ warning-1 += -Wold-style-definition
warning-1 += $(call cc-option, -Wmissing-include-dirs)
warning-1 += $(call cc-option, -Wunused-but-set-variable)
warning-1 += $(call cc-disable-warning, missing-field-initializers)
+warning-1 += $(call cc-disable-warning, format-truncation)
+warning-1 += $(call cc-disable-warning, sign-compare)
warning-2 := -Waggregate-return
warning-2 += -Wcast-align
@@ -55,6 +62,7 @@ warning-2 += -Wnested-externs
warning-2 += -Wshadow
warning-2 += $(call cc-option, -Wlogical-op)
warning-2 += $(call cc-option, -Wmissing-field-initializers)
+warning-2 += $(call cc-option, -Wformat-truncation)
warning-3 := -Wbad-function-cast
warning-3 += -Wcast-qual
@@ -66,6 +74,7 @@ warning-3 += -Wredundant-decls
warning-3 += -Wswitch-default
warning-3 += $(call cc-option, -Wpacked-bitfield-compat)
warning-3 += $(call cc-option, -Wvla)
+warning-3 += $(call cc-option, -Wsign-compare)
warning := $(warning-$(findstring 1, $(BUILD_ENABLE_EXTRA_GCC_CHECKS)))
warning += $(warning-$(findstring 2, $(BUILD_ENABLE_EXTRA_GCC_CHECKS)))
diff --git a/VERSION b/VERSION
index 9b56abd2..55562f5e 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-v4.19.1
+v4.20.1
diff --git a/btrfstune.c b/btrfstune.c
index 1e378ba1..7e6d0ac2 100644
--- a/btrfstune.c
+++ b/btrfstune.c
@@ -73,6 +73,116 @@ static int update_seeding_flag(struct btrfs_root *root, int set_flag)
return ret;
}
+/*
+ * Return 0 for no unfinished fsid change.
+ * Return >0 for unfinished fsid change, and restore unfinished fsid/
+ * chunk_tree_id into fsid_ret/chunk_id_ret.
+ */
+static int check_unfinished_fsid_change(struct btrfs_fs_info *fs_info,
+ uuid_t fsid_ret, uuid_t chunk_id_ret)
+{
+ struct btrfs_root *tree_root = fs_info->tree_root;
+ u64 flags = btrfs_super_flags(fs_info->super_copy);
+
+ if (flags & (BTRFS_SUPER_FLAG_CHANGING_FSID |
+ BTRFS_SUPER_FLAG_CHANGING_FSID_V2)) {
+ memcpy(fsid_ret, fs_info->super_copy->fsid, BTRFS_FSID_SIZE);
+ read_extent_buffer(tree_root->node, chunk_id_ret,
+ btrfs_header_chunk_tree_uuid(tree_root->node),
+ BTRFS_UUID_SIZE);
+ return 1;
+ }
+ return 0;
+}
+
+static int set_metadata_uuid(struct btrfs_root *root, const char *uuid_string)
+{
+ struct btrfs_super_block *disk_super;
+ uuid_t new_fsid, unused1, unused2;
+ struct btrfs_trans_handle *trans;
+ bool new_uuid = true;
+ u64 incompat_flags;
+ bool uuid_changed;
+ u64 super_flags;
+ int ret;
+
+ disk_super = root->fs_info->super_copy;
+ super_flags = btrfs_super_flags(disk_super);
+ incompat_flags = btrfs_super_incompat_flags(disk_super);
+ uuid_changed = incompat_flags & BTRFS_FEATURE_INCOMPAT_METADATA_UUID;
+
+ if (super_flags & BTRFS_SUPER_FLAG_SEEDING) {
+ fprintf(stderr, "cannot set metadata UUID on a seed device\n");
+ return 1;
+ }
+
+ if (check_unfinished_fsid_change(root->fs_info, unused1, unused2)) {
+ fprintf(stderr,
+ "UUID rewrite in progress, cannot change fsid\n");
+ return 1;
+ }
+
+ if (uuid_string)
+ uuid_parse(uuid_string, new_fsid);
+ else
+ uuid_generate(new_fsid);
+
+ new_uuid = (memcmp(new_fsid, disk_super->fsid, BTRFS_FSID_SIZE) != 0);
+
+ /* Step 1 sets the in progress flag */
+ trans = btrfs_start_transaction(root, 1);
+ super_flags |= BTRFS_SUPER_FLAG_CHANGING_FSID_V2;
+ btrfs_set_super_flags(disk_super, super_flags);
+ ret = btrfs_commit_transaction(trans, root);
+ if (ret < 0)
+ return ret;
+
+ if (new_uuid && uuid_changed && memcmp(disk_super->metadata_uuid,
+ new_fsid, BTRFS_FSID_SIZE) == 0) {
+ /*
+ * Changing fsid to be the same as metadata uuid, so just
+ * disable the flag
+ */
+ memcpy(disk_super->fsid, &new_fsid, BTRFS_FSID_SIZE);
+ incompat_flags &= ~BTRFS_FEATURE_INCOMPAT_METADATA_UUID;
+ btrfs_set_super_incompat_flags(disk_super, incompat_flags);
+ memset(disk_super->metadata_uuid, 0, BTRFS_FSID_SIZE);
+ } else if (new_uuid && uuid_changed && memcmp(disk_super->metadata_uuid,
+ new_fsid, BTRFS_FSID_SIZE)) {
+ /*
+ * Changing fsid on an already changed FS, in this case we
+ * only change the fsid and don't touch metadata uuid as it
+ * has already the correct value
+ */
+ memcpy(disk_super->fsid, &new_fsid, BTRFS_FSID_SIZE);
+ } else if (new_uuid && !uuid_changed) {
+ /*
+ * First time changing the fsid, copy the fsid to metadata_uuid
+ */
+ incompat_flags |= BTRFS_FEATURE_INCOMPAT_METADATA_UUID;
+ btrfs_set_super_incompat_flags(disk_super, incompat_flags);
+ memcpy(disk_super->metadata_uuid, disk_super->fsid,
+ BTRFS_FSID_SIZE);
+ memcpy(disk_super->fsid, &new_fsid, BTRFS_FSID_SIZE);
+ } else {
+ /* Setting the same fsid as current, do nothing */
+ return 0;
+ }
+
+ trans = btrfs_start_transaction(root, 1);
+
+ /*
+ * Step 2 is to write the metadata_uuid, set the incompat flag and
+ * clear the in progress flag
+ */
+ super_flags &= ~BTRFS_SUPER_FLAG_CHANGING_FSID_V2;
+ btrfs_set_super_flags(disk_super, super_flags);
+
+ /* Then actually copy the metadata uuid and set the incompat bit */
+
+ return btrfs_commit_transaction(trans, root);
+}
+
static int set_super_incompat_flags(struct btrfs_root *root, u64 flags)
{
struct btrfs_trans_handle *trans;
@@ -91,15 +201,15 @@ static int set_super_incompat_flags(struct btrfs_root *root, u64 flags)
return ret;
}
-static int change_buffer_header_uuid(struct extent_buffer *eb)
+static int change_buffer_header_uuid(struct extent_buffer *eb, uuid_t new_fsid)
{
struct btrfs_fs_info *fs_info = eb->fs_info;
int same_fsid = 1;
int same_chunk_tree_uuid = 1;
int ret;
- same_fsid = !memcmp_extent_buffer(eb, fs_info->new_fsid,
- btrfs_header_fsid(), BTRFS_FSID_SIZE);
+ same_fsid = !memcmp_extent_buffer(eb, new_fsid, btrfs_header_fsid(),
+ BTRFS_FSID_SIZE);
same_chunk_tree_uuid =
!memcmp_extent_buffer(eb, fs_info->new_chunk_tree_uuid,
btrfs_header_chunk_tree_uuid(eb),
@@ -107,7 +217,7 @@ static int change_buffer_header_uuid(struct extent_buffer *eb)
if (same_fsid && same_chunk_tree_uuid)
return 0;
if (!same_fsid)
- write_extent_buffer(eb, fs_info->new_fsid, btrfs_header_fsid(),
+ write_extent_buffer(eb, new_fsid, btrfs_header_fsid(),
BTRFS_FSID_SIZE);
if (!same_chunk_tree_uuid)
write_extent_buffer(eb, fs_info->new_chunk_tree_uuid,
@@ -118,7 +228,7 @@ static int change_buffer_header_uuid(struct extent_buffer *eb)
return ret;
}
-static int change_extents_uuid(struct btrfs_fs_info *fs_info)
+static int change_extents_uuid(struct btrfs_fs_info *fs_info, uuid_t new_fsid)
{
struct btrfs_root *root = fs_info->extent_root;
struct btrfs_path path;
@@ -157,7 +267,7 @@ static int change_extents_uuid(struct btrfs_fs_info *fs_info)
ret = PTR_ERR(eb);
goto out;
}
- ret = change_buffer_header_uuid(eb);
+ ret = change_buffer_header_uuid(eb, new_fsid);
free_extent_buffer(eb);
if (ret < 0) {
error("failed to change uuid of tree block: %llu",
@@ -179,29 +289,28 @@ out:
return ret;
}
-static int change_device_uuid(struct extent_buffer *eb, int slot)
+static int change_device_uuid(struct extent_buffer *eb, int slot,
+ uuid_t new_fsid)
{
struct btrfs_dev_item *di;
struct btrfs_fs_info *fs_info = eb->fs_info;
int ret = 0;
di = btrfs_item_ptr(eb, slot, struct btrfs_dev_item);
- if (!memcmp_extent_buffer(eb, fs_info->new_fsid,
+ if (!memcmp_extent_buffer(eb, new_fsid,
(unsigned long)btrfs_device_fsid(di),
BTRFS_FSID_SIZE))
return ret;
- write_extent_buffer(eb, fs_info->new_fsid,
- (unsigned long)btrfs_device_fsid(di),
+ write_extent_buffer(eb, new_fsid, (unsigned long)btrfs_device_fsid(di),
BTRFS_FSID_SIZE);
ret = write_tree_block(NULL, fs_info, eb);
return ret;
}
-static int change_devices_uuid(struct btrfs_fs_info *fs_info)
+static int change_devices_uuid(struct btrfs_root *root, uuid_t new_fsid)
{
- struct btrfs_root *root = fs_info->chunk_root;
struct btrfs_path path;
struct btrfs_key key = {0, 0, 0};
int ret = 0;
@@ -217,7 +326,8 @@ static int change_devices_uuid(struct btrfs_fs_info *fs_info)
if (key.type != BTRFS_DEV_ITEM_KEY ||
key.objectid != BTRFS_DEV_ITEMS_OBJECTID)
goto next;
- ret = change_device_uuid(path.nodes[0], path.slots[0]);
+ ret = change_device_uuid(path.nodes[0], path.slots[0],
+ new_fsid);
if (ret < 0)
goto out;
next:
@@ -234,7 +344,7 @@ out:
return ret;
}
-static int change_fsid_prepare(struct btrfs_fs_info *fs_info)
+static int change_fsid_prepare(struct btrfs_fs_info *fs_info, uuid_t new_fsid)
{
struct btrfs_root *tree_root = fs_info->tree_root;
u64 flags = btrfs_super_flags(fs_info->super_copy);
@@ -243,11 +353,14 @@ static int change_fsid_prepare(struct btrfs_fs_info *fs_info)
flags |= BTRFS_SUPER_FLAG_CHANGING_FSID;
btrfs_set_super_flags(fs_info->super_copy, flags);
- memcpy(fs_info->super_copy->fsid, fs_info->new_fsid, BTRFS_FSID_SIZE);
+ memcpy(fs_info->super_copy->fsid, new_fsid, BTRFS_FSID_SIZE);
ret = write_all_supers(fs_info);
if (ret < 0)
return ret;
+ /* Also need to change the metadatauuid of the fs info */
+ memcpy(fs_info->fs_devices->metadata_uuid, new_fsid, BTRFS_FSID_SIZE);
+
/* also restore new chunk_tree_id into tree_root for restore */
write_extent_buffer(tree_root->node, fs_info->new_chunk_tree_uuid,
btrfs_header_chunk_tree_uuid(tree_root->node),
@@ -265,26 +378,6 @@ static int change_fsid_done(struct btrfs_fs_info *fs_info)
return write_all_supers(fs_info);
}
-/*
- * Return 0 for no unfinished fsid change.
- * Return >0 for unfinished fsid change, and restore unfinished fsid/
- * chunk_tree_id into fsid_ret/chunk_id_ret.
- */
-static int check_unfinished_fsid_change(struct btrfs_fs_info *fs_info,
- uuid_t fsid_ret, uuid_t chunk_id_ret)
-{
- struct btrfs_root *tree_root = fs_info->tree_root;
- u64 flags = btrfs_super_flags(fs_info->super_copy);
-
- if (flags & BTRFS_SUPER_FLAG_CHANGING_FSID) {
- memcpy(fsid_ret, fs_info->super_copy->fsid, BTRFS_FSID_SIZE);
- read_extent_buffer(tree_root->node, chunk_id_ret,
- btrfs_header_chunk_tree_uuid(tree_root->node),
- BTRFS_UUID_SIZE);
- return 1;
- }
- return 0;
-}
/*
* Change fsid of a given fs.
@@ -320,10 +413,9 @@ static int change_uuid(struct btrfs_fs_info *fs_info, const char *new_fsid_str)
uuid_generate(new_chunk_id);
}
- fs_info->new_fsid = new_fsid;
fs_info->new_chunk_tree_uuid = new_chunk_id;
- memcpy(old_fsid, (const char*)fs_info->fsid, BTRFS_UUID_SIZE);
+ memcpy(old_fsid, (const char*)fs_info->fs_devices->fsid, BTRFS_UUID_SIZE);
uuid_unparse(old_fsid, uuid_buf);
printf("Current fsid: %s\n", uuid_buf);
@@ -331,13 +423,13 @@ static int change_uuid(struct btrfs_fs_info *fs_info, const char *new_fsid_str)
printf("New fsid: %s\n", uuid_buf);
/* Now we can begin fsid change */
printf("Set superblock flag CHANGING_FSID\n");
- ret = change_fsid_prepare(fs_info);
+ ret = change_fsid_prepare(fs_info, new_fsid);
if (ret < 0)
goto out;
/* Change extents first */
printf("Change fsid in extents\n");
- ret = change_extents_uuid(fs_info);
+ ret = change_extents_uuid(fs_info, new_fsid);
if (ret < 0) {
error("failed to change UUID of metadata: %d", ret);
goto out;
@@ -345,17 +437,15 @@ static int change_uuid(struct btrfs_fs_info *fs_info, const char *new_fsid_str)
/* Then devices */
printf("Change fsid on devices\n");
- ret = change_devices_uuid(fs_info);
+ ret = change_devices_uuid(fs_info->chunk_root, new_fsid);
if (ret < 0) {
error("failed to change UUID of devices: %d", ret);
goto out;
}
/* Last, change fsid in super */
- memcpy(fs_info->fs_devices->fsid, fs_info->new_fsid,
- BTRFS_FSID_SIZE);
- memcpy(fs_info->super_copy->fsid, fs_info->new_fsid,
- BTRFS_FSID_SIZE);
+ memcpy(fs_info->fs_devices->fsid, new_fsid, BTRFS_FSID_SIZE);
+ memcpy(fs_info->super_copy->fsid, new_fsid, BTRFS_FSID_SIZE);
ret = write_all_supers(fs_info);
if (ret < 0)
goto out;
@@ -363,7 +453,6 @@ static int change_uuid(struct btrfs_fs_info *fs_info, const char *new_fsid_str)
/* Now fsid change is done */
printf("Clear superblock flag CHANGING_FSID\n");
ret = change_fsid_done(fs_info);
- fs_info->new_fsid = NULL;
fs_info->new_chunk_tree_uuid = NULL;
printf("Fsid change finished\n");
out:
@@ -373,13 +462,22 @@ out:
static void print_usage(void)
{
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");
+ printf("Tune settings of filesystem features on an unmounted device\n\n");
+ printf("Options:\n");
+ printf(" change feature status:\n");
+ printf("\t-r enable extended inode refs (mkfs: extref, for hardlink limits)\n");
+ printf("\t-x enable skinny metadata extent refs (mkfs: skinny-metadata)\n");
+ printf("\t-n enable no-holes feature (mkfs: no-holes, more efficient sparse file representation)\n");
+ printf("\t-S <0|1> set/unset seeding status of a device\n");
+ printf(" uuid changes:\n");
+ printf("\t-u rewrite fsid, use a random one\n");
+ printf("\t-U UUID rewrite fsid to UUID\n");
+ printf("\t-m change fsid in metadata_uuid to a random UUID\n");
+ printf("\t (incompat change, more lightweight than -u|-U)\n");
+ printf("\t-M UUID change fsid in metadata_uuid to UUID\n");
+ printf(" general:\n");
+ printf("\t-f allow dangerous operations, make sure that you are aware of the dangers\n");
+ printf("\t--help print this help\n");
}
int main(int argc, char *argv[])
@@ -391,6 +489,7 @@ int main(int argc, char *argv[])
int seeding_flag = 0;
u64 seeding_value = 0;
int random_fsid = 0;
+ int change_metadata_uuid = 0;
char *new_fsid_str = NULL;
int ret;
u64 super_flags = 0;
@@ -401,7 +500,7 @@ int main(int argc, char *argv[])
{ "help", no_argument, NULL, GETOPT_VAL_HELP},
{ NULL, 0, NULL, 0 }
};
- int c = getopt_long(argc, argv, "S:rxfuU:n", long_options, NULL);
+ int c = getopt_long(argc, argv, "S:rxfuU:nmM:", long_options, NULL);
if (c < 0)
break;
@@ -430,6 +529,15 @@ int main(int argc, char *argv[])
ctree_flags |= OPEN_CTREE_IGNORE_FSID_MISMATCH;
random_fsid = 1;
break;
+ case 'M':
+ ctree_flags |= OPEN_CTREE_IGNORE_FSID_MISMATCH;
+ change_metadata_uuid = 1;
+ new_fsid_str = optarg;
+ break;
+ case 'm':
+ ctree_flags |= OPEN_CTREE_IGNORE_FSID_MISMATCH;
+ change_metadata_uuid = 1;
+ break;
case GETOPT_VAL_HELP:
default:
print_usage();
@@ -448,7 +556,8 @@ int main(int argc, char *argv[])
error("random fsid can't be used with specified fsid");
return 1;
}
- if (!super_flags && !seeding_flag && !(random_fsid || new_fsid_str)) {
+ if (!super_flags && !seeding_flag && !(random_fsid || new_fsid_str) &&
+ !change_metadata_uuid) {
error("at least one option should be specified");
print_usage();
return 1;
@@ -495,6 +604,12 @@ int main(int argc, char *argv[])
}
if (seeding_flag) {
+ if (btrfs_fs_incompat(root->fs_info, METADATA_UUID)) {
+ fprintf(stderr, "SEED flag cannot be changed on a metadata-uuid changed fs\n");
+ ret = 1;
+ goto out;
+ }
+
if (!seeding_value && !force) {
warning(
"this is dangerous, clearing the seeding flag may cause the derived device not to be mountable!");
@@ -519,7 +634,33 @@ int main(int argc, char *argv[])
total++;
}
- if (random_fsid || new_fsid_str) {
+ if (change_metadata_uuid) {
+ if (seeding_flag) {
+ fprintf(stderr,
+ "Not allowed to set both seeding flag and uuid metadata\n");
+ ret = 1;
+ goto out;
+ }
+
+ if (new_fsid_str)
+ ret = set_metadata_uuid(root, new_fsid_str);
+ else
+ ret = set_metadata_uuid(root, NULL);
+
+ if (!ret)
+ success++;
+ total++;
+ }
+
+ if (random_fsid || (new_fsid_str && !change_metadata_uuid)) {
+ if (btrfs_fs_incompat(root->fs_info, METADATA_UUID)) {
+ fprintf(stderr,
+ "Cannot rewrite fsid while METADATA_UUID flag is active. \n"
+ "Ensure fsid and metadata_uuid match before retrying.\n");
+ ret = 1;
+ goto out;
+ }
+
if (!force) {
warning(
"it's recommended to run 'btrfs check --readonly' before this operation.\n"
diff --git a/check/main.c b/check/main.c
index db18827b..7547209c 100644
--- a/check/main.c
+++ b/check/main.c
@@ -462,6 +462,8 @@ static struct inode_record *clone_inode_rec(struct inode_record *orig_rec)
struct inode_backref *tmp;
struct orphan_data_extent *src_orphan;
struct orphan_data_extent *dst_orphan;
+ struct mismatch_dir_hash_record *hash_record;
+ struct mismatch_dir_hash_record *new_record;
struct rb_node *rb;
size_t size;
int ret;
@@ -473,6 +475,7 @@ static struct inode_record *clone_inode_rec(struct inode_record *orig_rec)
rec->refs = 1;
INIT_LIST_HEAD(&rec->backrefs);
INIT_LIST_HEAD(&rec->orphan_extents);
+ INIT_LIST_HEAD(&rec->mismatch_dir_hash);
rec->holes = RB_ROOT;
list_for_each_entry(orig, &orig_rec->backrefs, list) {
@@ -494,6 +497,16 @@ static struct inode_record *clone_inode_rec(struct inode_record *orig_rec)
memcpy(dst_orphan, src_orphan, sizeof(*src_orphan));
list_add_tail(&dst_orphan->list, &rec->orphan_extents);
}
+ list_for_each_entry(hash_record, &orig_rec->mismatch_dir_hash, list) {
+ size = sizeof(*hash_record) + hash_record->namelen;
+ new_record = malloc(size);
+ if (!new_record) {
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+ memcpy(&new_record, hash_record, size);
+ list_add_tail(&new_record->list, &rec->mismatch_dir_hash);
+ }
ret = copy_file_extent_holes(&rec->holes, &orig_rec->holes);
if (ret < 0)
goto cleanup_rb;
@@ -522,6 +535,13 @@ cleanup:
list_del(&orig->list);
free(orig);
}
+ if (!list_empty(&rec->mismatch_dir_hash)) {
+ list_for_each_entry_safe(hash_record, new_record,
+ &rec->mismatch_dir_hash, list) {
+ list_del(&hash_record->list);
+ free(hash_record);
+ }
+ }
free(rec);
@@ -621,6 +641,25 @@ static void print_inode_error(struct btrfs_root *root, struct inode_record *rec)
round_up(rec->isize,
root->fs_info->sectorsize));
}
+
+ /* Print dir item with mismatch hash */
+ if (errors & I_ERR_MISMATCH_DIR_HASH) {
+ struct mismatch_dir_hash_record *hash_record;
+
+ fprintf(stderr, "Dir items with mismatch hash:\n");
+ list_for_each_entry(hash_record, &rec->mismatch_dir_hash,
+ list) {
+ char *namebuf = (char *)(hash_record + 1);
+ u32 crc;
+
+ crc = btrfs_name_hash(namebuf, hash_record->namelen);
+ fprintf(stderr,
+ "\tname: %.*s namelen: %u wanted 0x%08x has 0x%08llx\n",
+ hash_record->namelen, namebuf,
+ hash_record->namelen, crc,
+ hash_record->key.offset);
+ }
+ }
}
static void print_ref_error(int errors)
@@ -682,6 +721,7 @@ static struct inode_record *get_inode_rec(struct cache_tree *inode_cache,
rec->refs = 1;
INIT_LIST_HEAD(&rec->backrefs);
INIT_LIST_HEAD(&rec->orphan_extents);
+ INIT_LIST_HEAD(&rec->mismatch_dir_hash);
rec->holes = RB_ROOT;
node = malloc(sizeof(*node));
@@ -718,6 +758,8 @@ static void free_orphan_data_extents(struct list_head *orphan_extents)
static void free_inode_rec(struct inode_record *rec)
{
struct inode_backref *backref;
+ struct mismatch_dir_hash_record *hash;
+ struct mismatch_dir_hash_record *next;
if (--rec->refs > 0)
return;
@@ -727,6 +769,8 @@ static void free_inode_rec(struct inode_record *rec)
list_del(&backref->list);
free(backref);
}
+ list_for_each_entry_safe(hash, next, &rec->mismatch_dir_hash, list)
+ free(hash);
free_orphan_data_extents(&rec->orphan_extents);
free_file_extent_holes(&rec->holes);
free(rec);
@@ -1273,6 +1317,25 @@ out:
return has_parent ? 0 : 2;
}
+static int add_mismatch_dir_hash(struct inode_record *dir_rec,
+ struct btrfs_key *key, const char *namebuf,
+ int namelen)
+{
+ struct mismatch_dir_hash_record *hash_record;
+
+ hash_record = malloc(sizeof(*hash_record) + namelen);
+ if (!hash_record) {
+ error("failed to allocate memory for mismatch dir hash rec");
+ return -ENOMEM;
+ }
+ memcpy(&hash_record->key, key, sizeof(*key));
+ memcpy(hash_record + 1, namebuf, namelen);
+ hash_record->namelen = namelen;
+
+ list_add(&hash_record->list, &dir_rec->mismatch_dir_hash);
+ return 0;
+}
+
static int process_dir_item(struct extent_buffer *eb,
int slot, struct btrfs_key *key,
struct shared_node *active_node)
@@ -1300,6 +1363,8 @@ static int process_dir_item(struct extent_buffer *eb,
di = btrfs_item_ptr(eb, slot, struct btrfs_dir_item);
total = btrfs_item_size_nr(eb, slot);
while (cur < total) {
+ int ret;
+
nritems++;
btrfs_dir_item_key_to_cpu(eb, di, &location);
name_len = btrfs_dir_name_len(eb, di);
@@ -1324,10 +1389,12 @@ static int process_dir_item(struct extent_buffer *eb,
if (key->type == BTRFS_DIR_ITEM_KEY &&
key->offset != btrfs_name_hash(namebuf, len)) {
- rec->errors |= I_ERR_ODD_DIR_ITEM;
- error("DIR_ITEM[%llu %llu] name %s namelen %u filetype %u mismatch with its hash, wanted %llu have %llu",
- key->objectid, key->offset, namebuf, len, filetype,
- key->offset, btrfs_name_hash(namebuf, len));
+ rec->errors |= I_ERR_MISMATCH_DIR_HASH;
+ ret = add_mismatch_dir_hash(rec, key, namebuf, len);
+ /* Fatal error, ENOMEM */
+ if (ret < 0)
+ return ret;
+ goto next;
}
if (location.type == BTRFS_INODE_ITEM_KEY) {
@@ -1348,6 +1415,7 @@ static int process_dir_item(struct extent_buffer *eb,
len, filetype, key->type, error);
}
+next:
len = sizeof(*di) + name_len + data_len;
di = (struct btrfs_dir_item *)((char *)di + len);
cur += len;
@@ -2590,6 +2658,41 @@ out:
return ret;
}
+static int repair_mismatch_dir_hash(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root,
+ struct inode_record *rec)
+{
+ struct mismatch_dir_hash_record *hash;
+ int ret;
+
+ printf(
+ "Deleting bad dir items with invalid hash for root %llu ino %llu\n",
+ root->root_key.objectid, rec->ino);
+ while (!list_empty(&rec->mismatch_dir_hash)) {
+ char *namebuf;
+
+ hash = list_entry(rec->mismatch_dir_hash.next,
+ struct mismatch_dir_hash_record, list);
+ namebuf = (char *)(hash + 1);
+
+ ret = delete_corrupted_dir_item(trans, root, &hash->key,
+ namebuf, hash->namelen);
+ if (ret < 0)
+ break;
+
+ /* Also reduce dir isize */
+ rec->found_size -= hash->namelen;
+ list_del(&hash->list);
+ free(hash);
+ }
+ if (!ret) {
+ rec->errors &= ~I_ERR_MISMATCH_DIR_HASH;
+ /* We rely on later dir isize repair to reset dir isize */
+ rec->errors |= I_ERR_DIR_ISIZE_WRONG;
+ }
+ return ret;
+}
+
static int try_repair_inode(struct btrfs_root *root, struct inode_record *rec)
{
struct btrfs_trans_handle *trans;
@@ -2603,7 +2706,8 @@ static int try_repair_inode(struct btrfs_root *root, struct inode_record *rec)
I_ERR_FILE_EXTENT_ORPHAN |
I_ERR_FILE_EXTENT_DISCOUNT |
I_ERR_FILE_NBYTES_WRONG |
- I_ERR_INLINE_RAM_BYTES_WRONG)))
+ I_ERR_INLINE_RAM_BYTES_WRONG |
+ I_ERR_MISMATCH_DIR_HASH)))
return rec->errors;
/*
@@ -2618,6 +2722,8 @@ static int try_repair_inode(struct btrfs_root *root, struct inode_record *rec)
return PTR_ERR(trans);
btrfs_init_path(&path);
+ if (!ret && rec->errors & I_ERR_MISMATCH_DIR_HASH)
+ ret = repair_mismatch_dir_hash(trans, root, rec);
if (rec->errors & I_ERR_NO_INODE_ITEM)
ret = repair_inode_no_item(trans, root, &path, rec);
if (!ret && rec->errors & I_ERR_FILE_EXTENT_ORPHAN)
@@ -2712,6 +2818,11 @@ static int check_inode_recs(struct btrfs_root *root,
rec = get_inode_rec(inode_cache, root_dirid, 0);
BUG_ON(IS_ERR(rec));
if (rec) {
+ if (repair) {
+ ret = try_repair_inode(root, rec);
+ if (ret < 0)
+ error++;
+ }
ret = check_root_dir(rec);
if (ret) {
fprintf(stderr, "root %llu root dir %llu error\n",
@@ -3362,9 +3473,10 @@ skip_walking:
printf("Try to repair the btree for root %llu\n",
root->root_key.objectid);
ret = repair_btree(root, &corrupt_blocks);
- if (ret < 0)
+ if (ret < 0) {
errno = -ret;
fprintf(stderr, "Failed to repair btree: %m\n");
+ }
if (!ret)
printf("Btree for root %llu is fixed\n",
root->root_key.objectid);
@@ -7944,6 +8056,13 @@ static int check_device_used(struct device_record *dev_rec,
struct device_extent_record *dev_extent_rec;
u64 total_byte = 0;
+ if (dev_rec->byte_used > dev_rec->total_byte) {
+ error(
+ "device %llu has incorrect used bytes %llu > total bytes %llu",
+ dev_rec->devid, dev_rec->byte_used, dev_rec->total_byte);
+ return -EUCLEAN;
+ }
+
cache = search_cache_extent2(&dext_cache->tree, dev_rec->devid, 0);
while (cache) {
dev_extent_rec = container_of(cache,
@@ -8230,6 +8349,102 @@ out:
return ret;
}
+/*
+ * Check if all dev extents are valid (not overlapping nor beyond device
+ * boundary).
+ *
+ * Dev extents <-> chunk cross checking is already done in check_chunks().
+ */
+static int check_dev_extents(struct btrfs_fs_info *fs_info)
+{
+ struct btrfs_path path;
+ struct btrfs_key key;
+ struct btrfs_root *dev_root = fs_info->dev_root;
+ int ret;
+ u64 prev_devid = 0;
+ u64 prev_dev_ext_end = 0;
+
+ btrfs_init_path(&path);
+
+ key.objectid = 1;
+ key.type = BTRFS_DEV_EXTENT_KEY;
+ key.offset = 0;
+
+ ret = btrfs_search_slot(NULL, dev_root, &key, &path, 0, 0);
+ if (ret < 0) {
+ errno = -ret;
+ error("failed to search device tree: %m");
+ goto out;
+ }
+ if (path.slots[0] >= btrfs_header_nritems(path.nodes[0])) {
+ ret = btrfs_next_leaf(dev_root, &path);
+ if (ret < 0) {
+ errno = -ret;
+ error("failed to find next leaf: %m");
+ goto out;
+ }
+ if (ret > 0) {
+ ret = 0;
+ goto out;
+ }
+ }
+
+ while (1) {
+ struct btrfs_dev_extent *dev_ext;
+ struct btrfs_device *dev;
+ u64 devid;
+ u64 physical_offset;
+ u64 physical_len;
+
+ btrfs_item_key_to_cpu(path.nodes[0], &key, path.slots[0]);
+ if (key.type != BTRFS_DEV_EXTENT_KEY)
+ break;
+ dev_ext = btrfs_item_ptr(path.nodes[0], path.slots[0],
+ struct btrfs_dev_extent);
+ devid = key.objectid;
+ physical_offset = key.offset;
+ physical_len = btrfs_dev_extent_length(path.nodes[0], dev_ext);
+
+ dev = btrfs_find_device(fs_info, devid, NULL, NULL);
+ if (!dev) {
+ error("failed to find device with devid %llu", devid);
+ ret = -EUCLEAN;
+ goto out;
+ }
+ if (prev_devid == devid && prev_dev_ext_end > physical_offset) {
+ error(
+"dev extent devid %llu physical offset %llu overlap with previous dev extent end %llu",
+ devid, physical_offset, prev_dev_ext_end);
+ ret = -EUCLEAN;
+ goto out;
+ }
+ if (physical_offset + physical_len > dev->total_bytes) {
+ error(
+"dev extent devid %llu physical offset %llu len %llu is beyond device boudnary %llu",
+ devid, physical_offset, physical_len,
+ dev->total_bytes);
+ ret = -EUCLEAN;
+ goto out;
+ }
+ prev_devid = devid;
+ prev_dev_ext_end = physical_offset + physical_len;
+
+ ret = btrfs_next_item(dev_root, &path);
+ if (ret < 0) {
+ errno = -ret;
+ error("failed to find next leaf: %m");
+ goto out;
+ }
+ if (ret > 0) {
+ ret = 0;
+ break;
+ }
+ }
+out:
+ btrfs_release_path(&path);
+ return ret;
+}
+
static int check_chunks_and_extents(struct btrfs_fs_info *fs_info)
{
struct rb_root dev_cache;
@@ -8324,6 +8539,12 @@ again:
goto out;
}
+ ret = check_dev_extents(fs_info);
+ if (ret < 0) {
+ err = ret;
+ goto out;
+ }
+
ret = check_chunks(&chunk_cache, &block_group_cache,
&dev_extent_cache, NULL, NULL, NULL, 0);
if (ret) {
@@ -8424,7 +8645,7 @@ static int btrfs_fsck_reinit_root(struct btrfs_trans_handle *trans,
btrfs_set_header_backref_rev(c, BTRFS_MIXED_BACKREF_REV);
btrfs_set_header_owner(c, root->root_key.objectid);
- write_extent_buffer(c, root->fs_info->fsid,
+ write_extent_buffer(c, root->fs_info->fs_devices->metadata_uuid,
btrfs_header_fsid(), BTRFS_FSID_SIZE);
write_extent_buffer(c, root->fs_info->chunk_tree_uuid,
diff --git a/check/mode-common.c b/check/mode-common.c
index 2efa4dc5..fed102b0 100644
--- a/check/mode-common.c
+++ b/check/mode-common.c
@@ -744,3 +744,54 @@ void cleanup_excluded_extents(struct btrfs_fs_info *fs_info)
}
fs_info->excluded_extents = NULL;
}
+
+/*
+ * Delete one corrupted dir item whose hash doesn't match its name.
+ *
+ * Since its hash is incorrect, we can't use btrfs_name_hash() to calculate
+ * the search key, but rely on @di_key parameter to do the search.
+ */
+int delete_corrupted_dir_item(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root,
+ struct btrfs_key *di_key, char *namebuf,
+ u32 namelen)
+{
+ struct btrfs_dir_item *di_item;
+ struct btrfs_path path;
+ int ret;
+
+ btrfs_init_path(&path);
+ ret = btrfs_search_slot(trans, root, di_key, &path, 0, 1);
+ if (ret > 0) {
+ error("key (%llu %u %llu) doesn't exist in root %llu",
+ di_key->objectid, di_key->type, di_key->offset,
+ root->root_key.objectid);
+ ret = -ENOENT;
+ goto out;
+ }
+ if (ret < 0) {
+ error("failed to search root %llu: %d",
+ root->root_key.objectid, ret);
+ goto out;
+ }
+
+ di_item = btrfs_match_dir_item_name(root, &path, namebuf, namelen);
+ if (!di_item) {
+ /*
+ * This is possible if the dir_item has incorrect namelen.
+ * But in that case, we shouldn't reach repair path here.
+ */
+ error("no dir item named '%s' found with key (%llu %u %llu)",
+ namebuf, di_key->objectid, di_key->type,
+ di_key->offset);
+ ret = -ENOENT;
+ goto out;
+ }
+ ret = btrfs_delete_one_dir_name(trans, root, &path, di_item);
+ if (ret < 0)
+ error("failed to delete one dir name: %d", ret);
+
+out:
+ btrfs_release_path(&path);
+ return ret;
+}
diff --git a/check/mode-common.h b/check/mode-common.h
index 6b05f8ba..1fb3cda7 100644
--- a/check/mode-common.h
+++ b/check/mode-common.h
@@ -121,5 +121,9 @@ void reset_cached_block_groups(struct btrfs_fs_info *fs_info);
int pin_metadata_blocks(struct btrfs_fs_info *fs_info);
int exclude_metadata_blocks(struct btrfs_fs_info *fs_info);
void cleanup_excluded_extents(struct btrfs_fs_info *fs_info);
+int delete_corrupted_dir_item(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root,
+ struct btrfs_key *di_key, char *namebuf,
+ u32 namelen);
#endif
diff --git a/check/mode-lowmem.c b/check/mode-lowmem.c
index 6fb397ab..fc6228a0 100644
--- a/check/mode-lowmem.c
+++ b/check/mode-lowmem.c
@@ -1474,16 +1474,52 @@ out:
}
/*
+ * A wrapper for delete_corrupted_dir_item(), with support part like
+ * start/commit transaction.
+ */
+static int lowmem_delete_corrupted_dir_item(struct btrfs_root *root,
+ struct btrfs_key *di_key,
+ char *namebuf, u32 name_len)
+{
+ struct btrfs_trans_handle *trans;
+ int ret;
+
+ trans = btrfs_start_transaction(root, 1);
+ if (IS_ERR(trans)) {
+ ret = PTR_ERR(trans);
+ error("failed to start transaction: %d", ret);
+ return ret;
+ }
+
+ ret = delete_corrupted_dir_item(trans, root, di_key, namebuf, name_len);
+ if (ret < 0) {
+ btrfs_abort_transaction(trans, ret);
+ } else {
+ ret = btrfs_commit_transaction(trans, root);
+ if (ret < 0)
+ error("failed to commit transaction: %d", ret);
+ }
+ return ret;
+}
+
+/*
* Call repair_inode_item_missing and repair_ternary_lowmem to repair
*
* Returns error after repair
*/
-static int repair_dir_item(struct btrfs_root *root, u64 dirid, u64 ino,
- u64 index, u8 filetype, char *namebuf, u32 name_len,
- int err)
+static int repair_dir_item(struct btrfs_root *root, struct btrfs_key *di_key,
+ u64 ino, u64 index, u8 filetype, char *namebuf,
+ u32 name_len, int err)
{
+ u64 dirid = di_key->objectid;
int ret;
+ if (err & (DIR_ITEM_HASH_MISMATCH)) {
+ ret = lowmem_delete_corrupted_dir_item(root, di_key, namebuf,
+ name_len);
+ if (!ret)
+ err &= ~(DIR_ITEM_HASH_MISMATCH);
+ }
if (err & INODE_ITEM_MISSING) {
ret = repair_inode_item_missing(root, ino, filetype);
if (!ret)
@@ -1631,11 +1667,12 @@ begin:
if (di_key->type == BTRFS_DIR_ITEM_KEY &&
di_key->offset != btrfs_name_hash(namebuf, len)) {
- err |= -EIO;
error("root %llu DIR_ITEM[%llu %llu] name %s namelen %u filetype %u mismatch with its hash, wanted %llu have %llu",
root->objectid, di_key->objectid, di_key->offset,
namebuf, len, filetype, di_key->offset,
btrfs_name_hash(namebuf, len));
+ tmp_err |= DIR_ITEM_HASH_MISMATCH;
+ goto next;
}
btrfs_dir_item_key_to_cpu(node, di, &location);
@@ -1683,7 +1720,7 @@ begin:
next:
if (tmp_err && repair) {
- ret = repair_dir_item(root, di_key->objectid,
+ ret = repair_dir_item(root, di_key,
location.objectid, index,
imode_to_type(mode), namebuf,
name_len, tmp_err);
@@ -2142,7 +2179,7 @@ out:
error("failed to set nbytes in inode %llu root %llu",
ino, root->root_key.objectid);
else
- printf("Set nbytes in inode item %llu root %llu\n to %llu", ino,
+ printf("Set nbytes in inode item %llu root %llu to %llu\n", ino,
root->root_key.objectid, nbytes);
/* research path */
@@ -4095,6 +4132,8 @@ static int check_dev_item(struct btrfs_fs_info *fs_info,
u64 dev_id;
u64 used;
u64 total = 0;
+ u64 prev_devid = 0;
+ u64 prev_dev_ext_end = 0;
int ret;
dev_item = btrfs_item_ptr(eb, slot, struct btrfs_dev_item);
@@ -4102,6 +4141,12 @@ static int check_dev_item(struct btrfs_fs_info *fs_info,
used = btrfs_device_bytes_used(eb, dev_item);
total_bytes = btrfs_device_total_bytes(eb, dev_item);
+ if (used > total_bytes) {
+ error(
+ "device %llu has incorrect used bytes %llu > total bytes %llu",
+ dev_id, used, total_bytes);
+ return ACCOUNTING_MISMATCH;
+ }
key.objectid = dev_id;
key.type = BTRFS_DEV_EXTENT_KEY;
key.offset = 0;
@@ -4116,8 +4161,16 @@ static int check_dev_item(struct btrfs_fs_info *fs_info,
return REFERENCER_MISSING;
}
- /* Iterate dev_extents to calculate the used space of a device */
+ /*
+ * Iterate dev_extents to calculate the used space of a device
+ *
+ * Also make sure no dev extents overlap and end beyond device boundary
+ */
while (1) {
+ u64 devid;
+ u64 physical_offset;
+ u64 physical_len;
+
if (path.slots[0] >= btrfs_header_nritems(path.nodes[0]))
goto next;
@@ -4129,7 +4182,27 @@ static int check_dev_item(struct btrfs_fs_info *fs_info,
ptr = btrfs_item_ptr(path.nodes[0], path.slots[0],
struct btrfs_dev_extent);
- total += btrfs_dev_extent_length(path.nodes[0], ptr);
+ devid = key.objectid;
+ physical_offset = key.offset;
+ physical_len = btrfs_dev_extent_length(path.nodes[0], ptr);
+
+ if (prev_devid == devid && physical_offset < prev_dev_ext_end) {
+ error(
+"dev extent devid %llu offset %llu len %llu overlap with previous dev extent end %llu",
+ devid, physical_offset, physical_len,
+ prev_dev_ext_end);
+ return ACCOUNTING_MISMATCH;
+ }
+ if (physical_offset + physical_len > total_bytes) {
+ error(
+"dev extent devid %llu offset %llu len %llu is beyond device boundary %llu",
+ devid, physical_offset, physical_len,
+ total_bytes);
+ return ACCOUNTING_MISMATCH;
+ }
+ prev_devid = devid;
+ prev_dev_ext_end = physical_offset + physical_len;
+ total += physical_len;
next:
ret = btrfs_next_item(dev_root, &path);
if (ret)
diff --git a/check/mode-lowmem.h b/check/mode-lowmem.h
index 0ad2a9e3..46b9b191 100644
--- a/check/mode-lowmem.h
+++ b/check/mode-lowmem.h
@@ -45,6 +45,7 @@
#define BG_ACCOUNTING_ERROR (1<<21) /* Block group accounting error */
#define FATAL_ERROR (1<<22) /* Fatal bit for errno */
#define INODE_FLAGS_ERROR (1<<23) /* Invalid inode flags */
+#define DIR_ITEM_HASH_MISMATCH (1<<24) /* Dir item hash mismatch */
/*
* Error bit for low memory mode check.
diff --git a/check/mode-original.h b/check/mode-original.h
index ec2842e0..25ca2741 100644
--- a/check/mode-original.h
+++ b/check/mode-original.h
@@ -188,6 +188,7 @@ struct file_extent_hole {
#define I_ERR_FILE_EXTENT_TOO_LARGE (1 << 15)
#define I_ERR_ODD_INODE_FLAGS (1 << 16)
#define I_ERR_INLINE_RAM_BYTES_WRONG (1 << 17)
+#define I_ERR_MISMATCH_DIR_HASH (1 << 18)
struct inode_record {
struct list_head backrefs;
@@ -213,10 +214,23 @@ struct inode_record {
u64 extent_end;
struct rb_root holes;
struct list_head orphan_extents;
+ struct list_head mismatch_dir_hash;
u32 refs;
};
+/*
+ * To record one dir_item with mismatch hash.
+ *
+ * Since the hash is incorrect, we must record the hash (key).
+ */
+struct mismatch_dir_hash_record {
+ struct list_head list;
+ struct btrfs_key key;
+ int namelen;
+ /* namebuf follows here */
+};
+
struct root_backref {
struct list_head list;
unsigned int found_dir_item:1;
diff --git a/chunk-recover.c b/chunk-recover.c
index 1d30db51..f3e7774e 100644
--- a/chunk-recover.c
+++ b/chunk-recover.c
@@ -40,6 +40,7 @@
#include "utils.h"
#include "btrfsck.h"
#include "commands.h"
+#include "rescue.h"
struct recover_control {
int verbose;
@@ -759,7 +760,7 @@ static int scan_one_device(void *dev_scan_struct)
rc->nodesize)
break;
- if (memcmp_extent_buffer(buf, rc->fs_devices->fsid,
+ if (memcmp_extent_buffer(buf, rc->fs_devices->metadata_uuid,
btrfs_header_fsid(),
BTRFS_FSID_SIZE)) {
bytenr += rc->sectorsize;
@@ -1155,7 +1156,7 @@ static int __rebuild_chunk_root(struct btrfs_trans_handle *trans,
btrfs_set_header_level(cow, 0);
btrfs_set_header_backref_rev(cow, BTRFS_MIXED_BACKREF_REV);
btrfs_set_header_owner(cow, BTRFS_CHUNK_TREE_OBJECTID);
- write_extent_buffer(cow, root->fs_info->fsid,
+ write_extent_buffer(cow, root->fs_info->fs_devices->metadata_uuid,
btrfs_header_fsid(), BTRFS_FSID_SIZE);
write_extent_buffer(cow, root->fs_info->chunk_tree_uuid,
@@ -1192,7 +1193,8 @@ static int __rebuild_device_items(struct btrfs_trans_handle *trans,
btrfs_set_stack_device_io_width(dev_item, dev->io_width);
btrfs_set_stack_device_sector_size(dev_item, dev->sector_size);
memcpy(dev_item->uuid, dev->uuid, BTRFS_UUID_SIZE);
- memcpy(dev_item->fsid, dev->fs_devices->fsid, BTRFS_UUID_SIZE);
+ memcpy(dev_item->fsid, dev->fs_devices->metadata_uuid,
+ BTRFS_FSID_SIZE);
ret = btrfs_insert_item(trans, root, &key,
dev_item, sizeof(*dev_item));
@@ -1432,6 +1434,7 @@ open_ctree_with_broken_chunk(struct recover_control *rc)
struct btrfs_fs_info *fs_info;
struct btrfs_super_block *disk_super;
struct extent_buffer *eb;
+ u64 features;
int ret;
fs_info = btrfs_new_fs_info(1, BTRFS_SUPER_INFO_OFFSET);
@@ -1455,7 +1458,7 @@ open_ctree_with_broken_chunk(struct recover_control *rc)
goto out_devices;
}
- memcpy(fs_info->fsid, &disk_super->fsid, BTRFS_FSID_SIZE);
+ ASSERT(!memcmp(disk_super->fsid, rc->fs_devices->fsid, BTRFS_FSID_SIZE));
fs_info->sectorsize = btrfs_super_sectorsize(disk_super);
fs_info->nodesize = btrfs_super_nodesize(disk_super);
fs_info->stripesize = btrfs_super_stripesize(disk_super);
@@ -1464,6 +1467,13 @@ open_ctree_with_broken_chunk(struct recover_control *rc)
if (ret)
goto out_devices;
+ features = btrfs_super_incompat_flags(disk_super);
+
+ if (features & BTRFS_FEATURE_INCOMPAT_METADATA_UUID)
+ ASSERT(!memcmp(disk_super->metadata_uuid,
+ fs_info->fs_devices->metadata_uuid,
+ BTRFS_FSID_SIZE));
+
btrfs_setup_root(fs_info->chunk_root, fs_info,
BTRFS_CHUNK_TREE_OBJECTID);
diff --git a/cmds-balance.c b/cmds-balance.c
index 6cc26c35..15dc385e 100644
--- a/cmds-balance.c
+++ b/cmds-balance.c
@@ -481,11 +481,12 @@ static int do_balance(const char *path, struct btrfs_ioctl_balance_args *args,
"There may be more info in syslog - try dmesg | tail\n");
ret = 1;
}
+ } else if (ret > 0) {
+ error("balance: %s", btrfs_err_str(ret));
} else {
printf("Done, had to relocate %llu out of %llu chunks\n",
(unsigned long long)args->stat.completed,
(unsigned long long)args->stat.considered);
- ret = 0;
}
out:
@@ -508,7 +509,7 @@ static const char * const cmd_balance_start_usage[] = {
"-m[filters] act on metadata chunks",
"-s[filters] act on system chunks (only under -f)",
"-v be verbose",
- "-f force reducing of metadata integrity",
+ "-f force a reduction of metadata integrity",
"--full-balance do not print warning and do not delay start",
"--background|--bg",
" run the balance as a background process",
diff --git a/cmds-filesystem.c b/cmds-filesystem.c
index d1af21ee..b8beec13 100644
--- a/cmds-filesystem.c
+++ b/cmds-filesystem.c
@@ -173,6 +173,7 @@ static int match_search_item_kernel(u8 *fsid, char *mnt, char *label,
return 0;
}
+/* Search for user visible uuid 'search' in registered filesystems */
static int uuid_search(struct btrfs_fs_devices *fs_devices, const char *search)
{
char uuidbuf[BTRFS_UUID_UNPARSED_SIZE];
@@ -498,6 +499,7 @@ static int copy_fs_devices(struct btrfs_fs_devices *dst,
int ret = 0;
memcpy(dst->fsid, src->fsid, BTRFS_FSID_SIZE);
+ memcpy(dst->metadata_uuid, src->metadata_uuid, BTRFS_FSID_SIZE);
INIT_LIST_HEAD(&dst->devices);
dst->seed = NULL;
diff --git a/cmds-inspect-dump-super.c b/cmds-inspect-dump-super.c
index e965267c..97e9624d 100644
--- a/cmds-inspect-dump-super.c
+++ b/cmds-inspect-dump-super.c
@@ -228,7 +228,8 @@ static struct readable_flag_entry incompat_flags_array[] = {
DEF_INCOMPAT_FLAG_ENTRY(EXTENDED_IREF),
DEF_INCOMPAT_FLAG_ENTRY(RAID56),
DEF_INCOMPAT_FLAG_ENTRY(SKINNY_METADATA),
- DEF_INCOMPAT_FLAG_ENTRY(NO_HOLES)
+ DEF_INCOMPAT_FLAG_ENTRY(NO_HOLES),
+ DEF_INCOMPAT_FLAG_ENTRY(METADATA_UUID)
};
static const int incompat_flags_num = sizeof(incompat_flags_array) /
sizeof(struct readable_flag_entry);
@@ -319,6 +320,10 @@ static void dump_superblock(struct btrfs_super_block *sb, int full)
u8 *p;
u32 csum_size;
u16 csum_type;
+ bool metadata_uuid_present = (btrfs_super_incompat_flags(sb) &
+ BTRFS_FEATURE_INCOMPAT_METADATA_UUID);
+ int cmp_res = 0;
+
csum_type = btrfs_super_csum_type(sb);
csum_size = BTRFS_CSUM_SIZE;
@@ -365,6 +370,12 @@ static void dump_superblock(struct btrfs_super_block *sb, int full)
uuid_unparse(sb->fsid, buf);
printf("fsid\t\t\t%s\n", buf);
+ if (metadata_uuid_present) {
+ uuid_unparse(sb->metadata_uuid, buf);
+ printf("metadata_uuid\t\t%s\n", buf);
+ } else {
+ printf("metadata_uuid\t\t%s\n", buf);
+ }
printf("label\t\t\t");
s = sb->label;
@@ -424,9 +435,14 @@ static void dump_superblock(struct btrfs_super_block *sb, int full)
printf("dev_item.uuid\t\t%s\n", buf);
uuid_unparse(sb->dev_item.fsid, buf);
+ if (metadata_uuid_present) {
+ cmp_res = !memcmp(sb->dev_item.fsid, sb->metadata_uuid,
+ BTRFS_FSID_SIZE);
+ } else {
+ cmp_res = !memcmp(sb->dev_item.fsid, sb->fsid, BTRFS_FSID_SIZE);
+ }
printf("dev_item.fsid\t\t%s %s\n", buf,
- !memcmp(sb->dev_item.fsid, sb->fsid, BTRFS_FSID_SIZE) ?
- "[match]" : "[DON'T MATCH]");
+ cmp_res ? "[match]" : "[DON'T MATCH]");
printf("dev_item.type\t\t%llu\n", (unsigned long long)
btrfs_stack_device_type(&sb->dev_item));
diff --git a/cmds-rescue.c b/cmds-rescue.c
index 01fbdef9..beef9be2 100644
--- a/cmds-rescue.c
+++ b/cmds-rescue.c
@@ -26,15 +26,13 @@
#include "commands.h"
#include "utils.h"
#include "help.h"
+#include "rescue.h"
static const char * const rescue_cmd_group_usage[] = {
"btrfs rescue <command> [options] <path>",
NULL
};
-int btrfs_recover_chunk_tree(const char *path, int verbose, int yes);
-int btrfs_recover_superblocks(const char *path, int verbose, int yes);
-
static const char * const cmd_rescue_chunk_recover_usage[] = {
"btrfs rescue chunk-recover [options] <device>",
"Recover the chunk tree by scanning the devices one by one.",
diff --git a/cmds-subvolume.c b/cmds-subvolume.c
index a8395aac..c69d3705 100644
--- a/cmds-subvolume.c
+++ b/cmds-subvolume.c
@@ -912,13 +912,13 @@ static int cmd_subvol_find_new(int argc, char **argv)
}
static const char * const cmd_subvol_show_usage[] = {
- "btrfs subvolume show [options] <subvol-path>|<mnt>",
- "Show more information about the subvolume",
+ "btrfs subvolume show [options] <path>",
+ "Show more information about the subvolume (UUIDs, generations, times, snapshots)",
"-r|--rootid rootid of the subvolume",
"-u|--uuid uuid of the subvolume",
"",
- "If no option is specified, <subvol-path> will be shown, otherwise",
- "the rootid or uuid are resolved relative to the <mnt> path.",
+ "If no option is specified, subvolume at <path> will be shown, otherwise",
+ "the rootid or uuid are resolved relative to the <path>.",
NULL
};
diff --git a/configure b/configure
index 381ad05a..510a6e6b 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.19.1 .
+# Generated by GNU Autoconf 2.69 for btrfs-progs v4.20.1 .
#
# 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.19.1 '
-PACKAGE_STRING='btrfs-progs v4.19.1 '
+PACKAGE_VERSION='v4.20.1 '
+PACKAGE_STRING='btrfs-progs v4.20.1 '
PACKAGE_BUGREPORT='linux-btrfs@vger.kernel.org'
PACKAGE_URL='http://btrfs.wiki.kernel.org'
@@ -1326,7 +1326,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.19.1 to adapt to many kinds of systems.
+\`configure' configures btrfs-progs v4.20.1 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1391,7 +1391,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of btrfs-progs v4.19.1 :";;
+ short | recursive ) echo "Configuration of btrfs-progs v4.20.1 :";;
esac
cat <<\_ACEOF
@@ -1522,7 +1522,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-btrfs-progs configure v4.19.1
+btrfs-progs configure v4.20.1
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
@@ -1891,7 +1891,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.19.1 , which was
+It was created by btrfs-progs $as_me v4.20.1 , which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
@@ -7357,7 +7357,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.19.1 , which was
+This file was extended by btrfs-progs $as_me v4.20.1 , which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -7420,7 +7420,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.19.1
+btrfs-progs config.status v4.20.1
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"
diff --git a/convert/common.c b/convert/common.c
index a9b24043..04b59019 100644
--- a/convert/common.c
+++ b/convert/common.c
@@ -107,9 +107,11 @@ static int setup_temp_super(int fd, struct btrfs_mkfs_config *cfg,
ret = -EINVAL;
goto out;
}
+ uuid_copy(super->metadata_uuid, super->fsid);
} else {
uuid_generate(super->fsid);
uuid_unparse(super->fsid, cfg->fs_uuid);
+ uuid_copy(super->metadata_uuid, super->fsid);
}
uuid_generate(chunk_uuid);
uuid_unparse(chunk_uuid, cfg->chunk_uuid);
diff --git a/ctree.c b/ctree.c
index 295cd5ed..7cb3f845 100644
--- a/ctree.c
+++ b/ctree.c
@@ -23,6 +23,7 @@
#include "internal.h"
#include "sizes.h"
#include "messages.h"
+#include "volumes.h"
static int split_node(struct btrfs_trans_handle *trans, struct btrfs_root
*root, struct btrfs_path *path, int level);
@@ -134,7 +135,7 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans,
else
btrfs_set_header_owner(cow, new_root_objectid);
- write_extent_buffer(cow, root->fs_info->fsid,
+ write_extent_buffer(cow, root->fs_info->fs_devices->metadata_uuid,
btrfs_header_fsid(), BTRFS_FSID_SIZE);
WARN_ON(btrfs_header_generation(buf) > trans->transid);
@@ -308,7 +309,7 @@ int __btrfs_cow_block(struct btrfs_trans_handle *trans,
else
btrfs_set_header_owner(cow, root->root_key.objectid);
- write_extent_buffer(cow, root->fs_info->fsid,
+ write_extent_buffer(cow, root->fs_info->fs_devices->metadata_uuid,
btrfs_header_fsid(), BTRFS_FSID_SIZE);
WARN_ON(!(buf->flags & EXTENT_BAD_TRANSID) &&
@@ -1532,7 +1533,7 @@ static int noinline insert_new_root(struct btrfs_trans_handle *trans,
btrfs_node_key(lower, &lower_key, 0);
c = btrfs_alloc_free_block(trans, root, root->fs_info->nodesize,
- root->root_key.objectid, &lower_key,
+ root->root_key.objectid, &lower_key,
level, root->node->start, 0);
if (IS_ERR(c))
@@ -1548,7 +1549,7 @@ static int noinline insert_new_root(struct btrfs_trans_handle *trans,
root_add_used(root, root->fs_info->nodesize);
- write_extent_buffer(c, root->fs_info->fsid,
+ write_extent_buffer(c, root->fs_info->fs_devices->metadata_uuid,
btrfs_header_fsid(), BTRFS_FSID_SIZE);
write_extent_buffer(c, root->fs_info->chunk_tree_uuid,
@@ -1669,7 +1670,7 @@ static int split_node(struct btrfs_trans_handle *trans, struct btrfs_root
btrfs_set_header_generation(split, trans->transid);
btrfs_set_header_backref_rev(split, BTRFS_MIXED_BACKREF_REV);
btrfs_set_header_owner(split, root->root_key.objectid);
- write_extent_buffer(split, root->fs_info->fsid,
+ write_extent_buffer(split, root->fs_info->fs_devices->metadata_uuid,
btrfs_header_fsid(), BTRFS_FSID_SIZE);
write_extent_buffer(split, root->fs_info->chunk_tree_uuid,
btrfs_header_chunk_tree_uuid(split),
@@ -2231,7 +2232,7 @@ again:
}
}
}
-
+
if (split == 0)
btrfs_cpu_key_to_disk(&disk_key, ins_key);
else
@@ -2251,7 +2252,7 @@ again:
btrfs_set_header_backref_rev(right, BTRFS_MIXED_BACKREF_REV);
btrfs_set_header_owner(right, root->root_key.objectid);
btrfs_set_header_level(right, 0);
- write_extent_buffer(right, root->fs_info->fsid,
+ write_extent_buffer(right, root->fs_info->fs_devices->metadata_uuid,
btrfs_header_fsid(), BTRFS_FSID_SIZE);
write_extent_buffer(right, root->fs_info->chunk_tree_uuid,
@@ -2966,7 +2967,7 @@ int btrfs_next_sibling_tree_block(struct btrfs_fs_info *fs_info,
struct extent_buffer *next = NULL;
BUG_ON(path->lowest_level + 1 >= BTRFS_MAX_LEVEL);
- while(level < BTRFS_MAX_LEVEL) {
+ do {
if (!path->nodes[level])
return 1;
@@ -2986,7 +2987,7 @@ int btrfs_next_sibling_tree_block(struct btrfs_fs_info *fs_info,
if (!extent_buffer_uptodate(next))
return -EIO;
break;
- }
+ } while (level < BTRFS_MAX_LEVEL);
path->slots[level] = slot;
while(1) {
level--;
@@ -3106,3 +3107,134 @@ int btrfs_next_extent_item(struct btrfs_root *root,
return 0;
}
}
+
+/*
+ * Search uuid tree - unmounted
+ *
+ * return -ENOENT for !found, < 0 for errors, or 0 if an item was found
+ */
+static int btrfs_uuid_tree_lookup(struct btrfs_root *uuid_root, u8 *uuid,
+ u8 type, u64 subid)
+{
+ int ret;
+ struct btrfs_path *path = NULL;
+ struct extent_buffer *eb;
+ int slot;
+ u32 item_size;
+ unsigned long offset;
+ struct btrfs_key key;
+
+ if (!uuid_root) {
+ ret = -ENOENT;
+ goto out;
+ }
+
+ path = btrfs_alloc_path();
+ if (!path) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ btrfs_uuid_to_key(uuid, &key.objectid, &key.offset);
+ key.type = type;
+ ret = btrfs_search_slot(NULL, uuid_root, &key, path, 0, 0);
+ if (ret < 0) {
+ goto out;
+ } else if (ret > 0) {
+ ret = -ENOENT;
+ goto out;
+ }
+
+ eb = path->nodes[0];
+ slot = path->slots[0];
+ item_size = btrfs_item_size_nr(eb, slot);
+ offset = btrfs_item_ptr_offset(eb, slot);
+ ret = -ENOENT;
+
+ if (!IS_ALIGNED(item_size, sizeof(u64))) {
+ warning("uuid item with invalid size %lu!",
+ (unsigned long)item_size);
+ goto out;
+ }
+ while (item_size) {
+ __le64 data;
+
+ read_extent_buffer(eb, &data, offset, sizeof(data));
+ if (le64_to_cpu(data) == subid) {
+ ret = 0;
+ break;
+ }
+ offset += sizeof(data);
+ item_size -= sizeof(data);
+ }
+
+out:
+ btrfs_free_path(path);
+ return ret;
+}
+
+int btrfs_uuid_tree_add(struct btrfs_trans_handle *trans, u8 *uuid, u8 type,
+ u64 subvol_id_cpu)
+{
+ struct btrfs_fs_info *fs_info = trans->fs_info;
+ struct btrfs_root *uuid_root = fs_info->uuid_root;
+ int ret;
+ struct btrfs_path *path = NULL;
+ struct btrfs_key key;
+ struct extent_buffer *eb;
+ int slot;
+ unsigned long offset;
+ __le64 subvol_id_le;
+
+ if (!uuid_root) {
+ warning("%s: uuid root is not initialized", __func__);
+ return -EINVAL;
+ }
+
+ ret = btrfs_uuid_tree_lookup(uuid_root, uuid, type, subvol_id_cpu);
+ if (ret != -ENOENT)
+ return ret;
+
+ key.type = type;
+ btrfs_uuid_to_key(uuid, &key.objectid, &key.offset);
+
+ path = btrfs_alloc_path();
+ if (!path) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ret = btrfs_insert_empty_item(trans, uuid_root, path, &key,
+ sizeof(subvol_id_le));
+ if (ret >= 0) {
+ /* Add an item for the type for the first time */
+ eb = path->nodes[0];
+ slot = path->slots[0];
+ offset = btrfs_item_ptr_offset(eb, slot);
+ } else if (ret == -EEXIST) {
+ /*
+ * An item with that type already exists.
+ * Extend the item and store the new subvol_id at the end.
+ */
+ btrfs_extend_item(uuid_root, path, sizeof(subvol_id_le));
+ eb = path->nodes[0];
+ slot = path->slots[0];
+ offset = btrfs_item_ptr_offset(eb, slot);
+ offset += btrfs_item_size_nr(eb, slot) - sizeof(subvol_id_le);
+ } else if (ret < 0) {
+ warning(
+ "inserting uuid item failed (0x%016llx, 0x%016llx) type %u: %d",
+ (unsigned long long)key.objectid,
+ (unsigned long long)key.offset, type, ret);
+ goto out;
+ }
+
+ ret = 0;
+ subvol_id_le = cpu_to_le64(subvol_id_cpu);
+ write_extent_buffer(eb, &subvol_id_le, offset, sizeof(subvol_id_le));
+ btrfs_mark_buffer_dirty(eb);
+
+out:
+ btrfs_free_path(path);
+ return ret;
+}
diff --git a/ctree.h b/ctree.h
index f9c49d60..abc20e28 100644
--- a/ctree.h
+++ b/ctree.h
@@ -330,6 +330,7 @@ static inline unsigned long btrfs_chunk_item_size(int num_stripes)
#define BTRFS_SUPER_FLAG_METADUMP (1ULL << 33)
#define BTRFS_SUPER_FLAG_METADUMP_V2 (1ULL << 34)
#define BTRFS_SUPER_FLAG_CHANGING_FSID (1ULL << 35)
+#define BTRFS_SUPER_FLAG_CHANGING_FSID_V2 (1ULL << 36)
#define BTRFS_BACKREF_REV_MAX 256
#define BTRFS_BACKREF_REV_SHIFT 56
@@ -454,8 +455,9 @@ struct btrfs_super_block {
__le64 cache_generation;
__le64 uuid_tree_generation;
+ u8 metadata_uuid[BTRFS_FSID_SIZE];
/* future expansion */
- __le64 reserved[30];
+ __le64 reserved[28];
u8 sys_chunk_array[BTRFS_SYSTEM_CHUNK_ARRAY_SIZE];
struct btrfs_root_backup super_roots[BTRFS_NUM_BACKUP_ROOTS];
} __attribute__ ((__packed__));
@@ -489,6 +491,7 @@ struct btrfs_super_block {
#define BTRFS_FEATURE_INCOMPAT_RAID56 (1ULL << 7)
#define BTRFS_FEATURE_INCOMPAT_SKINNY_METADATA (1ULL << 8)
#define BTRFS_FEATURE_INCOMPAT_NO_HOLES (1ULL << 9)
+#define BTRFS_FEATURE_INCOMPAT_METADATA_UUID (1ULL << 10)
#define BTRFS_FEATURE_COMPAT_SUPP 0ULL
@@ -511,7 +514,8 @@ struct btrfs_super_block {
BTRFS_FEATURE_INCOMPAT_RAID56 | \
BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS | \
BTRFS_FEATURE_INCOMPAT_SKINNY_METADATA | \
- BTRFS_FEATURE_INCOMPAT_NO_HOLES)
+ BTRFS_FEATURE_INCOMPAT_NO_HOLES | \
+ BTRFS_FEATURE_INCOMPAT_METADATA_UUID)
/*
* A leaf is full of items. offset and size tell us where to find
@@ -1089,8 +1093,6 @@ struct btrfs_block_group_cache {
struct btrfs_device;
struct btrfs_fs_devices;
struct btrfs_fs_info {
- u8 fsid[BTRFS_FSID_SIZE];
- u8 *new_fsid;
u8 chunk_tree_uuid[BTRFS_UUID_SIZE];
u8 *new_chunk_tree_uuid;
struct btrfs_root *fs_root;
@@ -1101,6 +1103,7 @@ struct btrfs_fs_info {
struct btrfs_root *csum_root;
struct btrfs_root *quota_root;
struct btrfs_root *free_space_root;
+ struct btrfs_root *uuid_root;
struct rb_root fs_root_tree;
@@ -2720,6 +2723,10 @@ int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans,
struct btrfs_root *root, const char *name,
u16 name_len, const void *data, u16 data_len,
u64 dir);
+struct btrfs_dir_item *btrfs_match_dir_item_name(struct btrfs_root *root,
+ struct btrfs_path *path,
+ const char *name, int name_len);
+
/* inode-map.c */
int btrfs_find_free_objectid(struct btrfs_trans_handle *trans,
struct btrfs_root *fs_root,
@@ -2774,11 +2781,15 @@ int btrfs_csum_truncate(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct btrfs_path *path,
u64 isize);
-/* uuid-tree.c */
+/* uuid-tree.c, interface for mounted mounted filesystem */
int btrfs_lookup_uuid_subvol_item(int fd, const u8 *uuid, u64 *subvol_id);
int btrfs_lookup_uuid_received_subvol_item(int fd, const u8 *uuid,
u64 *subvol_id);
+/* uuid-tree.c, interface for unmounte filesystem */
+int btrfs_uuid_tree_add(struct btrfs_trans_handle *trans, u8 *uuid, u8 type,
+ u64 subvol_id_cpu);
+
static inline int is_fstree(u64 rootid)
{
if (rootid == BTRFS_FS_TREE_OBJECTID ||
@@ -2787,6 +2798,8 @@ static inline int is_fstree(u64 rootid)
return 0;
}
+void btrfs_uuid_to_key(const u8 *uuid, u64 *key_objectid, u64 *key_offset);
+
/* inode.c */
int check_dir_conflict(struct btrfs_root *root, char *name, int namelen,
u64 dir, u64 index);
diff --git a/debian/changelog b/debian/changelog
index 8f30355b..ca405e4d 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+btrfs-progs (4.20.1-1) unstable; urgency=medium
+
+ * New upstream release
+
+ -- Dimitri John Ledkov <xnox@ubuntu.com> Sat, 26 Jan 2019 00:34:29 +0000
+
btrfs-progs (4.19.1-2) unstable; urgency=medium
* Rebuild with libzstd support on.
diff --git a/debian/patches/python3-use-deb-layout.patch b/debian/patches/python3-use-deb-layout.patch
index c44773ce..fed530fa 100644
--- a/debian/patches/python3-use-deb-layout.patch
+++ b/debian/patches/python3-use-deb-layout.patch
@@ -3,11 +3,11 @@ Author: Dimitri John Ledkov <xnox@ubuntu.com>
Forwarded: not-needed
Last-Update: 2018-05-14
-Index: btrfs-progs/Makefile
+Index: btrfs-progs-4.20.1/Makefile
===================================================================
---- btrfs-progs.orig/Makefile
-+++ btrfs-progs/Makefile
-@@ -668,7 +668,7 @@ endif
+--- btrfs-progs-4.20.1.orig/Makefile
++++ btrfs-progs-4.20.1/Makefile
+@@ -680,7 +680,7 @@ endif
ifeq ($(PYTHON_BINDINGS),1)
install_python: libbtrfsutil_python
$(Q)cd libbtrfsutil/python; \
diff --git a/dir-item.c b/dir-item.c
index d64f71e3..fa69dd1d 100644
--- a/dir-item.c
+++ b/dir-item.c
@@ -22,10 +22,6 @@
#include "hash.h"
#include "transaction.h"
-static struct btrfs_dir_item *btrfs_match_dir_item_name(struct btrfs_root *root,
- struct btrfs_path *path,
- const char *name, int name_len);
-
static struct btrfs_dir_item *insert_with_overflow(struct btrfs_trans_handle
*trans,
struct btrfs_root *root,
@@ -323,7 +319,7 @@ static int verify_dir_item(struct btrfs_root *root,
return 0;
}
-static struct btrfs_dir_item *btrfs_match_dir_item_name(struct btrfs_root *root,
+struct btrfs_dir_item *btrfs_match_dir_item_name(struct btrfs_root *root,
struct btrfs_path *path,
const char *name, int name_len)
{
diff --git a/disk-io.c b/disk-io.c
index 5fafa144..797b9b79 100644
--- a/disk-io.c
+++ b/disk-io.c
@@ -55,8 +55,9 @@ static int check_tree_block(struct btrfs_fs_info *fs_info,
struct extent_buffer *buf)
{
- struct btrfs_fs_devices *fs_devices;
+ struct btrfs_fs_devices *fs_devices = fs_info->fs_devices;
u32 nodesize = fs_info->nodesize;
+ bool fsid_match = false;
int ret = BTRFS_BAD_FSID;
if (buf->start != btrfs_header_bytenr(buf))
@@ -72,12 +73,26 @@ static int check_tree_block(struct btrfs_fs_info *fs_info,
btrfs_header_level(buf) != 0)
return BTRFS_BAD_NRITEMS;
- fs_devices = fs_info->fs_devices;
while (fs_devices) {
- if (fs_info->ignore_fsid_mismatch ||
- !memcmp_extent_buffer(buf, fs_devices->fsid,
- btrfs_header_fsid(),
- BTRFS_FSID_SIZE)) {
+ /*
+ * Checking the incompat flag is only valid for the current
+ * fs. For seed devices it's forbidden to have their uuid
+ * changed so reading ->fsid in this case is fine
+ */
+ if (fs_devices == fs_info->fs_devices &&
+ btrfs_fs_incompat(fs_info, METADATA_UUID))
+ fsid_match = !memcmp_extent_buffer(buf,
+ fs_devices->metadata_uuid,
+ btrfs_header_fsid(),
+ BTRFS_FSID_SIZE);
+ else
+ fsid_match = !memcmp_extent_buffer(buf,
+ fs_devices->fsid,
+ btrfs_header_fsid(),
+ BTRFS_FSID_SIZE);
+
+
+ if (fs_info->ignore_fsid_mismatch || fsid_match) {
ret = 0;
break;
}
@@ -103,7 +118,7 @@ static void print_tree_block_error(struct btrfs_fs_info *fs_info,
read_extent_buffer(eb, buf, btrfs_header_fsid(),
BTRFS_UUID_SIZE);
uuid_unparse(buf, found_uuid);
- uuid_unparse(fs_info->fsid, fs_uuid);
+ uuid_unparse(fs_info->fs_devices->metadata_uuid, fs_uuid);
fprintf(stderr, "fsid mismatch, want=%s, have=%s\n",
fs_uuid, found_uuid);
break;
@@ -638,8 +653,7 @@ static int btrfs_fs_roots_compare_objectids(struct rb_node *node,
return 0;
}
-static int btrfs_fs_roots_compare_roots(struct rb_node *node1,
- struct rb_node *node2)
+int btrfs_fs_roots_compare_roots(struct rb_node *node1, struct rb_node *node2)
{
struct btrfs_root *root;
@@ -665,6 +679,8 @@ struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info,
return fs_info->dev_root;
if (location->objectid == BTRFS_CSUM_TREE_OBJECTID)
return fs_info->csum_root;
+ if (location->objectid == BTRFS_UUID_TREE_OBJECTID)
+ return fs_info->uuid_root ? fs_info->uuid_root : ERR_PTR(-ENOENT);
if (location->objectid == BTRFS_QUOTA_TREE_OBJECTID)
return fs_info->quota_enabled ? fs_info->quota_root :
ERR_PTR(-ENOENT);
@@ -701,6 +717,7 @@ void btrfs_free_fs_info(struct btrfs_fs_info *fs_info)
free(fs_info->dev_root);
free(fs_info->csum_root);
free(fs_info->free_space_root);
+ free(fs_info->uuid_root);
free(fs_info->super_copy);
free(fs_info->log_root_tree);
free(fs_info);
@@ -721,12 +738,14 @@ struct btrfs_fs_info *btrfs_new_fs_info(int writable, u64 sb_bytenr)
fs_info->csum_root = calloc(1, sizeof(struct btrfs_root));
fs_info->quota_root = calloc(1, sizeof(struct btrfs_root));
fs_info->free_space_root = calloc(1, sizeof(struct btrfs_root));
+ fs_info->uuid_root = calloc(1, sizeof(struct btrfs_root));
fs_info->super_copy = calloc(1, BTRFS_SUPER_INFO_SIZE);
if (!fs_info->tree_root || !fs_info->extent_root ||
!fs_info->chunk_root || !fs_info->dev_root ||
!fs_info->csum_root || !fs_info->quota_root ||
- !fs_info->free_space_root || !fs_info->super_copy)
+ !fs_info->free_space_root || !fs_info->uuid_root ||
+ !fs_info->super_copy)
goto free_all;
extent_io_tree_init(&fs_info->extent_cache);
@@ -896,6 +915,15 @@ int btrfs_setup_all_roots(struct btrfs_fs_info *fs_info, u64 root_tree_bytenr,
return ret;
fs_info->csum_root->track_dirty = 1;
+ ret = find_and_setup_root(root, fs_info, BTRFS_UUID_TREE_OBJECTID,
+ fs_info->uuid_root);
+ if (ret) {
+ free(fs_info->uuid_root);
+ fs_info->uuid_root = NULL;
+ } else {
+ fs_info->uuid_root->track_dirty = 1;
+ }
+
ret = find_and_setup_root(root, fs_info, BTRFS_QUOTA_TREE_OBJECTID,
fs_info->quota_root);
if (ret) {
@@ -964,6 +992,8 @@ void btrfs_release_all_roots(struct btrfs_fs_info *fs_info)
free_extent_buffer(fs_info->log_root_tree->node);
if (fs_info->chunk_root)
free_extent_buffer(fs_info->chunk_root->node);
+ if (fs_info->uuid_root)
+ free_extent_buffer(fs_info->uuid_root->node);
}
static void free_map_lookup(struct cache_extent *ce)
@@ -1169,7 +1199,12 @@ static struct btrfs_fs_info *__open_ctree_fd(int fp, const char *path,
goto out_devices;
}
- memcpy(fs_info->fsid, &disk_super->fsid, BTRFS_FSID_SIZE);
+ ASSERT(!memcmp(disk_super->fsid, fs_devices->fsid, BTRFS_FSID_SIZE));
+ ASSERT(!memcmp(disk_super->fsid, fs_devices->fsid, BTRFS_FSID_SIZE));
+ if (btrfs_fs_incompat(fs_info, METADATA_UUID))
+ ASSERT(!memcmp(disk_super->metadata_uuid,
+ fs_devices->metadata_uuid, BTRFS_FSID_SIZE));
+
fs_info->sectorsize = btrfs_super_sectorsize(disk_super);
fs_info->nodesize = btrfs_super_nodesize(disk_super);
fs_info->stripesize = btrfs_super_stripesize(disk_super);
@@ -1290,6 +1325,7 @@ static int check_super(struct btrfs_super_block *sb, unsigned sbflags)
u32 crc;
u16 csum_type;
int csum_size;
+ u8 *metadata_uuid;
if (btrfs_super_magic(sb) != BTRFS_MAGIC) {
if (btrfs_super_magic(sb) == BTRFS_MAGIC_TEMPORARY) {
@@ -1378,11 +1414,16 @@ static int check_super(struct btrfs_super_block *sb, unsigned sbflags)
goto error_out;
}
- if (memcmp(sb->fsid, sb->dev_item.fsid, BTRFS_UUID_SIZE) != 0) {
+ if (btrfs_super_incompat_flags(sb) & BTRFS_FEATURE_INCOMPAT_METADATA_UUID)
+ metadata_uuid = sb->metadata_uuid;
+ else
+ metadata_uuid = sb->fsid;
+
+ if (memcmp(metadata_uuid, sb->dev_item.fsid, BTRFS_FSID_SIZE) != 0) {
char fsid[BTRFS_UUID_UNPARSED_SIZE];
char dev_fsid[BTRFS_UUID_UNPARSED_SIZE];
- uuid_unparse(sb->fsid, fsid);
+ uuid_unparse(sb->metadata_uuid, fsid);
uuid_unparse(sb->dev_item.fsid, dev_fsid);
if (sbflags & SBREAD_IGNORE_FSID_MISMATCH) {
warning("ignored: dev_item fsid mismatch: %s != %s",
@@ -1454,6 +1495,7 @@ int btrfs_read_dev_super(int fd, struct btrfs_super_block *sb, u64 sb_bytenr,
unsigned sbflags)
{
u8 fsid[BTRFS_FSID_SIZE];
+ u8 metadata_uuid[BTRFS_FSID_SIZE];
int fsid_is_initialized = 0;
char tmp[BTRFS_SUPER_INFO_SIZE];
struct btrfs_super_block *buf = (struct btrfs_super_block *)tmp;
@@ -1461,6 +1503,7 @@ int btrfs_read_dev_super(int fd, struct btrfs_super_block *sb, u64 sb_bytenr,
int ret;
int max_super = sbflags & SBREAD_RECOVER ? BTRFS_SUPER_MIRROR_MAX : 1;
u64 transid = 0;
+ bool metadata_uuid_set = false;
u64 bytenr;
if (sb_bytenr != BTRFS_SUPER_INFO_OFFSET) {
@@ -1505,9 +1548,18 @@ int btrfs_read_dev_super(int fd, struct btrfs_super_block *sb, u64 sb_bytenr,
continue;
if (!fsid_is_initialized) {
+ if (btrfs_super_incompat_flags(buf) &
+ BTRFS_FEATURE_INCOMPAT_METADATA_UUID) {
+ metadata_uuid_set = true;
+ memcpy(metadata_uuid, buf->metadata_uuid,
+ sizeof(metadata_uuid));
+ }
memcpy(fsid, buf->fsid, sizeof(fsid));
fsid_is_initialized = 1;
- } else if (memcmp(fsid, buf->fsid, sizeof(fsid))) {
+ } else if (memcmp(fsid, buf->fsid, sizeof(fsid)) ||
+ (metadata_uuid_set && memcmp(metadata_uuid,
+ buf->metadata_uuid,
+ sizeof(metadata_uuid)))) {
/*
* the superblocks (the original one and
* its backups) contain data of different
@@ -1608,7 +1660,8 @@ int write_all_supers(struct btrfs_fs_info *fs_info)
btrfs_set_stack_device_io_width(dev_item, dev->io_width);
btrfs_set_stack_device_sector_size(dev_item, dev->sector_size);
memcpy(dev_item->uuid, dev->uuid, BTRFS_UUID_SIZE);
- memcpy(dev_item->fsid, dev->fs_devices->fsid, BTRFS_UUID_SIZE);
+ memcpy(dev_item->fsid, fs_info->fs_devices->metadata_uuid,
+ BTRFS_FSID_SIZE);
flags = btrfs_super_flags(sb);
btrfs_set_super_flags(sb, flags | BTRFS_HEADER_FLAG_WRITTEN);
@@ -1723,3 +1776,76 @@ int btrfs_set_buffer_uptodate(struct extent_buffer *eb)
{
return set_extent_buffer_uptodate(eb);
}
+
+struct btrfs_root *btrfs_create_tree(struct btrfs_trans_handle *trans,
+ struct btrfs_fs_info *fs_info,
+ u64 objectid)
+{
+ struct extent_buffer *leaf;
+ struct btrfs_root *tree_root = fs_info->tree_root;
+ struct btrfs_root *root;
+ struct btrfs_key key;
+ int ret = 0;
+
+ root = kzalloc(sizeof(*root), GFP_KERNEL);
+ if (!root)
+ return ERR_PTR(-ENOMEM);
+
+ btrfs_setup_root(root, fs_info, objectid);
+ root->root_key.objectid = objectid;
+ root->root_key.type = BTRFS_ROOT_ITEM_KEY;
+ root->root_key.offset = 0;
+
+ leaf = btrfs_alloc_free_block(trans, root, fs_info->nodesize, objectid,
+ NULL, 0, 0, 0);
+ if (IS_ERR(leaf)) {
+ ret = PTR_ERR(leaf);
+ leaf = NULL;
+ goto fail;
+ }
+
+ memset_extent_buffer(leaf, 0, 0, sizeof(struct btrfs_header));
+ btrfs_set_header_bytenr(leaf, leaf->start);
+ btrfs_set_header_generation(leaf, trans->transid);
+ btrfs_set_header_backref_rev(leaf, BTRFS_MIXED_BACKREF_REV);
+ btrfs_set_header_owner(leaf, objectid);
+ root->node = leaf;
+ write_extent_buffer(leaf, fs_info->fs_devices->metadata_uuid,
+ btrfs_header_fsid(), BTRFS_FSID_SIZE);
+ write_extent_buffer(leaf, fs_info->chunk_tree_uuid,
+ btrfs_header_chunk_tree_uuid(leaf),
+ BTRFS_UUID_SIZE);
+ btrfs_mark_buffer_dirty(leaf);
+
+ extent_buffer_get(root->node);
+ root->commit_root = root->node;
+ root->track_dirty = 1;
+
+ root->root_item.flags = 0;
+ root->root_item.byte_limit = 0;
+ btrfs_set_root_bytenr(&root->root_item, leaf->start);
+ btrfs_set_root_generation(&root->root_item, trans->transid);
+ btrfs_set_root_level(&root->root_item, 0);
+ btrfs_set_root_refs(&root->root_item, 1);
+ btrfs_set_root_used(&root->root_item, leaf->len);
+ btrfs_set_root_last_snapshot(&root->root_item, 0);
+ btrfs_set_root_dirid(&root->root_item, 0);
+ memset(root->root_item.uuid, 0, BTRFS_UUID_SIZE);
+ root->root_item.drop_level = 0;
+
+ key.objectid = objectid;
+ key.type = BTRFS_ROOT_ITEM_KEY;
+ key.offset = 0;
+ ret = btrfs_insert_root(trans, tree_root, &key, &root->root_item);
+ if (ret)
+ goto fail;
+
+ return root;
+
+fail:
+ if (leaf)
+ free_extent_buffer(leaf);
+
+ kfree(root);
+ return ERR_PTR(ret);
+}
diff --git a/disk-io.h b/disk-io.h
index 05cbbce6..ddf3a380 100644
--- a/disk-io.h
+++ b/disk-io.h
@@ -197,5 +197,9 @@ int write_tree_block(struct btrfs_trans_handle *trans,
struct btrfs_fs_info *fs_info,
struct extent_buffer *eb);
int write_and_map_eb(struct btrfs_fs_info *fs_info, struct extent_buffer *eb);
+int btrfs_fs_roots_compare_roots(struct rb_node *node1, struct rb_node *node2);
+struct btrfs_root *btrfs_create_tree(struct btrfs_trans_handle *trans,
+ struct btrfs_fs_info *fs_info,
+ u64 objectid);
#endif
diff --git a/free-space-tree.c b/free-space-tree.c
index 6ef57928..c854768b 100644
--- a/free-space-tree.c
+++ b/free-space-tree.c
@@ -20,39 +20,11 @@
#include "disk-io.h"
#include "free-space-cache.h"
#include "free-space-tree.h"
+#include "volumes.h"
#include "transaction.h"
#include "bitops.h"
#include "internal.h"
-static inline void set_free_space_tree_thresholds(struct btrfs_block_group_cache *cache,
- u64 sectorsize)
-{
- u32 bitmap_range;
- size_t bitmap_size;
- u64 num_bitmaps, total_bitmap_size;
-
- /*
- * We convert to bitmaps when the disk space required for using extents
- * exceeds that required for using bitmaps.
- */
- bitmap_range = sectorsize * BTRFS_FREE_SPACE_BITMAP_BITS;
- num_bitmaps = div_u64(cache->key.offset + bitmap_range - 1,
- bitmap_range);
- bitmap_size = sizeof(struct btrfs_item) + BTRFS_FREE_SPACE_BITMAP_SIZE;
- total_bitmap_size = num_bitmaps * bitmap_size;
- cache->bitmap_high_thresh = div_u64(total_bitmap_size,
- sizeof(struct btrfs_item));
-
- /*
- * We allow for a small buffer between the high threshold and low
- * threshold to avoid thrashing back and forth between the two formats.
- */
- if (cache->bitmap_high_thresh > 100)
- cache->bitmap_low_thresh = cache->bitmap_high_thresh - 100;
- else
- cache->bitmap_low_thresh = 0;
-}
-
static struct btrfs_free_space_info *
search_free_space_info(struct btrfs_trans_handle *trans,
struct btrfs_fs_info *fs_info,
@@ -1420,78 +1392,6 @@ out:
return ret;
}
-static struct btrfs_root *btrfs_create_tree(struct btrfs_trans_handle *trans,
- struct btrfs_fs_info *fs_info,
- u64 objectid)
-{
- struct extent_buffer *leaf;
- struct btrfs_root *tree_root = fs_info->tree_root;
- struct btrfs_root *root;
- struct btrfs_key key;
- int ret = 0;
-
- root = kzalloc(sizeof(*root), GFP_KERNEL);
- if (!root)
- return ERR_PTR(-ENOMEM);
-
- btrfs_setup_root(root, fs_info, objectid);
- root->root_key.objectid = objectid;
- root->root_key.type = BTRFS_ROOT_ITEM_KEY;
- root->root_key.offset = 0;
-
- leaf = btrfs_alloc_free_block(trans, root, fs_info->nodesize, objectid,
- NULL, 0, 0, 0);
- if (IS_ERR(leaf)) {
- ret = PTR_ERR(leaf);
- leaf = NULL;
- goto fail;
- }
-
- memset_extent_buffer(leaf, 0, 0, sizeof(struct btrfs_header));
- btrfs_set_header_bytenr(leaf, leaf->start);
- btrfs_set_header_generation(leaf, trans->transid);
- btrfs_set_header_backref_rev(leaf, BTRFS_MIXED_BACKREF_REV);
- btrfs_set_header_owner(leaf, objectid);
- root->node = leaf;
- write_extent_buffer(leaf, fs_info->fsid, btrfs_header_fsid(), BTRFS_FSID_SIZE);
- write_extent_buffer(leaf, fs_info->chunk_tree_uuid,
- btrfs_header_chunk_tree_uuid(leaf),
- BTRFS_UUID_SIZE);
- btrfs_mark_buffer_dirty(leaf);
-
- extent_buffer_get(root->node);
- root->commit_root = root->node;
- root->track_dirty = 1;
-
- root->root_item.flags = 0;
- root->root_item.byte_limit = 0;
- btrfs_set_root_bytenr(&root->root_item, leaf->start);
- btrfs_set_root_generation(&root->root_item, trans->transid);
- btrfs_set_root_level(&root->root_item, 0);
- btrfs_set_root_refs(&root->root_item, 1);
- btrfs_set_root_used(&root->root_item, leaf->len);
- btrfs_set_root_last_snapshot(&root->root_item, 0);
- btrfs_set_root_dirid(&root->root_item, 0);
- memset(root->root_item.uuid, 0, BTRFS_UUID_SIZE);
- root->root_item.drop_level = 0;
-
- key.objectid = objectid;
- key.type = BTRFS_ROOT_ITEM_KEY;
- key.offset = 0;
- ret = btrfs_insert_root(trans, tree_root, &key, &root->root_item);
- if (ret)
- goto fail;
-
- return root;
-
-fail:
- if (leaf)
- free_extent_buffer(leaf);
-
- kfree(root);
- return ERR_PTR(ret);
-}
-
#define btrfs_set_fs_compat_ro(__fs_info, opt) \
__btrfs_set_fs_compat_ro((__fs_info), BTRFS_FEATURE_COMPAT_RO_##opt)
diff --git a/fsfeatures.c b/fsfeatures.c
index 7d85d60f..13ad0308 100644
--- a/fsfeatures.c
+++ b/fsfeatures.c
@@ -225,3 +225,26 @@ u32 get_running_kernel_version(void)
return version;
}
+int btrfs_check_nodesize(u32 nodesize, u32 sectorsize, u64 features)
+{
+ if (nodesize < sectorsize) {
+ error("illegal nodesize %u (smaller than %u)",
+ nodesize, sectorsize);
+ return -1;
+ } else if (nodesize > BTRFS_MAX_METADATA_BLOCKSIZE) {
+ error("illegal nodesize %u (larger than %u)",
+ nodesize, BTRFS_MAX_METADATA_BLOCKSIZE);
+ return -1;
+ } else if (nodesize & (sectorsize - 1)) {
+ error("illegal nodesize %u (not aligned to %u)",
+ nodesize, sectorsize);
+ return -1;
+ } else if (features & BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS &&
+ nodesize != sectorsize) {
+ error(
+ "illegal nodesize %u (not equal to %u for mixed block group)",
+ nodesize, sectorsize);
+ return -1;
+ }
+ return 0;
+}
diff --git a/image/main.c b/image/main.c
index 39d5265d..4fba8283 100644
--- a/image/main.c
+++ b/image/main.c
@@ -1404,7 +1404,7 @@ static void *restore_worker(void *data)
list_del_init(&async->list);
if (mdres->compress_method == COMPRESS_ZLIB) {
- size = compress_size;
+ size = compress_size;
pthread_mutex_unlock(&mdres->mutex);
ret = uncompress(buffer, (unsigned long *)&size,
async->buffer, async->bufsize);
@@ -1596,9 +1596,12 @@ static int fill_mdres_info(struct mdrestore_struct *mdres,
super = (struct btrfs_super_block *)outbuf;
mdres->nodesize = btrfs_super_nodesize(super);
- memcpy(mdres->fsid, super->fsid, BTRFS_FSID_SIZE);
- memcpy(mdres->uuid, super->dev_item.uuid,
- BTRFS_UUID_SIZE);
+ if (btrfs_super_incompat_flags(super) &
+ BTRFS_FEATURE_INCOMPAT_METADATA_UUID)
+ memcpy(mdres->fsid, super->metadata_uuid, BTRFS_FSID_SIZE);
+ else
+ memcpy(mdres->fsid, super->fsid, BTRFS_FSID_SIZE);
+ memcpy(mdres->uuid, super->dev_item.uuid, BTRFS_UUID_SIZE);
mdres->devid = le64_to_cpu(super->dev_item.devid);
free(buffer);
return 0;
@@ -1725,7 +1728,7 @@ static int read_chunk_block(struct mdrestore_struct *mdres, u8 *buffer,
if (memcmp(mdres->fsid, eb->data + offsetof(struct btrfs_header, fsid),
BTRFS_FSID_SIZE)) {
- error("filesystem UUID of eb %llu does not match",
+ error("filesystem metadata UUID of eb %llu does not match",
(unsigned long long)bytenr);
ret = -EIO;
goto out;
@@ -2039,9 +2042,13 @@ static int build_chunk_tree(struct mdrestore_struct *mdres,
super = (struct btrfs_super_block *)buffer;
chunk_root_bytenr = btrfs_super_chunk_root(super);
mdres->nodesize = btrfs_super_nodesize(super);
- memcpy(mdres->fsid, super->fsid, BTRFS_FSID_SIZE);
- memcpy(mdres->uuid, super->dev_item.uuid,
- BTRFS_UUID_SIZE);
+ if (btrfs_super_incompat_flags(super) &
+ BTRFS_FEATURE_INCOMPAT_METADATA_UUID)
+ memcpy(mdres->fsid, super->metadata_uuid, BTRFS_FSID_SIZE);
+ else
+ memcpy(mdres->fsid, super->fsid, BTRFS_FSID_SIZE);
+
+ memcpy(mdres->uuid, super->dev_item.uuid, BTRFS_UUID_SIZE);
mdres->devid = le64_to_cpu(super->dev_item.devid);
free(buffer);
pthread_mutex_unlock(&mdres->mutex);
@@ -2084,46 +2091,86 @@ static void remap_overlapping_chunks(struct mdrestore_struct *mdres)
}
}
-static int fixup_devices(struct btrfs_fs_info *fs_info,
- struct mdrestore_struct *mdres, off_t dev_size)
+static int fixup_device_size(struct btrfs_trans_handle *trans,
+ struct mdrestore_struct *mdres, int out_fd)
{
- struct btrfs_trans_handle *trans;
+ struct btrfs_fs_info *fs_info = trans->fs_info;
struct btrfs_dev_item *dev_item;
+ struct btrfs_dev_extent *dev_ext;
struct btrfs_path path;
struct extent_buffer *leaf;
struct btrfs_root *root = fs_info->chunk_root;
struct btrfs_key key;
+ struct stat buf;
u64 devid, cur_devid;
+ u64 dev_size; /* Get from last dev extents */
int ret;
- if (btrfs_super_log_root(fs_info->super_copy)) {
- warning(
- "log tree detected, its generation will not match superblock");
- }
- trans = btrfs_start_transaction(fs_info->tree_root, 1);
- if (IS_ERR(trans)) {
- error("cannot starting transaction %ld", PTR_ERR(trans));
- return PTR_ERR(trans);
- }
-
dev_item = &fs_info->super_copy->dev_item;
+ btrfs_init_path(&path);
devid = btrfs_stack_device_id(dev_item);
+ key.objectid = devid;
+ key.type = BTRFS_DEV_EXTENT_KEY;
+ key.offset = (u64)-1;
+
+ ret = btrfs_search_slot(NULL, fs_info->dev_root, &key, &path, 0, 0);
+ if (ret < 0) {
+ errno = -ret;
+ error("failed to locate last dev extent of devid %llu: %m",
+ devid);
+ btrfs_release_path(&path);
+ return ret;
+ }
+ if (ret == 0) {
+ error("found invalid dev extent devid %llu offset -1", devid);
+ btrfs_release_path(&path);
+ return -EUCLEAN;
+ }
+ ret = btrfs_previous_item(fs_info->dev_root, &path, devid,
+ BTRFS_DEV_EXTENT_KEY);
+ if (ret > 0)
+ ret = -ENOENT;
+ if (ret < 0) {
+ errno = -ret;
+ error("failed to locate last dev extent of devid %llu: %m",
+ devid);
+ btrfs_release_path(&path);
+ return ret;
+ }
+
+ btrfs_item_key_to_cpu(path.nodes[0], &key, path.slots[0]);
+ dev_ext = btrfs_item_ptr(path.nodes[0], path.slots[0],
+ struct btrfs_dev_extent);
+ dev_size = key.offset + btrfs_dev_extent_length(path.nodes[0], dev_ext);
+ btrfs_release_path(&path);
+
btrfs_set_stack_device_total_bytes(dev_item, dev_size);
btrfs_set_stack_device_bytes_used(dev_item, mdres->alloced_chunks);
+ ret = fstat(out_fd, &buf);
+ if (ret < 0) {
+ error("failed to stat result image: %m");
+ return -errno;
+ }
+ if (S_ISREG(buf.st_mode)) {
+ /* Don't forget to enlarge the real file */
+ ret = ftruncate64(out_fd, dev_size);
+ if (ret < 0) {
+ error("failed to enlarge result image: %m");
+ return -errno;
+ }
+ }
key.objectid = BTRFS_DEV_ITEMS_OBJECTID;
key.type = BTRFS_DEV_ITEM_KEY;
key.offset = 0;
- btrfs_init_path(&path);
-
again:
ret = btrfs_search_slot(trans, root, &key, &path, -1, 1);
if (ret < 0) {
error("search failed: %d", ret);
- exit(1);
+ return ret;
}
while (1) {
@@ -2170,12 +2217,192 @@ again:
}
btrfs_release_path(&path);
+ return 0;
+}
+
+static void fixup_block_groups(struct btrfs_fs_info *fs_info)
+{
+ struct btrfs_block_group_cache *bg;
+ struct btrfs_mapping_tree *map_tree = &fs_info->mapping_tree;
+ struct cache_extent *ce;
+ struct map_lookup *map;
+ u64 extra_flags;
+
+ for (ce = search_cache_extent(&map_tree->cache_tree, 0); ce;
+ ce = next_cache_extent(ce)) {
+ map = container_of(ce, struct map_lookup, ce);
+
+ bg = btrfs_lookup_block_group(fs_info, ce->start);
+ if (!bg) {
+ warning(
+ "cannot find block group %llu, filesystem may not be mountable",
+ ce->start);
+ continue;
+ }
+ extra_flags = map->type & BTRFS_BLOCK_GROUP_PROFILE_MASK;
+
+ if (bg->flags == map->type)
+ continue;
+
+ /* Update the block group item and mark the bg dirty */
+ bg->flags = map->type;
+ btrfs_set_block_group_flags(&bg->item, bg->flags);
+ set_extent_bits(&fs_info->block_group_cache, ce->start,
+ ce->start + ce->size - 1, BLOCK_GROUP_DIRTY);
+
+ /*
+ * Chunk and bg flags can be different, changing bg flags
+ * without update avail_data/meta_alloc_bits will lead to
+ * ENOSPC.
+ * So here we set avail_*_alloc_bits to match chunk types.
+ */
+ if (map->type & BTRFS_BLOCK_GROUP_DATA)
+ fs_info->avail_data_alloc_bits = extra_flags;
+ if (map->type & BTRFS_BLOCK_GROUP_METADATA)
+ fs_info->avail_metadata_alloc_bits = extra_flags;
+ if (map->type & BTRFS_BLOCK_GROUP_SYSTEM)
+ fs_info->avail_system_alloc_bits = extra_flags;
+ }
+}
+
+static int remove_all_dev_extents(struct btrfs_trans_handle *trans)
+{
+ struct btrfs_fs_info *fs_info = trans->fs_info;
+ struct btrfs_root *root = fs_info->dev_root;
+ struct btrfs_path path;
+ struct btrfs_key key;
+ struct extent_buffer *leaf;
+ int slot;
+ int ret;
+
+ key.objectid = 1;
+ key.type = BTRFS_DEV_EXTENT_KEY;
+ key.offset = 0;
+ btrfs_init_path(&path);
+
+ ret = btrfs_search_slot(trans, root, &key, &path, -1, 1);
+ if (ret < 0) {
+ errno = -ret;
+ error("failed to search dev tree: %m");
+ return ret;
+ }
+
+ while (1) {
+ slot = path.slots[0];
+ leaf = path.nodes[0];
+ if (slot >= btrfs_header_nritems(leaf)) {
+ ret = btrfs_next_leaf(root, &path);
+ if (ret < 0) {
+ errno = -ret;
+ error("failed to search dev tree: %m");
+ goto out;
+ }
+ if (ret > 0) {
+ ret = 0;
+ goto out;
+ }
+ }
+
+ btrfs_item_key_to_cpu(leaf, &key, slot);
+ if (key.type != BTRFS_DEV_EXTENT_KEY)
+ break;
+ ret = btrfs_del_item(trans, root, &path);
+ if (ret < 0) {
+ errno = -ret;
+ error("failed to delete dev extent %llu, %llu: %m",
+ key.objectid, key.offset);
+ goto out;
+ }
+ }
+out:
+ btrfs_release_path(&path);
+ return ret;
+}
+
+static int fixup_dev_extents(struct btrfs_trans_handle *trans)
+{
+ struct btrfs_fs_info *fs_info = trans->fs_info;
+ struct btrfs_mapping_tree *map_tree = &fs_info->mapping_tree;
+ struct btrfs_device *dev;
+ struct cache_extent *ce;
+ struct map_lookup *map;
+ u64 devid = btrfs_stack_device_id(&fs_info->super_copy->dev_item);
+ int i;
+ int ret;
+
+ ret = remove_all_dev_extents(trans);
+ if (ret < 0) {
+ errno = -ret;
+ error("failed to remove all existing dev extents: %m");
+ }
+
+ dev = btrfs_find_device(fs_info, devid, NULL, NULL);
+ if (!dev) {
+ error("faild to find devid %llu", devid);
+ return -ENODEV;
+ }
+
+ /* Rebuild all dev extents using chunk maps */
+ for (ce = search_cache_extent(&map_tree->cache_tree, 0); ce;
+ ce = next_cache_extent(ce)) {
+ u64 stripe_len;
+
+ map = container_of(ce, struct map_lookup, ce);
+ stripe_len = calc_stripe_length(map->type, ce->size,
+ map->num_stripes);
+ for (i = 0; i < map->num_stripes; i++) {
+ ret = btrfs_insert_dev_extent(trans, dev, ce->start,
+ stripe_len, map->stripes[i].physical);
+ if (ret < 0) {
+ errno = -ret;
+ error(
+ "failed to insert dev extent %llu %llu: %m",
+ devid, map->stripes[i].physical);
+ goto out;
+ }
+ }
+ }
+out:
+ return ret;
+}
+
+static int fixup_chunks_and_devices(struct btrfs_fs_info *fs_info,
+ struct mdrestore_struct *mdres, int out_fd)
+{
+ struct btrfs_trans_handle *trans;
+ int ret;
+
+ if (btrfs_super_log_root(fs_info->super_copy)) {
+ warning(
+ "log tree detected, its generation will not match superblock");
+ }
+ trans = btrfs_start_transaction(fs_info->tree_root, 1);
+ if (IS_ERR(trans)) {
+ error("cannot start transaction %ld", PTR_ERR(trans));
+ return PTR_ERR(trans);
+ }
+
+ fixup_block_groups(fs_info);
+ ret = fixup_dev_extents(trans);
+ if (ret < 0)
+ goto error;
+
+ ret = fixup_device_size(trans, mdres, out_fd);
+ if (ret < 0)
+ goto error;
+
ret = btrfs_commit_transaction(trans, fs_info->tree_root);
if (ret) {
error("unable to commit transaction: %d", ret);
return ret;
}
return 0;
+error:
+ errno = -ret;
+ error(
+"failed to fix chunks and devices mapping, the fs may not be mountable: %m");
+ btrfs_abort_transaction(trans, ret);
+ return ret;
}
static int restore_metadump(const char *input, FILE *out, int old_restore,
@@ -2282,7 +2509,7 @@ static int restore_metadump(const char *input, FILE *out, int old_restore,
return 1;
}
- ret = fixup_devices(info, &mdrestore, st.st_size);
+ ret = fixup_chunks_and_devices(info, &mdrestore, fileno(out));
close_ctree(info->chunk_root);
if (ret)
goto out;
@@ -2321,7 +2548,7 @@ static int update_disk_super_on_device(struct btrfs_fs_info *info,
key.offset = cur_devid;
btrfs_init_path(&path);
- ret = btrfs_search_slot(NULL, info->chunk_root, &key, &path, 0, 0);
+ ret = btrfs_search_slot(NULL, info->chunk_root, &key, &path, 0, 0);
if (ret) {
error("search key failed: %d", ret);
ret = -EIO;
diff --git a/kernel-shared/ulist.c b/kernel-shared/ulist.c
index 156a92fc..c21447a3 100644
--- a/kernel-shared/ulist.c
+++ b/kernel-shared/ulist.c
@@ -52,13 +52,13 @@ void ulist_init(struct ulist *ulist)
}
/**
- * ulist_fini - free up additionally allocated memory for the ulist
+ * ulist_release - free up additionally allocated memory for the ulist
* @ulist: the ulist from which to free the additional memory
*
* This is useful in cases where the base 'struct ulist' has been statically
* allocated.
*/
-static void ulist_fini(struct ulist *ulist)
+void ulist_release(struct ulist *ulist)
{
struct ulist_node *node;
struct ulist_node *next;
@@ -79,7 +79,7 @@ static void ulist_fini(struct ulist *ulist)
*/
void ulist_reinit(struct ulist *ulist)
{
- ulist_fini(ulist);
+ ulist_release(ulist);
ulist_init(ulist);
}
@@ -105,13 +105,13 @@ struct ulist *ulist_alloc(gfp_t gfp_mask)
* ulist_free - free dynamically allocated ulist
* @ulist: ulist to free
*
- * It is not necessary to call ulist_fini before.
+ * It is not necessary to call ulist_release before.
*/
void ulist_free(struct ulist *ulist)
{
if (!ulist)
return;
- ulist_fini(ulist);
+ ulist_release(ulist);
kfree(ulist);
}
diff --git a/libbtrfsutil/python/tests/test_subvolume.py b/libbtrfsutil/python/tests/test_subvolume.py
index 99ec97bc..b06a1d3d 100644
--- a/libbtrfsutil/python/tests/test_subvolume.py
+++ b/libbtrfsutil/python/tests/test_subvolume.py
@@ -168,12 +168,13 @@ class TestSubvolume(BtrfsTestCase):
with drop_privs():
try:
- self._test_subvolume_info(subvol, snapshot)
+ btrfsutil.subvolume_info(self.mountpoint)
except OSError as e:
if e.errno == errno.ENOTTY:
self.skipTest('BTRFS_IOC_GET_SUBVOL_INFO is not available')
else:
raise
+ self._test_subvolume_info(subvol, snapshot)
def test_read_only(self):
for arg in self.path_or_fd(self.mountpoint):
@@ -487,6 +488,13 @@ class TestSubvolume(BtrfsTestCase):
try:
os.chdir(self.mountpoint)
with drop_privs():
+ try:
+ list(btrfsutil.SubvolumeIterator('.'))
+ except OSError as e:
+ if e.errno == errno.ENOTTY:
+ self.skipTest('BTRFS_IOC_GET_SUBVOL_ROOTREF is not available')
+ else:
+ raise
self._test_subvolume_iterator()
finally:
os.chdir(pwd)
diff --git a/messages.h b/messages.h
index ec7d9338..59604794 100644
--- a/messages.h
+++ b/messages.h
@@ -26,13 +26,13 @@
#ifdef DEBUG_TRACE_ON_ERROR
#define PRINT_TRACE_ON_ERROR print_trace()
#else
-#define PRINT_TRACE_ON_ERROR
+#define PRINT_TRACE_ON_ERROR do { } while (0)
#endif
#ifdef DEBUG_ABORT_ON_ERROR
#define DO_ABORT_ON_ERROR abort()
#else
-#define DO_ABORT_ON_ERROR
+#define DO_ABORT_ON_ERROR do { } while (0)
#endif
#define error(fmt, ...) \
diff --git a/mkfs/main.c b/mkfs/main.c
index b6748f7f..b442e6e4 100644
--- a/mkfs/main.c
+++ b/mkfs/main.c
@@ -39,6 +39,7 @@
#include "utils.h"
#include "list_sort.h"
#include "help.h"
+#include "rbtree-utils.h"
#include "mkfs/common.h"
#include "mkfs/rootdir.h"
#include "fsfeatures.h"
@@ -309,38 +310,6 @@ static int create_raid_groups(struct btrfs_trans_handle *trans,
return ret;
}
-static int create_tree(struct btrfs_trans_handle *trans,
- struct btrfs_root *root, u64 objectid)
-{
- struct btrfs_key location;
- struct btrfs_root_item root_item;
- struct extent_buffer *tmp;
- u8 uuid[BTRFS_UUID_SIZE] = {0};
- int ret;
-
- ret = btrfs_copy_root(trans, root, root->node, &tmp, objectid);
- if (ret)
- return ret;
-
- memcpy(&root_item, &root->root_item, sizeof(root_item));
- btrfs_set_root_bytenr(&root_item, tmp->start);
- btrfs_set_root_level(&root_item, btrfs_header_level(tmp));
- btrfs_set_root_generation(&root_item, trans->transid);
- /* clear uuid and o/ctime of source tree */
- memcpy(root_item.uuid, uuid, BTRFS_UUID_SIZE);
- btrfs_set_stack_timespec_sec(&root_item.otime, 0);
- btrfs_set_stack_timespec_sec(&root_item.ctime, 0);
- free_extent_buffer(tmp);
-
- location.objectid = objectid;
- location.type = BTRFS_ROOT_ITEM_KEY;
- location.offset = 0;
- ret = btrfs_insert_root(trans, root->fs_info->tree_root,
- &location, &root_item);
-
- return ret;
-}
-
static void print_usage(int ret)
{
printf("Usage: mkfs.btrfs [options] dev [ dev ... ]\n");
@@ -709,6 +678,98 @@ static void update_chunk_allocation(struct btrfs_fs_info *fs_info,
}
}
+static int create_data_reloc_tree(struct btrfs_trans_handle *trans)
+{
+ struct btrfs_fs_info *fs_info = trans->fs_info;
+ struct btrfs_inode_item *inode;
+ struct btrfs_root *root;
+ struct btrfs_path path;
+ struct btrfs_key key;
+ u64 ino = BTRFS_FIRST_FREE_OBJECTID;
+ char *name = "..";
+ int ret;
+
+ root = btrfs_create_tree(trans, fs_info, BTRFS_DATA_RELOC_TREE_OBJECTID);
+ if (IS_ERR(root)) {
+ ret = PTR_ERR(root);
+ goto out;
+ }
+ /* Update dirid as created tree has default dirid 0 */
+ btrfs_set_root_dirid(&root->root_item, ino);
+ ret = btrfs_update_root(trans, fs_info->tree_root, &root->root_key,
+ &root->root_item);
+ if (ret < 0)
+ goto out;
+
+ /* Cache this tree so it can be cleaned up at close_ctree() */
+ ret = rb_insert(&fs_info->fs_root_tree, &root->rb_node,
+ btrfs_fs_roots_compare_roots);
+ if (ret < 0)
+ goto out;
+
+ /* Insert INODE_ITEM */
+ ret = btrfs_new_inode(trans, root, ino, 0755 | S_IFDIR);
+ if (ret < 0)
+ goto out;
+
+ /* then INODE_REF */
+ ret = btrfs_insert_inode_ref(trans, root, name, strlen(name), ino, ino,
+ 0);
+ if (ret < 0)
+ goto out;
+
+ /* Update nlink of that inode item */
+ key.objectid = ino;
+ key.type = BTRFS_INODE_ITEM_KEY;
+ key.offset = 0;
+ btrfs_init_path(&path);
+
+ ret = btrfs_search_slot(trans, root, &key, &path, 0, 1);
+ if (ret > 0) {
+ ret = -ENOENT;
+ btrfs_release_path(&path);
+ goto out;
+ }
+ if (ret < 0) {
+ btrfs_release_path(&path);
+ goto out;
+ }
+ inode = btrfs_item_ptr(path.nodes[0], path.slots[0],
+ struct btrfs_inode_item);
+ btrfs_set_inode_nlink(path.nodes[0], inode, 1);
+ btrfs_mark_buffer_dirty(path.nodes[0]);
+ btrfs_release_path(&path);
+ return 0;
+out:
+ btrfs_abort_transaction(trans, ret);
+ return ret;
+}
+
+static int create_uuid_tree(struct btrfs_trans_handle *trans)
+{
+ struct btrfs_fs_info *fs_info = trans->fs_info;
+ struct btrfs_root *root;
+ int ret = 0;
+
+ ASSERT(fs_info->uuid_root == NULL);
+ root = btrfs_create_tree(trans, fs_info, BTRFS_UUID_TREE_OBJECTID);
+ if (IS_ERR(root)) {
+ ret = PTR_ERR(root);
+ goto out;
+ }
+
+ add_root_to_dirty_list(root);
+ fs_info->uuid_root = root;
+ ret = btrfs_uuid_tree_add(trans, fs_info->fs_root->root_item.uuid,
+ BTRFS_UUID_KEY_SUBVOL,
+ fs_info->fs_root->root_key.objectid);
+ if (ret < 0)
+ btrfs_abort_transaction(trans, ret);
+
+out:
+ return ret;
+}
+
int main(int argc, char **argv)
{
char *file;
@@ -1203,13 +1264,13 @@ raid_groups:
goto out;
}
- ret = create_tree(trans, root, BTRFS_DATA_RELOC_TREE_OBJECTID);
+ ret = create_data_reloc_tree(trans);
if (ret) {
error("unable to create data reloc tree: %d", ret);
goto out;
}
- ret = create_tree(trans, root, BTRFS_UUID_TREE_OBJECTID);
+ ret = create_uuid_tree(trans);
if (ret)
warning(
"unable to create uuid tree, will be created after mount: %d", ret);
diff --git a/rescue.h b/rescue.h
new file mode 100644
index 00000000..de486e2e
--- /dev/null
+++ b/rescue.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2018 SUSE. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License v2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef __BTRFS_RESCUE_H__
+#define __BTRFS_RESCUE_H__
+
+int btrfs_recover_superblocks(const char *path, int verbose, int yes);
+int btrfs_recover_chunk_tree(const char *path, int verbose, int yes);
+
+#endif
diff --git a/send-stream.c b/send-stream.c
index cb942b86..a0ac5025 100644
--- a/send-stream.c
+++ b/send-stream.c
@@ -157,8 +157,7 @@ static int read_cmd(struct btrfs_send_stream *sctx)
tlv_type = le16_to_cpu(tlv_hdr->tlv_type);
tlv_len = le16_to_cpu(tlv_hdr->tlv_len);
- if (tlv_type == 0 || tlv_type > BTRFS_SEND_A_MAX
- || tlv_len > BTRFS_SEND_BUF_SIZE) {
+ if (tlv_type == 0 || tlv_type > BTRFS_SEND_A_MAX) {
error("invalid tlv in cmd tlv_type = %hu, tlv_len = %hu",
tlv_type, tlv_len);
ret = -EINVAL;
diff --git a/string-table.c b/string-table.c
index 95833768..45528570 100644
--- a/string-table.c
+++ b/string-table.c
@@ -48,6 +48,7 @@ struct string_table *table_create(int columns, int rows)
* '>' the text is right aligned. If fmt is equal to '=' the text will
* be replaced by a '=====' dimensioned on the basis of the column width
*/
+__attribute__ ((format (printf, 4, 0)))
char *table_vprintf(struct string_table *tab, int column, int row,
const char *fmt, va_list ap)
{
diff --git a/super-recover.c b/super-recover.c
index 86b3df98..a1af7178 100644
--- a/super-recover.c
+++ b/super-recover.c
@@ -34,6 +34,7 @@
#include "crc32c.h"
#include "volumes.h"
#include "commands.h"
+#include "rescue.h"
struct btrfs_recover_superblock {
struct btrfs_fs_devices *fs_devices;
diff --git a/tests/cli-tests/009-btrfstune/test.sh b/tests/cli-tests/009-btrfstune/test.sh
new file mode 100755
index 00000000..c7399465
--- /dev/null
+++ b/tests/cli-tests/009-btrfstune/test.sh
@@ -0,0 +1,62 @@
+#!/bin/bash
+# test all command line options of btrfstune
+
+source "$TEST_TOP/common"
+
+check_prereq btrfstune
+
+setup_root_helper
+prepare_test_dev
+
+test_do_mkfs() {
+ run_check $SUDO_HELPER "$TOP/mkfs.btrfs" -f "$@" "$TEST_DEV"
+}
+
+run_mayfail "$TOP/btrfstune" || true
+run_check "$TOP/btrfstune" --help
+
+run_mustfail "must not work on non-existent device" \
+ "$TOP/btrfstune" -r file-does-not-exist
+
+test_do_mkfs -O ^extref
+run_check "$TOP/btrfstune" -r "$TEST_DEV"
+
+test_do_mkfs -O ^skinny-metadata
+run_check "$TOP/btrfstune" -x "$TEST_DEV"
+
+test_do_mkfs -O ^no-holes
+run_check "$TOP/btrfstune" -n "$TEST_DEV"
+
+test_do_mkfs
+run_check "$TOP/btrfstune" -S 1 "$TEST_DEV"
+echo n | run_mayfail "$TOP/btrfstune" -S 0 "$TEST_DEV" || true
+run_check "$TOP/btrfstune" -f -S 0 "$TEST_DEV"
+
+run_mustfail "negative number for seeding status" \
+ "$TOP/btrfstune" -f -S -1 "$TEST_DEV"
+
+test_do_mkfs
+echo n | run_mayfail "$TOP/btrfstune" -u "$TEST_DEV" || true
+run_check "$TOP/btrfstune" -f -u "$TEST_DEV"
+
+uuid="e315420e-3a1f-4d81-849e-93b68b85b76f"
+baduuid="1-2-3-4-5"
+test_do_mkfs
+echo n | run_mayfail "$TOP/btrfstune" -U "$uuid" "$TEST_DEV" || true
+run_check "$TOP/btrfstune" -f -U "$uuid" "$TEST_DEV"
+
+run_mustfail "non-conforming uuid accepted" \
+ "$TOP/btrfstune" -U "$baduuid" "$TEST_DEV"
+
+test_do_mkfs
+echo n | run_mayfail "$TOP/btrfstune" -m "$TEST_DEV" || true
+run_check "$TOP/btrfstune" -f -m "$TEST_DEV"
+
+uuid="2a9716ee-2786-4baa-ab85-f82c50fa883c"
+test_do_mkfs
+run_mayfail "$TOP/btrfstune" -M "$uuid" "$TEST_DEV" || true
+test_do_mkfs
+run_check "$TOP/btrfstune" -f -M "$uuid" "$TEST_DEV"
+
+run_mustfail "non-conforming uuid accepted" \
+ "$TOP/btrfstune" -M "$baduuid" "$TEST_DEV"
diff --git a/tests/fsck-tests/015-tree-reloc-tree/test.sh b/tests/fsck-tests/015-tree-reloc-tree/test.sh
deleted file mode 100755
index 5d9d5122..00000000
--- a/tests/fsck-tests/015-tree-reloc-tree/test.sh
+++ /dev/null
@@ -1,16 +0,0 @@
-#!/bin/bash
-# Make sure btrfs check won't report any false alerts for valid image with
-# reloc tree.
-#
-# Also due to the short life span of reloc tree, save the as dump example for
-# later usage.
-
-source "$TEST_TOP/common"
-
-check_prereq btrfs
-
-check_image() {
- run_check "$TOP/btrfs" check "$1"
-}
-
-check_all_images
diff --git a/tests/fsck-tests/020-extent-ref-cases/test.sh b/tests/fsck-tests/020-extent-ref-cases/test.sh
index a1bf75b1..e7a55728 100755
--- a/tests/fsck-tests/020-extent-ref-cases/test.sh
+++ b/tests/fsck-tests/020-extent-ref-cases/test.sh
@@ -14,6 +14,11 @@
# Containing a block group and its first extent at
# the beginning of leaf.
# Which caused false alert for lowmem mode.
+#
+# Special cases with some rare backref types
+# * reloc tree
+# For both fs tree and data reloc tree.
+# Special for its backref pointing to itself and its short life span.
source "$TEST_TOP/common"
diff --git a/tests/fsck-tests/015-tree-reloc-tree/tree_reloc_for_data_reloc.img.xz b/tests/fsck-tests/020-extent-ref-cases/tree_reloc_for_data_reloc.img.xz
index 66d8bde6..66d8bde6 100644
--- a/tests/fsck-tests/015-tree-reloc-tree/tree_reloc_for_data_reloc.img.xz
+++ b/tests/fsck-tests/020-extent-ref-cases/tree_reloc_for_data_reloc.img.xz
Binary files differ
diff --git a/tests/fsck-tests/015-tree-reloc-tree/tree_reloc_for_fs_tree.img.xz b/tests/fsck-tests/020-extent-ref-cases/tree_reloc_for_fs_tree.img.xz
index 22af324b..22af324b 100644
--- a/tests/fsck-tests/015-tree-reloc-tree/tree_reloc_for_fs_tree.img.xz
+++ b/tests/fsck-tests/020-extent-ref-cases/tree_reloc_for_fs_tree.img.xz
Binary files differ
diff --git a/tests/fsck-tests/026-bad-dir-item-name/description.txt b/tests/fsck-tests/026-bad-dir-item-name/description.txt
new file mode 100644
index 00000000..2bdb0f81
--- /dev/null
+++ b/tests/fsck-tests/026-bad-dir-item-name/description.txt
@@ -0,0 +1,41 @@
+"default_case.img.xz" contains the fs with the following tree dump of fs tree:
+
+ [snip]
+ item 2 key (256 DIR_ITEM 751495445) itemoff 16019 itemsize 92
+ location key (259 INODE_ITEM 0) type FILE
+ transid 9 data_len 0 name_len 13
+ name: foor.WvG1c1Td
+ ^^^^^^^^^^^^^ Hash doesn't match with key
+ location key (260 INODE_ITEM 0) type FILE
+ transid 12 data_len 0 name_len 19
+ name: user.J3__T_Km3dVsW_
+ item 3 key (256 DIR_INDEX 4) itemoff 15976 itemsize 43
+ location key (259 INODE_ITEM 0) type FILE
+ transid 9 data_len 0 name_len 13
+ name: foor.WvG1c1Td
+ item 4 key (256 DIR_INDEX 5) itemoff 15927 itemsize 49
+ location key (260 INODE_ITEM 0) type FILE
+ transid 12 data_len 0 name_len 19
+ name: user.J3__T_Km3dVsW_
+ item 5 key (259 INODE_ITEM 0) itemoff 15767 itemsize 160
+ generation 9 transid 9 size 0 nbytes 0
+ block group 0 mode 100644 links 1 uid 0 gid 0 rdev 0
+ sequence 1 flags 0x0(none)
+ atime 1499844359.341125147 (2017-07-12 15:25:59)
+ ctime 1499844359.341125147 (2017-07-12 15:25:59)
+ mtime 1499844359.341125147 (2017-07-12 15:25:59)
+ otime 1499844359.341125147 (2017-07-12 15:25:59)
+ item 6 key (259 INODE_REF 256) itemoff 15744 itemsize 23
+ index 4 namelen 13 name: foor.WvG1c1Td
+ item 7 key (260 INODE_ITEM 0) itemoff 15584 itemsize 160
+ generation 12 transid 12 size 0 nbytes 0
+ block group 0 mode 100644 links 1 uid 0 gid 0 rdev 0
+ sequence 1 flags 0x0(none)
+ atime 1499844544.931130070 (2017-07-12 15:29:04)
+ ctime 1499844544.931130070 (2017-07-12 15:29:04)
+ mtime 1499844544.931130070 (2017-07-12 15:29:04)
+ otime 1499844544.931130070 (2017-07-12 15:29:04)
+ item 8 key (260 INODE_REF 256) itemoff 15555 itemsize 29
+ index 5 namelen 19 name: user.J3__T_Km3dVsW_
+
+Test case is going to check if btrfs check can detect and repair it.
diff --git a/tests/fsck-tests/026-bad-dir-item-name/test.sh b/tests/fsck-tests/026-bad-dir-item-name/test.sh
deleted file mode 100755
index a38bf045..00000000
--- a/tests/fsck-tests/026-bad-dir-item-name/test.sh
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/bin/bash
-#
-# confirm whether check detects name and hash mismatch in dir_item
-
-source "$TEST_TOP/common"
-
-check_prereq btrfs
-
-image=$(extract_image "./default_case.img.xz")
-
-run_mustfail "dir_item hash mismatch not found" "$TOP/btrfs" check "$image"
-
-rm -f "$image"
diff --git a/tests/fsck-tests/036-bad-dev-extents/over_dev_boundary.img.xz b/tests/fsck-tests/036-bad-dev-extents/over_dev_boundary.img.xz
new file mode 100644
index 00000000..47cb2a70
--- /dev/null
+++ b/tests/fsck-tests/036-bad-dev-extents/over_dev_boundary.img.xz
Binary files differ
diff --git a/tests/fsck-tests/036-bad-dev-extents/test.sh b/tests/fsck-tests/036-bad-dev-extents/test.sh
new file mode 100755
index 00000000..88ea0aec
--- /dev/null
+++ b/tests/fsck-tests/036-bad-dev-extents/test.sh
@@ -0,0 +1,20 @@
+#!/bin/bash
+#
+# Due to DUP chunk allocator bugs, we could allocate DUP chunks while its dev
+# extents could exist beyond device boundary.
+# And since all related items (block group, chunk, device used bytes) are all
+# valid, btrfs check won't report any error.
+#
+# This test case contains hand crafted minimal image, to test if btrfs check
+# can detect and report such error.
+
+source "$TEST_TOP/common"
+
+check_prereq btrfs
+
+check_image() {
+ run_mustfail "btrfs check failed to detect invalid dev extents" \
+ "$TOP/btrfs" check "$1"
+}
+
+check_all_images
diff --git a/tests/fsck-tests/037-freespacetree-repair/test.sh b/tests/fsck-tests/037-freespacetree-repair/test.sh
index 261d7ccb..a0bdf9e2 100755
--- a/tests/fsck-tests/037-freespacetree-repair/test.sh
+++ b/tests/fsck-tests/037-freespacetree-repair/test.sh
@@ -59,8 +59,11 @@ run_check "$TOP/mkfs.btrfs" -n 4k -f "$TEST_DEV"
run_check_mount_test_dev -oclear_cache,space_cache=v2
# create files which will populate the FST
-for i in {1..3000}; do
- run_check $SUDO_HELPER fallocate -l 4k "$TEST_MNT/file.$i"
+for i in {0..9}; do
+ for j in {1..300}; do
+ run_check $SUDO_HELPER fallocate -l 4k "$TEST_MNT/file.$j$i" &
+ done
+ wait
done
run_check_umount_test_dev
diff --git a/tests/misc-tests/021-image-multi-devices/test.sh b/tests/misc-tests/021-image-multi-devices/test.sh
index 5430847f..26beae6e 100755
--- a/tests/misc-tests/021-image-multi-devices/test.sh
+++ b/tests/misc-tests/021-image-multi-devices/test.sh
@@ -37,6 +37,9 @@ run_check $SUDO_HELPER wipefs -a "$loop2"
run_check $SUDO_HELPER "$TOP/btrfs-image" -r "$IMAGE" "$loop1"
+# Run check to make sure there is nothing wrong for the recovered image
+run_check "$TOP/btrfs" check "$loop1"
+
run_check $SUDO_HELPER mount "$loop1" "$TEST_MNT"
new_md5=$(run_check_stdout md5sum "$TEST_MNT/foobar" | cut -d ' ' -f 1)
run_check $SUDO_HELPER umount "$TEST_MNT"
diff --git a/tests/misc-tests/034-metadata-uuid/disk1.raw.xz b/tests/misc-tests/034-metadata-uuid/disk1.raw.xz
new file mode 100644
index 00000000..24f47d2b
--- /dev/null
+++ b/tests/misc-tests/034-metadata-uuid/disk1.raw.xz
Binary files differ
diff --git a/tests/misc-tests/034-metadata-uuid/disk2.raw.xz b/tests/misc-tests/034-metadata-uuid/disk2.raw.xz
new file mode 100644
index 00000000..a1c80371
--- /dev/null
+++ b/tests/misc-tests/034-metadata-uuid/disk2.raw.xz
Binary files differ
diff --git a/tests/misc-tests/034-metadata-uuid/disk3.raw.xz b/tests/misc-tests/034-metadata-uuid/disk3.raw.xz
new file mode 100644
index 00000000..25e9be69
--- /dev/null
+++ b/tests/misc-tests/034-metadata-uuid/disk3.raw.xz
Binary files differ
diff --git a/tests/misc-tests/034-metadata-uuid/disk4.raw.xz b/tests/misc-tests/034-metadata-uuid/disk4.raw.xz
new file mode 100644
index 00000000..f591cfec
--- /dev/null
+++ b/tests/misc-tests/034-metadata-uuid/disk4.raw.xz
Binary files differ
diff --git a/tests/misc-tests/034-metadata-uuid/disk5.raw.xz b/tests/misc-tests/034-metadata-uuid/disk5.raw.xz
new file mode 100644
index 00000000..e9095b78
--- /dev/null
+++ b/tests/misc-tests/034-metadata-uuid/disk5.raw.xz
Binary files differ
diff --git a/tests/misc-tests/034-metadata-uuid/disk6.raw.xz b/tests/misc-tests/034-metadata-uuid/disk6.raw.xz
new file mode 100644
index 00000000..9926ae49
--- /dev/null
+++ b/tests/misc-tests/034-metadata-uuid/disk6.raw.xz
Binary files differ
diff --git a/tests/misc-tests/034-metadata-uuid/test.sh b/tests/misc-tests/034-metadata-uuid/test.sh
new file mode 100755
index 00000000..72af0472
--- /dev/null
+++ b/tests/misc-tests/034-metadata-uuid/test.sh
@@ -0,0 +1,225 @@
+#!/bin/bash
+
+source "$TEST_TOP/common"
+
+check_prereq mkfs.btrfs
+check_prereq btrfs
+check_prereq btrfstune
+check_prereq btrfs-image
+
+setup_root_helper
+prepare_test_dev
+
+function read_fsid {
+ local dev="$1"
+
+ echo $(run_check_stdout $SUDO_HELPER "$TOP/btrfs" inspect-internal \
+ dump-super "$dev" | awk '/fsid/ {print $2}' | head -n 1)
+}
+
+function read_metadata_uuid {
+ local dev="$1"
+
+ echo $(run_check_stdout $SUDO_HELPER "$TOP/btrfs" inspect-internal \
+ dump-super "$dev" | awk '/metadata_uuid/ {print $2}')
+}
+
+function check_btrfstune {
+ local fsid
+
+ echo "Checking btrfstune logic" >> "$RESULTS"
+ # test with random uuid
+ run_check $SUDO_HELPER "$TOP/btrfstune" -m "$TEST_DEV"
+
+ # check that specific uuid can set
+ run_check $SUDO_HELPER "$TOP/btrfstune" -M d88c8333-a652-4476-b225-2e9284eb59f1 "$TEST_DEV"
+
+ # test that having seed on already changed device doesn't work
+ run_mustfail "Managed to set seed on metadata uuid fs" \
+ $SUDO_HELPER "$TOP/btrfstune" -S 1 "$TEST_DEV"
+
+ # test that setting both seed and -m|M is forbidden
+ run_check $SUDO_HELPER "$TOP/mkfs.btrfs" -f "$TEST_DEV"
+ run_mustfail "Succeeded setting seed and changing fs uuid" \
+ $SUDO_HELPER "$TOP/btrfstune" -S 1 -m "$TEST_DEV"
+
+ # test that having -m|-M on seed device is forbidden
+ run_check $SUDO_HELPER "$TOP/mkfs.btrfs" -f "$TEST_DEV"
+ run_check $SUDO_HELPER "$TOP/btrfstune" -S 1 "$TEST_DEV"
+ run_mustfail "Succeded changing fsid on a seed device" $SUDO_HELPER "$TOP/btrfstune" -m "$TEST_DEV"
+
+ # test that using -U|-u on an fs with METADATA_UUID flag is forbidden
+ run_check $SUDO_HELPER "$TOP/mkfs.btrfs" -f "$TEST_DEV"
+ run_check $SUDO_HELPER "$TOP/btrfstune" -m "$TEST_DEV"
+ run_mustfail "Succeeded triggering FSID rewrite while METADATA_UUID is active" \
+ $SUDO_HELPER "$TOP/btrfstune" -u "$TEST_DEV"
+
+}
+
+function check_dump_super_output {
+ local fsid
+ local metadata_uuid
+ local dev_item_match
+ local old_metadata_uuid
+
+ echo "Checking dump-super output" >> "$RESULTS"
+ # assert that metadata/fsid match on non-changed fs
+ fsid=$(read_fsid "$TEST_DEV")
+ metadata_uuid=$(read_metadata_uuid "$TEST_DEV")
+ [ "$fsid" = "$metadata_uuid" ] || _fail "fsid ("$fsid") doesn't match metadata_uuid ("$metadata_uuid")"
+
+ dev_item_match=$(run_check_stdout $SUDO_HELPER "$TOP/btrfs" inspect-internal dump-super \
+ "$TEST_DEV" | awk '/dev_item.fsid/ {print $3}')
+
+ [ $dev_item_match = "[match]" ] || _fail "dev_item.fsid doesn't match on non-metadata uuid fs"
+
+
+ echo "Checking output after fsid change" >> "$RESULTS"
+ # change metadatauuid and ensure everything in the output is still correct
+ old_metadata_uuid=$metadata_uuid
+ run_check $SUDO_HELPER "$TOP/btrfstune" -M d88c8333-a652-4476-b225-2e9284eb59f1 "$TEST_DEV"
+ fsid=$(read_fsid "$TEST_DEV")
+ metadata_uuid=$(read_metadata_uuid "$TEST_DEV")
+ dev_item_match=$(run_check_stdout $SUDO_HELPER "$TOP/btrfs" \
+ inspect-internal dump-super "$TEST_DEV" | awk '/dev_item.fsid/ {print $3}')
+
+ [ "$dev_item_match" = "[match]" ] || _fail "dev_item.fsid doesn't match on metadata uuid fs"
+ [ "$fsid" = "d88c8333-a652-4476-b225-2e9284eb59f1" ] || _fail "btrfstune metadata UUID change failed"
+ [ "$old_metadata_uuid" = "$metadata_uuid" ] || _fail "Metadata uuid change unexpectedly"
+
+ echo "Checking for incompat textual representation" >> "$RESULTS"
+ # check for textual output of the new incompat feature
+ run_check_stdout $SUDO_HELPER "$TOP/btrfs" inspect-internal dump-super \
+ "$TEST_DEV" | grep -q METADATA_UUID
+ [ $? -eq 0 ] || _fail "Didn't find textual representation of METADATA_UUID feature"
+
+ echo "Checking setting fsid back to original" >> "$RESULTS"
+ # ensure that setting the fsid back to the original works
+ run_check $SUDO_HELPER "$TOP/btrfstune" -M "$old_metadata_uuid" "$TEST_DEV"
+
+ fsid=$(read_fsid "$TEST_DEV")
+ metadata_uuid=$(read_metadata_uuid "$TEST_DEV")
+
+ [ "$fsid" = "$metadata_uuid" ] || _fail "FSID and METADATA_UUID don't match"
+ run_check_stdout $SUDO_HELPER "$TOP/btrfs" inspect-internal dump-super \
+ "$TEST_DEV" | grep -q METADATA_UUID
+ [ $? -eq 1 ] || _fail "METADATA_UUID feature still shown as enabled"
+}
+
+function check_image_restore {
+ local metadata_uuid
+ local fsid
+ local fsid_restored
+ local metadata_uuid_restored
+
+ echo "TESTING btrfs-image restore" >> "$RESULTS"
+ run_check $SUDO_HELPER "$TOP/mkfs.btrfs" -f "$TEST_DEV"
+ run_check $SUDO_HELPER "$TOP/btrfstune" -m "$TEST_DEV"
+ fsid=$(read_fsid "$TEST_DEV")
+ metadata_uuid=$(read_metadata_uuid "$TEST_DEV")
+ run_mayfail $SUDO_HELPER "$TOP/btrfs-image" "$TEST_DEV" /tmp/test-img.dump
+ # erase the fs by creating a new one, wipefs is not sufficient as it just
+ # deletes the fs magic string
+ run_check $SUDO_HELPER "$TOP/mkfs.btrfs" -f "$TEST_DEV"
+ run_check $SUDO_HELPER "$TOP/btrfs-image" -r /tmp/test-img.dump "$TEST_DEV"
+ fsid_restored=$(read_fsid "$TEST_DEV")
+ metadata_uuid_restored=$(read_metadata_uuid "$TEST_DEV")
+
+ [ "$fsid" = "$fsid_restored" ] || _fail "FSID don't match after restore"
+ [ "$metadata_uuid" = "$metadata_uuid_restored" ] || _fail "metadata uuids don't match after restore"
+}
+
+function check_inprogress_flag {
+ # check the flag is indeed cleared
+ run_check_stdout $SUDO_HELPER "$TOP/btrfs" inspect-internal dump-super \
+ $1 | grep -q 0x1000000001
+ [ $? -eq 1 ] || _fail "Found BTRFS_SUPER_FLAG_CHANGING_FSID_V2 set for $1"
+
+ run_check_stdout $SUDO_HELPER $TOP/btrfs inspect-internal dump-super \
+ $2 | grep -q 0x1000000001
+ [ $? -eq 1 ] || _fail "Found BTRFS_SUPER_FLAG_CHANGING_FSID_V2 set for $2"
+}
+
+function check_completed {
+ # check that metadata uuid is indeed completed
+ run_check_stdout $SUDO_HELPER "$TOP/btrfs" inspect-internal dump-super \
+ $1 | grep -q METADATA_UUID
+ [ $? -eq 0 ] || _fail "METADATA_UUID not set on $1"
+
+ run_check_stdout $SUDO_HELPER $TOP/btrfs inspect-internal dump-super \
+ $2 | grep -q METADATA_UUID
+ [ $? -eq 0 ] || _fail "METADATA_UUID not set on $2"
+}
+
+function check_multi_fsid_change {
+ check_inprogress_flag $1 $2
+ check_completed $1 $2
+}
+
+function failure_recovery {
+ local image1
+ local image2
+ local loop1
+ local loop2
+ local devcount
+
+ image1=$(extract_image "$1")
+ image2=$(extract_image "$2")
+ loop1=$(run_check_stdout $SUDO_HELPER losetup --find --show "$image1")
+ loop2=$(run_check_stdout $SUDO_HELPER losetup --find --show "$image2")
+
+ # Mount and unmount, on trans commit all disks should be consistent
+ run_check $SUDO_HELPER mount "$loop1" "$TEST_MNT"
+ run_check $SUDO_HELPER umount "$TEST_MNT"
+
+ # perform any specific check
+ $3 "$loop1" "$loop2"
+
+ # cleanup
+ run_check $SUDO_HELPER losetup -d "$loop1"
+ run_check $SUDO_HELPER losetup -d "$loop2"
+ rm -f "$image1" "$image2"
+}
+
+function reload_btrfs {
+ rmmod btrfs
+ modprobe btrfs
+}
+
+# for full coverage we need btrfs to actually be a module
+modinfo btrfs > /dev/null 2>&1 || _not_run "btrfs must be a module"
+modprobe -r btrfs || _not_run "btrfs must be unloadable"
+modprobe btrfs || _not_run "loading btrfs module failed"
+
+run_check $SUDO_HELPER "$TOP/mkfs.btrfs" -f "$TEST_DEV"
+check_btrfstune
+
+run_check $SUDO_HELPER "$TOP/mkfs.btrfs" -f "$TEST_DEV"
+check_dump_super_output
+
+run_check $SUDO_HELPER "$TOP/mkfs.btrfs" -f "$TEST_DEV"
+check_image_restore
+
+# disk1 is an image which has no metadata uuid flags set and disk2 is part of
+# the same fs but has the in-progress flag set. Test that whicever is scanned
+# first will result in consistent filesystem.
+failure_recovery "./disk1.raw.xz" "./disk2.raw.xz" check_inprogress_flag
+reload_btrfs
+failure_recovery "./disk2.raw.xz" "./disk1.raw.xz" check_inprogress_flag
+
+reload_btrfs
+
+# disk4 contains an image in with the in-progress flag set and disk 3 is part
+# of the same filesystem but has both METADATA_UUID incompat and a new
+# metadata uuid set. So disk 3 must always take precedence
+failure_recovery "./disk3.raw.xz" "./disk4.raw.xz" check_completed
+reload_btrfs
+failure_recovery "./disk4.raw.xz" "./disk3.raw.xz" check_completed
+
+# disk5 contains an image which has undergone a successful fsid change more
+# than once, disk6 on the other hand is member of the same filesystem but
+# hasn't completed its last change. Thus it has both the FSID_CHANGING flag set
+# and METADATA_UUID flag set.
+failure_recovery "./disk5.raw.xz" "./disk6.raw.xz" check_multi_fsid_change
+reload_btrfs
+failure_recovery "./disk6.raw.xz" "./disk5.raw.xz" check_multi_fsid_change
diff --git a/tests/misc-tests/035-receive-common-mount-point-prefix/test.sh b/tests/misc-tests/035-receive-common-mount-point-prefix/test.sh
new file mode 100755
index 00000000..375ade20
--- /dev/null
+++ b/tests/misc-tests/035-receive-common-mount-point-prefix/test.sh
@@ -0,0 +1,48 @@
+#!/bin/bash
+# Test that receive determines the correct mount point path when there is
+# another mount point that matches the destination's path as a prefix.
+
+source "$TEST_TOP/common"
+
+check_prereq btrfs
+check_prereq mkfs.btrfs
+
+setup_root_helper
+
+rm -f dev1 dev2
+run_check truncate -s 1G dev1
+run_check truncate -s 1G dev2
+chmod a+w dev1 dev2
+
+loop1=$(run_check_stdout $SUDO_HELPER losetup --find --show dev1)
+loop2=$(run_check_stdout $SUDO_HELPER losetup --find --show dev2)
+
+run_check $SUDO_HELPER "$TOP/mkfs.btrfs" -f "$loop1"
+run_check $SUDO_HELPER "$TOP/mkfs.btrfs" -f "$loop2"
+
+run_check $SUDO_HELPER mount "$loop1" "$TEST_MNT"
+run_check $SUDO_HELPER mkdir "$TEST_MNT/ddis"
+run_check $SUDO_HELPER mkdir "$TEST_MNT/ddis-not-a-mount"
+run_check $SUDO_HELPER mount "$loop2" "$TEST_MNT/ddis"
+
+echo "some data" | $SUDO_HELPER tee "$TEST_MNT/ddis/file" > /dev/null
+
+run_check $SUDO_HELPER "$TOP/btrfs" subvolume snapshot -r \
+ "$TEST_MNT/ddis" "$TEST_MNT/ddis/snap"
+
+run_check truncate -s 0 send.data
+chmod a+w send.data
+run_check $SUDO_HELPER "$TOP/btrfs" send -f send.data "$TEST_MNT/ddis/snap"
+
+# The following receive used to fail because it incorrectly determined the mount
+# point of the destination path to be $TEST_MNT/ddis and not $TEST_MNT.
+run_check $SUDO_HELPER "$TOP/btrfs" receive -f send.data \
+ "$TEST_MNT/ddis-not-a-mount"
+
+run_check $SUDO_HELPER umount "$TEST_MNT/ddis"
+run_check $SUDO_HELPER umount "$TEST_MNT"
+
+# Cleanup loop devices and send data.
+run_check $SUDO_HELPER losetup -d "$loop1"
+run_check $SUDO_HELPER losetup -d "$loop2"
+rm -f dev1 dev2 send.data
diff --git a/utils-lib.c b/utils-lib.c
index 2ac421be..123f64a1 100644
--- a/utils-lib.c
+++ b/utils-lib.c
@@ -1,4 +1,5 @@
#include "kerncompat.h"
+#include "utils.h"
#include <unistd.h>
#include <stdlib.h>
#include <limits.h>
diff --git a/utils.c b/utils.c
index 3a4bc92a..2c60ef21 100644
--- a/utils.c
+++ b/utils.c
@@ -1134,15 +1134,25 @@ int pretty_size_snprintf(u64 size, char *str, size_t str_size, unsigned unit_mod
num_divs = 0;
last_size = size;
switch (unit_mode & UNITS_MODE_MASK) {
- case UNITS_TBYTES: base *= mult; num_divs++;
- case UNITS_GBYTES: base *= mult; num_divs++;
- case UNITS_MBYTES: base *= mult; num_divs++;
- case UNITS_KBYTES: num_divs++;
- break;
+ case UNITS_TBYTES:
+ base *= mult;
+ num_divs++;
+ __attribute__ ((fallthrough));
+ case UNITS_GBYTES:
+ base *= mult;
+ num_divs++;
+ __attribute__ ((fallthrough));
+ case UNITS_MBYTES:
+ base *= mult;
+ num_divs++;
+ __attribute__ ((fallthrough));
+ case UNITS_KBYTES:
+ num_divs++;
+ break;
case UNITS_BYTES:
- base = 1;
- num_divs = 0;
- break;
+ base = 1;
+ num_divs = 0;
+ break;
default:
if (negative) {
s64 ssize = (s64)size;
@@ -1907,13 +1917,17 @@ int test_num_disk_vs_raid(u64 metadata_profile, u64 data_profile,
default:
case 4:
allowed |= BTRFS_BLOCK_GROUP_RAID10;
+ __attribute__ ((fallthrough));
case 3:
allowed |= BTRFS_BLOCK_GROUP_RAID6;
+ __attribute__ ((fallthrough));
case 2:
allowed |= BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID1 |
BTRFS_BLOCK_GROUP_RAID5;
+ __attribute__ ((fallthrough));
case 1:
allowed |= BTRFS_BLOCK_GROUP_DUP;
+ __attribute__ ((fallthrough));
}
if (dev_cnt > 1 && profile & BTRFS_BLOCK_GROUP_DUP) {
@@ -2048,7 +2062,7 @@ int find_mount_root(const char *path, char **mount_root)
int fd;
struct mntent *ent;
int len;
- int ret;
+ int ret = 0;
int not_btrfs = 1;
int longest_matchlen = 0;
char *longest_match = NULL;
@@ -2064,18 +2078,25 @@ int find_mount_root(const char *path, char **mount_root)
while ((ent = getmntent(mnttab))) {
len = strlen(ent->mnt_dir);
- if (strncmp(ent->mnt_dir, path, len) == 0) {
+ if (strncmp(ent->mnt_dir, path, len) == 0 &&
+ (path[len] == '/' || path[len] == '\0')) {
/* match found and use the latest match */
if (longest_matchlen <= len) {
free(longest_match);
longest_matchlen = len;
longest_match = strdup(ent->mnt_dir);
+ if (!longest_match) {
+ ret = -errno;
+ break;
+ }
not_btrfs = strcmp(ent->mnt_type, "btrfs");
}
}
}
endmntent(mnttab);
+ if (ret)
+ return ret;
if (!longest_match)
return -ENOENT;
if (not_btrfs) {
@@ -2252,29 +2273,6 @@ int btrfs_tree_search2_ioctl_supported(int fd)
return ret;
}
-int btrfs_check_nodesize(u32 nodesize, u32 sectorsize, u64 features)
-{
- if (nodesize < sectorsize) {
- error("illegal nodesize %u (smaller than %u)",
- nodesize, sectorsize);
- return -1;
- } else if (nodesize > BTRFS_MAX_METADATA_BLOCKSIZE) {
- error("illegal nodesize %u (larger than %u)",
- nodesize, BTRFS_MAX_METADATA_BLOCKSIZE);
- return -1;
- } else if (nodesize & (sectorsize - 1)) {
- error("illegal nodesize %u (not aligned to %u)",
- nodesize, sectorsize);
- return -1;
- } else if (features & BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS &&
- nodesize != sectorsize) {
- error("illegal nodesize %u (not equal to %u for mixed block group)",
- nodesize, sectorsize);
- return -1;
- }
- return 0;
-}
-
/*
* Copy a path argument from SRC to DEST and check the SRC length if it's at
* most PATH_MAX and fits into DEST. DESTLEN is supposed to be exact size of
diff --git a/uuid-tree.c b/uuid-tree.c
index 320eb67e..422260fa 100644
--- a/uuid-tree.c
+++ b/uuid-tree.c
@@ -23,17 +23,19 @@
#include "transaction.h"
#include "disk-io.h"
#include "print-tree.h"
+#include "utils.h"
-
-static void btrfs_uuid_to_key(const u8 *uuid, u64 *key_objectid,
- u64 *key_offset)
+void btrfs_uuid_to_key(const u8 *uuid, u64 *key_objectid, u64 *key_offset)
{
*key_objectid = get_unaligned_le64(uuid);
*key_offset = get_unaligned_le64(uuid + sizeof(u64));
}
-
-/* return -ENOENT for !found, < 0 for errors, or 0 if an item was found */
+/*
+ * Search uuid tree - mounted
+ *
+ * return -ENOENT for !found, < 0 for errors, or 0 if an item was found
+ */
static int btrfs_uuid_tree_lookup_any(int fd, const u8 *uuid, u8 type,
u64 *subid)
{
diff --git a/volumes.c b/volumes.c
index 30090ce5..2c6aaf42 100644
--- a/volumes.c
+++ b/volumes.c
@@ -142,13 +142,19 @@ static struct btrfs_device *find_device(struct btrfs_fs_devices *fs_devices,
return NULL;
}
-static struct btrfs_fs_devices *find_fsid(u8 *fsid)
+static struct btrfs_fs_devices *find_fsid(u8 *fsid, u8 *metadata_uuid)
{
struct btrfs_fs_devices *fs_devices;
list_for_each_entry(fs_devices, &fs_uuids, list) {
- if (memcmp(fsid, fs_devices->fsid, BTRFS_FSID_SIZE) == 0)
+ if (metadata_uuid && (memcmp(fsid, fs_devices->fsid,
+ BTRFS_FSID_SIZE) == 0) &&
+ (memcmp(metadata_uuid, fs_devices->metadata_uuid,
+ BTRFS_FSID_SIZE) == 0)) {
return fs_devices;
+ } else if (memcmp(fsid, fs_devices->fsid, BTRFS_FSID_SIZE) == 0){
+ return fs_devices;
+ }
}
return NULL;
}
@@ -160,8 +166,15 @@ static int device_list_add(const char *path,
struct btrfs_device *device;
struct btrfs_fs_devices *fs_devices;
u64 found_transid = btrfs_super_generation(disk_super);
+ bool metadata_uuid = (btrfs_super_incompat_flags(disk_super) &
+ BTRFS_FEATURE_INCOMPAT_METADATA_UUID);
+
+ if (metadata_uuid)
+ fs_devices = find_fsid(disk_super->fsid,
+ disk_super->metadata_uuid);
+ else
+ fs_devices = find_fsid(disk_super->fsid, NULL);
- fs_devices = find_fsid(disk_super->fsid);
if (!fs_devices) {
fs_devices = kzalloc(sizeof(*fs_devices), GFP_NOFS);
if (!fs_devices)
@@ -169,6 +182,13 @@ static int device_list_add(const char *path,
INIT_LIST_HEAD(&fs_devices->devices);
list_add(&fs_devices->list, &fs_uuids);
memcpy(fs_devices->fsid, disk_super->fsid, BTRFS_FSID_SIZE);
+ if (metadata_uuid)
+ memcpy(fs_devices->metadata_uuid,
+ disk_super->metadata_uuid, BTRFS_FSID_SIZE);
+ else
+ memcpy(fs_devices->metadata_uuid, fs_devices->fsid,
+ BTRFS_FSID_SIZE);
+
fs_devices->latest_devid = devid;
fs_devices->latest_trans = found_transid;
fs_devices->lowest_devid = (u64)-1;
@@ -530,10 +550,12 @@ static int find_free_dev_extent(struct btrfs_device *device, u64 num_bytes,
return find_free_dev_extent_start(device, num_bytes, 0, start, len);
}
-static int btrfs_alloc_dev_extent(struct btrfs_trans_handle *trans,
- struct btrfs_device *device,
- u64 chunk_offset, u64 num_bytes, u64 *start,
- int convert)
+/*
+ * Insert one device extent into the fs.
+ */
+int btrfs_insert_dev_extent(struct btrfs_trans_handle *trans,
+ struct btrfs_device *device,
+ u64 chunk_offset, u64 num_bytes, u64 start)
{
int ret;
struct btrfs_path *path;
@@ -546,18 +568,8 @@ static int btrfs_alloc_dev_extent(struct btrfs_trans_handle *trans,
if (!path)
return -ENOMEM;
- /*
- * For convert case, just skip search free dev_extent, as caller
- * is responsible to make sure it's free.
- */
- if (!convert) {
- ret = find_free_dev_extent(device, num_bytes, start, NULL);
- if (ret)
- goto err;
- }
-
key.objectid = device->devid;
- key.offset = *start;
+ key.offset = start;
key.type = BTRFS_DEV_EXTENT_KEY;
ret = btrfs_insert_empty_item(trans, root, path, &key,
sizeof(*extent));
@@ -583,6 +595,22 @@ err:
return ret;
}
+/*
+ * Allocate one free dev extent and insert it into the fs.
+ */
+static int btrfs_alloc_dev_extent(struct btrfs_trans_handle *trans,
+ struct btrfs_device *device,
+ u64 chunk_offset, u64 num_bytes, u64 *start)
+{
+ int ret;
+
+ ret = find_free_dev_extent(device, num_bytes, start, NULL);
+ if (ret)
+ return ret;
+ return btrfs_insert_dev_extent(trans, device, chunk_offset, num_bytes,
+ *start);
+}
+
static int find_next_chunk(struct btrfs_fs_info *fs_info, u64 *offset)
{
struct btrfs_root *root = fs_info->chunk_root;
@@ -713,7 +741,8 @@ int btrfs_add_device(struct btrfs_trans_handle *trans,
ptr = (unsigned long)btrfs_device_uuid(dev_item);
write_extent_buffer(leaf, device->uuid, ptr, BTRFS_UUID_SIZE);
ptr = (unsigned long)btrfs_device_fsid(dev_item);
- write_extent_buffer(leaf, fs_info->fsid, ptr, BTRFS_UUID_SIZE);
+ write_extent_buffer(leaf, fs_info->fs_devices->metadata_uuid, ptr,
+ BTRFS_UUID_SIZE);
btrfs_mark_buffer_dirty(leaf);
ret = 0;
@@ -1107,7 +1136,7 @@ again:
list_move_tail(&device->dev_list, dev_list);
ret = btrfs_alloc_dev_extent(trans, device, key.offset,
- calc_size, &dev_offset, 0);
+ calc_size, &dev_offset);
if (ret < 0)
goto out_chunk_map;
@@ -1241,8 +1270,12 @@ int btrfs_alloc_data_chunk(struct btrfs_trans_handle *trans,
while (index < num_stripes) {
struct btrfs_stripe *stripe;
- ret = btrfs_alloc_dev_extent(trans, device, key.offset,
- calc_size, &dev_offset, convert);
+ if (convert)
+ ret = btrfs_insert_dev_extent(trans, device, key.offset,
+ calc_size, dev_offset);
+ else
+ ret = btrfs_alloc_dev_extent(trans, device, key.offset,
+ calc_size, &dev_offset);
BUG_ON(ret);
device->bytes_used += calc_size;
@@ -1686,7 +1719,7 @@ struct btrfs_device *btrfs_find_device(struct btrfs_fs_info *fs_info, u64 devid,
cur_devices = fs_info->fs_devices;
while (cur_devices) {
if (!fsid ||
- (!memcmp(cur_devices->fsid, fsid, BTRFS_UUID_SIZE) ||
+ (!memcmp(cur_devices->metadata_uuid, fsid, BTRFS_FSID_SIZE) ||
fs_info->ignore_fsid_mismatch)) {
device = find_device(cur_devices, devid, uuid);
if (device)
@@ -1968,7 +2001,7 @@ static int open_seed_devices(struct btrfs_fs_info *fs_info, u8 *fsid)
fs_devices = fs_devices->seed;
}
- fs_devices = find_fsid(fsid);
+ fs_devices = find_fsid(fsid, NULL);
if (!fs_devices) {
/* missing all seed devices */
fs_devices = kzalloc(sizeof(*fs_devices), GFP_NOFS);
@@ -2007,9 +2040,9 @@ static int read_one_dev(struct btrfs_fs_info *fs_info,
BTRFS_UUID_SIZE);
read_extent_buffer(leaf, fs_uuid,
(unsigned long)btrfs_device_fsid(dev_item),
- BTRFS_UUID_SIZE);
+ BTRFS_FSID_SIZE);
- if (memcmp(fs_uuid, fs_info->fsid, BTRFS_UUID_SIZE)) {
+ if (memcmp(fs_uuid, fs_info->fs_devices->fsid, BTRFS_UUID_SIZE)) {
ret = open_seed_devices(fs_info, fs_uuid);
if (ret)
return ret;
diff --git a/volumes.h b/volumes.h
index b4ea93f0..e30bcef7 100644
--- a/volumes.h
+++ b/volumes.h
@@ -71,6 +71,7 @@ struct btrfs_device {
struct btrfs_fs_devices {
u8 fsid[BTRFS_FSID_SIZE]; /* FS specific uuid */
+ u8 metadata_uuid[BTRFS_FSID_SIZE]; /* FS specific uuid */
/* the device with this id has the most recent copy of the super */
u64 latest_devid;
@@ -268,6 +269,9 @@ int btrfs_open_devices(struct btrfs_fs_devices *fs_devices,
int flags);
int btrfs_close_devices(struct btrfs_fs_devices *fs_devices);
void btrfs_close_all_devices(void);
+int btrfs_insert_dev_extent(struct btrfs_trans_handle *trans,
+ struct btrfs_device *device,
+ u64 chunk_offset, u64 num_bytes, u64 start);
int btrfs_add_device(struct btrfs_trans_handle *trans,
struct btrfs_fs_info *fs_info,
struct btrfs_device *device);