1. 21 12月, 2022 2 次提交
    • J
      btrfs: scrub: fix uninitialized return value in recover_scrub_rbio · e7fc357e
      Josef Bacik 提交于
      Commit 75b47033 ("btrfs: raid56: migrate recovery and scrub recovery
      path to use error_bitmap") introduced an uninitialized return variable.
      
      This can be caught by gcc 12.1 by -Wmaybe-uninitialized:
      
        CC [M]  fs/btrfs/raid56.o
      fs/btrfs/raid56.c: In function ‘scrub_rbio’:
      fs/btrfs/raid56.c:2801:15: warning: ‘ret’ may be used uninitialized [-Wmaybe-uninitialized]
       2801 |         ret = recover_scrub_rbio(rbio);
            |               ^~~~~~~~~~~~~~~~~~~~~~~~
      fs/btrfs/raid56.c:2649:13: note: ‘ret’ was declared here
       2649 |         int ret;
      
      The warning is disabled by default so we haven't caught that.
      
      Due to the bug the raid56 scrub fstests have been failing since the
      patch was merged, so initialize that.
      
      Fixes: 75b47033 ("btrfs: raid56: migrate recovery and scrub recovery path to use error_bitmap")
      Signed-off-by: NJosef Bacik <josef@toxicpanda.com>
      Reviewed-by: NDavid Sterba <dsterba@suse.com>
      Signed-off-by: NDavid Sterba <dsterba@suse.com>
      e7fc357e
    • B
      btrfs: fix resolving backrefs for inline extent followed by prealloc · 560840af
      Boris Burkov 提交于
      If a file consists of an inline extent followed by a regular or prealloc
      extent, then a legitimate attempt to resolve a logical address in the
      non-inline region will result in add_all_parents reading the invalid
      offset field of the inline extent. If the inline extent item is placed
      in the leaf eb s.t. it is the first item, attempting to access the
      offset field will not only be meaningless, it will go past the end of
      the eb and cause this panic:
      
        [17.626048] BTRFS warning (device dm-2): bad eb member end: ptr 0x3fd4 start 30834688 member offset 16377 size 8
        [17.631693] general protection fault, probably for non-canonical address 0x5088000000000: 0000 [#1] SMP PTI
        [17.635041] CPU: 2 PID: 1267 Comm: btrfs Not tainted 5.12.0-07246-g75175d5adc74-dirty #199
        [17.637969] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.14.0-0-g155821a1990b-prebuilt.qemu.org 04/01/2014
        [17.641995] RIP: 0010:btrfs_get_64+0xe7/0x110
        [17.649890] RSP: 0018:ffffc90001f73a08 EFLAGS: 00010202
        [17.651652] RAX: 0000000000000001 RBX: ffff88810c42d000 RCX: 0000000000000000
        [17.653921] RDX: 0005088000000000 RSI: ffffc90001f73a0f RDI: 0000000000000001
        [17.656174] RBP: 0000000000000ff9 R08: 0000000000000007 R09: c0000000fffeffff
        [17.658441] R10: ffffc90001f73790 R11: ffffc90001f73788 R12: ffff888106afe918
        [17.661070] R13: 0000000000003fd4 R14: 0000000000003f6f R15: cdcdcdcdcdcdcdcd
        [17.663617] FS:  00007f64e7627d80(0000) GS:ffff888237c80000(0000) knlGS:0000000000000000
        [17.666525] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
        [17.668664] CR2: 000055d4a39152e8 CR3: 000000010c596002 CR4: 0000000000770ee0
        [17.671253] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
        [17.673634] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
        [17.676034] PKRU: 55555554
        [17.677004] Call Trace:
        [17.677877]  add_all_parents+0x276/0x480
        [17.679325]  find_parent_nodes+0xfae/0x1590
        [17.680771]  btrfs_find_all_leafs+0x5e/0xa0
        [17.682217]  iterate_extent_inodes+0xce/0x260
        [17.683809]  ? btrfs_inode_flags_to_xflags+0x50/0x50
        [17.685597]  ? iterate_inodes_from_logical+0xa1/0xd0
        [17.687404]  iterate_inodes_from_logical+0xa1/0xd0
        [17.689121]  ? btrfs_inode_flags_to_xflags+0x50/0x50
        [17.691010]  btrfs_ioctl_logical_to_ino+0x131/0x190
        [17.692946]  btrfs_ioctl+0x104a/0x2f60
        [17.694384]  ? selinux_file_ioctl+0x182/0x220
        [17.695995]  ? __x64_sys_ioctl+0x84/0xc0
        [17.697394]  __x64_sys_ioctl+0x84/0xc0
        [17.698697]  do_syscall_64+0x33/0x40
        [17.700017]  entry_SYSCALL_64_after_hwframe+0x44/0xae
        [17.701753] RIP: 0033:0x7f64e72761b7
        [17.709355] RSP: 002b:00007ffefb067f58 EFLAGS: 00000246 ORIG_RAX: 0000000000000010
        [17.712088] RAX: ffffffffffffffda RBX: 0000000000000003 RCX: 00007f64e72761b7
        [17.714667] RDX: 00007ffefb067fb0 RSI: 00000000c0389424 RDI: 0000000000000003
        [17.717386] RBP: 00007ffefb06d188 R08: 000055d4a390d2b0 R09: 00007f64e7340a60
        [17.719938] R10: 0000000000000231 R11: 0000000000000246 R12: 0000000000000001
        [17.722383] R13: 0000000000000000 R14: 00000000c0389424 R15: 000055d4a38fd2a0
        [17.724839] Modules linked in:
      
      Fix the bug by detecting the inline extent item in add_all_parents and
      skipping to the next extent item.
      
      CC: stable@vger.kernel.org # 4.9+
      Reviewed-by: NQu Wenruo <wqu@suse.com>
      Signed-off-by: NBoris Burkov <boris@bur.io>
      Signed-off-by: NDavid Sterba <dsterba@suse.com>
      560840af
  2. 16 12月, 2022 5 次提交
  3. 06 12月, 2022 33 次提交
    • F
      btrfs: print transaction aborted messages with an error level · b7af0635
      Filipe Manana 提交于
      Currently we print the transaction aborted message with a debug level, but
      a transaction abort is an exceptional event that indicates something went
      wrong and it's useful to have it printed with an error level as it helps
      analysing problems in a production environment, where debug level messages
      are typically not logged. For example reports from syzbot never include
      the transaction aborted message, since the log level on the test machines
      is above the debug level.
      
      So change the log level from debug to error.
      Reviewed-by: NAnand Jain <anand.jain@oracle.com>
      Reviewed-by: NJohannes Thumshirn <johannes.thumshirn@wdc.com>
      Signed-off-by: NFilipe Manana <fdmanana@suse.com>
      Reviewed-by: NDavid Sterba <dsterba@suse.com>
      Signed-off-by: NDavid Sterba <dsterba@suse.com>
      b7af0635
    • J
      btrfs: sync some cleanups from progs into uapi/btrfs.h · a2813530
      Josef Bacik 提交于
      When syncing this code into btrfs-progs Dave noticed there's some things
      we were losing in the sync that are needed.  This syncs those changes
      into the kernel, which include a few comments that weren't in the
      kernel, some whitespace changes, an attribute, and the cplusplus bit.
      Signed-off-by: NJosef Bacik <josef@toxicpanda.com>
      Reviewed-by: NDavid Sterba <dsterba@suse.com>
      Signed-off-by: NDavid Sterba <dsterba@suse.com>
      a2813530
    • F
      btrfs: do not BUG_ON() on ENOMEM when dropping extent items for a range · 162d053e
      Filipe Manana 提交于
      If we get -ENOMEM while dropping file extent items in a given range, at
      btrfs_drop_extents(), due to failure to allocate memory when attempting to
      increment the reference count for an extent or drop the reference count,
      we handle it with a BUG_ON(). This is excessive, instead we can simply
      abort the transaction and return the error to the caller. In fact most
      callers of btrfs_drop_extents(), directly or indirectly, already abort
      the transaction if btrfs_drop_extents() returns any error.
      
      Also, we already have error paths at btrfs_drop_extents() that may return
      -ENOMEM and in those cases we abort the transaction, like for example
      anything that changes the b+tree may return -ENOMEM due to a failure to
      allocate a new extent buffer when COWing an existing extent buffer, such
      as a call to btrfs_duplicate_item() for example.
      
      So replace the BUG_ON() calls with proper logic to abort the transaction
      and return the error.
      
      Reported-by: syzbot+0b1fb6b0108c27419f9f@syzkaller.appspotmail.com
      Link: https://lore.kernel.org/linux-btrfs/00000000000089773e05ee4b9cb4@google.com/
      CC: stable@vger.kernel.org # 5.4+
      Reviewed-by: NJosef Bacik <josef@toxicpanda.com>
      Signed-off-by: NFilipe Manana <fdmanana@suse.com>
      Reviewed-by: NDavid Sterba <dsterba@suse.com>
      Signed-off-by: NDavid Sterba <dsterba@suse.com>
      162d053e
    • V
      btrfs: fix extent map use-after-free when handling missing device in read_one_chunk · 1742e1c9
      void0red 提交于
      Store the error code before freeing the extent_map. Though it's
      reference counted structure, in that function it's the first and last
      allocation so this would lead to a potential use-after-free.
      
      The error can happen eg. when chunk is stored on a missing device and
      the degraded mount option is missing.
      
      Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=216721Reported-by: Neriri <1527030098@qq.com>
      Fixes: adfb69af ("btrfs: add_missing_dev() should return the actual error")
      CC: stable@vger.kernel.org # 4.9+
      Signed-off-by: Nvoid0red <void0red@gmail.com>
      Reviewed-by: NDavid Sterba <dsterba@suse.com>
      Signed-off-by: NDavid Sterba <dsterba@suse.com>
      1742e1c9
    • F
      btrfs: remove outdated logic from overwrite_item() and add assertion · 3eb42344
      Filipe Manana 提交于
      As of commit 193df624 ("btrfs: search for last logged dir index if
      it's not cached in the inode"), the overwrite_item() function is always
      called for a root that is from a fs/subvolume tree. In other words, now
      it's only used during log replay to modify a fs/subvolume tree. Therefore
      we can remove the logic that checks if we are dealing with a log tree at
      overwrite_item().
      
      So remove that logic, replacing it with an assertion and document that if
      we ever need to support a log root there, we will need to clone the leaf
      from the fs/subvolume tree and then release it before modifying the log
      tree, which is needed to avoid a potential deadlock, similar to the one
      recently fixed by a patch with the subject:
      
        "btrfs: do not modify log tree while holding a leaf from fs tree locked"
      Reviewed-by: NJosef Bacik <josef@toxicpanda.com>
      Signed-off-by: NFilipe Manana <fdmanana@suse.com>
      Reviewed-by: NDavid Sterba <dsterba@suse.com>
      Signed-off-by: NDavid Sterba <dsterba@suse.com>
      3eb42344
    • F
      btrfs: unify overwrite_item() and do_overwrite_item() · 3a8d1db3
      Filipe Manana 提交于
      After commit 193df624 ("btrfs: search for last logged dir index if
      it's not cached in the inode"), there are no more callers of
      do_overwrite_item(), except overwrite_item().
      
      Originally both used to be the same function, but were split in
      commit 086dcbfa ("btrfs: insert items in batches when logging a
      directory when possible"), as there was the need to execute all logic
      of overwrite_item() but skip the tree search, since in the context of
      directory logging we already had a path with a leaf to copy data from.
      
      So unify them again as there is no more need to have them split.
      Reviewed-by: NJosef Bacik <josef@toxicpanda.com>
      Signed-off-by: NFilipe Manana <fdmanana@suse.com>
      Reviewed-by: NDavid Sterba <dsterba@suse.com>
      Signed-off-by: NDavid Sterba <dsterba@suse.com>
      3a8d1db3
    • A
      btrfs: replace strncpy() with strscpy() · 63d5429f
      Artem Chernyshev 提交于
      Using strncpy() on NUL-terminated strings are deprecated.  To avoid
      possible forming of non-terminated string strscpy() should be used.
      
      Found by Linux Verification Center (linuxtesting.org) with SVACE.
      
      CC: stable@vger.kernel.org # 4.9+
      Signed-off-by: NArtem Chernyshev <artem.chernyshev@red-soft.ru>
      Reviewed-by: NDavid Sterba <dsterba@suse.com>
      Signed-off-by: NDavid Sterba <dsterba@suse.com>
      63d5429f
    • J
      btrfs: fix uninitialized variable in find_first_clear_extent_bit · 26df39a9
      Josef Bacik 提交于
      This was caught when syncing extent-io-tree.c into btrfs-progs.  This
      however isn't really a problem, the only way next would be uninitialized
      is if we found the range we were looking for, and in this case we don't
      care about next.  However it's a compile error, so fix it up.
      Signed-off-by: NJosef Bacik <josef@toxicpanda.com>
      Signed-off-by: NDavid Sterba <dsterba@suse.com>
      26df39a9
    • J
      btrfs: fix uninitialized parent in insert_state · d7c9e1be
      Josef Bacik 提交于
      I don't know how this isn't caught when we build this in the kernel, but
      while syncing extent-io-tree.c into btrfs-progs I got an error because
      parent could potentially be uninitialized when we link in a new node,
      specifically when the extent_io_tree is empty.  This means we could have
      garbage in the parent color.  I don't know what the ramifications are of
      that, but it's probably not great, so fix this by initializing parent to
      NULL.  I spot checked all of our other usages in btrfs and we appear to
      be doing the correct thing everywhere else.
      
      Fixes: c7e118cf ("btrfs: open code rbtree search in insert_state")
      CC: stable@vger.kernel.org # 6.0+
      Signed-off-by: NJosef Bacik <josef@toxicpanda.com>
      Reviewed-by: NDavid Sterba <dsterba@suse.com>
      Signed-off-by: NDavid Sterba <dsterba@suse.com>
      d7c9e1be
    • C
      btrfs: add might_sleep() annotations · a4c853af
      ChenXiaoSong 提交于
      Add annotations to functions that might sleep due to allocations or IO
      and could be called from various contexts. In case of btrfs_search_slot
      it's not obvious why it would sleep:
      
          btrfs_search_slot
            setup_nodes_for_search
              reada_for_balance
                btrfs_readahead_node_child
                  btrfs_readahead_tree_block
                    btrfs_find_create_tree_block
                      alloc_extent_buffer
                        kmem_cache_zalloc
                          /* allocate memory non-atomically, might sleep */
                          kmem_cache_alloc(GFP_NOFS|__GFP_NOFAIL|__GFP_ZERO)
                    read_extent_buffer_pages
                      submit_extent_page
                        /* disk IO, might sleep */
                        submit_one_bio
      
      Other examples where the sleeping could happen is in 3 places might
      sleep in update_qgroup_limit_item(), as shown below:
      
        update_qgroup_limit_item
          btrfs_alloc_path
            /* allocate memory non-atomically, might sleep */
            kmem_cache_zalloc(btrfs_path_cachep, GFP_NOFS)
      Signed-off-by: NChenXiaoSong <chenxiaosong2@huawei.com>
      Reviewed-by: NDavid Sterba <dsterba@suse.com>
      Signed-off-by: NDavid Sterba <dsterba@suse.com>
      a4c853af
    • J
      btrfs: add stack helpers for a few btrfs items · 054056bd
      Josef Bacik 提交于
      We don't have these defined in the kernel because we don't have any
      users of these helpers.  However we do use them in btrfs-progs, so
      define them to make keeping accessors.h in sync between progs and the
      kernel easier.
      Signed-off-by: NJosef Bacik <josef@toxicpanda.com>
      Signed-off-by: NDavid Sterba <dsterba@suse.com>
      054056bd
    • J
      btrfs: add nr_global_roots to the super block definition · 0c703003
      Josef Bacik 提交于
      We already have this defined in btrfs-progs, add it to the kernel to
      make it easier to sync these files into btrfs-progs.
      Signed-off-by: NJosef Bacik <josef@toxicpanda.com>
      Signed-off-by: NDavid Sterba <dsterba@suse.com>
      0c703003
    • J
      btrfs: remove BTRFS_LEAF_DATA_OFFSET · 8009adf3
      Josef Bacik 提交于
      This is simply the same thing as btrfs_item_nr_offset(leaf, 0), so
      remove this helper and replace it's usage with the above statement.
      Signed-off-by: NJosef Bacik <josef@toxicpanda.com>
      Signed-off-by: NDavid Sterba <dsterba@suse.com>
      8009adf3
    • J
      btrfs: add helpers for manipulating leaf items and data · 637e3b48
      Josef Bacik 提交于
      We have some gnarly memmove and copy_extent_buffer calls for leaf
      manipulation.  This is because our item offsets aren't absolute, they're
      based on 0 being where the items start in the leaf, which is after the
      btrfs_header.  This means any manipulation of the data requires adding
      sizeof(struct btrfs_header) to the offsets we pull from the items.
      Moving the items themselves is easier as the helpers are absolute
      offsets, however we of course have to call the helpers to get the
      offsets for the item numbers.  This makes for
      copy_extent_buffer/memmove_extent_buffer calls that are kind of hard to
      reason about what's happening.
      
      Fix this by pushing this logic into helpers.  For data we'll only use
      the item provided offsets, and the helpers will use the
      BTRFS_LEAF_DATA_OFFSET addition for the offsets.  Additionally for the
      item manipulation simply pass in the item numbers, and then the helpers
      will call the offset helper to get the actual offset into the leaf.
      
      The diffstat makes this look like more code, but that's simply because I
      added comments for the helpers, it's net negative for the amount of
      code, and is easier to reason.
      Signed-off-by: NJosef Bacik <josef@toxicpanda.com>
      Signed-off-by: NDavid Sterba <dsterba@suse.com>
      637e3b48
    • J
      btrfs: add eb to btrfs_node_key_ptr_offset · e23efd8e
      Josef Bacik 提交于
      This is a change needed for extent tree v2, as we will be growing the
      header size.  This exists in btrfs-progs currently, and not having it
      makes syncing accessors.[ch] more problematic.  So make this change to
      set us up for extent tree v2 and match what btrfs-progs does to make
      syncing easier.
      Signed-off-by: NJosef Bacik <josef@toxicpanda.com>
      Signed-off-by: NDavid Sterba <dsterba@suse.com>
      e23efd8e
    • J
      btrfs: pass the extent buffer for the btrfs_item_nr helpers · 42c9419a
      Josef Bacik 提交于
      This is actually a change for extent tree v2, but it exists in
      btrfs-progs but not in the kernel.  This makes it annoying to sync
      accessors.h with btrfs-progs, and since this is the way I need it for
      extent-tree v2 simply update these helpers to take the extent buffer in
      order to make syncing possible now, and make the extent tree v2 stuff
      easier moving forward.
      Signed-off-by: NJosef Bacik <josef@toxicpanda.com>
      Signed-off-by: NDavid Sterba <dsterba@suse.com>
      42c9419a
    • J
      btrfs: move the csum helpers into ctree.h · 0e6c40eb
      Josef Bacik 提交于
      These got moved because of copy+paste, but this code exists in ctree.c,
      so move the declarations back into ctree.h.
      Signed-off-by: NJosef Bacik <josef@toxicpanda.com>
      Signed-off-by: NDavid Sterba <dsterba@suse.com>
      0e6c40eb
    • J
      btrfs: move eb offset helpers into extent_io.h · 9b48adda
      Josef Bacik 提交于
      These are very specific to how the extent buffer is defined, so this
      differs between btrfs-progs and the kernel.  Make things easier by
      moving these helpers into extent_io.h so we don't have to worry about
      this when syncing ctree.h.
      Signed-off-by: NJosef Bacik <josef@toxicpanda.com>
      Signed-off-by: NDavid Sterba <dsterba@suse.com>
      9b48adda
    • J
      btrfs: move file_extent_item helpers into file-item.h · 6bfd0ffa
      Josef Bacik 提交于
      These helpers use functions that are in multiple places, which makes it
      tricky to sync them into btrfs-progs.  Move them to file-item.h and then
      include file-item.h in places that use these helpers.
      Signed-off-by: NJosef Bacik <josef@toxicpanda.com>
      Signed-off-by: NDavid Sterba <dsterba@suse.com>
      6bfd0ffa
    • J
      btrfs: move leaf_data_end into ctree.c · 3a3178c7
      Josef Bacik 提交于
      This is only used in ctree.c, with the exception of zero'ing out extent
      buffers we're getting ready to write out.  In theory we shouldn't have
      an extent buffer with 0 items that we're writing out, however I'd rather
      be safe than sorry so open code it in extent_io.c, and then copy the
      helper into ctree.c.  This will make it easier to sync accessors.[ch]
      into btrfs-progs, as this requires a helper that isn't defined in
      accessors.h.
      Signed-off-by: NJosef Bacik <josef@toxicpanda.com>
      Signed-off-by: NDavid Sterba <dsterba@suse.com>
      3a3178c7
    • J
      btrfs: move root helpers back into ctree.h · 1fe5ebc4
      Josef Bacik 提交于
      These accidentally got brought into accessors.h, but belong with the
      btrfs_root definitions which are currently in ctree.h.  Move these to
      make it easier to sync accessors.[ch] into btrfs-progs.
      Signed-off-by: NJosef Bacik <josef@toxicpanda.com>
      Signed-off-by: NDavid Sterba <dsterba@suse.com>
      1fe5ebc4
    • C
      btrfs: move repair_io_failure to bio.c · bacf60e5
      Christoph Hellwig 提交于
      repair_io_failure ties directly into all the glory low-level details of
      mapping a bio with a logic address to the actual physical location.
      Move it right below btrfs_submit_bio to keep all the related logic
      together.
      
      Also move btrfs_repair_eb_io_failure to its caller in disk-io.c now that
      repair_io_failure is available in a header.
      Reviewed-by: NJosef Bacik <josef@toxicpanda.com>
      Reviewed-by: NJohannes Thumshirn <johannes.thumshirn@wdc.com>
      Signed-off-by: NChristoph Hellwig <hch@lst.de>
      Reviewed-by: NDavid Sterba <dsterba@suse.com>
      Signed-off-by: NDavid Sterba <dsterba@suse.com>
      bacf60e5
    • C
      btrfs: split the bio submission path into a separate file · 103c1972
      Christoph Hellwig 提交于
      The code used by btrfs_submit_bio only interacts with the rest of
      volumes.c through __btrfs_map_block (which itself is a more generic
      version of two exported helpers) and does not really have anything
      to do with volumes.c.  Create a new bio.c file and a bio.h header
      going along with it for the btrfs_bio-based storage layer, which
      will grow even more going forward.
      
      Also update the file with my copyright notice given that a large
      part of the moved code was written or rewritten by me.
      Reviewed-by: NJosef Bacik <josef@toxicpanda.com>
      Reviewed-by: NJohannes Thumshirn <johannes.thumshirn@wdc.com>
      Signed-off-by: NChristoph Hellwig <hch@lst.de>
      Reviewed-by: NDavid Sterba <dsterba@suse.com>
      Signed-off-by: NDavid Sterba <dsterba@suse.com>
      103c1972
    • C
      btrfs: move struct btrfs_tree_parent_check out of disk-io.h · 27137fac
      Christoph Hellwig 提交于
      Move struct btrfs_tree_parent_check out of disk-io.h so that volumes.h
      an various .c files don't have to include disk-io.h just for it.
      Reviewed-by: NJosef Bacik <josef@toxicpanda.com>
      Reviewed-by: NJohannes Thumshirn <johannes.thumshirn@wdc.com>
      Reviewed-by: NQu Wenruo <wqu@suse.com>
      Signed-off-by: NChristoph Hellwig <hch@lst.de>
      Reviewed-by: NDavid Sterba <dsterba@suse.com>
      [ use tree-checker.h for the structure ]
      Signed-off-by: NDavid Sterba <dsterba@suse.com>
      27137fac
    • Q
      btrfs: raid56: do data csum verification during RMW cycle · 7a315072
      Qu Wenruo 提交于
      [BUG]
      For the following small script, btrfs will be unable to recover the
      content of file1:
      
        mkfs.btrfs -f -m raid1 -d raid5 -b 1G $dev1 $dev2 $dev3
      
        mount $dev1 $mnt
        xfs_io -f -c "pwrite -S 0xff 0 64k" -c sync $mnt/file1
        md5sum $mnt/file1
        umount $mnt
      
        # Corrupt the above 64K data stripe.
        xfs_io -f -c "pwrite -S 0x00 323026944 64K" -c sync $dev3
        mount $dev1 $mnt
      
        # Write a new 64K, which should be in the other data stripe
        # And this is a sub-stripe write, which will cause RMW
        xfs_io -f -c "pwrite 0 64k" -c sync $mnt/file2
        md5sum $mnt/file1
        umount $mnt
      
      Above md5sum would fail.
      
      [CAUSE]
      There is a long existing problem for raid56 (not limited to btrfs
      raid56) that, if we already have some corrupted on-disk data, and then
      trigger a sub-stripe write (which needs RMW cycle), it can cause further
      damage into P/Q stripe.
      
        Disk 1: data 1 |0x000000000000| <- Corrupted
        Disk 2: data 2 |0x000000000000|
        Disk 2: parity |0xffffffffffff|
      
      In above case, data 1 is already corrupted, the original data should be
      64KiB of 0xff.
      
      At this stage, if we read data 1, and it has data checksum, we can still
      recovery going via the regular RAID56 recovery path.
      
      But if now we decide to write some data into data 2, then we need to go
      RMW.
      Let's say we want to write 64KiB of '0x00' into data 2, then we read the
      on-disk data of data 1, calculate the new parity, resulting the
      following layout:
      
        Disk 1: data 1 |0x000000000000| <- Corrupted
        Disk 2: data 2 |0x000000000000| <- New '0x00' writes
        Disk 2: parity |0x000000000000| <- New Parity.
      
      But the new parity is calculated using the *corrupted* data 1, we can
      no longer recover the correct data of data1.  Thus the corruption is
      forever there.
      
      [FIX]
      To solve above problem, this patch will do a full stripe data checksum
      verification at RMW time.
      
      This involves the following changes:
      
      - Always read the full stripe (including data/P/Q) when doing RMW
        Before we only read the missing data sectors, but since we may do a
        data csum verification and recovery, we need to read everything out.
      
        Please note that, if we have a cached rbio, we don't need to read
        anything, and can treat it the same as full stripe write.
      
        As only stripe with all its csum matches can be cached.
      
      - Verify the data csum during read.
        The goal is only the rbio stripe sectors, and only if the rbio
        already has csum_buf/csum_bitmap filled.
      
        And sectors which cannot pass csum verification will have their bit
        set in error_bitmap.
      
      - Always call recovery_sectors() after we read out all the sectors
        Since error_bitmap will be updated during read, recover_sectors()
        can easily find out all the bad sectors and try to recover (if still
        under tolerance).
      
        And since recovery_sectors() is already migrated to use error_bitmap,
        it can skip vertical stripes which don't have any error.
      
      - Verify the repaired sectors against its csum in recover_vertical()
      
      - Rename rmw_read_and_wait() to rmw_read_wait_recover()
        Since we will always recover the sectors, the old name is no longer
        accurate.
      
        Furthermore since recovery is already done in rmw_read_wait_recover(),
        we no longer need to call recovery_sectors() inside rmw_rbio().
      
      Obviously this will have a performance impact, as we are doing more
      work during RMW cycle:
      
      - Fetch the data checksums
      - Do checksum verification for all data stripes
      - Do checksum verification again after repair
      
      But for full stripe write or cached rbio we won't have the overhead all,
      thus for fully optimized RAID56 workload (always full stripe write),
      there should be no extra overhead.
      
      To me, the extra overhead looks reasonable, as data consistency is way
      more important than performance.
      Signed-off-by: NQu Wenruo <wqu@suse.com>
      Signed-off-by: NDavid Sterba <dsterba@suse.com>
      7a315072
    • Q
      btrfs: raid56: prepare data checksums for later RMW verification · c5a41562
      Qu Wenruo 提交于
      This is for later data checksum verification at RMW time.
      
      This patch will try to allocate the needed memory for a locked rbio if
      the rbio is for data exclusively (we don't want to handle mixed bg yet).
      The memory will be released when the rbio is finished.
      Signed-off-by: NQu Wenruo <wqu@suse.com>
      Signed-off-by: NDavid Sterba <dsterba@suse.com>
      c5a41562
    • Q
      btrfs: introduce a bitmap based csum range search function · 97e38239
      Qu Wenruo 提交于
      Although we have an existing function, btrfs_lookup_csums_range(), to
      find all data checksums for a range, it's based on a btrfs_ordered_sum
      list.
      
      For the incoming RAID56 data checksum verification at RMW time, we don't
      want to waste time by allocating temporary memory.
      
      So this patch will introduce a new helper, btrfs_lookup_csums_bitmap().
      It will use bitmap based result, which will be a perfect fit for later
      RAID56 usage.
      Signed-off-by: NQu Wenruo <wqu@suse.com>
      Signed-off-by: NDavid Sterba <dsterba@suse.com>
      97e38239
    • Q
      btrfs: refactor checksum calculations in btrfs_lookup_csums_range() · cb649e81
      Qu Wenruo 提交于
      The refactoring involves the following parts:
      
      - Introduce bytes_to_csum_size() and csum_size_to_bytes() helpers
        As we have quite some open-coded calculations, some of them are even
        split into two assignments just to fit 80 chars limit.
      
      - Remove the @csum_size parameter from max_ordered_sum_bytes()
        Csum size can be fetched from @fs_info.
        And we will use the csum_size_to_bytes() helper anyway.
      
      - Add a comment explaining how we handle the first search result
      
      - Use newly introduced helpers to cleanup btrfs_lookup_csums_range()
      
      - Move variables declaration to the minimal scope
      
      - Never mix number of sectors with bytes
        There are several locations doing things like:
      
       			size = min_t(size_t, csum_end - start,
      				     max_ordered_sum_bytes(fs_info));
      			...
      			size >>= fs_info->sectorsize_bits
      
        Or
      
      			offset = (start - key.offset) >> fs_info->sectorsize_bits;
      			offset *= csum_size;
      
        Make sure these variables can only represent BYTES inside the
        function, by using the above bytes_to_csum_size() helpers.
      Signed-off-by: NQu Wenruo <wqu@suse.com>
      Signed-off-by: NDavid Sterba <dsterba@suse.com>
      cb649e81
    • L
      btrfs: allocate btrfs_io_context without GFP_NOFAIL · 9f0eac07
      Li zeming 提交于
      The __GFP_NOFAIL flag could loop indefinitely when allocation memory in
      alloc_btrfs_io_context. The callers starting from __btrfs_map_block
      already handle errors so it's safe to drop the flag.
      Signed-off-by: NLi zeming <zeming@nfschina.com>
      Reviewed-by: NDavid Sterba <dsterba@suse.com>
      Signed-off-by: NDavid Sterba <dsterba@suse.com>
      9f0eac07
    • Q
      btrfs: use btrfs_dev_name() helper to handle missing devices better · cb3e217b
      Qu Wenruo 提交于
      [BUG]
      If dev-replace failed to re-construct its data/metadata, the kernel
      message would be incorrect for the missing device:
      
       BTRFS info (device dm-1): dev_replace from <missing disk> (devid 2) to /dev/mapper/test-scratch2 started
       BTRFS error (device dm-1): failed to rebuild valid logical 38862848 for dev (efault)
      
      Note the above "dev (efault)" of the second line.
      While the first line is properly reporting "<missing disk>".
      
      [CAUSE]
      Although dev-replace is using btrfs_dev_name(), the heavy lifting work
      is still done by scrub (scrub is reused by both dev-replace and regular
      scrub).
      
      Unfortunately scrub code never uses btrfs_dev_name() helper, as it's
      only declared locally inside dev-replace.c.
      
      [FIX]
      Fix the output by:
      
      - Move the btrfs_dev_name() helper to volumes.h
      
      - Use btrfs_dev_name() to replace open-coded rcu_str_deref() calls
        Only zoned code is not touched, as I'm not familiar with degraded
        zoned code.
      
      - Constify return value and parameter
      
      Now the output looks pretty sane:
      
       BTRFS info (device dm-1): dev_replace from <missing disk> (devid 2) to /dev/mapper/test-scratch2 started
       BTRFS error (device dm-1): failed to rebuild valid logical 38862848 for dev <missing disk>
      Reviewed-by: NAnand Jain <anand.jain@oracle.com>
      Signed-off-by: NQu Wenruo <wqu@suse.com>
      Signed-off-by: NDavid Sterba <dsterba@suse.com>
      cb3e217b
    • F
      btrfs: use cached state when looking for delalloc ranges with lseek · 3c32c721
      Filipe Manana 提交于
      During lseek (SEEK_HOLE/DATA), whenever we find a hole or prealloc extent,
      we will look for delalloc in that range, and one of the things we do for
      that is to find out ranges in the inode's io_tree marked with
      EXTENT_DELALLOC, using calls to count_range_bits().
      
      Typically there's a single, or few, searches in the io_tree for delalloc
      per lseek call. However it's common for applications to keep calling
      lseek with SEEK_HOLE and SEEK_DATA to find where extents and holes are in
      a file, read the extents and skip holes in order to avoid unnecessary IO
      and save disk space by preserving holes.
      
      One popular user is the cp utility from coreutils. Starting with coreutils
      9.0, cp uses SEEK_HOLE and SEEK_DATA to iterate over the extents of a
      file. Before 9.0, it used fiemap to figure out where holes and extents are
      in the source file. Another popular user is the tar utility when used with
      the --sparse / -S option to detect and preserve holes.
      
      Given that the pattern is to keep calling lseek with a start offset that
      matches the returned offset from the previous lseek call, we can benefit
      from caching the last extent state visited in count_range_bits() and use
      it for the next count_range_bits() from the next lseek call. Example,
      the following strace excerpt from running tar:
      
         $ strace tar cJSvf foo.tar.xz qemu_disk_file.raw
         (...)
         lseek(5, 125019574272, SEEK_HOLE)       = 125024989184
         lseek(5, 125024989184, SEEK_DATA)       = 125024993280
         lseek(5, 125024993280, SEEK_HOLE)       = 125025239040
         lseek(5, 125025239040, SEEK_DATA)       = 125025255424
         lseek(5, 125025255424, SEEK_HOLE)       = 125025353728
         lseek(5, 125025353728, SEEK_DATA)       = 125025357824
         lseek(5, 125025357824, SEEK_HOLE)       = 125026766848
         lseek(5, 125026766848, SEEK_DATA)       = 125026770944
         lseek(5, 125026770944, SEEK_HOLE)       = 125027053568
         (...)
      
      Shows that pattern, which is the same as with cp from coreutils 9.0+.
      
      So start using a cached state for the delalloc searches in lseek, and
      store it in struct file's private data so that it can be reused across
      lseek calls.
      
      This change is part of a patchset that is comprised of the following
      patches:
      
        1/9 btrfs: remove leftover setting of EXTENT_UPTODATE state in an inode's io_tree
        2/9 btrfs: add an early exit when searching for delalloc range for lseek/fiemap
        3/9 btrfs: skip unnecessary delalloc searches during lseek/fiemap
        4/9 btrfs: search for delalloc more efficiently during lseek/fiemap
        5/9 btrfs: remove no longer used btrfs_next_extent_map()
        6/9 btrfs: allow passing a cached state record to count_range_bits()
        7/9 btrfs: update stale comment for count_range_bits()
        8/9 btrfs: use cached state when looking for delalloc ranges with fiemap
        9/9 btrfs: use cached state when looking for delalloc ranges with lseek
      
      The following test was run before and after applying the whole patchset:
      
         $ cat test-cp.sh
         #!/bin/bash
      
         DEV=/dev/sdh
         MNT=/mnt/sdh
      
         # coreutils 8.32, cp uses fiemap to detect holes and extents
         #CP_PROG=/usr/bin/cp
         # coreutils 9.1, cp uses SEEK_HOLE/DATA to detect holes and extents
         CP_PROG=/home/fdmanana/git/hub/coreutils/src/cp
      
         umount $DEV &> /dev/null
         mkfs.btrfs -f $DEV
         mount $DEV $MNT
      
         FILE_SIZE=$((1024 * 1024 * 1024))
         echo "Creating file with a size of $((FILE_SIZE / 1024 / 1024))M"
         # Create a very sparse file, where each extent has a length of 4K and
         # is preceded by a 4K hole and followed by another 4K hole.
         start=$(date +%s%N)
         echo -n > $MNT/foobar
         for ((off = 0; off < $FILE_SIZE; off += 8192)); do
                 xfs_io -c "pwrite -S 0xab $off 4K" $MNT/foobar > /dev/null
                 echo -ne "\r$off / $FILE_SIZE ..."
         done
         end=$(date +%s%N)
         echo -e "\nFile created ($(( (end - start) / 1000000 )) milliseconds)"
      
         start=$(date +%s%N)
         $CP_PROG $MNT/foobar /dev/null
         end=$(date +%s%N)
         dur=$(( (end - start) / 1000000 ))
         echo "cp took $dur milliseconds with data/metadata cached and delalloc"
      
         # Flush all delalloc.
         sync
      
         start=$(date +%s%N)
         $CP_PROG $MNT/foobar /dev/null
         end=$(date +%s%N)
         dur=$(( (end - start) / 1000000 ))
         echo "cp took $dur milliseconds with data/metadata cached and no delalloc"
      
         # Unmount and mount again to test the case without any metadata
         # loaded in memory.
         umount $MNT
         mount $DEV $MNT
      
         start=$(date +%s%N)
         $CP_PROG $MNT/foobar /dev/null
         end=$(date +%s%N)
         dur=$(( (end - start) / 1000000 ))
         echo "cp took $dur milliseconds without data/metadata cached and no delalloc"
      
         umount $MNT
      
      The results, running on a box with a non-debug kernel (Debian's default
      kernel config), were the following:
      
      128M file, before patchset:
      
         cp took 16574 milliseconds with data/metadata cached and delalloc
         cp took 122 milliseconds with data/metadata cached and no delalloc
         cp took 20144 milliseconds without data/metadata cached and no delalloc
      
      128M file, after patchset:
      
         cp took 6277 milliseconds with data/metadata cached and delalloc
         cp took 109 milliseconds with data/metadata cached and no delalloc
         cp took 210 milliseconds without data/metadata cached and no delalloc
      
      512M file, before patchset:
      
         cp took 14369 milliseconds with data/metadata cached and delalloc
         cp took 429 milliseconds with data/metadata cached and no delalloc
         cp took 88034 milliseconds without data/metadata cached and no delalloc
      
      512M file, after patchset:
      
         cp took 12106 milliseconds with data/metadata cached and delalloc
         cp took 427 milliseconds with data/metadata cached and no delalloc
         cp took 824 milliseconds without data/metadata cached and no delalloc
      
      1G file, before patchset:
      
         cp took 10074 milliseconds with data/metadata cached and delalloc
         cp took 886 milliseconds with data/metadata cached and no delalloc
         cp took 181261 milliseconds without data/metadata cached and no delalloc
      
      1G file, after patchset:
      
         cp took 3320 milliseconds with data/metadata cached and delalloc
         cp took 880 milliseconds with data/metadata cached and no delalloc
         cp took 1801 milliseconds without data/metadata cached and no delalloc
      Reported-by: NWang Yugui <wangyugui@e16-tech.com>
      Link: https://lore.kernel.org/linux-btrfs/20221106073028.71F9.409509F4@e16-tech.com/
      Link: https://lore.kernel.org/linux-btrfs/CAL3q7H5NSVicm7nYBJ7x8fFkDpno8z3PYt5aPU43Bajc1H0h1Q@mail.gmail.com/Signed-off-by: NFilipe Manana <fdmanana@suse.com>
      Signed-off-by: NDavid Sterba <dsterba@suse.com>
      3c32c721
    • F
      btrfs: use cached state when looking for delalloc ranges with fiemap · b3e744fe
      Filipe Manana 提交于
      During fiemap, whenever we find a hole or prealloc extent, we will look
      for delalloc in that range, and one of the things we do for that is to
      find out ranges in the inode's io_tree marked with EXTENT_DELALLOC, using
      calls to count_range_bits().
      
      Since we process file extents from left to right, if we have a file with
      several holes or prealloc extents, we benefit from keeping a cached extent
      state record for calls to count_range_bits(). Most of the time the last
      extent state record we visited in one call to count_range_bits() matches
      the first extent state record we will use in the next call to
      count_range_bits(), so there's a benefit here. So use an extent state
      record to cache results from count_range_bits() calls during fiemap.
      
      This change is part of a patchset that has the goal to make performance
      better for applications that use lseek's SEEK_HOLE and SEEK_DATA modes to
      iterate over the extents of a file. Two examples are the cp program from
      coreutils 9.0+ and the tar program (when using its --sparse / -S option).
      A sample test and results are listed in the changelog of the last patch
      in the series:
      
        1/9 btrfs: remove leftover setting of EXTENT_UPTODATE state in an inode's io_tree
        2/9 btrfs: add an early exit when searching for delalloc range for lseek/fiemap
        3/9 btrfs: skip unnecessary delalloc searches during lseek/fiemap
        4/9 btrfs: search for delalloc more efficiently during lseek/fiemap
        5/9 btrfs: remove no longer used btrfs_next_extent_map()
        6/9 btrfs: allow passing a cached state record to count_range_bits()
        7/9 btrfs: update stale comment for count_range_bits()
        8/9 btrfs: use cached state when looking for delalloc ranges with fiemap
        9/9 btrfs: use cached state when looking for delalloc ranges with lseek
      Reported-by: NWang Yugui <wangyugui@e16-tech.com>
      Link: https://lore.kernel.org/linux-btrfs/20221106073028.71F9.409509F4@e16-tech.com/
      Link: https://lore.kernel.org/linux-btrfs/CAL3q7H5NSVicm7nYBJ7x8fFkDpno8z3PYt5aPU43Bajc1H0h1Q@mail.gmail.com/Signed-off-by: NFilipe Manana <fdmanana@suse.com>
      Signed-off-by: NDavid Sterba <dsterba@suse.com>
      b3e744fe
    • F
      btrfs: update stale comment for count_range_bits() · 1ee51a06
      Filipe Manana 提交于
      The comment for count_range_bits() mentions that the search is fast if we
      are asking for a range with the EXTENT_DIRTY bit set. However that is no
      longer true since we don't use that bit and the optimization for that was
      removed in:
      
        commit 71528e9e ("btrfs: get rid of extent_io_tree::dirty_bytes")
      
      So remove that part of the comment mentioning the no longer existing
      optimized case, and, while at it, add proper documentation describing the
      purpose, arguments and return value of the function.
      Signed-off-by: NFilipe Manana <fdmanana@suse.com>
      Signed-off-by: NDavid Sterba <dsterba@suse.com>
      1ee51a06