Skip to content

Instantly share code, notes, and snippets.

@CyberShadow
Created May 3, 2023 07:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save CyberShadow/e88008a4051c03aa86ac7e473bf5afb9 to your computer and use it in GitHub Desktop.
Save CyberShadow/e88008a4051c03aa86ac7e473bf5afb9 to your computer and use it in GitHub Desktop.
btrfs regression debugging
#!/bin/bash
set -eEuo pipefail
cd "$(dirname "$0")"
pwd=$PWD
cd ~/work/extern/linux
if true
then
~/libexec/git-clean -fdx
~/libexec/ccache-run make ARCH=x86_64 defconfig || exit 125
cat >> .config <<EOF
CONFIG_NET_9P=y
CONFIG_NET_9P_VIRTIO=y
CONFIG_NET_9P_DEBUG=y
CONFIG_9P_FS=y
CONFIG_9P_FS_POSIX_ACL=y
CONFIG_PCI=y
CONFIG_VIRTIO_PCI=y
CONFIG_PCI_HOST_GENERIC=y
CONFIG_BTRFS_FS=y
# CONFIG_PVPANIC=y
EOF
~/libexec/ccache-run make ARCH=x86_64 olddefconfig || exit 125
~/libexec/ccache-run make -j"$(nproc)" || exit 125
fi
fs=/tmp/2023-05-01/fs
rm -f "$fs"/result.txt
# shellcheck disable=SC2054
args=(
env -i
DISPLAY="$DISPLAY"
HOME="$HOME"
PATH=/usr/bin
# ~/libexec/t
~/libexec/bwrap-unshare
--unshare-user
--dev-bind / /
--bind "$pwd"/init "$(realpath "$fs"/bin/init)"
--dir "$fs"/btdu
--ro-bind ~/work/btdu "$fs"/btdu
qemu-system-x86_64
-enable-kvm
-kernel arch/x86/boot/bzImage
# -drive file=fat:rw:"$fs"
-virtfs local,path="$fs",mount_tag=root,security_model=passthrough,mount_tag=fsRoot
-drive file=/tmp/2023-05-01/badimage,format=raw
# -device pvpanic
# -fsdev local,security_model=passthrough,multidevs=remap,id=fsdev-fsRoot,path="$fs"
# -device virtio-9p-pci,id=fsRoot,fsdev=fsdev-fsRoot,mount_tag=fsRoot
-append "root=fsRoot rw rootfstype=9p rootflags=trans=virtio,version=9p2000.L,msize=5000000,cache=mmap,posixacl panic=-1 console=ttyS0"
-nographic
-no-reboot
# -net nic -net user
) ; "${args[@]}"
cat "$fs"/result.txt || exit 125
if grep -qF '<UNREACHABLE>' "$fs"/result.txt ; then
exit 0 # good/old
else
exit 1 # bad/new
fi
#!/bin/bash
set -eEuo pipefail
patch="$PWD"/patch-rev.diff
cd "$(dirname "$0")"
pwd=$PWD
cd ~/work/extern/linux
if true
then
# ~/libexec/git-clean -fdx
# ~/libexec/ccache-run make ARCH=x86_64 defconfig || exit 125
# cat >> .config <<EOF
# CONFIG_NET_9P=y
# CONFIG_NET_9P_VIRTIO=y
# CONFIG_NET_9P_DEBUG=y
# CONFIG_9P_FS=y
# CONFIG_9P_FS_POSIX_ACL=y
# CONFIG_PCI=y
# CONFIG_VIRTIO_PCI=y
# CONFIG_PCI_HOST_GENERIC=y
# CONFIG_BTRFS_FS=y
# # CONFIG_PVPANIC=y
# EOF
# ~/libexec/ccache-run make ARCH=x86_64 olddefconfig || exit 125
git reset --hard
git checkout 6ce6ba534418132f4c727d5707fe2794c797299c
patch -p1 < "$patch"
~/libexec/ccache-run make -j"$(nproc)" # || exit 125
fi
fs=/tmp/2023-05-01/fs
rm -f "$fs"/result.txt
# shellcheck disable=SC2054
args=(
env -i
DISPLAY="$DISPLAY"
HOME="$HOME"
PATH=/usr/bin
# ~/libexec/t
~/libexec/bwrap-unshare
--unshare-user
--dev-bind / /
--bind "$pwd"/init "$(realpath "$fs"/bin/init)"
--dir "$fs"/btdu
--ro-bind ~/work/btdu "$fs"/btdu
qemu-system-x86_64
-enable-kvm
-kernel arch/x86/boot/bzImage
# -drive file=fat:rw:"$fs"
-virtfs local,path="$fs",mount_tag=root,security_model=passthrough,mount_tag=fsRoot
-drive file=/tmp/2023-05-01/badimage,format=raw
# -device pvpanic
# -fsdev local,security_model=passthrough,multidevs=remap,id=fsdev-fsRoot,path="$fs"
# -device virtio-9p-pci,id=fsRoot,fsdev=fsdev-fsRoot,mount_tag=fsRoot
-append "root=fsRoot rw rootfstype=9p rootflags=trans=virtio,version=9p2000.L,msize=5000000,cache=mmap,posixacl panic=-1 console=ttyS0"
-nographic
-no-reboot
# -net nic -net user
) ; "${args[@]}"
cat "$fs"/result.txt || exit 125
if grep -qF '<UNREACHABLE>' "$fs"/result.txt ; then
exit 0 # good/old
else
exit 1 # bad/new
fi
#!/bin/bash
set -xeEuo pipefail
mount -t proc proc /proc
mount -t sysfs sysfs /sys
mount -o ro /dev/sda /mnt
#/bin/bash
/btdu/btdu --headless --du --max-samples=100000 /mnt > /result.txt
#!/bin/bash
set -eEuo pipefail
cd /tmp/2023-05-01
exec pacstrap -N -K -c "$PWD"/fs base
#!/bin/bash
set -eEuo pipefail
umount mnt || true
image=/tmp/2023-05-01/badimage
rm -f "$image"
rm -rf mnt
dd if=/dev/null of="$image" bs=2G count=0 seek=1
mkfs.btrfs "$image"
mkdir -p mnt
{
trap 'rmdir mnt' EXIT
sudo true
{
trap 'sudo umount mnt' EXIT
sudo mount "$image" mnt
sudo chown "$UID" mnt/.
dd if=/dev/urandom of=mnt/file bs=1G count=1
for _ in $(seq $((4*1024))) ; do
sync mnt
dd if=/dev/urandom of=mnt/file bs=$((1024*1024)) count=1 seek=$((RANDOM*RANDOM*RANDOM%(1024))) conv=notrunc
done
}
}
diff --git a/fs/btrfs/backref.c b/fs/btrfs/backref.c
index 432064ee788e..9be11a342de5 100644
--- a/fs/btrfs/backref.c
+++ b/fs/btrfs/backref.c
@@ -35,13 +35,15 @@ static int check_extent_in_eb(const struct btrfs_key *key,
const struct extent_buffer *eb,
const struct btrfs_file_extent_item *fi,
u64 extent_item_pos,
- struct extent_inode_elem **eie)
+ struct extent_inode_elem **eie,
+ bool ignore_offset)
{
const u64 data_len = btrfs_file_extent_num_bytes(eb, fi);
u64 offset = 0;
struct extent_inode_elem *e;
- if (!btrfs_file_extent_compression(eb, fi) &&
+ if (!ignore_offset &&
+ !btrfs_file_extent_compression(eb, fi) &&
!btrfs_file_extent_encryption(eb, fi) &&
!btrfs_file_extent_other_encoding(eb, fi)) {
u64 data_offset;
@@ -79,7 +81,8 @@ static void free_inode_elem_list(struct extent_inode_elem *eie)
static int find_extent_in_eb(const struct extent_buffer *eb,
u64 wanted_disk_byte, u64 extent_item_pos,
- struct extent_inode_elem **eie)
+ struct extent_inode_elem **eie,
+ bool ignore_offset)
{
u64 disk_byte;
struct btrfs_key key;
@@ -108,7 +111,7 @@ static int find_extent_in_eb(const struct extent_buffer *eb,
if (disk_byte != wanted_disk_byte)
continue;
- ret = check_extent_in_eb(&key, eb, fi, extent_item_pos, eie);
+ ret = check_extent_in_eb(&key, eb, fi, extent_item_pos, eie, ignore_offset);
if (ret < 0)
return ret;
}
@@ -447,9 +450,9 @@ static int is_shared_data_backref(struct preftrees *preftrees, u64 bytenr)
static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path,
struct ulist *parents,
struct preftrees *preftrees, struct prelim_ref *ref,
- int level, u64 time_seq, u64 extent_item_pos)
+ int level, u64 time_seq, const u64 *extent_item_pos,
+ bool ignore_offset)
{
- const bool ignore_offset = (extent_item_pos == BTRFS_IGNORE_EXTENT_OFFSET);
int ret = 0;
int slot;
struct extent_buffer *eb;
@@ -525,9 +528,10 @@ static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path,
count++;
else
goto next;
- if (!ignore_offset) {
+ if (extent_item_pos) {
ret = check_extent_in_eb(&key, eb, fi,
- extent_item_pos, &eie);
+ *extent_item_pos,
+ &eie, ignore_offset);
if (ret < 0)
break;
}
@@ -537,7 +541,7 @@ static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path,
eie, (void **)&old, GFP_NOFS);
if (ret < 0)
break;
- if (!ret && !ignore_offset) {
+ if (!ret && extent_item_pos) {
while (old->next)
old = old->next;
old->next = eie;
@@ -566,7 +570,7 @@ static int resolve_indirect_ref(struct btrfs_fs_info *fs_info,
struct btrfs_path *path, u64 time_seq,
struct preftrees *preftrees,
struct prelim_ref *ref, struct ulist *parents,
- u64 extent_item_pos)
+ const u64 *extent_item_pos, bool ignore_offset)
{
struct btrfs_root *root;
struct extent_buffer *eb;
@@ -660,7 +664,7 @@ static int resolve_indirect_ref(struct btrfs_fs_info *fs_info,
}
ret = add_all_parents(root, path, parents, preftrees, ref, level,
- time_seq, extent_item_pos);
+ time_seq, extent_item_pos, ignore_offset);
out:
btrfs_put_root(root);
out_free:
@@ -708,8 +712,8 @@ static void free_leaf_list(struct ulist *ulist)
static int resolve_indirect_refs(struct btrfs_fs_info *fs_info,
struct btrfs_path *path, u64 time_seq,
struct preftrees *preftrees,
- u64 extent_item_pos,
- struct share_check *sc)
+ const u64 *extent_item_pos,
+ struct share_check *sc, bool ignore_offset)
{
int err;
int ret = 0;
@@ -752,7 +756,8 @@ static int resolve_indirect_refs(struct btrfs_fs_info *fs_info,
goto out;
}
err = resolve_indirect_ref(fs_info, path, time_seq, preftrees,
- ref, parents, extent_item_pos);
+ ref, parents, extent_item_pos,
+ ignore_offset);
/*
* we can only tolerate ENOENT,otherwise,we should catch error
* and return directly.
@@ -1335,21 +1340,18 @@ static void store_backref_shared_cache(struct btrfs_backref_share_check_ctx *ctx
*
* Otherwise this returns 0 for success and <0 for an error.
*
- * @extent_item_pos is meaningful only if we are dealing with a data extent.
- * If its value is not BTRFS_IGNORE_EXTENT_OFFSET, then only collect references
- * from file extent items that refer to a section of the data extent that
- * contains @extent_item_pos. If its value is BTRFS_IGNORE_EXTENT_OFFSET then
- * collect references for every file extent item that points to the data extent.
+ * If ignore_offset is set to false, only extent refs whose offsets match
+ * extent_item_pos are returned. If true, every extent ref is returned
+ * and extent_item_pos is ignored.
*
* FIXME some caching might speed things up
*/
static int find_parent_nodes(struct btrfs_trans_handle *trans,
struct btrfs_fs_info *fs_info, u64 bytenr,
u64 time_seq, struct ulist *refs,
- struct ulist *roots, u64 extent_item_pos,
- struct share_check *sc)
+ struct ulist *roots, const u64 *extent_item_pos,
+ struct share_check *sc, bool ignore_offset)
{
- const bool ignore_offset = (extent_item_pos == BTRFS_IGNORE_EXTENT_OFFSET);
struct btrfs_root *root = btrfs_extent_root(fs_info, bytenr);
struct btrfs_key key;
struct btrfs_path *path;
@@ -1537,7 +1539,7 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans,
WARN_ON(!RB_EMPTY_ROOT(&preftrees.indirect_missing_keys.root.rb_root));
ret = resolve_indirect_refs(fs_info, path, time_seq, &preftrees,
- extent_item_pos, sc);
+ extent_item_pos, sc, ignore_offset);
if (ret)
goto out;
@@ -1571,7 +1573,8 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans,
goto out;
}
if (ref->count && ref->parent) {
- if (!ignore_offset && !ref->inode_list && ref->level == 0) {
+ if (extent_item_pos && !ref->inode_list &&
+ ref->level == 0) {
struct extent_buffer *eb;
eb = read_tree_block(fs_info, ref->parent, 0,
@@ -1589,7 +1592,7 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans,
if (!path->skip_locking)
btrfs_tree_read_lock(eb);
ret = find_extent_in_eb(eb, bytenr,
- extent_item_pos, &eie);
+ *extent_item_pos, &eie, ignore_offset);
if (!path->skip_locking)
btrfs_tree_read_unlock(eb);
free_extent_buffer(eb);
@@ -1608,7 +1611,7 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans,
(void **)&eie, GFP_NOFS);
if (ret < 0)
goto out;
- if (!ret && !ignore_offset) {
+ if (!ret && extent_item_pos) {
/*
* We've recorded that parent, so we must extend
* its inode list here.
@@ -1662,7 +1665,7 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans,
int btrfs_find_all_leafs(struct btrfs_trans_handle *trans,
struct btrfs_fs_info *fs_info, u64 bytenr,
u64 time_seq, struct ulist **leafs,
- u64 extent_item_pos)
+ const u64 *extent_item_pos, bool ignore_offset)
{
int ret;
@@ -1671,7 +1674,7 @@ int btrfs_find_all_leafs(struct btrfs_trans_handle *trans,
return -ENOMEM;
ret = find_parent_nodes(trans, fs_info, bytenr, time_seq,
- *leafs, NULL, extent_item_pos, NULL);
+ *leafs, NULL, extent_item_pos, NULL, ignore_offset);
if (ret < 0 && ret != -ENOENT) {
free_leaf_list(*leafs);
return ret;
@@ -1695,7 +1698,8 @@ int btrfs_find_all_leafs(struct btrfs_trans_handle *trans,
*/
static int btrfs_find_all_roots_safe(struct btrfs_trans_handle *trans,
struct btrfs_fs_info *fs_info, u64 bytenr,
- u64 time_seq, struct ulist **roots)
+ u64 time_seq, struct ulist **roots,
+ bool ignore_offset)
{
struct ulist *tmp;
struct ulist_node *node = NULL;
@@ -1714,8 +1718,7 @@ static int btrfs_find_all_roots_safe(struct btrfs_trans_handle *trans,
ULIST_ITER_INIT(&uiter);
while (1) {
ret = find_parent_nodes(trans, fs_info, bytenr, time_seq,
- tmp, *roots, BTRFS_IGNORE_EXTENT_OFFSET,
- NULL);
+ tmp, *roots, NULL, NULL, ignore_offset);
if (ret < 0 && ret != -ENOENT) {
ulist_free(tmp);
ulist_free(*roots);
@@ -1742,7 +1745,8 @@ int btrfs_find_all_roots(struct btrfs_trans_handle *trans,
if (!trans && !skip_commit_root_sem)
down_read(&fs_info->commit_root_sem);
- ret = btrfs_find_all_roots_safe(trans, fs_info, bytenr, time_seq, roots);
+ ret = btrfs_find_all_roots_safe(trans, fs_info, bytenr,
+ time_seq, roots, false);
if (!trans && !skip_commit_root_sem)
up_read(&fs_info->commit_root_sem);
return ret;
@@ -1841,7 +1845,7 @@ int btrfs_is_data_extent_shared(struct btrfs_inode *inode, u64 bytenr,
bool cached;
ret = find_parent_nodes(trans, fs_info, bytenr, elem.seq, &ctx->refs,
- NULL, BTRFS_IGNORE_EXTENT_OFFSET, &shared);
+ NULL, NULL, &shared, false);
if (ret == BACKREF_FOUND_SHARED ||
ret == BACKREF_FOUND_NOT_SHARED) {
/* If shared must return 1, otherwise return 0. */
@@ -2282,7 +2286,8 @@ static int iterate_leaf_refs(struct btrfs_fs_info *fs_info,
int iterate_extent_inodes(struct btrfs_fs_info *fs_info,
u64 extent_item_objectid, u64 extent_item_pos,
int search_commit_root,
- iterate_extent_inodes_t *iterate, void *ctx)
+ iterate_extent_inodes_t *iterate, void *ctx,
+ bool ignore_offset)
{
int ret;
struct btrfs_trans_handle *trans = NULL;
@@ -2313,14 +2318,16 @@ int iterate_extent_inodes(struct btrfs_fs_info *fs_info,
down_read(&fs_info->commit_root_sem);
ret = btrfs_find_all_leafs(trans, fs_info, extent_item_objectid,
- seq_elem.seq, &refs, extent_item_pos);
+ seq_elem.seq, &refs,
+ &extent_item_pos, ignore_offset);
if (ret)
goto out;
ULIST_ITER_INIT(&ref_uiter);
while (!ret && (ref_node = ulist_next(refs, &ref_uiter))) {
ret = btrfs_find_all_roots_safe(trans, fs_info, ref_node->val,
- seq_elem.seq, &roots);
+ seq_elem.seq, &roots,
+ ignore_offset);
if (ret)
break;
ULIST_ITER_INIT(&root_uiter);
@@ -2388,14 +2395,10 @@ int iterate_inodes_from_logical(u64 logical, struct btrfs_fs_info *fs_info,
if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK)
return -EINVAL;
- if (ignore_offset)
- extent_item_pos = BTRFS_IGNORE_EXTENT_OFFSET;
- else
- extent_item_pos = logical - found_key.objectid;
-
+ extent_item_pos = logical - found_key.objectid;
ret = iterate_extent_inodes(fs_info, found_key.objectid,
extent_item_pos, search_commit_root,
- build_ino_list, ctx);
+ build_ino_list, ctx, ignore_offset);
return ret;
}
diff --git a/fs/btrfs/backref.h b/fs/btrfs/backref.h
index 2eb99f23cc8f..8d3598155f3b 100644
--- a/fs/btrfs/backref.h
+++ b/fs/btrfs/backref.h
@@ -12,13 +12,6 @@
#include "disk-io.h"
#include "extent_io.h"
-/*
- * Pass to backref walking functions to tell them to include references from
- * all file extent items that point to the target data extent, regardless if
- * they refer to the whole extent or just sections of it (bookend extents).
- */
-#define BTRFS_IGNORE_EXTENT_OFFSET ((u64)-1)
-
struct inode_fs_paths {
struct btrfs_path *btrfs_path;
struct btrfs_root *fs_root;
@@ -99,7 +92,8 @@ int tree_backref_for_extent(unsigned long *ptr, struct extent_buffer *eb,
int iterate_extent_inodes(struct btrfs_fs_info *fs_info,
u64 extent_item_objectid,
u64 extent_offset, int search_commit_root,
- iterate_extent_inodes_t *iterate, void *ctx);
+ iterate_extent_inodes_t *iterate, void *ctx,
+ bool ignore_offset);
int iterate_inodes_from_logical(u64 logical, struct btrfs_fs_info *fs_info,
struct btrfs_path *path, void *ctx,
@@ -110,7 +104,7 @@ int paths_from_inode(u64 inum, struct inode_fs_paths *ipath);
int btrfs_find_all_leafs(struct btrfs_trans_handle *trans,
struct btrfs_fs_info *fs_info, u64 bytenr,
u64 time_seq, struct ulist **leafs,
- u64 extent_item_pos);
+ const u64 *extent_item_pos, bool ignore_offset);
int btrfs_find_all_roots(struct btrfs_trans_handle *trans,
struct btrfs_fs_info *fs_info, u64 bytenr,
u64 time_seq, struct ulist **roots,
diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c
index 45690f7b5900..d119986d1599 100644
--- a/fs/btrfs/relocation.c
+++ b/fs/btrfs/relocation.c
@@ -3417,7 +3417,7 @@ int add_data_references(struct reloc_control *rc,
btrfs_release_path(path);
ret = btrfs_find_all_leafs(NULL, fs_info, extent_key->objectid,
- 0, &leaves, BTRFS_IGNORE_EXTENT_OFFSET);
+ 0, &leaves, NULL, true);
if (ret < 0)
return ret;
diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c
index 6c7dc89709fc..3c22573bfe0d 100644
--- a/fs/btrfs/scrub.c
+++ b/fs/btrfs/scrub.c
@@ -969,7 +969,7 @@ static void scrub_print_warning(const char *errstr, struct scrub_block *sblock)
swarn.dev = dev;
iterate_extent_inodes(fs_info, found_key.objectid,
extent_item_pos, 1,
- scrub_print_warning_inode, &swarn);
+ scrub_print_warning_inode, &swarn, false);
}
out:
diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c
index 6bf06939f891..49759cd9eecb 100644
--- a/fs/btrfs/send.c
+++ b/fs/btrfs/send.c
@@ -1467,7 +1467,7 @@ static int find_extent_clone(struct send_ctx *sctx,
extent_item_pos = 0;
ret = iterate_extent_inodes(fs_info, found_key.objectid,
extent_item_pos, 1, __iterate_backrefs,
- &backref_ctx);
+ &backref_ctx, false);
if (ret < 0)
goto out;
#!/bin/bash
set -eEuo pipefail
git -C ~/work/extern/linux bisect reset || true
git -C ~/work/extern/linux bisect start v6.2 v6.0
git -C ~/work/extern/linux bisect run "$PWD"/bisect-oracle.sh
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment