1. 03 6月, 2015 32 次提交
    • F
      Btrfs: fix hang during inode eviction due to concurrent readahead · 6ca07097
      Filipe Manana 提交于
      Zygo Blaxell and other users have reported occasional hangs while an
      inode is being evicted, leading to traces like the following:
      
      [ 5281.972322] INFO: task rm:20488 blocked for more than 120 seconds.
      [ 5281.973836]       Not tainted 4.0.0-rc5-btrfs-next-9+ #2
      [ 5281.974818] "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
      [ 5281.976364] rm              D ffff8800724cfc38     0 20488   7747 0x00000000
      [ 5281.977506]  ffff8800724cfc38 ffff8800724cfc38 ffff880065da5c50 0000000000000001
      [ 5281.978461]  ffff8800724cffd8 ffff8801540a5f50 0000000000000008 ffff8801540a5f78
      [ 5281.979541]  ffff8801540a5f50 ffff8800724cfc58 ffffffff8143107e 0000000000000123
      [ 5281.981396] Call Trace:
      [ 5281.982066]  [<ffffffff8143107e>] schedule+0x74/0x83
      [ 5281.983341]  [<ffffffffa03b33cf>] wait_on_state+0xac/0xcd [btrfs]
      [ 5281.985127]  [<ffffffff81075cd6>] ? signal_pending_state+0x31/0x31
      [ 5281.986715]  [<ffffffffa03b4b71>] wait_extent_bit.constprop.32+0x7c/0xde [btrfs]
      [ 5281.988680]  [<ffffffffa03b540b>] lock_extent_bits+0x5d/0x88 [btrfs]
      [ 5281.990200]  [<ffffffffa03a621d>] btrfs_evict_inode+0x24e/0x5be [btrfs]
      [ 5281.991781]  [<ffffffff8116964d>] evict+0xa0/0x148
      [ 5281.992735]  [<ffffffff8116a43d>] iput+0x18f/0x1e5
      [ 5281.993796]  [<ffffffff81160d4a>] do_unlinkat+0x15b/0x1fa
      [ 5281.994806]  [<ffffffff81435b54>] ? ret_from_sys_call+0x1d/0x58
      [ 5281.996120]  [<ffffffff8107d314>] ? trace_hardirqs_on_caller+0x18f/0x1ab
      [ 5281.997562]  [<ffffffff8123960b>] ? trace_hardirqs_on_thunk+0x3a/0x3f
      [ 5281.998815]  [<ffffffff81161a16>] SyS_unlinkat+0x29/0x2b
      [ 5281.999920]  [<ffffffff81435b32>] system_call_fastpath+0x12/0x17
      [ 5282.001299] 1 lock held by rm/20488:
      [ 5282.002066]  #0:  (sb_writers#12){.+.+.+}, at: [<ffffffff8116dd81>] mnt_want_write+0x24/0x4b
      
      This happens when we have readahead, which calls readpages(), happening
      right before the inode eviction handler is invoked. So the reason is
      essentially:
      
      1) readpages() is called while a reference on the inode is held, so
         eviction can not be triggered before readpages() returns. It also
         locks one or more ranges in the inode's io_tree (which is done at
         extent_io.c:__do_contiguous_readpages());
      
      2) readpages() submits several read bios, all with an end io callback
         that runs extent_io.c:end_bio_extent_readpage() and that is executed
         by other task when a bio finishes, corresponding to a work queue
         (fs_info->end_io_workers) worker kthread. This callback unlocks
         the ranges in the inode's io_tree that were previously locked in
         step 1;
      
      3) readpages() returns, the reference on the inode is dropped;
      
      4) One or more of the read bios previously submitted are still not
         complete (their end io callback was not yet invoked or has not
         yet finished execution);
      
      5) Inode eviction is triggered (through an unlink call for example).
         The inode reference count was not incremented before submitting
         the read bios, therefore this is possible;
      
      6) The eviction handler starts executing and enters the loop that
         iterates over all extent states in the inode's io_tree;
      
      7) The loop picks one extent state record and uses its ->start and
         ->end fields, after releasing the inode's io_tree spinlock, to
         call lock_extent_bits() and clear_extent_bit(). The call to lock
         the range [state->start, state->end] blocks because the whole
         range or a part of it was locked by the previous call to
         readpages() and the corresponding end io callback, which unlocks
         the range was not yet executed;
      
      8) The end io callback for the read bio is executed and unlocks the
         range [state->start, state->end] (or a superset of that range).
         And at clear_extent_bit() the extent_state record state is used
         as a second argument to split_state(), which sets state->start to
         a larger value;
      
      9) The task executing the eviction handler is woken up by the task
         executing the bio's end io callback (through clear_state_bit) and
         the eviction handler locks the range
         [old value for state->start, state->end]. Shortly after, when
         calling clear_extent_bit(), it unlocks the range
         [new value for state->start, state->end], so it ends up unlocking
         only part of the range that it locked, leaving an extent state
         record in the io_tree that represents the unlocked subrange;
      
      10) The eviction handler loop, in its next iteration, gets the
          extent_state record for the subrange that it did not unlock in the
          previous step and then tries to lock it, resulting in an hang.
      
      So fix this by not using the ->start and ->end fields of an existing
      extent_state record. This is a simple solution, and an alternative
      could be to bump the inode's reference count before submitting each
      read bio and having it dropped in the bio's end io callback. But that
      would be a more invasive/complex change and would not protect against
      other possible places that are not holding a reference on the inode
      as well. Something to consider in the future.
      
      Many thanks to Zygo Blaxell for reporting, in the mailing list, the
      issue, a set of scripts to trigger it and testing this fix.
      Reported-by: NZygo Blaxell <ce3g8jdj@umail.furryterror.org>
      Tested-by: NZygo Blaxell <ce3g8jdj@umail.furryterror.org>
      Signed-off-by: NFilipe Manana <fdmanana@suse.com>
      Signed-off-by: NChris Mason <clm@fb.com>
      6ca07097
    • L
      Btrfs: fix up read_tree_block to return proper error · 64c043de
      Liu Bo 提交于
      The return value of read_tree_block() can confuse callers as it always
      returns NULL for either -ENOMEM or -EIO, so it's likely that callers
      parse it to a wrong error, for instance, in btrfs_read_tree_root().
      
      This fixes the above issue.
      Signed-off-by: NLiu Bo <bo.li.liu@oracle.com>
      Reviewed-by: NDavid Sterba <dsterba@suse.cz>
      Signed-off-by: NChris Mason <clm@fb.com>
      64c043de
    • L
      Btrfs: add missing free_extent_buffer · 8635eda9
      Liu Bo 提交于
      read_tree_block may take a reference on the 'eb', a following
      free_extent_buffer is necessary.
      Signed-off-by: NLiu Bo <bo.li.liu@oracle.com>
      Reviewed-by: NDavid Sterba <dsterba@suse.cz>
      Signed-off-by: NChris Mason <clm@fb.com>
      8635eda9
    • L
      Btrfs: remove csum_bytes_left · 0c304304
      Liu Bo 提交于
      After commit 8407f553
      ("Btrfs: fix data corruption after fast fsync and writeback error"),
      during wait_ordered_extents(), we wait for ordered extent setting
      BTRFS_ORDERED_IO_DONE or BTRFS_ORDERED_IOERR, at which point we've
      already got checksum information, so we don't need to check
      (csum_bytes_left == 0) in the whole logging path.
      Signed-off-by: NLiu Bo <bo.li.liu@oracle.com>
      Signed-off-by: NChris Mason <clm@fb.com>
      0c304304
    • F
      Btrfs: fix -ENOSPC on block group removal · 39c2d7fa
      Filipe Manana 提交于
      Unlike when attempting to allocate a new block group, where we check
      that we have enough space in the system space_info to update the device
      items and insert a new chunk item in the chunk tree, we were not checking
      if the system space_info had enough space for updating the device items
      and deleting the chunk item in the chunk tree. This often lead to -ENOSPC
      error when attempting to allocate blocks for the chunk tree (during btree
      node/leaf COW operations) while updating the device items or deleting the
      chunk item, which resulted in the current transaction being aborted and
      turning the filesystem into read-only mode.
      
      While running fstests generic/038, which stresses allocation of block
      groups and removal of unused block groups, with a large scratch device
      (750Gb) this happened often, despite more than enough unallocated space,
      and resulted in the following trace:
      
      [68663.586604] WARNING: CPU: 3 PID: 1521 at fs/btrfs/super.c:260 __btrfs_abort_transaction+0x52/0x114 [btrfs]()
      [68663.600407] BTRFS: Transaction aborted (error -28)
      (...)
      [68663.730829] Call Trace:
      [68663.732585]  [<ffffffff8142fa46>] dump_stack+0x4f/0x7b
      [68663.734334]  [<ffffffff8108b6a2>] ? console_unlock+0x361/0x3ad
      [68663.739980]  [<ffffffff81045ea5>] warn_slowpath_common+0xa1/0xbb
      [68663.757153]  [<ffffffffa036ca6d>] ? __btrfs_abort_transaction+0x52/0x114 [btrfs]
      [68663.760925]  [<ffffffff81045f05>] warn_slowpath_fmt+0x46/0x48
      [68663.762854]  [<ffffffffa03b159d>] ? btrfs_update_device+0x15a/0x16c [btrfs]
      [68663.764073]  [<ffffffffa036ca6d>] __btrfs_abort_transaction+0x52/0x114 [btrfs]
      [68663.765130]  [<ffffffffa03b3638>] btrfs_remove_chunk+0x597/0x5ee [btrfs]
      [68663.765998]  [<ffffffffa0384663>] ? btrfs_delete_unused_bgs+0x245/0x296 [btrfs]
      [68663.767068]  [<ffffffffa0384676>] btrfs_delete_unused_bgs+0x258/0x296 [btrfs]
      [68663.768227]  [<ffffffff8143527f>] ? _raw_spin_unlock_irq+0x2d/0x4c
      [68663.769081]  [<ffffffffa038b109>] cleaner_kthread+0x13d/0x16c [btrfs]
      [68663.799485]  [<ffffffffa038afcc>] ? btrfs_alloc_root+0x28/0x28 [btrfs]
      [68663.809208]  [<ffffffff8105f367>] kthread+0xef/0xf7
      [68663.828795]  [<ffffffff810e603f>] ? time_hardirqs_on+0x15/0x28
      [68663.844942]  [<ffffffff8105f278>] ? __kthread_parkme+0xad/0xad
      [68663.846486]  [<ffffffff81435a88>] ret_from_fork+0x58/0x90
      [68663.847760]  [<ffffffff8105f278>] ? __kthread_parkme+0xad/0xad
      [68663.849503] ---[ end trace 798477c6d6dbaad6 ]---
      [68663.850525] BTRFS: error (device sdc) in btrfs_remove_chunk:2652: errno=-28 No space left
      
      So fix this by verifying that enough space exists in system space_info,
      and reserving the space in the chunk block reserve, before attempting to
      delete the block group and allocate a new system chunk if we don't have
      enough space to perform the necessary updates and delete in the chunk
      tree. Like for the block group creation case, we don't error our if we
      fail to allocate a new system chunk, since we might end up not needing
      it (no node/leaf splits happen during the COW operations and/or we end
      up not needing to COW any btree nodes or leafs because they were already
      COWed in the current transaction and their writeback didn't start yet).
      Signed-off-by: NFilipe Manana <fdmanana@suse.com>
      Signed-off-by: NChris Mason <clm@fb.com>
      39c2d7fa
    • F
      Btrfs: fix -ENOSPC when finishing block group creation · 4fbcdf66
      Filipe Manana 提交于
      While creating a block group, we often end up getting ENOSPC while updating
      the chunk tree, which leads to a transaction abortion that produces a trace
      like the following:
      
      [30670.116368] WARNING: CPU: 4 PID: 20735 at fs/btrfs/super.c:260 __btrfs_abort_transaction+0x52/0x106 [btrfs]()
      [30670.117777] BTRFS: Transaction aborted (error -28)
      (...)
      [30670.163567] Call Trace:
      [30670.163906]  [<ffffffff8142fa46>] dump_stack+0x4f/0x7b
      [30670.164522]  [<ffffffff8108b6a2>] ? console_unlock+0x361/0x3ad
      [30670.165171]  [<ffffffff81045ea5>] warn_slowpath_common+0xa1/0xbb
      [30670.166323]  [<ffffffffa035daa7>] ? __btrfs_abort_transaction+0x52/0x106 [btrfs]
      [30670.167213]  [<ffffffff81045f05>] warn_slowpath_fmt+0x46/0x48
      [30670.167862]  [<ffffffffa035daa7>] __btrfs_abort_transaction+0x52/0x106 [btrfs]
      [30670.169116]  [<ffffffffa03743d7>] btrfs_create_pending_block_groups+0x101/0x130 [btrfs]
      [30670.170593]  [<ffffffffa038426a>] __btrfs_end_transaction+0x84/0x366 [btrfs]
      [30670.171960]  [<ffffffffa038455c>] btrfs_end_transaction+0x10/0x12 [btrfs]
      [30670.174649]  [<ffffffffa036eb6b>] btrfs_check_data_free_space+0x11f/0x27c [btrfs]
      [30670.176092]  [<ffffffffa039450d>] btrfs_fallocate+0x7c8/0xb96 [btrfs]
      [30670.177218]  [<ffffffff812459f2>] ? __this_cpu_preempt_check+0x13/0x15
      [30670.178622]  [<ffffffff81152447>] vfs_fallocate+0x14c/0x1de
      [30670.179642]  [<ffffffff8116b915>] ? __fget_light+0x2d/0x4f
      [30670.180692]  [<ffffffff81152863>] SyS_fallocate+0x47/0x62
      [30670.186737]  [<ffffffff81435b32>] system_call_fastpath+0x12/0x17
      [30670.187792] ---[ end trace 0373e6b491c4a8cc ]---
      
      This is because we don't do proper space reservation for the chunk block
      reserve when we have multiple tasks allocating chunks in parallel.
      
      So block group creation has 2 phases, and the first phase essentially
      checks if there is enough space in the system space_info, allocating a
      new system chunk if there isn't, while the second phase updates the
      device, extent and chunk trees. However, because the updates to the
      chunk tree happen in the second phase, if we have N tasks, each with
      its own transaction handle, allocating new chunks in parallel and if
      there is only enough space in the system space_info to allocate M chunks,
      where M < N, none of the tasks ends up allocating a new system chunk in
      the first phase and N - M tasks will get -ENOSPC when attempting to
      update the chunk tree in phase 2 if they need to COW any nodes/leafs
      from the chunk tree.
      
      Fix this by doing proper reservation in the chunk block reserve.
      
      The issue could be reproduced by running fstests generic/038 in a loop,
      which eventually triggered the problem.
      Signed-off-by: NFilipe Manana <fdmanana@suse.com>
      Signed-off-by: NChris Mason <clm@fb.com>
      4fbcdf66
    • J
      Btrfs: set UNWRITTEN for prealloc'ed extents in fiemap · 0d2b2372
      Josef Bacik 提交于
      We should be doing this, it's weird we hadn't been doing this.
      Signed-off-by: NJosef Bacik <jbacik@fb.com>
      Signed-off-by: NChris Mason <clm@fb.com>
      0d2b2372
    • O
      Btrfs: show subvol= and subvolid= in /proc/mounts · c8d3fe02
      Omar Sandoval 提交于
      Now that we're guaranteed to have a meaningful root dentry, we can just
      export seq_dentry() and use it in btrfs_show_options(). The subvolume ID
      is easy to get and can also be useful, so put that in there, too.
      Reviewed-by: NDavid Sterba <dsterba@suse.cz>
      Signed-off-by: NOmar Sandoval <osandov@osandov.com>
      Signed-off-by: NChris Mason <clm@fb.com>
      c8d3fe02
    • O
      Btrfs: unify subvol= and subvolid= mounting · 05dbe683
      Omar Sandoval 提交于
      Currently, mounting a subvolume with subvolid= takes a different code
      path than mounting with subvol=. This isn't really a big deal except for
      the fact that mounts done with subvolid= or the default subvolume don't
      have a dentry that's connected to the dentry tree like in the subvol=
      case. To unify the code paths, when given subvolid= or using the default
      subvolume ID, translate it into a subvolume name by walking
      ROOT_BACKREFs in the root tree and INODE_REFs in the filesystem trees.
      Reviewed-by: NDavid Sterba <dsterba@suse.cz>
      Signed-off-by: NOmar Sandoval <osandov@osandov.com>
      Signed-off-by: NChris Mason <clm@fb.com>
      05dbe683
    • O
      Btrfs: fail on mismatched subvol and subvolid mount options · bb289b7b
      Omar Sandoval 提交于
      There's nothing to stop a user from passing both subvol= and subvolid=
      to mount, but if they don't refer to the same subvolume, someone is
      going to be surprised at some point. Error out on this case, but allow
      users to pass in both if they do match (which they could, for example,
      get out of /proc/mounts).
      Reviewed-by: NDavid Sterba <dsterba@suse.cz>
      Signed-off-by: NOmar Sandoval <osandov@osandov.com>
      Signed-off-by: NChris Mason <clm@fb.com>
      bb289b7b
    • O
      Btrfs: clean up error handling in mount_subvol() · fa330659
      Omar Sandoval 提交于
      In preparation for new functionality in mount_subvol(), give it
      ownership of subvol_name and tidy up the error paths.
      Reviewed-by: NDavid Sterba <dsterba@suse.cz>
      Signed-off-by: NOmar Sandoval <osandov@osandov.com>
      Signed-off-by: NChris Mason <clm@fb.com>
      fa330659
    • O
      Btrfs: remove all subvol options before mounting top-level · e6e4dbe8
      Omar Sandoval 提交于
      Currently, setup_root_args() substitutes 's/subvol=[^,]*/subvolid=0/'.
      But, this means that if the user passes both a subvol and subvolid for
      some reason, we won't actually mount the top-level when we recursively
      mount. For example, consider:
      
      mkfs.btrfs -f /dev/sdb
      mount /dev/sdb /mnt
      btrfs subvol create /mnt/subvol1 # subvolid=257
      btrfs subvol create /mnt/subvol2 # subvolid=258
      umount /mnt
      mount -osubvol=/subvol1,subvolid=258 /dev/sdb /mnt
      
      In the final mount, subvol=/subvol1,subvolid=258 becomes
      subvolid=0,subvolid=258, and the last option takes precedence, so we
      mount subvol2 and try to look up subvol1 inside of it, which fails.
      
      So, instead, do a thorough scan through the argument list and remove any
      subvol= and subvolid= options, then append subvolid=0 to the end. This
      implicitly makes subvol= take precedence over subvolid=, but we're about
      to add a stricter check for that. This also makes setup_root_args() more
      generic, which we'll need soon.
      Reviewed-by: NDavid Sterba <dsterba@suse.cz>
      Signed-off-by: NOmar Sandoval <osandov@osandov.com>
      Signed-off-by: NChris Mason <clm@fb.com>
      e6e4dbe8
    • O
      Btrfs: lock superblock before remounting for rw subvol · 773cd04e
      Omar Sandoval 提交于
      Since commit 0723a047 ("btrfs: allow mounting btrfs subvolumes with
      different ro/rw options"), when mounting a subvolume read/write when
      another subvolume has previously been mounted read-only, we first do a
      remount. However, this should be done with the superblock locked, as per
      sync_filesystem():
      
      	/*
      	 * We need to be protected against the filesystem going from
      	 * r/o to r/w or vice versa.
      	 */
      	WARN_ON(!rwsem_is_locked(&sb->s_umount));
      
      This WARN_ON can easily be hit with:
      
      mkfs.btrfs -f /dev/vdb
      mount /dev/vdb /mnt
      btrfs subvol create /mnt/vol1
      btrfs subvol create /mnt/vol2
      umount /mnt
      mount -oro,subvol=/vol1 /dev/vdb /mnt
      mount -orw,subvol=/vol2 /dev/vdb /mnt2
      
      Fixes: 0723a047 ("btrfs: allow mounting btrfs subvolumes with different ro/rw options")
      Reviewed-by: NDavid Sterba <dsterba@suse.cz>
      Signed-off-by: NOmar Sandoval <osandov@osandov.com>
      Signed-off-by: NChris Mason <clm@fb.com>
      773cd04e
    • F
      Btrfs: wake up extent state waiters on unlock through clear_extent_bits · 0f31871f
      Filipe Manana 提交于
      When we clear an extent state's EXTENT_LOCKED bit with clear_extent_bits()
      through free_io_failure(), we weren't waking up any tasks waiting for the
      extent's state EXTENT_LOCKED bit, leading to an hang.
      
      So make sure clear_extent_bits() ends up waking up any waiters if the
      bit EXTENT_LOCKED is supplied by its callers.
      
      Zygo Blaxell was experiencing such hangs at inode eviction time after
      file unlinks. Thanks to him for a set of scripts to reproduce the issue.
      Reported-by: NZygo Blaxell <ce3g8jdj@umail.furryterror.org>
      Signed-off-by: NFilipe Manana <fdmanana@suse.com>
      Reviewed-by: NLiu Bo <bo.li.liu@oracle.com>
      Signed-off-by: NChris Mason <clm@fb.com>
      0f31871f
    • F
      Btrfs: fix chunk allocation regression leading to transaction abort · c152b63e
      Filipe Manana 提交于
      With commit 1b984508 ("Btrfs: fix find_free_dev_extent() malfunction
      in case device tree has hole") introduced in the kernel 4.1 merge window,
      we end up using part of a device hole for which there are already pending
      chunks or pinned chunks. Before that commit we didn't use the hole and
      would just move on to the next hole in the device.
      
      However when we adjust the start offset for the chunk allocation and we
      have pinned chunks, we set it blindly to the end offset of the pinned
      chunk we are currently processing, which is dangerous because we can
      have a pending chunk that has a start offset that matches the end offset
      of our pinned chunk - leading us to a case where we end up getting two
      pending chunks that start at the same physical device offset, which makes
      us later abort the current transaction with -EEXIST when finishing the
      chunk allocation at btrfs_create_pending_block_groups():
      
      [194737.659017] ------------[ cut here ]------------
      [194737.660192] WARNING: CPU: 15 PID: 31111 at fs/btrfs/super.c:260 __btrfs_abort_transaction+0x52/0x106 [btrfs]()
      [194737.662209] BTRFS: Transaction aborted (error -17)
      [194737.663175] Modules linked in: btrfs dm_snapshot dm_bufio dm_flakey dm_mod crc32c_generic xor raid6_pq nfsd auth_rpcgss oid_registry nfs_acl nfs lockd grace fscache sunrpc loop fuse
      [194737.674015] CPU: 15 PID: 31111 Comm: xfs_io Tainted: G        W       4.0.0-rc5-btrfs-next-9+ #2
      [194737.675986] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.7.5-0-ge51488c-20140602_164612-nilsson.home.kraxel.org 04/01/2014
      [194737.682999]  0000000000000009 ffff8800564c7a98 ffffffff8142fa46 ffffffff8108b6a2
      [194737.684540]  ffff8800564c7ae8 ffff8800564c7ad8 ffffffff81045ea5 ffff8800564c7b78
      [194737.686017]  ffffffffa0383aa7 00000000ffffffef ffff88000c7ba000 ffff8801a1f66f40
      [194737.687509] Call Trace:
      [194737.688068]  [<ffffffff8142fa46>] dump_stack+0x4f/0x7b
      [194737.689027]  [<ffffffff8108b6a2>] ? console_unlock+0x361/0x3ad
      [194737.690095]  [<ffffffff81045ea5>] warn_slowpath_common+0xa1/0xbb
      [194737.691198]  [<ffffffffa0383aa7>] ? __btrfs_abort_transaction+0x52/0x106 [btrfs]
      [194737.693789]  [<ffffffff81045f05>] warn_slowpath_fmt+0x46/0x48
      [194737.695065]  [<ffffffffa0383aa7>] __btrfs_abort_transaction+0x52/0x106 [btrfs]
      [194737.696806]  [<ffffffffa039a3bd>] btrfs_create_pending_block_groups+0x101/0x130 [btrfs]
      [194737.698683]  [<ffffffffa03aa433>] __btrfs_end_transaction+0x84/0x366 [btrfs]
      [194737.700329]  [<ffffffffa03aa725>] btrfs_end_transaction+0x10/0x12 [btrfs]
      [194737.701924]  [<ffffffffa0394b51>] btrfs_check_data_free_space+0x11f/0x27c [btrfs]
      [194737.703675]  [<ffffffffa03b8ba4>] __btrfs_buffered_write+0x16a/0x4c8 [btrfs]
      [194737.705417]  [<ffffffffa03bb502>] ? btrfs_file_write_iter+0x19a/0x431 [btrfs]
      [194737.707058]  [<ffffffffa03bb511>] ? btrfs_file_write_iter+0x1a9/0x431 [btrfs]
      [194737.708560]  [<ffffffffa03bb68d>] btrfs_file_write_iter+0x325/0x431 [btrfs]
      [194737.710673]  [<ffffffff81067d85>] ? get_parent_ip+0xe/0x3e
      [194737.712076]  [<ffffffff811534c3>] new_sync_write+0x7c/0xa0
      [194737.713293]  [<ffffffff81153b58>] vfs_write+0xb2/0x117
      [194737.714443]  [<ffffffff81154424>] SyS_pwrite64+0x64/0x82
      [194737.715646]  [<ffffffff81435b32>] system_call_fastpath+0x12/0x17
      [194737.717175] ---[ end trace f2d5dc04e56d7e48 ]---
      [194737.718170] BTRFS: error (device sdc) in btrfs_create_pending_block_groups:9524: errno=-17 Object already exists
      
      The -EEXIST failure comes from btrfs_finish_chunk_alloc(), called by
      btrfs_create_pending_block_groups(), when it attempts to insert a
      duplicated device extent item via btrfs_alloc_dev_extent().
      
      This issue was reproducible with fstests generic/038 running in a loop for
      several hours (it's very hard to hit) and using MOUNT_OPTIONS="-o discard".
      Applying Jeff's recent patch titled "btrfs: add missing discards when
      unpinning extents with -o discard" makes the issue much easier to reproduce
      (usually within 4 to 5 hours), since it pins chunks for longer periods of
      time when an unused block group is deleted by the cleaner kthread.
      
      Fix this by making sure that we never adjust the start offset to a lower
      value than it currently has.
      
      Fixes: 1b984508 ("Btrfs: fix find_free_dev_extent() malfunction in case device tree has hole"
      Signed-off-by: NFilipe Manana <fdmanana@suse.com>
      Signed-off-by: NChris Mason <clm@fb.com>
      c152b63e
    • S
      btrfs: use after free when closing devices · 2037a093
      Sasha Levin 提交于
      __btrfs_close_devices() would call_rcu to free the device, which is racy with
      list_for_each_entry() accessing the memory to retrieve the next device on the
      list.
      Signed-off-by: NSasha Levin <sasha.levin@oracle.com>
      Reviewed-by: NDavid Sterba <dsterba@suse.cz>
      Signed-off-by: NChris Mason <clm@fb.com>
      2037a093
    • D
      btrfs: make root id query unprivileged · 01b810b8
      David Sterba 提交于
      The INO_LOOKUP ioctl can lookup path for a given inode number and is
      thus restricted. As a sideefect it can find the root id of the
      containing subvolume and we're using this int the 'btrfs inspect rootid'
      command.
      
      The restriction is unnecessary in case we set the ioctl args
       args::treeid    = 0
       args::objectid  = 256 (BTRFS_FIRST_FREE_OBJECTID)
      
      Then the path will be empty and the treeid is filled with the root id of
      the inode on which the ioctl is called. This behaviour is unchanged,
      after the root restriction is removed.
      Signed-off-by: NDavid Sterba <dsterba@suse.cz>
      Signed-off-by: NChris Mason <clm@fb.com>
      01b810b8
    • F
      Btrfs: fix block group ->space_info null pointer dereference · 2e6e5183
      Filipe Manana 提交于
      When we create a block group we add it to the rbtree of block groups
      before setting its ->space_info field (while it's NULL). This is
      problematic since other tasks can access the block group from the
      rbtree and attempt to use its ->space_info before it is set by
      btrfs_make_block_group().
      
      This can happen for example when a concurrent fitrim ioctl operation
      is ongoing, which produces a trace like the following when
      CONFIG_DEBUG_PAGEALLOC is set.
      
      [11509.604369] BUG: unable to handle kernel NULL pointer dereference at 0000000000000018
      [11509.606373] IP: [<ffffffff8107d675>] __lock_acquire+0xb4/0xf02
      [11509.608179] PGD 2296a8067 PUD 22f4a2067 PMD 0
      [11509.608179] Oops: 0000 [#1] PREEMPT SMP DEBUG_PAGEALLOC
      [11509.608179] Modules linked in: btrfs crc32c_generic xor raid6_pq nfsd auth_rpcgss oid_registry nfs_acl nfs lockd grace fscache sunrpc loop fuse acpi_cpufreq processor i2c_piix4 psmou
      [11509.608179] CPU: 10 PID: 8538 Comm: fstrim Tainted: G        W       4.0.0-rc5-btrfs-next-9+ #2
      [11509.608179] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.7.5-0-ge51488c-20140602_164612-nilsson.home.kraxel.org 04/01/2014
      [11509.608179] task: ffff88009f5c46d0 ti: ffff8801b3edc000 task.ti: ffff8801b3edc000
      [11509.608179] RIP: 0010:[<ffffffff8107d675>]  [<ffffffff8107d675>] __lock_acquire+0xb4/0xf02
      [11509.608179] RSP: 0018:ffff8801b3edf9e8  EFLAGS: 00010002
      [11509.608179] RAX: 0000000000000046 RBX: 0000000000000000 RCX: 0000000000000000
      [11509.608179] RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000018
      [11509.608179] RBP: ffff8801b3edfaa8 R08: 0000000000000001 R09: 0000000000000000
      [11509.608179] R10: 0000000000000000 R11: ffff88009f5c4f98 R12: 0000000000000000
      [11509.608179] R13: 0000000000000000 R14: 0000000000000018 R15: ffff88009f5c46d0
      [11509.608179] FS:  00007f280a10e840(0000) GS:ffff88023ed40000(0000) knlGS:0000000000000000
      [11509.608179] CS:  0010 DS: 0000 ES: 0000 CR0: 000000008005003b
      [11509.608179] CR2: 0000000000000018 CR3: 00000002119bc000 CR4: 00000000000006e0
      [11509.608179] Stack:
      [11509.608179]  0000000000000000 0000000000000000 0000000000000004 0000000000000000
      [11509.608179]  ffff880100000000 ffffffff00000000 0000000000000001 ffffffff00000000
      [11509.608179]  0000000000000001 0000000000000000 ffff880100000000 00000000000006c4
      [11509.608179] Call Trace:
      [11509.608179]  [<ffffffff8107dc57>] ? __lock_acquire+0x696/0xf02
      [11509.608179]  [<ffffffff8107e806>] lock_acquire+0xa5/0x116
      [11509.608179]  [<ffffffffa04cc876>] ? do_trimming+0x51/0x145 [btrfs]
      [11509.608179]  [<ffffffff81434f37>] _raw_spin_lock+0x34/0x44
      [11509.608179]  [<ffffffffa04cc876>] ? do_trimming+0x51/0x145 [btrfs]
      [11509.608179]  [<ffffffffa04cc876>] do_trimming+0x51/0x145 [btrfs]
      [11509.608179]  [<ffffffffa04cde7d>] btrfs_trim_block_group+0x201/0x491 [btrfs]
      [11509.608179]  [<ffffffffa04849e2>] btrfs_trim_fs+0xe0/0x129 [btrfs]
      [11509.608179]  [<ffffffffa04bb80a>] btrfs_ioctl_fitrim+0x138/0x167 [btrfs]
      [11509.608179]  [<ffffffffa04c002f>] btrfs_ioctl+0x50d/0x21e8 [btrfs]
      [11509.608179]  [<ffffffff81123bda>] ? might_fault+0x58/0xb5
      [11509.608179]  [<ffffffff81123bda>] ? might_fault+0x58/0xb5
      [11509.608179]  [<ffffffff81123bda>] ? might_fault+0x58/0xb5
      [11509.608179]  [<ffffffff81158050>] ? cp_new_stat+0x147/0x15e
      [11509.608179]  [<ffffffff81163041>] do_vfs_ioctl+0x3c6/0x479
      [11509.608179]  [<ffffffff81158116>] ? SYSC_newfstat+0x25/0x2e
      [11509.608179]  [<ffffffff81435b54>] ? ret_from_sys_call+0x1d/0x58
      [11509.608179]  [<ffffffff8116b915>] ? __fget_light+0x2d/0x4f
      [11509.608179]  [<ffffffff8116314e>] SyS_ioctl+0x5a/0x7f
      [11509.608179]  [<ffffffff81435b32>] system_call_fastpath+0x12/0x17
      [11509.608179] Code: f4 01 00 0f 85 c0 00 00 00 48 c7 c1 f3 1f 7d 81 48 c7 c2 aa cb 7c 81 be fc 0b 00 00 eb 70 83 3d 61 eb 9c 00 00 0f 84 a5 00 00 00 <49> 81 3e 40 a3 2b 82 b8 00 00 00
      [11509.608179] RIP  [<ffffffff8107d675>] __lock_acquire+0xb4/0xf02
      [11509.608179]  RSP <ffff8801b3edf9e8>
      [11509.608179] CR2: 0000000000000018
      [11509.608179] ---[ end trace 570a5c6769f0e49a ]---
      
      Which corresponds to the following access in fs/btrfs/free-space-cache.c:
      
        static int do_trimming(struct btrfs_block_group_cache *block_group,
                               u64 *total_trimmed, u64 start, u64 bytes,
                               u64 reserved_start, u64 reserved_bytes,
                               struct btrfs_trim_range *trim_entry)
        {
             struct btrfs_space_info *space_info = block_group->space_info;
        (...)
             spin_lock(&space_info->lock);
             ^^^^^ - block_group->space_info is NULL...
      
      Fix this by ensuring the block group's ->space_info is set before adding
      the block group to the rbtree.
      Signed-off-by: NFilipe Manana <fdmanana@suse.com>
      Signed-off-by: NChris Mason <clm@fb.com>
      2e6e5183
    • A
      Btrfs: check error before reporting missing device and add uuid · 33b97e43
      Anand Jain 提交于
      Report missing device when add is successful,
      otherwise it would exit as ENOMEM. And add uuid
      to the report.
      Signed-off-by: NAnand Jain <anand.jain@oracle.com>
      Reviewed-by: NDavid Sterba <dsterba@suse.cz>
      Signed-off-by: NChris Mason <clm@fb.com>
      33b97e43
    • Q
      btrfs: Fix superblock csum type check. · 1f6e4b3f
      Qu Wenruo 提交于
      Old csum type check is wrong and can't catch csum_type 1(not supported).
      
      Fix it to avoid hostile 0 division.
      Reported-by: NLukas Lueg <lukas.lueg@gmail.com>
      Signed-off-by: NQu Wenruo <quwenruo@cn.fujitsu.com>
      Reviewed-by: NDavid Sterba <dsterba@suse.cz>
      Signed-off-by: NChris Mason <clm@fb.com>
      1f6e4b3f
    • F
      Btrfs: incremental send, fix clone operations for compressed extents · 619d8c4e
      Filipe Manana 提交于
      Marc reported a problem where the receiving end of an incremental send
      was performing clone operations that failed with -EINVAL. This happened
      because, unlike for uncompressed extents, we were not checking if the
      source clone offset and length, after summing the data offset, falls
      within the source file's boundaries.
      
      So make sure we do such checks when attempting to issue clone operations
      for compressed extents.
      
      Problem reproducible with the following steps:
      
        $ mkfs.btrfs -f /dev/sdb
        $ mount -o compress /dev/sdb /mnt
        $ mkfs.btrfs -f /dev/sdc
        $ mount -o compress /dev/sdc /mnt2
      
        # Create the file with a single extent of 128K. This creates a metadata file
        # extent item with a data start offset of 0 and a logical length of 128K.
        $ xfs_io -f -c "pwrite -S 0xaa 64K 128K" -c "fsync" /mnt/foo
      
        # Now rewrite the range 64K to 112K of our file. This will make the inode's
        # metadata continue to point to the 128K extent we created before, but now
        # with an extent item that points to the extent with a data start offset of
        # 112K and a logical length of 16K.
        # That metadata file extent item is associated with the logical file offset
        # at 176K and covers the logical file range 176K to 192K.
        $ xfs_io -c "pwrite -S 0xbb 64K 112K" -c "fsync" /mnt/foo
      
        # Now rewrite the range 180K to 12K. This will make the inode's metadata
        # continue to point the the 128K extent we created earlier, with a single
        # extent item that points to it with a start offset of 112K and a logical
        # length of 4K.
        # That metadata file extent item is associated with the logical file offset
        # at 176K and covers the logical file range 176K to 180K.
        $ xfs_io -c "pwrite -S 0xcc 180K 12K" -c "fsync" /mnt/foo
      
        $ btrfs subvolume snapshot -r /mnt /mnt/snap1
      
        $ touch /mnt/bar
        # Calls the btrfs clone ioctl.
        $ ~/xfstests/src/cloner -s $((176 * 1024)) -d $((176 * 1024)) \
          -l $((4 * 1024)) /mnt/foo /mnt/bar
      
        $ btrfs subvolume snapshot -r /mnt /mnt/snap2
      
        $ btrfs send /mnt/snap1 | btrfs receive /mnt2
        At subvol /mnt/snap1
        At subvol snap1
      
        $ btrfs send -p /mnt/snap1 /mnt/snap2 | btrfs receive /mnt2
        At subvol /mnt/snap2
        At snapshot snap2
        ERROR: failed to clone extents to bar
        Invalid argument
      
      A test case for fstests follows soon.
      Reported-by: NMarc MERLIN <marc@merlins.org>
      Tested-by: NMarc MERLIN <marc@merlins.org>
      Signed-off-by: NFilipe Manana <fdmanana@suse.com>
      Tested-by: NDavid Sterba <dsterba@suse.cz>
      Tested-by: NJan Alexander Steffens (heftig) <jan.steffens@gmail.com>
      Signed-off-by: NChris Mason <clm@fb.com>
      619d8c4e
    • C
      btrfs: qgroup: Fix possible leak in btrfs_add_qgroup_relation() · ab3680dd
      Christian Engelmayer 提交于
      Commit 9c8b35b1 ("btrfs: quota: Automatically update related qgroups or
      mark INCONSISTENT flags when assigning/deleting a qgroup relations.")
      introduced the allocation of a temporary ulist in function
      btrfs_add_qgroup_relation() and added the corresponding cleanup to the out
      path. However, the allocation was introduced before the src/dst level check
      that directly returns. Fix the possible leakage of the ulist by moving the
      allocation after the input validation. Detected by Coverity CID 1295988.
      Signed-off-by: NChristian Engelmayer <cengelma@gmx.at>
      Reviewed-by: NDavid Sterba <dsterba@suse.cz>
      Signed-off-by: NChris Mason <clm@fb.com>
      ab3680dd
    • F
      Btrfs: fix mutex unlock without prior lock on space cache truncation · 35c76642
      Filipe Manana 提交于
      If the call to btrfs_truncate_inode_items() failed and we don't have a block
      group, we were unlocking the cache_write_mutex without having locked it (we
      do it only if we have a block group).
      
      Fixes: 1bbc621e ("Btrfs: allow block group cache writeout
                            outside critical section in commit")
      Signed-off-by: NFilipe Manana <fdmanana@suse.com>
      Reviewed-by: NDavid Sterba <dsterba@suse.cz>
      Signed-off-by: NChris Mason <clm@fb.com>
      35c76642
    • A
      Btrfs: log when missing device is created · 816fcebe
      Anand Jain 提交于
      Signed-off-by: NAnand Jain <anand.jain@oracle.com>
      Reviewed-by: NDavid Sterba <dsterba@suse.cz>
      Signed-off-by: NChris Mason <clm@fb.com>
      816fcebe
    • D
      btrfs: fix warnings after changes in btrfs_abort_transaction · 6d13f549
      David Sterba 提交于
      fs/btrfs/volumes.c: In function ‘btrfs_create_uuid_tree’:
      fs/btrfs/volumes.c:3909:3: warning: format ‘%d’ expects argument of type ‘int’, but argument 4 has type ‘long int’ [-Wformat=]
         btrfs_abort_transaction(trans, tree_root,
         ^
        CC [M]  fs/btrfs/ioctl.o
      fs/btrfs/ioctl.c: In function ‘create_subvol’:
      fs/btrfs/ioctl.c:549:3: warning: format ‘%d’ expects argument of type ‘int’, but argument 4 has type ‘long int’ [-Wformat=]
         btrfs_abort_transaction(trans, root, PTR_ERR(new_root));
      
      PTR_ERR returns long, but we're really using 'int' for the error codes
      everywhere so just set and use the local variable.
      Signed-off-by: NDavid Sterba <dsterba@suse.cz>
      Signed-off-by: NChris Mason <clm@fb.com>
      6d13f549
    • D
      btrfs: add 'cold' compiler annotations to all error handling functions · c0d19e2b
      David Sterba 提交于
      The annotated functios will be placed into .text.unlikely section. The
      annotation also hints compiler to move the code out of the hot paths,
      and may implicitly mark if-statement leading to that block as unlikely.
      
      This is a heuristic, the impact on the generated code is not
      significant.
      Signed-off-by: NDavid Sterba <dsterba@suse.cz>
      Signed-off-by: NChris Mason <clm@fb.com>
      c0d19e2b
    • D
      btrfs: report exact callsite where transaction abort occurs · 1a9a8a71
      David Sterba 提交于
      WARN is called from a single location and all bugreports say that's in
      super.c __btrfs_abort_transaction. This is slightly confusing as we'd
      rather want to know the exact callsite. Whereas this information is
      printed in the syslog below the stacktrace, this requires further look
      and we usually see only the headline from WARNING.
      
      Moving the WARN into the macro has to inline some code and increases
      code by a few kilobytes:
      
        text    data     bss     dec     hex filename
      835481   20305   14120  869906   d4612 btrfs.ko.before
      842883   20305   14120  877308   d62fc btrfs.ko.after
      
      The delta is +7k (130+ calls), measured on 3.19 x86_64, distro config.
      The increase is not small and could lead to worse icache use. The code
      is on error/exit paths that can be recognized by compiler as cold and
      moved out of the way so the impact is speculated to be low, if
      measurable at all.
      Signed-off-by: NDavid Sterba <dsterba@suse.cz>
      Signed-off-by: NChris Mason <clm@fb.com>
      1a9a8a71
    • D
      btrfs: let tree defrag work in SSD mode · 13028901
      David Sterba 提交于
      Long time ago (2008) the defrag was automatic for new b-tree writes but
      has been disabled after performance problems. There was a leftover in
      tree-defrag.c that effectively stops any defragmentation on b-trees.
      This is a bit unexpected and IMHO undesired. The SSD mode is an
      optimization and defrag is supposed to work if the users asks for it.
      
      Related commits:
      
      6702ed49
      Btrfs: Add run time btree defrag, and an ioctl to force btree defrag
      
      e18e4809
      Btrfs: Add mount -o ssd, which includes optimizations for seek free
      storage
      
      b3236e68
      Btrfs: Leave on the tree defragger in mount -o ssd, it still helps there
      
      9afbb0b7
      Btrfs: Disable tree defrag in SSD mode
      
      The last three commits switch the defrag+ssd off/on/off and the last one
      
      3f157a2f
      Btrfs: Online btree defragmentation fixes
      
      misses the bits from tree-defrag.c to revert to the behaviour introduced
      in e18e4809.
      Signed-off-by: NDavid Sterba <dsterba@suse.cz>
      Signed-off-by: NChris Mason <clm@fb.com>
      13028901
    • F
      Btrfs: check pending chunks when shrinking fs to avoid corruption · 53e489bc
      Filipe Manana 提交于
      When we shrink the usable size of a device (its total_bytes), we go over
      all the device extent items in the device tree and attempt to relocate
      the chunk of any device extent that goes beyond the new usable size for
      the device. We do that after setting the new usable size (total_bytes) in
      the device object, so that all new allocations (and reallocations) don't
      use areas of the device that go beyond the new (shorter) size. However we
      were not considering that before setting the new size in the device,
      pending chunks might have been created that use device extents that go
      beyond the new size, and those device extents are not yet in the device
      tree after we search the device tree - they are still attached to the
      list of new block group for some ongoing transaction handle, and they are
      only added to the device tree when the transaction handle is ended (via
      btrfs_create_pending_block_groups()).
      
      So check for pending chunks with device extents that go beyond the new
      size and if any exists, commit the current transaction and repeat the
      search in the device tree.
      
      Not doing this it would mean we would return success to user space while
      still having extents that go beyond the new size, and later user space
      could override those locations on the device while the fs still references
      them, causing all sorts of corruption and unexpected events.
      Signed-off-by: NFilipe Manana <fdmanana@suse.com>
      Signed-off-by: NChris Mason <clm@fb.com>
      53e489bc
    • O
      Btrfs: don't invalidate root dentry when subvolume deletion fails · 64ad6c48
      Omar Sandoval 提交于
      Since commit bafc9b75 ("vfs: More precise tests in d_invalidate"),
      mounted subvolumes can be deleted because d_invalidate() won't fail.
      However, we run into problems when we attempt to delete the default
      subvolume while it is mounted as the root filesystem:
      
      	# btrfs subvol list /
      	ID 257 gen 306 top level 5 path rootvol
      	ID 267 gen 334 top level 5 path snap1
      	# btrfs subvol get-default /
      	ID 267 gen 334 top level 5 path snap1
      	# btrfs inspect-internal rootid /
      	267
      	# mount -o subvol=/ /dev/vda1 /mnt
      	# btrfs subvol del /mnt/snap1
      	Delete subvolume (no-commit): '/mnt/snap1'
      	ERROR: cannot delete '/mnt/snap1' - Operation not permitted
      	# findmnt /
      	findmnt: can't read /proc/mounts: No such file or directory
      	# ls /proc
      	#
      
      Markus reported that this same scenario simply led to a kernel oops.
      
      This happens because in btrfs_ioctl_snap_destroy(), we call
      d_invalidate() before we check may_destroy_subvol(), which means that we
      detach the submounts and drop the dentry before erroring out. Instead,
      we should only invalidate the dentry once the deletion has succeeded.
      Additionally, the shrink_dcache_sb() isn't necessary; d_invalidate()
      will prune the dcache for the deleted subvolume.
      
      Cc: <stable@vger.kernel.org>
      Fixes: bafc9b75 ("vfs: More precise tests in d_invalidate")
      Reported-by: NMarkus Schauler <mschauler@gmail.com>
      Signed-off-by: NOmar Sandoval <osandov@osandov.com>
      Signed-off-by: NChris Mason <clm@fb.com>
      64ad6c48
    • F
      Btrfs: incremental send, check if orphanized dir inode needs delayed rename · 8b191a68
      Filipe Manana 提交于
      If a directory inode is orphanized, because some inode previously
      processed has a new name that collides with the old name of the current
      inode, we need to check if it needs its rename operation delayed too,
      as its ancestor-descendent relationship with some other inode might
      have been reversed between the parent and send snapshots and therefore
      its rename operation needs to happen after that other inode is renamed.
      
      For example, for the following reproducer where this is needed (provided
      by Robbie Ko):
      
        $ mkfs.btrfs -f /dev/sdb
        $ mount /dev/sdb /mnt
        $ mkfs.btrfs -f /dev/sdc
        $ mount /dev/sdc /mnt2
      
        $ mkdir -p /mnt/data/n1/n2
        $ mkdir /mnt/data/n4
        $ mkdir -p /mnt/data/t6/t7
        $ mkdir /mnt/data/t5
        $ mkdir /mnt/data/t7
        $ mkdir /mnt/data/n4/t2
        $ mkdir /mnt/data/t4
        $ mkdir /mnt/data/t3
        $ mv /mnt/data/t7 /mnt/data/n4/t2
        $ mv /mnt/data/t4 /mnt/data/n4/t2/t7
        $ mv /mnt/data/t5 /mnt/data/n4/t2/t7/t4
        $ mv /mnt/data/t6 /mnt/data/n4/t2/t7/t4/t5
        $ mv /mnt/data/n1/n2 /mnt/data/n4/t2/t7/t4/t5/t6
        $ mv /mnt/data/n1 /mnt/data/n4/t2/t7/t4/t5/t6
        $ mv /mnt/data/n4/t2/t7/t4/t5/t6/t7 /mnt/data/n4/t2/t7/t4/t5/t6/n2
        $ mv /mnt/data/t3 /mnt/data/n4/t2/t7/t4/t5/t6/n2/t7
      
        $ btrfs subvolume snapshot -r /mnt /mnt/snap1
      
        $ mv /mnt/data/n4/t2/t7/t4/t5/t6/n1 /mnt/data/n4
        $ mv /mnt/data/n4/t2 /mnt/data/n4/n1
        $ mv /mnt/data/n4/n1/t2/t7/t4/t5/t6/n2 /mnt/data/n4/n1/t2
        $ mv /mnt/data/n4/n1/t2/n2/t7/t3 /mnt/data/n4/n1/t2
        $ mv /mnt/data/n4/n1/t2/t7/t4/t5/t6 /mnt/data/n4/n1/t2
        $ mv /mnt/data/n4/n1/t2/t7/t4 /mnt/data/n4/n1/t2/t6
        $ mv /mnt/data/n4/n1/t2/t7 /mnt/data/n4/n1/t2/t3
        $ mv /mnt/data/n4/n1/t2/n2/t7 /mnt/data/n4/n1/t2
      
        $ btrfs subvolume snapshot -r /mnt /mnt/snap2
      
        $ btrfs send /mnt/snap1 | btrfs receive /mnt2
        $ btrfs send -p /mnt/snap1 /mnt/snap2 | btrfs receive /mnt2
        ERROR: send ioctl failed with -12: Cannot allocate memory
      
      Where the parent snapshot directory hierarchy is the following:
      
        .                                                        (ino 256)
        |-- data/                                                (ino 257)
              |-- n4/                                            (ino 260)
                   |-- t2/                                       (ino 265)
                        |-- t7/                                  (ino 264)
                             |-- t4/                             (ino 266)
                                  |-- t5/                        (ino 263)
                                       |-- t6/                   (ino 261)
                                            |-- n1/              (ino 258)
                                            |-- n2/              (ino 259)
                                                 |-- t7/         (ino 262)
                                                      |-- t3/    (ino 267)
      
      And the send snapshot's directory hierarchy is the following:
      
        .                                                        (ino 256)
        |-- data/                                                (ino 257)
              |-- n4/                                            (ino 260)
                   |-- n1/                                       (ino 258)
                        |-- t2/                                  (ino 265)
                             |-- n2/                             (ino 259)
                             |-- t3/                             (ino 267)
                             |    |-- t7                         (ino 264)
                             |
                             |-- t6/                             (ino 261)
                             |    |-- t4/                        (ino 266)
                             |         |-- t5/                   (ino 263)
                             |
                             |-- t7/                             (ino 262)
      
      While processing inode 262 we orphanize inode 264 and later attempt
      to rename inode 264 to its new name/location, which resulted in building
      an incorrect destination path string for the rename operation with the
      value "data/n4/t2/t7/t4/t5/t6/n2/t7/t3/t7". This rename operation must
      have been done only after inode 267 is processed and renamed, as the
      ancestor-descendent relationship between inodes 264 and 267 was reversed
      between both snapshots, because otherwise it results in an infinite loop
      when building the path string for inode 264 when we are processing an
      inode with a number larger than 264. That loop is the following:
      
        start inode 264, send progress of 265 for example
        parent of 264 -> 267
        parent of 267 -> 262
        parent of 262 -> 259
        parent of 259 -> 261
        parent of 261 -> 263
        parent of 263 -> 266
        parent of 266 -> 264
          |--> back to first iteration while current path string length
               is <= PATH_MAX, and fail with -ENOMEM otherwise
      
      So fix this by making the check if we need to delay a directory rename
      regardless of the current inode having been orphanized or not.
      
      A test case for fstests follows soon.
      
      Thanks to Robbie Ko for providing a reproducer for this problem.
      Reported-by: NRobbie Ko <robbieko@synology.com>
      Signed-off-by: NFilipe Manana <fdmanana@suse.com>
      8b191a68
    • F
      Btrfs: incremental send, don't delay directory renames unnecessarily · 80aa6027
      Filipe Manana 提交于
      Even though we delay the rename of directories when they become
      descendents of other directories that were also renamed in the send
      root to prevent infinite path build loops, we were doing it in cases
      where this was not needed and was actually harmful resulting in
      infinite path build loops as we ended up with a circular dependency
      of delayed directory renames.
      
      Consider the following reproducer:
      
        $ mkfs.btrfs -f /dev/sdb
        $ mount /dev/sdb /mnt
        $ mkfs.btrfs -f /dev/sdc
        $ mount /dev/sdc /mnt2
      
        $ mkdir /mnt/data
        $ mkdir /mnt/data/n1
        $ mkdir /mnt/data/n1/n2
        $ mkdir /mnt/data/n4
        $ mkdir /mnt/data/n1/n2/p1
        $ mkdir /mnt/data/n1/n2/p1/p2
        $ mkdir /mnt/data/t6
        $ mkdir /mnt/data/t7
        $ mkdir -p /mnt/data/t5/t7
        $ mkdir /mnt/data/t2
        $ mkdir /mnt/data/t4
        $ mkdir -p /mnt/data/t1/t3
        $ mkdir /mnt/data/p1
        $ mv /mnt/data/t1 /mnt/data/p1
        $ mkdir -p /mnt/data/p1/p2
        $ mv /mnt/data/t4 /mnt/data/p1/p2/t1
        $ mv /mnt/data/t5 /mnt/data/n4/t5
        $ mv /mnt/data/n1/n2/p1/p2 /mnt/data/n4/t5/p2
        $ mv /mnt/data/t7 /mnt/data/n4/t5/p2/t7
        $ mv /mnt/data/t2 /mnt/data/n4/t1
        $ mv /mnt/data/p1 /mnt/data/n4/t5/p2/p1
        $ mv /mnt/data/n1/n2 /mnt/data/n4/t5/p2/p1/p2/n2
        $ mv /mnt/data/n4/t5/p2/p1/p2/t1 /mnt/data/n4/t5/p2/p1/p2/n2/t1
        $ mv /mnt/data/n4/t5/t7 /mnt/data/n4/t5/p2/p1/p2/n2/t1/t7
        $ mv /mnt/data/n4/t5/p2/p1/t1/t3 /mnt/data/n4/t5/p2/p1/p2/n2/t1/t3
        $ mv /mnt/data/n4/t5/p2/p1/p2/n2/p1 /mnt/data/n4/t5/p2/p1/p2/n2/t1/t7/p1
        $ mv /mnt/data/t6 /mnt/data/n4/t5/p2/p1/p2/n2/t1/t3/t5
        $ mv /mnt/data/n4/t5/p2/p1/t1 /mnt/data/n4/t5/p2/p1/p2/n2/t1/t3/t1
        $ mv /mnt/data/n1 /mnt/data/n4/t5/p2/p1/p2/n2/t1/t7/p1/n1
      
        $ btrfs subvolume snapshot -r /mnt /mnt/snap1
      
        $ mv /mnt/data/n4/t1 /mnt/data/n4/t5/p2/p1/p2/n2/t1/t7/p1/t1
        $ mv /mnt/data/n4/t5/p2/p1/p2/n2/t1 /mnt/data/n4/
        $ mv /mnt/data/n4/t5/p2/p1/p2/n2 /mnt/data/n4/t1/n2
        $ mv /mnt/data/n4/t1/t7/p1 /mnt/data/n4/t1/n2/p1
        $ mv /mnt/data/n4/t1/t3/t1 /mnt/data/n4/t1/n2/t1
        $ mv /mnt/data/n4/t1/t3 /mnt/data/n4/t1/n2/t1/t3
        $ mv /mnt/data/n4/t5/p2/p1/p2 /mnt/data/n4/t1/n2/p1/p2
        $ mv /mnt/data/n4/t1/t7 /mnt/data/n4/t1/n2/p1/t7
        $ mv /mnt/data/n4/t5/p2/p1 /mnt/data/n4/t1/n2/p1/p2/p1
        $ mv /mnt/data/n4/t1/n2/t1/t3/t5 /mnt/data/n4/t1/n2/p1/p2/t5
        $ mv /mnt/data/n4/t5 /mnt/data/n4/t1/n2/p1/p2/p1/t5
        $ mv /mnt/data/n4/t1/n2/p1/p2/p1/t5/p2 /mnt/data/n4/t1/n2/p1/p2/p1/p2
        $ mv /mnt/data/n4/t1/n2/p1/p2/p1/p2/t7 /mnt/data/n4/t1/t7
      
        $ btrfs subvolume snapshot -r /mnt /mnt/snap2
      
        $ btrfs send /mnt/snap1 | btrfs receive /mnt2
        $ btrfs send -p /mnt/snap1 /mnt/snap2 | btrfs receive -vv /mnt2
        ERROR: send ioctl failed with -12: Cannot allocate memory
      
      This reproducer resulted in an infinite path build loop when building the
      path for inode 266 because the following circular dependency of delayed
      directory renames was created:
      
         ino 272 <- ino 261 <- ino 259 <- ino 268 <- ino 267 <- ino 261
      
      Where the notation "X <- Y" means the rename of inode X is delayed by the
      rename of inode Y (X will be renamed after Y is renamed). This resulted
      in an infinite path build loop of inode 266 because that inode has inode
      261 as an ancestor in the send root and inode 261 is in the circular
      dependency of delayed renames listed above.
      
      Fix this by not delaying the rename of a directory inode if an ancestor of
      the inode in the send root, which has a delayed rename operation, is not
      also a descendent of the inode in the parent root.
      
      Thanks to Robbie Ko for sending the reproducer example.
      A test case for xfstests follows soon.
      Reported-by: NRobbie Ko <robbieko@synology.com>
      Signed-off-by: NFilipe Manana <fdmanana@suse.com>
      80aa6027
  2. 29 5月, 2015 8 次提交