Skip to contentSkip to conversation

Bug or feature? logical_to_ino skips inodes with offset mismatch

DISCUSSION Hans van Kranenburg 1 participant 2 messages Feb 5, 2017 Btrfs file system

lore
Share & tools
lore
#0 lore raw

I was playing around with logical_to_ino and also implemented calling ino_lookup today to create a program that will print all data extents in a block group, and their related inodes and at least one filename per inode.

https://github.com/knorrie/python-btrfs/commits/develop
See "examples: show filenames for data extents"

I ran into the following behaviour of logical_to_ino:

If the offset value in a backreference of an extent_item does not match the offset value of the extent_data object in the fs tree, logical_to_ino will skip the inode that uses data from the extent, and not report it.

This leads to extents for which logical_to_ino does not give any result, while there's actually a file using data from the extent.

Is this a bug or a feature?

How to test (only relevant output lines pasted):

1. copy a file into place:

-# cp /boot/vmlinuz-4.9.0-1-amd64 /mnt/i320/fstree/

-# examples/show_block_group_contents.py 289406976 /mnt/i320/fstree/ extent vaddr 336048128 length 4186112 refs 1 gen 57 flags DATA
inline extent data backref root 5 objectid 266 offset 0 count 1

-# examples/show_block_group_data_extent_filenames.py 289406976 /mnt/i320/fstree/
extent vaddr 336048128 length 4186112 refs 1 gen 57 flags DATA

    root 5 inode 266 offset 0 path 'vmlinuz-4.9.0-1-amd64'

-# btrfs inspect-internal logical-resolve 336048128 . ./vmlinuz-4.9.0-1-amd64

2. Now, overwrite the beginning of the file, so we have a new extent for that data, and so that the old big extent holds 16kiB of 'wasted/unreachable' data at the beginning.

-# dd if=/dev/urandom bs=16k conv=notrunc of=vmlinuz-4.9.0-1-amd64 count=1

Result:

-# examples/show_block_group_contents.py 289406976 /mnt/i320/fstree/ extent vaddr 336048128 length 4186112 refs 1 gen 57 flags DATA
inline extent data backref root 5 objectid 266 offset 0 count 1
extent vaddr 341217280 length 16384 refs 1 gen 60 flags DATA
inline extent data backref root 5 objectid 266 offset 0 count 1

Notice that the backrefs both list offset 0, since there's only one per referenced inode and it doesn't get updated when the're a change in which parts of the extent are actually still used by the inode.

3. logical_to_ino does not list the inode any more as user of this extent now:

-# examples/show_block_group_data_extent_filenames.py 289406976 /mnt/i320/fstree/
extent vaddr 336048128 length 4186112 refs 1 gen 57 flags DATA extent vaddr 341217280 length 16384 refs 1 gen 60 flags DATA

    root 5 inode 266 offset 0 path 'vmlinuz-4.9.0-1-amd64'

-# btrfs inspect-internal logical-resolve 336048128 . <no output>

-# btrfs-debug-tree -t 5 /dev/i320/fstree

    item 6 key (266 EXTENT_DATA 0) itemoff 15765 itemsize 53
        extent data disk byte 341217280 nr 16384
        extent data offset 0 nr 16384 ram 16384
        extent compression(none)
    item 7 key (266 EXTENT_DATA 16384) itemoff 15712 itemsize 53
        extent data disk byte 336048128 nr 4186112
        extent data offset 16384 nr 4169728 ram 4186112
        extent compression(none)
Signature · 1 line
Hans van Kranenburg
#1 lore raw
Quoted 7 lines · Hans van Kranenburg

I was playing around with logical_to_ino and also implemented calling ino_lookup today to create a program that will print all data extents in a block group, and their related inodes and at least one filename per inode.

https://github.com/knorrie/python-btrfs/commits/develop
See "examples: show filenames for data extents"

Quoted 6 lines

I ran into the following behaviour of logical_to_ino:

If the offset value in a backreference of an extent_item does not match the offset value of the extent_data object in the fs tree, logical_to_ino will skip the inode that uses data from the extent, and not report it.

Ah, wait... To answer my own question... The reason is probably because the data at that exact place is not actually in use.

-# btrfs inspect-internal logical-resolve 336064511 . (+ 16KiB - 1) -# btrfs inspect-internal logical-resolve 336064512 . (+ 16KiB) ./vmlinuz-4.9.0-1-amd64
-# btrfs inspect-internal logical-resolve 336064513 . ./vmlinuz-4.9.0-1-amd64

Jups... Makes sense.

But, it also means that I cannot use logical_to_ino as a helper to expand shared backrefs to actual inode info... Meh.

Signature · 1 line
Hans van Kranenburg