1. 05 11月, 2020 1 次提交
    • A
      btrfs: dev-replace: fail mount if we don't have replace item with target device · cf89af14
      Anand Jain 提交于
      If there is a device BTRFS_DEV_REPLACE_DEVID without the device replace
      item, then it means the filesystem is inconsistent state. This is either
      corruption or a crafted image.  Fail the mount as this needs a closer
      look what is actually wrong.
      
      As of now if BTRFS_DEV_REPLACE_DEVID is present without the replace
      item, in __btrfs_free_extra_devids() we determine that there is an
      extra device, and free those extra devices but continue to mount the
      device.
      However, we were wrong in keeping tack of the rw_devices so the syzbot
      testcase failed:
      
        WARNING: CPU: 1 PID: 3612 at fs/btrfs/volumes.c:1166 close_fs_devices.part.0+0x607/0x800 fs/btrfs/volumes.c:1166
        Kernel panic - not syncing: panic_on_warn set ...
        CPU: 1 PID: 3612 Comm: syz-executor.2 Not tainted 5.9.0-rc4-syzkaller #0
        Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011
        Call Trace:
         __dump_stack lib/dump_stack.c:77 [inline]
         dump_stack+0x198/0x1fd lib/dump_stack.c:118
         panic+0x347/0x7c0 kernel/panic.c:231
         __warn.cold+0x20/0x46 kernel/panic.c:600
         report_bug+0x1bd/0x210 lib/bug.c:198
         handle_bug+0x38/0x90 arch/x86/kernel/traps.c:234
         exc_invalid_op+0x14/0x40 arch/x86/kernel/traps.c:254
         asm_exc_invalid_op+0x12/0x20 arch/x86/include/asm/idtentry.h:536
        RIP: 0010:close_fs_devices.part.0+0x607/0x800 fs/btrfs/volumes.c:1166
        RSP: 0018:ffffc900091777e0 EFLAGS: 00010246
        RAX: 0000000000040000 RBX: ffffffffffffffff RCX: ffffc9000c8b7000
        RDX: 0000000000040000 RSI: ffffffff83097f47 RDI: 0000000000000007
        RBP: dffffc0000000000 R08: 0000000000000001 R09: ffff8880988a187f
        R10: 0000000000000000 R11: 0000000000000001 R12: ffff88809593a130
        R13: ffff88809593a1ec R14: ffff8880988a1908 R15: ffff88809593a050
         close_fs_devices fs/btrfs/volumes.c:1193 [inline]
         btrfs_close_devices+0x95/0x1f0 fs/btrfs/volumes.c:1179
         open_ctree+0x4984/0x4a2d fs/btrfs/disk-io.c:3434
         btrfs_fill_super fs/btrfs/super.c:1316 [inline]
         btrfs_mount_root.cold+0x14/0x165 fs/btrfs/super.c:1672
      
      The fix here is, when we determine that there isn't a replace item
      then fail the mount if there is a replace target device (devid 0).
      
      CC: stable@vger.kernel.org # 4.19+
      Reported-by: syzbot+4cfe71a4da060be47502@syzkaller.appspotmail.com
      Signed-off-by: NAnand Jain <anand.jain@oracle.com>
      Reviewed-by: NDavid Sterba <dsterba@suse.com>
      Signed-off-by: NDavid Sterba <dsterba@suse.com>
      cf89af14
  2. 26 10月, 2020 1 次提交
    • F
      btrfs: fix readahead hang and use-after-free after removing a device · 66d204a1
      Filipe Manana 提交于
      Very sporadically I had test case btrfs/069 from fstests hanging (for
      years, it is not a recent regression), with the following traces in
      dmesg/syslog:
      
        [162301.160628] BTRFS info (device sdc): dev_replace from /dev/sdd (devid 2) to /dev/sdg started
        [162301.181196] BTRFS info (device sdc): scrub: finished on devid 4 with status: 0
        [162301.287162] BTRFS info (device sdc): dev_replace from /dev/sdd (devid 2) to /dev/sdg finished
        [162513.513792] INFO: task btrfs-transacti:1356167 blocked for more than 120 seconds.
        [162513.514318]       Not tainted 5.9.0-rc6-btrfs-next-69 #1
        [162513.514522] "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
        [162513.514747] task:btrfs-transacti state:D stack:    0 pid:1356167 ppid:     2 flags:0x00004000
        [162513.514751] Call Trace:
        [162513.514761]  __schedule+0x5ce/0xd00
        [162513.514765]  ? _raw_spin_unlock_irqrestore+0x3c/0x60
        [162513.514771]  schedule+0x46/0xf0
        [162513.514844]  wait_current_trans+0xde/0x140 [btrfs]
        [162513.514850]  ? finish_wait+0x90/0x90
        [162513.514864]  start_transaction+0x37c/0x5f0 [btrfs]
        [162513.514879]  transaction_kthread+0xa4/0x170 [btrfs]
        [162513.514891]  ? btrfs_cleanup_transaction+0x660/0x660 [btrfs]
        [162513.514894]  kthread+0x153/0x170
        [162513.514897]  ? kthread_stop+0x2c0/0x2c0
        [162513.514902]  ret_from_fork+0x22/0x30
        [162513.514916] INFO: task fsstress:1356184 blocked for more than 120 seconds.
        [162513.515192]       Not tainted 5.9.0-rc6-btrfs-next-69 #1
        [162513.515431] "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
        [162513.515680] task:fsstress        state:D stack:    0 pid:1356184 ppid:1356177 flags:0x00004000
        [162513.515682] Call Trace:
        [162513.515688]  __schedule+0x5ce/0xd00
        [162513.515691]  ? _raw_spin_unlock_irqrestore+0x3c/0x60
        [162513.515697]  schedule+0x46/0xf0
        [162513.515712]  wait_current_trans+0xde/0x140 [btrfs]
        [162513.515716]  ? finish_wait+0x90/0x90
        [162513.515729]  start_transaction+0x37c/0x5f0 [btrfs]
        [162513.515743]  btrfs_attach_transaction_barrier+0x1f/0x50 [btrfs]
        [162513.515753]  btrfs_sync_fs+0x61/0x1c0 [btrfs]
        [162513.515758]  ? __ia32_sys_fdatasync+0x20/0x20
        [162513.515761]  iterate_supers+0x87/0xf0
        [162513.515765]  ksys_sync+0x60/0xb0
        [162513.515768]  __do_sys_sync+0xa/0x10
        [162513.515771]  do_syscall_64+0x33/0x80
        [162513.515774]  entry_SYSCALL_64_after_hwframe+0x44/0xa9
        [162513.515781] RIP: 0033:0x7f5238f50bd7
        [162513.515782] Code: Bad RIP value.
        [162513.515784] RSP: 002b:00007fff67b978e8 EFLAGS: 00000206 ORIG_RAX: 00000000000000a2
        [162513.515786] RAX: ffffffffffffffda RBX: 000055b1fad2c560 RCX: 00007f5238f50bd7
        [162513.515788] RDX: 00000000ffffffff RSI: 000000000daf0e74 RDI: 000000000000003a
        [162513.515789] RBP: 0000000000000032 R08: 000000000000000a R09: 00007f5239019be0
        [162513.515791] R10: fffffffffffff24f R11: 0000000000000206 R12: 000000000000003a
        [162513.515792] R13: 00007fff67b97950 R14: 00007fff67b97906 R15: 000055b1fad1a340
        [162513.515804] INFO: task fsstress:1356185 blocked for more than 120 seconds.
        [162513.516064]       Not tainted 5.9.0-rc6-btrfs-next-69 #1
        [162513.516329] "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
        [162513.516617] task:fsstress        state:D stack:    0 pid:1356185 ppid:1356177 flags:0x00000000
        [162513.516620] Call Trace:
        [162513.516625]  __schedule+0x5ce/0xd00
        [162513.516628]  ? _raw_spin_unlock_irqrestore+0x3c/0x60
        [162513.516634]  schedule+0x46/0xf0
        [162513.516647]  wait_current_trans+0xde/0x140 [btrfs]
        [162513.516650]  ? finish_wait+0x90/0x90
        [162513.516662]  start_transaction+0x4d7/0x5f0 [btrfs]
        [162513.516679]  btrfs_setxattr_trans+0x3c/0x100 [btrfs]
        [162513.516686]  __vfs_setxattr+0x66/0x80
        [162513.516691]  __vfs_setxattr_noperm+0x70/0x200
        [162513.516697]  vfs_setxattr+0x6b/0x120
        [162513.516703]  setxattr+0x125/0x240
        [162513.516709]  ? lock_acquire+0xb1/0x480
        [162513.516712]  ? mnt_want_write+0x20/0x50
        [162513.516721]  ? rcu_read_lock_any_held+0x8e/0xb0
        [162513.516723]  ? preempt_count_add+0x49/0xa0
        [162513.516725]  ? __sb_start_write+0x19b/0x290
        [162513.516727]  ? preempt_count_add+0x49/0xa0
        [162513.516732]  path_setxattr+0xba/0xd0
        [162513.516739]  __x64_sys_setxattr+0x27/0x30
        [162513.516741]  do_syscall_64+0x33/0x80
        [162513.516743]  entry_SYSCALL_64_after_hwframe+0x44/0xa9
        [162513.516745] RIP: 0033:0x7f5238f56d5a
        [162513.516746] Code: Bad RIP value.
        [162513.516748] RSP: 002b:00007fff67b97868 EFLAGS: 00000202 ORIG_RAX: 00000000000000bc
        [162513.516750] RAX: ffffffffffffffda RBX: 0000000000000001 RCX: 00007f5238f56d5a
        [162513.516751] RDX: 000055b1fbb0d5a0 RSI: 00007fff67b978a0 RDI: 000055b1fbb0d470
        [162513.516753] RBP: 000055b1fbb0d5a0 R08: 0000000000000001 R09: 00007fff67b97700
        [162513.516754] R10: 0000000000000004 R11: 0000000000000202 R12: 0000000000000004
        [162513.516756] R13: 0000000000000024 R14: 0000000000000001 R15: 00007fff67b978a0
        [162513.516767] INFO: task fsstress:1356196 blocked for more than 120 seconds.
        [162513.517064]       Not tainted 5.9.0-rc6-btrfs-next-69 #1
        [162513.517365] "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
        [162513.517763] task:fsstress        state:D stack:    0 pid:1356196 ppid:1356177 flags:0x00004000
        [162513.517780] Call Trace:
        [162513.517786]  __schedule+0x5ce/0xd00
        [162513.517789]  ? _raw_spin_unlock_irqrestore+0x3c/0x60
        [162513.517796]  schedule+0x46/0xf0
        [162513.517810]  wait_current_trans+0xde/0x140 [btrfs]
        [162513.517814]  ? finish_wait+0x90/0x90
        [162513.517829]  start_transaction+0x37c/0x5f0 [btrfs]
        [162513.517845]  btrfs_attach_transaction_barrier+0x1f/0x50 [btrfs]
        [162513.517857]  btrfs_sync_fs+0x61/0x1c0 [btrfs]
        [162513.517862]  ? __ia32_sys_fdatasync+0x20/0x20
        [162513.517865]  iterate_supers+0x87/0xf0
        [162513.517869]  ksys_sync+0x60/0xb0
        [162513.517872]  __do_sys_sync+0xa/0x10
        [162513.517875]  do_syscall_64+0x33/0x80
        [162513.517878]  entry_SYSCALL_64_after_hwframe+0x44/0xa9
        [162513.517881] RIP: 0033:0x7f5238f50bd7
        [162513.517883] Code: Bad RIP value.
        [162513.517885] RSP: 002b:00007fff67b978e8 EFLAGS: 00000206 ORIG_RAX: 00000000000000a2
        [162513.517887] RAX: ffffffffffffffda RBX: 000055b1fad2c560 RCX: 00007f5238f50bd7
        [162513.517889] RDX: 0000000000000000 RSI: 000000007660add2 RDI: 0000000000000053
        [162513.517891] RBP: 0000000000000032 R08: 0000000000000067 R09: 00007f5239019be0
        [162513.517893] R10: fffffffffffff24f R11: 0000000000000206 R12: 0000000000000053
        [162513.517895] R13: 00007fff67b97950 R14: 00007fff67b97906 R15: 000055b1fad1a340
        [162513.517908] INFO: task fsstress:1356197 blocked for more than 120 seconds.
        [162513.518298]       Not tainted 5.9.0-rc6-btrfs-next-69 #1
        [162513.518672] "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
        [162513.519157] task:fsstress        state:D stack:    0 pid:1356197 ppid:1356177 flags:0x00000000
        [162513.519160] Call Trace:
        [162513.519165]  __schedule+0x5ce/0xd00
        [162513.519168]  ? _raw_spin_unlock_irqrestore+0x3c/0x60
        [162513.519174]  schedule+0x46/0xf0
        [162513.519190]  wait_current_trans+0xde/0x140 [btrfs]
        [162513.519193]  ? finish_wait+0x90/0x90
        [162513.519206]  start_transaction+0x4d7/0x5f0 [btrfs]
        [162513.519222]  btrfs_create+0x57/0x200 [btrfs]
        [162513.519230]  lookup_open+0x522/0x650
        [162513.519246]  path_openat+0x2b8/0xa50
        [162513.519270]  do_filp_open+0x91/0x100
        [162513.519275]  ? find_held_lock+0x32/0x90
        [162513.519280]  ? lock_acquired+0x33b/0x470
        [162513.519285]  ? do_raw_spin_unlock+0x4b/0xc0
        [162513.519287]  ? _raw_spin_unlock+0x29/0x40
        [162513.519295]  do_sys_openat2+0x20d/0x2d0
        [162513.519300]  do_sys_open+0x44/0x80
        [162513.519304]  do_syscall_64+0x33/0x80
        [162513.519307]  entry_SYSCALL_64_after_hwframe+0x44/0xa9
        [162513.519309] RIP: 0033:0x7f5238f4a903
        [162513.519310] Code: Bad RIP value.
        [162513.519312] RSP: 002b:00007fff67b97758 EFLAGS: 00000246 ORIG_RAX: 0000000000000055
        [162513.519314] RAX: ffffffffffffffda RBX: 00000000ffffffff RCX: 00007f5238f4a903
        [162513.519316] RDX: 0000000000000000 RSI: 00000000000001b6 RDI: 000055b1fbb0d470
        [162513.519317] RBP: 00007fff67b978c0 R08: 0000000000000001 R09: 0000000000000002
        [162513.519319] R10: 00007fff67b974f7 R11: 0000000000000246 R12: 0000000000000013
        [162513.519320] R13: 00000000000001b6 R14: 00007fff67b97906 R15: 000055b1fad1c620
        [162513.519332] INFO: task btrfs:1356211 blocked for more than 120 seconds.
        [162513.519727]       Not tainted 5.9.0-rc6-btrfs-next-69 #1
        [162513.520115] "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
        [162513.520508] task:btrfs           state:D stack:    0 pid:1356211 ppid:1356178 flags:0x00004002
        [162513.520511] Call Trace:
        [162513.520516]  __schedule+0x5ce/0xd00
        [162513.520519]  ? _raw_spin_unlock_irqrestore+0x3c/0x60
        [162513.520525]  schedule+0x46/0xf0
        [162513.520544]  btrfs_scrub_pause+0x11f/0x180 [btrfs]
        [162513.520548]  ? finish_wait+0x90/0x90
        [162513.520562]  btrfs_commit_transaction+0x45a/0xc30 [btrfs]
        [162513.520574]  ? start_transaction+0xe0/0x5f0 [btrfs]
        [162513.520596]  btrfs_dev_replace_finishing+0x6d8/0x711 [btrfs]
        [162513.520619]  btrfs_dev_replace_by_ioctl.cold+0x1cc/0x1fd [btrfs]
        [162513.520639]  btrfs_ioctl+0x2a25/0x36f0 [btrfs]
        [162513.520643]  ? do_sigaction+0xf3/0x240
        [162513.520645]  ? find_held_lock+0x32/0x90
        [162513.520648]  ? do_sigaction+0xf3/0x240
        [162513.520651]  ? lock_acquired+0x33b/0x470
        [162513.520655]  ? _raw_spin_unlock_irq+0x24/0x50
        [162513.520657]  ? lockdep_hardirqs_on+0x7d/0x100
        [162513.520660]  ? _raw_spin_unlock_irq+0x35/0x50
        [162513.520662]  ? do_sigaction+0xf3/0x240
        [162513.520671]  ? __x64_sys_ioctl+0x83/0xb0
        [162513.520672]  __x64_sys_ioctl+0x83/0xb0
        [162513.520677]  do_syscall_64+0x33/0x80
        [162513.520679]  entry_SYSCALL_64_after_hwframe+0x44/0xa9
        [162513.520681] RIP: 0033:0x7fc3cd307d87
        [162513.520682] Code: Bad RIP value.
        [162513.520684] RSP: 002b:00007ffe30a56bb8 EFLAGS: 00000202 ORIG_RAX: 0000000000000010
        [162513.520686] RAX: ffffffffffffffda RBX: 0000000000000004 RCX: 00007fc3cd307d87
        [162513.520687] RDX: 00007ffe30a57a30 RSI: 00000000ca289435 RDI: 0000000000000003
        [162513.520689] RBP: 0000000000000000 R08: 0000000000000000 R09: 0000000000000000
        [162513.520690] R10: 0000000000000008 R11: 0000000000000202 R12: 0000000000000003
        [162513.520692] R13: 0000557323a212e0 R14: 00007ffe30a5a520 R15: 0000000000000001
        [162513.520703]
      		  Showing all locks held in the system:
        [162513.520712] 1 lock held by khungtaskd/54:
        [162513.520713]  #0: ffffffffb40a91a0 (rcu_read_lock){....}-{1:2}, at: debug_show_all_locks+0x15/0x197
        [162513.520728] 1 lock held by in:imklog/596:
        [162513.520729]  #0: ffff8f3f0d781400 (&f->f_pos_lock){+.+.}-{3:3}, at: __fdget_pos+0x4d/0x60
        [162513.520782] 1 lock held by btrfs-transacti/1356167:
        [162513.520784]  #0: ffff8f3d810cc848 (&fs_info->transaction_kthread_mutex){+.+.}-{3:3}, at: transaction_kthread+0x4a/0x170 [btrfs]
        [162513.520798] 1 lock held by btrfs/1356190:
        [162513.520800]  #0: ffff8f3d57644470 (sb_writers#15){.+.+}-{0:0}, at: mnt_want_write_file+0x22/0x60
        [162513.520805] 1 lock held by fsstress/1356184:
        [162513.520806]  #0: ffff8f3d576440e8 (&type->s_umount_key#62){++++}-{3:3}, at: iterate_supers+0x6f/0xf0
        [162513.520811] 3 locks held by fsstress/1356185:
        [162513.520812]  #0: ffff8f3d57644470 (sb_writers#15){.+.+}-{0:0}, at: mnt_want_write+0x20/0x50
        [162513.520815]  #1: ffff8f3d80a650b8 (&type->i_mutex_dir_key#10){++++}-{3:3}, at: vfs_setxattr+0x50/0x120
        [162513.520820]  #2: ffff8f3d57644690 (sb_internal#2){.+.+}-{0:0}, at: start_transaction+0x40e/0x5f0 [btrfs]
        [162513.520833] 1 lock held by fsstress/1356196:
        [162513.520834]  #0: ffff8f3d576440e8 (&type->s_umount_key#62){++++}-{3:3}, at: iterate_supers+0x6f/0xf0
        [162513.520838] 3 locks held by fsstress/1356197:
        [162513.520839]  #0: ffff8f3d57644470 (sb_writers#15){.+.+}-{0:0}, at: mnt_want_write+0x20/0x50
        [162513.520843]  #1: ffff8f3d506465e8 (&type->i_mutex_dir_key#10){++++}-{3:3}, at: path_openat+0x2a7/0xa50
        [162513.520846]  #2: ffff8f3d57644690 (sb_internal#2){.+.+}-{0:0}, at: start_transaction+0x40e/0x5f0 [btrfs]
        [162513.520858] 2 locks held by btrfs/1356211:
        [162513.520859]  #0: ffff8f3d810cde30 (&fs_info->dev_replace.lock_finishing_cancel_unmount){+.+.}-{3:3}, at: btrfs_dev_replace_finishing+0x52/0x711 [btrfs]
        [162513.520877]  #1: ffff8f3d57644690 (sb_internal#2){.+.+}-{0:0}, at: start_transaction+0x40e/0x5f0 [btrfs]
      
      This was weird because the stack traces show that a transaction commit,
      triggered by a device replace operation, is blocking trying to pause any
      running scrubs but there are no stack traces of blocked tasks doing a
      scrub.
      
      After poking around with drgn, I noticed there was a scrub task that was
      constantly running and blocking for shorts periods of time:
      
        >>> t = find_task(prog, 1356190)
        >>> prog.stack_trace(t)
        #0  __schedule+0x5ce/0xcfc
        #1  schedule+0x46/0xe4
        #2  schedule_timeout+0x1df/0x475
        #3  btrfs_reada_wait+0xda/0x132
        #4  scrub_stripe+0x2a8/0x112f
        #5  scrub_chunk+0xcd/0x134
        #6  scrub_enumerate_chunks+0x29e/0x5ee
        #7  btrfs_scrub_dev+0x2d5/0x91b
        #8  btrfs_ioctl+0x7f5/0x36e7
        #9  __x64_sys_ioctl+0x83/0xb0
        #10 do_syscall_64+0x33/0x77
        #11 entry_SYSCALL_64+0x7c/0x156
      
      Which corresponds to:
      
      int btrfs_reada_wait(void *handle)
      {
          struct reada_control *rc = handle;
          struct btrfs_fs_info *fs_info = rc->fs_info;
      
          while (atomic_read(&rc->elems)) {
              if (!atomic_read(&fs_info->reada_works_cnt))
                  reada_start_machine(fs_info);
              wait_event_timeout(rc->wait, atomic_read(&rc->elems) == 0,
                                (HZ + 9) / 10);
          }
      (...)
      
      So the counter "rc->elems" was set to 1 and never decreased to 0, causing
      the scrub task to loop forever in that function. Then I used the following
      script for drgn to check the readahead requests:
      
        $ cat dump_reada.py
        import sys
        import drgn
        from drgn import NULL, Object, cast, container_of, execscript, \
            reinterpret, sizeof
        from drgn.helpers.linux import *
      
        mnt_path = b"/home/fdmanana/btrfs-tests/scratch_1"
      
        mnt = None
        for mnt in for_each_mount(prog, dst = mnt_path):
            pass
      
        if mnt is None:
            sys.stderr.write(f'Error: mount point {mnt_path} not found\n')
            sys.exit(1)
      
        fs_info = cast('struct btrfs_fs_info *', mnt.mnt.mnt_sb.s_fs_info)
      
        def dump_re(re):
            nzones = re.nzones.value_()
            print(f're at {hex(re.value_())}')
            print(f'\t logical {re.logical.value_()}')
            print(f'\t refcnt {re.refcnt.value_()}')
            print(f'\t nzones {nzones}')
            for i in range(nzones):
                dev = re.zones[i].device
                name = dev.name.str.string_()
                print(f'\t\t dev id {dev.devid.value_()} name {name}')
            print()
      
        for _, e in radix_tree_for_each(fs_info.reada_tree):
            re = cast('struct reada_extent *', e)
            dump_re(re)
      
        $ drgn dump_reada.py
        re at 0xffff8f3da9d25ad8
                logical 38928384
                refcnt 1
                nzones 1
                       dev id 0 name b'/dev/sdd'
        $
      
      So there was one readahead extent with a single zone corresponding to the
      source device of that last device replace operation logged in dmesg/syslog.
      Also the ID of that zone's device was 0 which is a special value set in
      the source device of a device replace operation when the operation finishes
      (constant BTRFS_DEV_REPLACE_DEVID set at btrfs_dev_replace_finishing()),
      confirming again that device /dev/sdd was the source of a device replace
      operation.
      
      Normally there should be as many zones in the readahead extent as there are
      devices, and I wasn't expecting the extent to be in a block group with a
      'single' profile, so I went and confirmed with the following drgn script
      that there weren't any single profile block groups:
      
        $ cat dump_block_groups.py
        import sys
        import drgn
        from drgn import NULL, Object, cast, container_of, execscript, \
            reinterpret, sizeof
        from drgn.helpers.linux import *
      
        mnt_path = b"/home/fdmanana/btrfs-tests/scratch_1"
      
        mnt = None
        for mnt in for_each_mount(prog, dst = mnt_path):
            pass
      
        if mnt is None:
            sys.stderr.write(f'Error: mount point {mnt_path} not found\n')
            sys.exit(1)
      
        fs_info = cast('struct btrfs_fs_info *', mnt.mnt.mnt_sb.s_fs_info)
      
        BTRFS_BLOCK_GROUP_DATA = (1 << 0)
        BTRFS_BLOCK_GROUP_SYSTEM = (1 << 1)
        BTRFS_BLOCK_GROUP_METADATA = (1 << 2)
        BTRFS_BLOCK_GROUP_RAID0 = (1 << 3)
        BTRFS_BLOCK_GROUP_RAID1 = (1 << 4)
        BTRFS_BLOCK_GROUP_DUP = (1 << 5)
        BTRFS_BLOCK_GROUP_RAID10 = (1 << 6)
        BTRFS_BLOCK_GROUP_RAID5 = (1 << 7)
        BTRFS_BLOCK_GROUP_RAID6 = (1 << 8)
        BTRFS_BLOCK_GROUP_RAID1C3 = (1 << 9)
        BTRFS_BLOCK_GROUP_RAID1C4 = (1 << 10)
      
        def bg_flags_string(bg):
            flags = bg.flags.value_()
            ret = ''
            if flags & BTRFS_BLOCK_GROUP_DATA:
                ret = 'data'
            if flags & BTRFS_BLOCK_GROUP_METADATA:
                if len(ret) > 0:
                    ret += '|'
                ret += 'meta'
            if flags & BTRFS_BLOCK_GROUP_SYSTEM:
                if len(ret) > 0:
                    ret += '|'
                ret += 'system'
            if flags & BTRFS_BLOCK_GROUP_RAID0:
                ret += ' raid0'
            elif flags & BTRFS_BLOCK_GROUP_RAID1:
                ret += ' raid1'
            elif flags & BTRFS_BLOCK_GROUP_DUP:
                ret += ' dup'
            elif flags & BTRFS_BLOCK_GROUP_RAID10:
                ret += ' raid10'
            elif flags & BTRFS_BLOCK_GROUP_RAID5:
                ret += ' raid5'
            elif flags & BTRFS_BLOCK_GROUP_RAID6:
                ret += ' raid6'
            elif flags & BTRFS_BLOCK_GROUP_RAID1C3:
                ret += ' raid1c3'
            elif flags & BTRFS_BLOCK_GROUP_RAID1C4:
                ret += ' raid1c4'
            else:
                ret += ' single'
      
            return ret
      
        def dump_bg(bg):
            print()
            print(f'block group at {hex(bg.value_())}')
            print(f'\t start {bg.start.value_()} length {bg.length.value_()}')
            print(f'\t flags {bg.flags.value_()} - {bg_flags_string(bg)}')
      
        bg_root = fs_info.block_group_cache_tree.address_of_()
        for bg in rbtree_inorder_for_each_entry('struct btrfs_block_group', bg_root, 'cache_node'):
            dump_bg(bg)
      
        $ drgn dump_block_groups.py
      
        block group at 0xffff8f3d673b0400
               start 22020096 length 16777216
               flags 258 - system raid6
      
        block group at 0xffff8f3d53ddb400
               start 38797312 length 536870912
               flags 260 - meta raid6
      
        block group at 0xffff8f3d5f4d9c00
               start 575668224 length 2147483648
               flags 257 - data raid6
      
        block group at 0xffff8f3d08189000
               start 2723151872 length 67108864
               flags 258 - system raid6
      
        block group at 0xffff8f3db70ff000
               start 2790260736 length 1073741824
               flags 260 - meta raid6
      
        block group at 0xffff8f3d5f4dd800
               start 3864002560 length 67108864
               flags 258 - system raid6
      
        block group at 0xffff8f3d67037000
               start 3931111424 length 2147483648
               flags 257 - data raid6
        $
      
      So there were only 2 reasons left for having a readahead extent with a
      single zone: reada_find_zone(), called when creating a readahead extent,
      returned NULL either because we failed to find the corresponding block
      group or because a memory allocation failed. With some additional and
      custom tracing I figured out that on every further ocurrence of the
      problem the block group had just been deleted when we were looping to
      create the zones for the readahead extent (at reada_find_extent()), so we
      ended up with only one zone in the readahead extent, corresponding to a
      device that ends up getting replaced.
      
      So after figuring that out it became obvious why the hang happens:
      
      1) Task A starts a scrub on any device of the filesystem, except for
         device /dev/sdd;
      
      2) Task B starts a device replace with /dev/sdd as the source device;
      
      3) Task A calls btrfs_reada_add() from scrub_stripe() and it is currently
         starting to scrub a stripe from block group X. This call to
         btrfs_reada_add() is the one for the extent tree. When btrfs_reada_add()
         calls reada_add_block(), it passes the logical address of the extent
         tree's root node as its 'logical' argument - a value of 38928384;
      
      4) Task A then enters reada_find_extent(), called from reada_add_block().
         It finds there isn't any existing readahead extent for the logical
         address 38928384, so it proceeds to the path of creating a new one.
      
         It calls btrfs_map_block() to find out which stripes exist for the block
         group X. On the first iteration of the for loop that iterates over the
         stripes, it finds the stripe for device /dev/sdd, so it creates one
         zone for that device and adds it to the readahead extent. Before getting
         into the second iteration of the loop, the cleanup kthread deletes block
         group X because it was empty. So in the iterations for the remaining
         stripes it does not add more zones to the readahead extent, because the
         calls to reada_find_zone() returned NULL because they couldn't find
         block group X anymore.
      
         As a result the new readahead extent has a single zone, corresponding to
         the device /dev/sdd;
      
      4) Before task A returns to btrfs_reada_add() and queues the readahead job
         for the readahead work queue, task B finishes the device replace and at
         btrfs_dev_replace_finishing() swaps the device /dev/sdd with the new
         device /dev/sdg;
      
      5) Task A returns to reada_add_block(), which increments the counter
         "->elems" of the reada_control structure allocated at btrfs_reada_add().
      
         Then it returns back to btrfs_reada_add() and calls
         reada_start_machine(). This queues a job in the readahead work queue to
         run the function reada_start_machine_worker(), which calls
         __reada_start_machine().
      
         At __reada_start_machine() we take the device list mutex and for each
         device found in the current device list, we call
         reada_start_machine_dev() to start the readahead work. However at this
         point the device /dev/sdd was already freed and is not in the device
         list anymore.
      
         This means the corresponding readahead for the extent at 38928384 is
         never started, and therefore the "->elems" counter of the reada_control
         structure allocated at btrfs_reada_add() never goes down to 0, causing
         the call to btrfs_reada_wait(), done by the scrub task, to wait forever.
      
      Note that the readahead request can be made either after the device replace
      started or before it started, however in pratice it is very unlikely that a
      device replace is able to start after a readahead request is made and is
      able to complete before the readahead request completes - maybe only on a
      very small and nearly empty filesystem.
      
      This hang however is not the only problem we can have with readahead and
      device removals. When the readahead extent has other zones other than the
      one corresponding to the device that is being removed (either by a device
      replace or a device remove operation), we risk having a use-after-free on
      the device when dropping the last reference of the readahead extent.
      
      For example if we create a readahead extent with two zones, one for the
      device /dev/sdd and one for the device /dev/sde:
      
      1) Before the readahead worker starts, the device /dev/sdd is removed,
         and the corresponding btrfs_device structure is freed. However the
         readahead extent still has the zone pointing to the device structure;
      
      2) When the readahead worker starts, it only finds device /dev/sde in the
         current device list of the filesystem;
      
      3) It starts the readahead work, at reada_start_machine_dev(), using the
         device /dev/sde;
      
      4) Then when it finishes reading the extent from device /dev/sde, it calls
         __readahead_hook() which ends up dropping the last reference on the
         readahead extent through the last call to reada_extent_put();
      
      5) At reada_extent_put() it iterates over each zone of the readahead extent
         and attempts to delete an element from the device's 'reada_extents'
         radix tree, resulting in a use-after-free, as the device pointer of the
         zone for /dev/sdd is now stale. We can also access the device after
         dropping the last reference of a zone, through reada_zone_release(),
         also called by reada_extent_put().
      
      And a device remove suffers the same problem, however since it shrinks the
      device size down to zero before removing the device, it is very unlikely to
      still have readahead requests not completed by the time we free the device,
      the only possibility is if the device has a very little space allocated.
      
      While the hang problem is exclusive to scrub, since it is currently the
      only user of btrfs_reada_add() and btrfs_reada_wait(), the use-after-free
      problem affects any path that triggers readhead, which includes
      btree_readahead_hook() and __readahead_hook() (a readahead worker can
      trigger readahed for the children of a node) for example - any path that
      ends up calling reada_add_block() can trigger the use-after-free after a
      device is removed.
      
      So fix this by waiting for any readahead requests for a device to complete
      before removing a device, ensuring that while waiting for existing ones no
      new ones can be made.
      
      This problem has been around for a very long time - the readahead code was
      added in 2011, device remove exists since 2008 and device replace was
      introduced in 2013, hard to pick a specific commit for a git Fixes tag.
      
      CC: stable@vger.kernel.org # 4.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>
      66d204a1
  3. 07 10月, 2020 7 次提交
    • A
      btrfs: move btrfs_dev_replace_update_device_in_mapping_tree to drop declaration · 0725c0c9
      Anand Jain 提交于
      The function is short and simple, we can get rid of the declaration as
      it's not necessary for a static function. Move it before its first
      caller.  No functional changes.
      Reviewed-by: NNikolay Borisov <nborisov@suse.com>
      Signed-off-by: NAnand Jain <anand.jain@oracle.com>
      Reviewed-by: NDavid Sterba <dsterba@suse.com>
      Signed-off-by: NDavid Sterba <dsterba@suse.com>
      0725c0c9
    • A
      btrfs: remove tmp variable for list traversal in btrfs_init_dev_replace_tgtdev · 1888709d
      Anand Jain 提交于
      In the function btrfs_init_dev_replace_tgtdev(), the local variable
      devices is used only once, we can remove it.
      Reviewed-by: NNikolay Borisov <nborisov@suse.com>
      Signed-off-by: NAnand Jain <anand.jain@oracle.com>
      Reviewed-by: NDavid Sterba <dsterba@suse.com>
      Signed-off-by: NDavid Sterba <dsterba@suse.com>
      1888709d
    • A
      btrfs: split and refactor btrfs_sysfs_remove_devices_dir · 53f8a74c
      Anand Jain 提交于
      Similar to btrfs_sysfs_add_devices_dir()'s refactoring, split
      btrfs_sysfs_remove_devices_dir() so that we don't have to use the device
      argument to indicate whether to free all devices or just one device.
      
      Export btrfs_sysfs_remove_device() as device operations outside of
      sysfs.c now calls this instead of btrfs_sysfs_remove_devices_dir().
      
      btrfs_sysfs_remove_devices_dir() is renamed to
      btrfs_sysfs_remove_fs_devices() to suite its new role.
      
      Now, no one outside of sysfs.c calls btrfs_sysfs_remove_fs_devices()
      so it is redeclared s static. And the same function had to be moved
      before its first caller.
      Reviewed-by: NNikolay Borisov <nborisov@suse.com>
      Signed-off-by: NAnand Jain <anand.jain@oracle.com>
      Reviewed-by: NDavid Sterba <dsterba@suse.com>
      Signed-off-by: NDavid Sterba <dsterba@suse.com>
      53f8a74c
    • A
      btrfs: simplify parameters of btrfs_sysfs_add_devices_dir · cd36da2e
      Anand Jain 提交于
      When we add a device we need to add it to sysfs, so instead of using the
      btrfs_sysfs_add_devices_dir() fs_devices argument to specify whether to
      add a device or all of fs_devices, call the helper function directly
      btrfs_sysfs_add_device() and thus make it non-static.
      Reviewed-by: NNikolay Borisov <nborisov@suse.com>
      Reviewed-by: NJosef Bacik <josef@toxicpanda.com>
      Signed-off-by: NAnand Jain <anand.jain@oracle.com>
      Reviewed-by: NDavid Sterba <dsterba@suse.com>
      Signed-off-by: NDavid Sterba <dsterba@suse.com>
      cd36da2e
    • A
      btrfs: fix replace of seed device · c6a5d954
      Anand Jain 提交于
      If you replace a seed device in a sprouted fs, it appears to have
      successfully replaced the seed device, but if you look closely, it
      didn't.  Here is an example.
      
        $ mkfs.btrfs /dev/sda
        $ btrfstune -S1 /dev/sda
        $ mount /dev/sda /btrfs
        $ btrfs device add /dev/sdb /btrfs
        $ umount /btrfs
        $ btrfs device scan --forget
        $ mount -o device=/dev/sda /dev/sdb /btrfs
        $ btrfs replace start -f /dev/sda /dev/sdc /btrfs
        $ echo $?
        0
      
        BTRFS info (device sdb): dev_replace from /dev/sda (devid 1) to /dev/sdc started
        BTRFS info (device sdb): dev_replace from /dev/sda (devid 1) to /dev/sdc finished
      
        $ btrfs fi show
        Label: none  uuid: ab2c88b7-be81-4a7e-9849-c3666e7f9f4f
      	  Total devices 2 FS bytes used 256.00KiB
      	  devid    1 size 3.00GiB used 520.00MiB path /dev/sdc
      	  devid    2 size 3.00GiB used 896.00MiB path /dev/sdb
      
        Label: none  uuid: 10bd3202-0415-43af-96a8-d5409f310a7e
      	  Total devices 1 FS bytes used 128.00KiB
      	  devid    1 size 3.00GiB used 536.00MiB path /dev/sda
      
      So as per the replace start command and kernel log replace was successful.
      Now let's try to clean mount.
      
        $ umount /btrfs
        $ btrfs device scan --forget
      
        $ mount -o device=/dev/sdc /dev/sdb /btrfs
        mount: /btrfs: wrong fs type, bad option, bad superblock on /dev/sdb, missing codepage or helper program, or other error.
      
        [  636.157517] BTRFS error (device sdc): failed to read chunk tree: -2
        [  636.180177] BTRFS error (device sdc): open_ctree failed
      
      That's because per dev items it is still looking for the original seed
      device.
      
       $ btrfs inspect-internal dump-tree -d /dev/sdb
      
      	item 0 key (DEV_ITEMS DEV_ITEM 1) itemoff 16185 itemsize 98
      		devid 1 total_bytes 3221225472 bytes_used 545259520
      		io_align 4096 io_width 4096 sector_size 4096 type 0
      		generation 6 start_offset 0 dev_group 0
      		seek_speed 0 bandwidth 0
      		uuid 59368f50-9af2-4b17-91da-8a783cc418d4  <--- seed uuid
      		fsid 10bd3202-0415-43af-96a8-d5409f310a7e  <--- seed fsid
      	item 1 key (DEV_ITEMS DEV_ITEM 2) itemoff 16087 itemsize 98
      		devid 2 total_bytes 3221225472 bytes_used 939524096
      		io_align 4096 io_width 4096 sector_size 4096 type 0
      		generation 0 start_offset 0 dev_group 0
      		seek_speed 0 bandwidth 0
      		uuid 56a0a6bc-4630-4998-8daf-3c3030c4256a  <- sprout uuid
      		fsid ab2c88b7-be81-4a7e-9849-c3666e7f9f4f <- sprout fsid
      
      But the replaced target has the following uuid+fsid in its superblock
      which doesn't match with the expected uuid+fsid in its devitem.
      
        $ btrfs in dump-super /dev/sdc | egrep '^generation|dev_item.uuid|dev_item.fsid|devid'
        generation	20
        dev_item.uuid	59368f50-9af2-4b17-91da-8a783cc418d4
        dev_item.fsid	ab2c88b7-be81-4a7e-9849-c3666e7f9f4f [match]
        dev_item.devid	1
      
      So if you provide the original seed device the mount shall be
      successful.  Which so long happening in the test case btrfs/163.
      
        $ btrfs device scan --forget
        $ mount -o device=/dev/sda /dev/sdb /btrfs
      
      Fix in this patch:
      If a seed is not sprouted then there is no replacement of it, because of
      its read-only filesystem with a read-only device. Similarly, in the case
      of a sprouted filesystem, the seed device is still read only. So, mark
      it as you can't replace a seed device, you can only add a new device and
      then delete the seed device. If replace is attempted then returns
      -EINVAL.
      Signed-off-by: NAnand Jain <anand.jain@oracle.com>
      Signed-off-by: NDavid Sterba <dsterba@suse.com>
      c6a5d954
    • G
      btrfs: enumerate the type of exclusive operation in progress · c3e1f96c
      Goldwyn Rodrigues 提交于
      Instead of using a flag bit for exclusive operation, use a variable to
      store which exclusive operation is being performed.  Introduce an API
      to start and finish an exclusive operation.
      
      This would enable another way for tools to check which operation is
      running on why starting an exclusive operation failed. The followup
      patch adds a sysfs_notify() to alert userspace when the state changes, so
      userspace can perform select() on it to get notified of the change.
      
      This would enable us to enqueue a command which will wait for current
      exclusive operation to complete before issuing the next exclusive
      operation. This has been done synchronously as opposed to a background
      process, or else error collection (if any) will become difficult.
      Reviewed-by: NNikolay Borisov <nborisov@suse.com>
      Signed-off-by: NGoldwyn Rodrigues <rgoldwyn@suse.com>
      Reviewed-by: NDavid Sterba <dsterba@suse.com>
      [ update comments ]
      Signed-off-by: NDavid Sterba <dsterba@suse.com>
      c3e1f96c
    • J
      btrfs: change nr to u64 in btrfs_start_delalloc_roots · b4912139
      Josef Bacik 提交于
      We have btrfs_wait_ordered_roots() which takes a u64 for nr, but
      btrfs_start_delalloc_roots() that takes an int for nr, which makes using
      them in conjunction, especially for something like (u64)-1, annoying and
      inconsistent.  Fix btrfs_start_delalloc_roots() to take a u64 for nr and
      adjust start_delalloc_inodes() and it's callers appropriately.
      
      This means we've adjusted start_delalloc_inodes() to take a pointer of
      nr since we want to preserve the ability for start-delalloc_inodes() to
      return an error, so simply make it do the nr adjusting as necessary.
      
      Part of adjusting the callers to this means changing
      btrfs_writeback_inodes_sb_nr() to take a u64 for items.  This may be
      confusing because it seems unrelated, but the caller of
      btrfs_writeback_inodes_sb_nr() already passes in a u64, it's just the
      function variable that needs to be changed.
      Reviewed-by: NNikolay Borisov <nborisov@suse.com>
      Tested-by: NNikolay Borisov <nborisov@suse.com>
      Reviewed-by: NJohannes Thumshirn <johannes.thumshirn@wdc.com>
      Signed-off-by: NJosef Bacik <josef@toxicpanda.com>
      Reviewed-by: NDavid Sterba <dsterba@suse.com>
      Signed-off-by: NDavid Sterba <dsterba@suse.com>
      b4912139
  4. 01 10月, 2020 2 次提交
    • F
      btrfs: fix filesystem corruption after a device replace · 4c8f3532
      Filipe Manana 提交于
      We use a device's allocation state tree to track ranges in a device used
      for allocated chunks, and we set ranges in this tree when allocating a new
      chunk. However after a device replace operation, we were not setting the
      allocated ranges in the new device's allocation state tree, so that tree
      is empty after a device replace.
      
      This means that a fitrim operation after a device replace will trim the
      device ranges that have allocated chunks and extents, as we trim every
      range for which there is not a range marked in the device's allocation
      state tree. It is also important during chunk allocation, since the
      device's allocation state is used to determine if a range is already
      allocated when allocating a new chunk.
      
      This is trivial to reproduce and the following script triggers the bug:
      
        $ cat reproducer.sh
        #!/bin/bash
      
        DEV1="/dev/sdg"
        DEV2="/dev/sdh"
        DEV3="/dev/sdi"
      
        wipefs -a $DEV1 $DEV2 $DEV3 &> /dev/null
      
        # Create a raid1 test fs on 2 devices.
        mkfs.btrfs -f -m raid1 -d raid1 $DEV1 $DEV2 > /dev/null
        mount $DEV1 /mnt/btrfs
      
        xfs_io -f -c "pwrite -S 0xab 0 10M" /mnt/btrfs/foo
      
        echo "Starting to replace $DEV1 with $DEV3"
        btrfs replace start -B $DEV1 $DEV3 /mnt/btrfs
        echo
      
        echo "Running fstrim"
        fstrim /mnt/btrfs
        echo
      
        echo "Unmounting filesystem"
        umount /mnt/btrfs
      
        echo "Mounting filesystem in degraded mode using $DEV3 only"
        wipefs -a $DEV1 $DEV2 &> /dev/null
        mount -o degraded $DEV3 /mnt/btrfs
        if [ $? -ne 0 ]; then
                dmesg | tail
                echo
                echo "Failed to mount in degraded mode"
                exit 1
        fi
      
        echo
        echo "File foo data (expected all bytes = 0xab):"
        od -A d -t x1 /mnt/btrfs/foo
      
        umount /mnt/btrfs
      
      When running the reproducer:
      
        $ ./replace-test.sh
        wrote 10485760/10485760 bytes at offset 0
        10 MiB, 2560 ops; 0.0901 sec (110.877 MiB/sec and 28384.5216 ops/sec)
        Starting to replace /dev/sdg with /dev/sdi
      
        Running fstrim
      
        Unmounting filesystem
        Mounting filesystem in degraded mode using /dev/sdi only
        mount: /mnt/btrfs: wrong fs type, bad option, bad superblock on /dev/sdi, missing codepage or helper program, or other error.
        [19581.748641] BTRFS info (device sdg): dev_replace from /dev/sdg (devid 1) to /dev/sdi started
        [19581.803842] BTRFS info (device sdg): dev_replace from /dev/sdg (devid 1) to /dev/sdi finished
        [19582.208293] BTRFS info (device sdi): allowing degraded mounts
        [19582.208298] BTRFS info (device sdi): disk space caching is enabled
        [19582.208301] BTRFS info (device sdi): has skinny extents
        [19582.212853] BTRFS warning (device sdi): devid 2 uuid 1f731f47-e1bb-4f00-bfbb-9e5a0cb4ba9f is missing
        [19582.213904] btree_readpage_end_io_hook: 25839 callbacks suppressed
        [19582.213907] BTRFS error (device sdi): bad tree block start, want 30490624 have 0
        [19582.214780] BTRFS warning (device sdi): failed to read root (objectid=7): -5
        [19582.231576] BTRFS error (device sdi): open_ctree failed
      
        Failed to mount in degraded mode
      
      So fix by setting all allocated ranges in the replace target device when
      the replace operation is finishing, when we are holding the chunk mutex
      and we can not race with new chunk allocations.
      
      A test case for fstests follows soon.
      
      Fixes: 1c11b63e ("btrfs: replace pending/pinned chunks lists with io tree")
      CC: stable@vger.kernel.org # 5.2+
      Reviewed-by: NNikolay Borisov <nborisov@suse.com>
      Reviewed-by: NJohannes Thumshirn <johannes.thumshirn@wdc.com>
      Signed-off-by: NFilipe Manana <fdmanana@suse.com>
      Signed-off-by: NDavid Sterba <dsterba@suse.com>
      4c8f3532
    • J
      btrfs: move btrfs_rm_dev_replace_free_srcdev outside of all locks · a466c85e
      Josef Bacik 提交于
      When closing and freeing the source device we could end up doing our
      final blkdev_put() on the bdev, which will grab the bd_mutex.  As such
      we want to be holding as few locks as possible, so move this call
      outside of the dev_replace->lock_finishing_cancel_unmount lock.  Since
      we're modifying the fs_devices we need to make sure we're holding the
      uuid_mutex here, so take that as well.
      
      There's a report from syzbot probably hitting one of the cases where
      the bd_mutex and device_list_mutex are taken in the wrong order, however
      it's not with device replace, like this patch fixes. As there's no
      reproducer available so far, we can't verify the fix.
      
      https://lore.kernel.org/lkml/000000000000fc04d105afcf86d7@google.com/
      dashboard link: https://syzkaller.appspot.com/bug?extid=84a0634dc5d21d488419
      
        WARNING: possible circular locking dependency detected
        5.9.0-rc5-syzkaller #0 Not tainted
        ------------------------------------------------------
        syz-executor.0/6878 is trying to acquire lock:
        ffff88804c17d780 (&bdev->bd_mutex){+.+.}-{3:3}, at: blkdev_put+0x30/0x520 fs/block_dev.c:1804
      
        but task is already holding lock:
        ffff8880908cfce0 (&fs_devs->device_list_mutex){+.+.}-{3:3}, at: close_fs_devices.part.0+0x2e/0x800 fs/btrfs/volumes.c:1159
      
        which lock already depends on the new lock.
      
        the existing dependency chain (in reverse order) is:
      
        -> #4 (&fs_devs->device_list_mutex){+.+.}-{3:3}:
      	 __mutex_lock_common kernel/locking/mutex.c:956 [inline]
      	 __mutex_lock+0x134/0x10e0 kernel/locking/mutex.c:1103
      	 btrfs_finish_chunk_alloc+0x281/0xf90 fs/btrfs/volumes.c:5255
      	 btrfs_create_pending_block_groups+0x2f3/0x700 fs/btrfs/block-group.c:2109
      	 __btrfs_end_transaction+0xf5/0x690 fs/btrfs/transaction.c:916
      	 find_free_extent_update_loop fs/btrfs/extent-tree.c:3807 [inline]
      	 find_free_extent+0x23b7/0x2e60 fs/btrfs/extent-tree.c:4127
      	 btrfs_reserve_extent+0x166/0x460 fs/btrfs/extent-tree.c:4206
      	 cow_file_range+0x3de/0x9b0 fs/btrfs/inode.c:1063
      	 btrfs_run_delalloc_range+0x2cf/0x1410 fs/btrfs/inode.c:1838
      	 writepage_delalloc+0x150/0x460 fs/btrfs/extent_io.c:3439
      	 __extent_writepage+0x441/0xd00 fs/btrfs/extent_io.c:3653
      	 extent_write_cache_pages.constprop.0+0x69d/0x1040 fs/btrfs/extent_io.c:4249
      	 extent_writepages+0xcd/0x2b0 fs/btrfs/extent_io.c:4370
      	 do_writepages+0xec/0x290 mm/page-writeback.c:2352
      	 __writeback_single_inode+0x125/0x1400 fs/fs-writeback.c:1461
      	 writeback_sb_inodes+0x53d/0xf40 fs/fs-writeback.c:1721
      	 wb_writeback+0x2ad/0xd40 fs/fs-writeback.c:1894
      	 wb_do_writeback fs/fs-writeback.c:2039 [inline]
      	 wb_workfn+0x2dc/0x13e0 fs/fs-writeback.c:2080
      	 process_one_work+0x94c/0x1670 kernel/workqueue.c:2269
      	 worker_thread+0x64c/0x1120 kernel/workqueue.c:2415
      	 kthread+0x3b5/0x4a0 kernel/kthread.c:292
      	 ret_from_fork+0x1f/0x30 arch/x86/entry/entry_64.S:294
      
        -> #3 (sb_internal#2){.+.+}-{0:0}:
      	 percpu_down_read include/linux/percpu-rwsem.h:51 [inline]
      	 __sb_start_write+0x234/0x470 fs/super.c:1672
      	 sb_start_intwrite include/linux/fs.h:1690 [inline]
      	 start_transaction+0xbe7/0x1170 fs/btrfs/transaction.c:624
      	 find_free_extent_update_loop fs/btrfs/extent-tree.c:3789 [inline]
      	 find_free_extent+0x25e1/0x2e60 fs/btrfs/extent-tree.c:4127
      	 btrfs_reserve_extent+0x166/0x460 fs/btrfs/extent-tree.c:4206
      	 cow_file_range+0x3de/0x9b0 fs/btrfs/inode.c:1063
      	 btrfs_run_delalloc_range+0x2cf/0x1410 fs/btrfs/inode.c:1838
      	 writepage_delalloc+0x150/0x460 fs/btrfs/extent_io.c:3439
      	 __extent_writepage+0x441/0xd00 fs/btrfs/extent_io.c:3653
      	 extent_write_cache_pages.constprop.0+0x69d/0x1040 fs/btrfs/extent_io.c:4249
      	 extent_writepages+0xcd/0x2b0 fs/btrfs/extent_io.c:4370
      	 do_writepages+0xec/0x290 mm/page-writeback.c:2352
      	 __writeback_single_inode+0x125/0x1400 fs/fs-writeback.c:1461
      	 writeback_sb_inodes+0x53d/0xf40 fs/fs-writeback.c:1721
      	 wb_writeback+0x2ad/0xd40 fs/fs-writeback.c:1894
      	 wb_do_writeback fs/fs-writeback.c:2039 [inline]
      	 wb_workfn+0x2dc/0x13e0 fs/fs-writeback.c:2080
      	 process_one_work+0x94c/0x1670 kernel/workqueue.c:2269
      	 worker_thread+0x64c/0x1120 kernel/workqueue.c:2415
      	 kthread+0x3b5/0x4a0 kernel/kthread.c:292
      	 ret_from_fork+0x1f/0x30 arch/x86/entry/entry_64.S:294
      
        -> #2 ((work_completion)(&(&wb->dwork)->work)){+.+.}-{0:0}:
      	 __flush_work+0x60e/0xac0 kernel/workqueue.c:3041
      	 wb_shutdown+0x180/0x220 mm/backing-dev.c:355
      	 bdi_unregister+0x174/0x590 mm/backing-dev.c:872
      	 del_gendisk+0x820/0xa10 block/genhd.c:933
      	 loop_remove drivers/block/loop.c:2192 [inline]
      	 loop_control_ioctl drivers/block/loop.c:2291 [inline]
      	 loop_control_ioctl+0x3b1/0x480 drivers/block/loop.c:2257
      	 vfs_ioctl fs/ioctl.c:48 [inline]
      	 __do_sys_ioctl fs/ioctl.c:753 [inline]
      	 __se_sys_ioctl fs/ioctl.c:739 [inline]
      	 __x64_sys_ioctl+0x193/0x200 fs/ioctl.c:739
      	 do_syscall_64+0x2d/0x70 arch/x86/entry/common.c:46
      	 entry_SYSCALL_64_after_hwframe+0x44/0xa9
      
        -> #1 (loop_ctl_mutex){+.+.}-{3:3}:
      	 __mutex_lock_common kernel/locking/mutex.c:956 [inline]
      	 __mutex_lock+0x134/0x10e0 kernel/locking/mutex.c:1103
      	 lo_open+0x19/0xd0 drivers/block/loop.c:1893
      	 __blkdev_get+0x759/0x1aa0 fs/block_dev.c:1507
      	 blkdev_get fs/block_dev.c:1639 [inline]
      	 blkdev_open+0x227/0x300 fs/block_dev.c:1753
      	 do_dentry_open+0x4b9/0x11b0 fs/open.c:817
      	 do_open fs/namei.c:3251 [inline]
      	 path_openat+0x1b9a/0x2730 fs/namei.c:3368
      	 do_filp_open+0x17e/0x3c0 fs/namei.c:3395
      	 do_sys_openat2+0x16d/0x420 fs/open.c:1168
      	 do_sys_open fs/open.c:1184 [inline]
      	 __do_sys_open fs/open.c:1192 [inline]
      	 __se_sys_open fs/open.c:1188 [inline]
      	 __x64_sys_open+0x119/0x1c0 fs/open.c:1188
      	 do_syscall_64+0x2d/0x70 arch/x86/entry/common.c:46
      	 entry_SYSCALL_64_after_hwframe+0x44/0xa9
      
        -> #0 (&bdev->bd_mutex){+.+.}-{3:3}:
      	 check_prev_add kernel/locking/lockdep.c:2496 [inline]
      	 check_prevs_add kernel/locking/lockdep.c:2601 [inline]
      	 validate_chain kernel/locking/lockdep.c:3218 [inline]
      	 __lock_acquire+0x2a96/0x5780 kernel/locking/lockdep.c:4426
      	 lock_acquire+0x1f3/0xae0 kernel/locking/lockdep.c:5006
      	 __mutex_lock_common kernel/locking/mutex.c:956 [inline]
      	 __mutex_lock+0x134/0x10e0 kernel/locking/mutex.c:1103
      	 blkdev_put+0x30/0x520 fs/block_dev.c:1804
      	 btrfs_close_bdev fs/btrfs/volumes.c:1117 [inline]
      	 btrfs_close_bdev fs/btrfs/volumes.c:1107 [inline]
      	 btrfs_close_one_device fs/btrfs/volumes.c:1133 [inline]
      	 close_fs_devices.part.0+0x1a4/0x800 fs/btrfs/volumes.c:1161
      	 close_fs_devices fs/btrfs/volumes.c:1193 [inline]
      	 btrfs_close_devices+0x95/0x1f0 fs/btrfs/volumes.c:1179
      	 close_ctree+0x688/0x6cb fs/btrfs/disk-io.c:4149
      	 generic_shutdown_super+0x144/0x370 fs/super.c:464
      	 kill_anon_super+0x36/0x60 fs/super.c:1108
      	 btrfs_kill_super+0x38/0x50 fs/btrfs/super.c:2265
      	 deactivate_locked_super+0x94/0x160 fs/super.c:335
      	 deactivate_super+0xad/0xd0 fs/super.c:366
      	 cleanup_mnt+0x3a3/0x530 fs/namespace.c:1118
      	 task_work_run+0xdd/0x190 kernel/task_work.c:141
      	 tracehook_notify_resume include/linux/tracehook.h:188 [inline]
      	 exit_to_user_mode_loop kernel/entry/common.c:163 [inline]
      	 exit_to_user_mode_prepare+0x1e1/0x200 kernel/entry/common.c:190
      	 syscall_exit_to_user_mode+0x7e/0x2e0 kernel/entry/common.c:265
      	 entry_SYSCALL_64_after_hwframe+0x44/0xa9
      
        other info that might help us debug this:
      
        Chain exists of:
          &bdev->bd_mutex --> sb_internal#2 --> &fs_devs->device_list_mutex
      
         Possible unsafe locking scenario:
      
      	 CPU0                    CPU1
      	 ----                    ----
          lock(&fs_devs->device_list_mutex);
      				 lock(sb_internal#2);
      				 lock(&fs_devs->device_list_mutex);
          lock(&bdev->bd_mutex);
      
         *** DEADLOCK ***
      
        3 locks held by syz-executor.0/6878:
         #0: ffff88809070c0e0 (&type->s_umount_key#70){++++}-{3:3}, at: deactivate_super+0xa5/0xd0 fs/super.c:365
         #1: ffffffff8a5b37a8 (uuid_mutex){+.+.}-{3:3}, at: btrfs_close_devices+0x23/0x1f0 fs/btrfs/volumes.c:1178
         #2: ffff8880908cfce0 (&fs_devs->device_list_mutex){+.+.}-{3:3}, at: close_fs_devices.part.0+0x2e/0x800 fs/btrfs/volumes.c:1159
      
        stack backtrace:
        CPU: 0 PID: 6878 Comm: syz-executor.0 Not tainted 5.9.0-rc5-syzkaller #0
        Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011
        Call Trace:
         __dump_stack lib/dump_stack.c:77 [inline]
         dump_stack+0x198/0x1fd lib/dump_stack.c:118
         check_noncircular+0x324/0x3e0 kernel/locking/lockdep.c:1827
         check_prev_add kernel/locking/lockdep.c:2496 [inline]
         check_prevs_add kernel/locking/lockdep.c:2601 [inline]
         validate_chain kernel/locking/lockdep.c:3218 [inline]
         __lock_acquire+0x2a96/0x5780 kernel/locking/lockdep.c:4426
         lock_acquire+0x1f3/0xae0 kernel/locking/lockdep.c:5006
         __mutex_lock_common kernel/locking/mutex.c:956 [inline]
         __mutex_lock+0x134/0x10e0 kernel/locking/mutex.c:1103
         blkdev_put+0x30/0x520 fs/block_dev.c:1804
         btrfs_close_bdev fs/btrfs/volumes.c:1117 [inline]
         btrfs_close_bdev fs/btrfs/volumes.c:1107 [inline]
         btrfs_close_one_device fs/btrfs/volumes.c:1133 [inline]
         close_fs_devices.part.0+0x1a4/0x800 fs/btrfs/volumes.c:1161
         close_fs_devices fs/btrfs/volumes.c:1193 [inline]
         btrfs_close_devices+0x95/0x1f0 fs/btrfs/volumes.c:1179
         close_ctree+0x688/0x6cb fs/btrfs/disk-io.c:4149
         generic_shutdown_super+0x144/0x370 fs/super.c:464
         kill_anon_super+0x36/0x60 fs/super.c:1108
         btrfs_kill_super+0x38/0x50 fs/btrfs/super.c:2265
         deactivate_locked_super+0x94/0x160 fs/super.c:335
         deactivate_super+0xad/0xd0 fs/super.c:366
         cleanup_mnt+0x3a3/0x530 fs/namespace.c:1118
         task_work_run+0xdd/0x190 kernel/task_work.c:141
         tracehook_notify_resume include/linux/tracehook.h:188 [inline]
         exit_to_user_mode_loop kernel/entry/common.c:163 [inline]
         exit_to_user_mode_prepare+0x1e1/0x200 kernel/entry/common.c:190
         syscall_exit_to_user_mode+0x7e/0x2e0 kernel/entry/common.c:265
         entry_SYSCALL_64_after_hwframe+0x44/0xa9
        RIP: 0033:0x460027
        RSP: 002b:00007fff59216328 EFLAGS: 00000246 ORIG_RAX: 00000000000000a6
        RAX: 0000000000000000 RBX: 0000000000076035 RCX: 0000000000460027
        RDX: 0000000000403188 RSI: 0000000000000002 RDI: 00007fff592163d0
        RBP: 0000000000000333 R08: 0000000000000000 R09: 000000000000000b
        R10: 0000000000000005 R11: 0000000000000246 R12: 00007fff59217460
        R13: 0000000002df2a60 R14: 0000000000000000 R15: 00007fff59217460
      Signed-off-by: NJosef Bacik <josef@toxicpanda.com>
      [ add syzbot reference ]
      Signed-off-by: NDavid Sterba <dsterba@suse.com>
      a466c85e
  5. 25 9月, 2020 1 次提交
  6. 24 3月, 2020 2 次提交
  7. 25 1月, 2020 1 次提交
    • D
      btrfs: dev-replace: remove warning for unknown return codes when finished · 4cea9037
      David Sterba 提交于
      The fstests btrfs/011 triggered a warning at the end of device replace,
      
        [ 1891.998975] BTRFS warning (device vdd): failed setting block group ro: -28
        [ 1892.038338] BTRFS error (device vdd): btrfs_scrub_dev(/dev/vdd, 1, /dev/vdb) failed -28
        [ 1892.059993] ------------[ cut here ]------------
        [ 1892.063032] WARNING: CPU: 2 PID: 2244 at fs/btrfs/dev-replace.c:506 btrfs_dev_replace_start.cold+0xf9/0x140 [btrfs]
        [ 1892.074346] CPU: 2 PID: 2244 Comm: btrfs Not tainted 5.5.0-rc7-default+ #942
        [ 1892.079956] RIP: 0010:btrfs_dev_replace_start.cold+0xf9/0x140 [btrfs]
      
        [ 1892.096576] RSP: 0018:ffffbb58c7b3fd10 EFLAGS: 00010286
        [ 1892.098311] RAX: 00000000ffffffe4 RBX: 0000000000000001 RCX: 8888888888888889
        [ 1892.100342] RDX: 0000000000000001 RSI: ffff9e889645f5d8 RDI: ffffffff92821080
        [ 1892.102291] RBP: ffff9e889645c000 R08: 000001b8878fe1f6 R09: 0000000000000000
        [ 1892.104239] R10: ffffbb58c7b3fd08 R11: 0000000000000000 R12: ffff9e88a0017000
        [ 1892.106434] R13: ffff9e889645f608 R14: ffff9e88794e1000 R15: ffff9e88a07b5200
        [ 1892.108642] FS:  00007fcaed3f18c0(0000) GS:ffff9e88bda00000(0000) knlGS:0000000000000000
        [ 1892.111558] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
        [ 1892.113492] CR2: 00007f52509ff420 CR3: 00000000603dd002 CR4: 0000000000160ee0
      
        [ 1892.115814] Call Trace:
        [ 1892.116896]  btrfs_dev_replace_by_ioctl+0x35/0x60 [btrfs]
        [ 1892.118962]  btrfs_ioctl+0x1d62/0x2550 [btrfs]
      
      caused by the previous patch ("btrfs: scrub: Require mandatory block
      group RO for dev-replace"). Hitting ENOSPC is possible and could happen
      when the block group is set read-only, preventing NOCOW writes to the
      area that's being accessed by dev-replace.
      
      This has happend with scratch devices of size 12G but not with 5G and
      20G, so this is depends on timing and other activity on the filesystem.
      The whole replace operation is restartable, the space state should be
      examined by the user in any case.
      
      The error code is propagated back to the ioctl caller so the kernel
      warning is causing false alerts.
      Signed-off-by: NDavid Sterba <dsterba@suse.com>
      4cea9037
  8. 24 1月, 2020 1 次提交
    • A
      btrfs: sysfs, add devid/dev_state kobject and device attributes · 668e48af
      Anand Jain 提交于
      New sysfs attributes that track the filesystem status of devices, stored
      in the per-filesystem directory in /sys/fs/btrfs/FSID/devinfo . There's
      a directory for each device, with name corresponding to the numerical
      device id.
      
        in_fs_metadata    - device is in the list of fs metadata
        missing           - device is missing (no device node or block device)
        replace_target    - device is target of replace
        writeable         - writes from fs are allowed
      
      These attributes reflect the state of the device::dev_state and created
      at mount time.
      
      Sample output:
        $ pwd
         /sys/fs/btrfs/6e1961f1-5918-4ecc-a22f-948897b409f7/devinfo/1/
        $ ls
          in_fs_metadata  missing  replace_target  writeable
        $ cat missing
          0
      
      The output from these attributes are 0 or 1. 0 indicates unset and 1
      indicates set.  These attributes are readonly.
      
      It is observed that the device delete thread and sysfs read thread will
      not race because the delete thread calls sysfs kobject_put() which in
      turn waits for existing sysfs read to complete.
      
      Note for device replace devid swap:
      
      During the replace the target device temporarily assumes devid 0 before
      assigning the devid of the soruce device.
      
      In btrfs_dev_replace_finishing() we remove source sysfs devid using the
      function btrfs_sysfs_remove_devices_attr(), so after that call
      kobject_rename() to update the devid in the sysfs.  This adds and calls
      btrfs_sysfs_update_devid() helper function to update the device id.
      Signed-off-by: NAnand Jain <anand.jain@oracle.com>
      Reviewed-by: NDavid Sterba <dsterba@suse.com>
      [ update changelog ]
      Signed-off-by: NDavid Sterba <dsterba@suse.com>
      668e48af
  9. 18 11月, 2019 1 次提交
  10. 09 9月, 2019 2 次提交
    • D
      btrfs: move cond_wake_up functions out of ctree · 602cbe91
      David Sterba 提交于
      The file ctree.h serves as a header for everything and has become quite
      bloated. Split some helpers that are generic and create a new file that
      should be the catch-all for code that's not btrfs-specific.
      Reviewed-by: NJohannes Thumshirn <jthumshirn@suse.de>
      Signed-off-by: NDavid Sterba <dsterba@suse.com>
      602cbe91
    • A
      btrfs: replace: BTRFS_DEV_REPLACE_ITEM_STATE_x defines should go · 27e022a9
      Anand Jain 提交于
      The BTRFS_DEV_REPLACE_ITEM_STATE_x defines, as shown in [1], are
      unused in both kernel and btrfs-progs (except for one instance of
      BTRFS_DEV_REPLACE_ITEM_STATE_NEVER_STARTED in kernel).
      
      [1]
      btrfs.h:#define BTRFS_IOCTL_DEV_REPLACE_STATE_FINISHED        2
      btrfs.h:#define BTRFS_IOCTL_DEV_REPLACE_STATE_CANCELED        3
      btrfs.h:#define BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED       4
      
      Further these define-values are different form its counterpart
      BTRFS_IOCTL_DEV_REPLACE_STATE_x series as shown in [2].
      
      [2]
      btrfs_tree.h:#define BTRFS_DEV_REPLACE_ITEM_STATE_SUSPENDED   2
      btrfs_tree.h:#define BTRFS_DEV_REPLACE_ITEM_STATE_FINISHED    3
      btrfs_tree.h:#define BTRFS_DEV_REPLACE_ITEM_STATE_CANCELED    4
      
      So this patch deletes the BTRFS_DEV_REPLACE_ITEM_STATE_x altogether, and
      one instance of BTRFS_DEV_REPLACE_ITEM_STATE_NEVER_STARTED is replaced
      with BTRFS_IOCTL_DEV_REPLACE_STATE_NEVER_STARTED in the kernel.
      Signed-off-by: NAnand Jain <anand.jain@oracle.com>
      Reviewed-by: NDavid Sterba <dsterba@suse.com>
      Signed-off-by: NDavid Sterba <dsterba@suse.com>
      27e022a9
  11. 01 7月, 2019 8 次提交
  12. 29 5月, 2019 1 次提交
    • N
      btrfs: Ensure replaced device doesn't have pending chunk allocation · debd1c06
      Nikolay Borisov 提交于
      Recent FITRIM work, namely bbbf7243 ("btrfs: combine device update
      operations during transaction commit") combined the way certain
      operations are recoded in a transaction. As a result an ASSERT was added
      in dev_replace_finish to ensure the new code works correctly.
      Unfortunately I got reports that it's possible to trigger the assert,
      meaning that during a device replace it's possible to have an unfinished
      chunk allocation on the source device.
      
      This is supposed to be prevented by the fact that a transaction is
      committed before finishing the replace oepration and alter acquiring the
      chunk mutex. This is not sufficient since by the time the transaction is
      committed and the chunk mutex acquired it's possible to allocate a chunk
      depending on the workload being executed on the replaced device. This
      bug has been present ever since device replace was introduced but there
      was never code which checks for it.
      
      The correct way to fix is to ensure that there is no pending device
      modification operation when the chunk mutex is acquire and if there is
      repeat transaction commit. Unfortunately it's not possible to just
      exclude the source device from btrfs_fs_devices::dev_alloc_list since
      this causes ENOSPC to be hit in transaction commit.
      
      Fixing that in another way would need to add special cases to handle the
      last writes and forbid new ones. The looped transaction fix is more
      obvious, and can be easily backported. The runtime of dev-replace is
      long so there's no noticeable delay caused by that.
      Reported-by: NDavid Sterba <dsterba@suse.com>
      Fixes: 391cd9df ("Btrfs: fix unprotected alloc list insertion during the finishing procedure of replace")
      CC: stable@vger.kernel.org # 4.4+
      Signed-off-by: NNikolay Borisov <nborisov@suse.com>
      Reviewed-by: NDavid Sterba <dsterba@suse.com>
      Signed-off-by: NDavid Sterba <dsterba@suse.com>
      debd1c06
  13. 30 4月, 2019 3 次提交
  14. 25 2月, 2019 3 次提交
  15. 17 12月, 2018 6 次提交