2018-04-03 20:16:55 +03:00
|
|
|
/* SPDX-License-Identifier: GPL-2.0 */
|
2008-03-24 22:01:56 +03:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2007 Oracle. All rights reserved.
|
|
|
|
*/
|
|
|
|
|
2018-04-03 20:16:55 +03:00
|
|
|
#ifndef BTRFS_VOLUMES_H
|
|
|
|
#define BTRFS_VOLUMES_H
|
2008-04-04 00:29:03 +04:00
|
|
|
|
2008-04-10 00:28:12 +04:00
|
|
|
#include <linux/bio.h>
|
2011-01-05 13:07:28 +03:00
|
|
|
#include <linux/sort.h>
|
2013-01-29 10:04:50 +04:00
|
|
|
#include <linux/btrfs.h>
|
2008-06-12 00:50:36 +04:00
|
|
|
#include "async-thread.h"
|
2008-04-10 00:28:12 +04:00
|
|
|
|
2018-07-03 12:10:05 +03:00
|
|
|
#define BTRFS_MAX_DATA_CHUNK_SIZE (10ULL * SZ_1G)
|
|
|
|
|
2014-09-03 17:35:43 +04:00
|
|
|
extern struct mutex uuid_mutex;
|
|
|
|
|
2015-12-14 19:42:10 +03:00
|
|
|
#define BTRFS_STRIPE_LEN SZ_64K
|
2011-01-05 13:07:28 +03:00
|
|
|
|
2019-06-03 12:05:03 +03:00
|
|
|
struct btrfs_io_geometry {
|
|
|
|
/* remaining bytes before crossing a stripe */
|
|
|
|
u64 len;
|
|
|
|
/* offset of logical address in chunk */
|
|
|
|
u64 offset;
|
|
|
|
/* length of single IO stripe */
|
|
|
|
u64 stripe_len;
|
|
|
|
/* number of stripe where address falls */
|
|
|
|
u64 stripe_nr;
|
|
|
|
/* offset of address in stripe */
|
|
|
|
u64 stripe_offset;
|
|
|
|
/* offset of raid56 stripe into the chunk */
|
|
|
|
u64 raid56_stripe_offset;
|
|
|
|
};
|
|
|
|
|
2014-09-03 17:35:38 +04:00
|
|
|
/*
|
|
|
|
* Use sequence counter to get consistent device stat data on
|
|
|
|
* 32-bit processors.
|
|
|
|
*/
|
|
|
|
#if BITS_PER_LONG==32 && defined(CONFIG_SMP)
|
|
|
|
#include <linux/seqlock.h>
|
|
|
|
#define __BTRFS_NEED_DEVICE_DATA_ORDERED
|
2021-01-21 14:39:10 +03:00
|
|
|
#define btrfs_device_data_ordered_init(device) \
|
|
|
|
seqcount_init(&device->data_seqcount)
|
2014-09-03 17:35:38 +04:00
|
|
|
#else
|
2021-01-21 14:39:10 +03:00
|
|
|
#define btrfs_device_data_ordered_init(device) do { } while (0)
|
2014-09-03 17:35:38 +04:00
|
|
|
#endif
|
|
|
|
|
2017-12-04 07:54:52 +03:00
|
|
|
#define BTRFS_DEV_STATE_WRITEABLE (0)
|
2017-12-04 07:54:53 +03:00
|
|
|
#define BTRFS_DEV_STATE_IN_FS_METADATA (1)
|
2017-12-04 07:54:54 +03:00
|
|
|
#define BTRFS_DEV_STATE_MISSING (2)
|
2017-12-04 07:54:55 +03:00
|
|
|
#define BTRFS_DEV_STATE_REPLACE_TGT (3)
|
2017-12-04 07:54:56 +03:00
|
|
|
#define BTRFS_DEV_STATE_FLUSH_SENT (4)
|
btrfs: fix readahead hang and use-after-free after removing a device
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: Josef Bacik <josef@toxicpanda.com>
Signed-off-by: Filipe Manana <fdmanana@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2020-10-12 13:55:24 +03:00
|
|
|
#define BTRFS_DEV_STATE_NO_READA (5)
|
2017-12-04 07:54:52 +03:00
|
|
|
|
2020-11-10 14:26:07 +03:00
|
|
|
struct btrfs_zoned_device_info;
|
|
|
|
|
2008-03-24 22:01:56 +03:00
|
|
|
struct btrfs_device {
|
2019-05-09 18:11:11 +03:00
|
|
|
struct list_head dev_list; /* device_list_mutex */
|
|
|
|
struct list_head dev_alloc_list; /* chunk mutex */
|
2019-03-25 15:31:22 +03:00
|
|
|
struct list_head post_commit_list; /* chunk mutex */
|
2008-11-18 05:11:30 +03:00
|
|
|
struct btrfs_fs_devices *fs_devices;
|
2016-06-23 01:54:56 +03:00
|
|
|
struct btrfs_fs_info *fs_info;
|
2009-04-20 23:50:09 +04:00
|
|
|
|
2019-12-04 23:19:01 +03:00
|
|
|
struct rcu_string __rcu *name;
|
2014-07-24 07:37:10 +04:00
|
|
|
|
|
|
|
u64 generation;
|
|
|
|
|
|
|
|
struct block_device *bdev;
|
|
|
|
|
2020-11-10 14:26:07 +03:00
|
|
|
struct btrfs_zoned_device_info *zone_info;
|
|
|
|
|
2014-07-24 07:37:10 +04:00
|
|
|
/* the mode sent to blkdev_get */
|
|
|
|
fmode_t mode;
|
|
|
|
|
2017-12-04 07:54:52 +03:00
|
|
|
unsigned long dev_state;
|
2017-08-23 09:45:59 +03:00
|
|
|
blk_status_t last_flush_error;
|
2008-04-22 17:22:07 +04:00
|
|
|
|
2014-09-03 17:35:38 +04:00
|
|
|
#ifdef __BTRFS_NEED_DEVICE_DATA_ORDERED
|
2021-01-21 14:39:10 +03:00
|
|
|
seqcount_t data_seqcount;
|
2014-09-03 17:35:38 +04:00
|
|
|
#endif
|
|
|
|
|
2008-03-24 22:01:56 +03:00
|
|
|
/* the internal btrfs device id */
|
|
|
|
u64 devid;
|
|
|
|
|
2014-07-24 07:37:12 +04:00
|
|
|
/* size of the device in memory */
|
2008-03-24 22:01:56 +03:00
|
|
|
u64 total_bytes;
|
|
|
|
|
2014-07-24 07:37:12 +04:00
|
|
|
/* size of the device on disk */
|
2009-04-27 15:29:03 +04:00
|
|
|
u64 disk_total_bytes;
|
|
|
|
|
2008-03-24 22:01:56 +03:00
|
|
|
/* bytes used */
|
|
|
|
u64 bytes_used;
|
|
|
|
|
|
|
|
/* optimal io alignment for this device */
|
|
|
|
u32 io_align;
|
|
|
|
|
|
|
|
/* optimal io width for this device */
|
|
|
|
u32 io_width;
|
2013-10-31 08:27:33 +04:00
|
|
|
/* type and info about this device */
|
|
|
|
u64 type;
|
2008-03-24 22:01:56 +03:00
|
|
|
|
|
|
|
/* minimal io size for this device */
|
|
|
|
u32 sector_size;
|
|
|
|
|
|
|
|
/* physical drive uuid (or lvm uuid) */
|
2008-04-15 23:41:47 +04:00
|
|
|
u8 uuid[BTRFS_UUID_SIZE];
|
2008-06-12 00:50:36 +04:00
|
|
|
|
2014-09-03 17:35:33 +04:00
|
|
|
/*
|
|
|
|
* size of the device on the current transaction
|
|
|
|
*
|
|
|
|
* This variant is update when committing the transaction,
|
2019-03-25 15:31:22 +03:00
|
|
|
* and protected by chunk mutex
|
2014-09-03 17:35:33 +04:00
|
|
|
*/
|
|
|
|
u64 commit_total_bytes;
|
|
|
|
|
2014-09-03 17:35:34 +04:00
|
|
|
/* bytes used on the current transaction */
|
|
|
|
u64 commit_bytes_used;
|
2014-09-03 17:35:33 +04:00
|
|
|
|
2013-10-31 08:27:33 +04:00
|
|
|
/* for sending down flush barriers */
|
|
|
|
struct bio *flush_bio;
|
|
|
|
struct completion flush_wait;
|
|
|
|
|
2011-03-08 16:14:00 +03:00
|
|
|
/* per-device scrub information */
|
2018-01-03 11:08:30 +03:00
|
|
|
struct scrub_ctx *scrub_ctx;
|
2011-03-08 16:14:00 +03:00
|
|
|
|
2011-05-23 16:30:00 +04:00
|
|
|
/* readahead state */
|
|
|
|
atomic_t reada_in_flight;
|
|
|
|
u64 reada_next;
|
|
|
|
struct reada_zone *reada_curr_zone;
|
|
|
|
struct radix_tree_root reada_zones;
|
|
|
|
struct radix_tree_root reada_extents;
|
2011-11-19 00:07:51 +04:00
|
|
|
|
2012-05-25 18:06:08 +04:00
|
|
|
/* disk I/O failure stats. For detailed description refer to
|
|
|
|
* enum btrfs_dev_stat_values in ioctl.h */
|
2012-05-25 18:06:10 +04:00
|
|
|
int dev_stats_valid;
|
2014-07-24 07:37:11 +04:00
|
|
|
|
|
|
|
/* Counter to record the change of device stats */
|
|
|
|
atomic_t dev_stats_ccnt;
|
2012-05-25 18:06:08 +04:00
|
|
|
atomic_t dev_stat_values[BTRFS_DEV_STAT_VALUES_MAX];
|
2019-03-27 15:24:12 +03:00
|
|
|
|
|
|
|
struct extent_io_tree alloc_state;
|
2020-01-06 14:38:31 +03:00
|
|
|
|
|
|
|
struct completion kobj_unregister;
|
|
|
|
/* For sysfs/FSID/devinfo/devid/ */
|
|
|
|
struct kobject devid_kobj;
|
2008-03-24 22:01:56 +03:00
|
|
|
};
|
|
|
|
|
2014-09-03 17:35:38 +04:00
|
|
|
/*
|
|
|
|
* If we read those variants at the context of their own lock, we needn't
|
|
|
|
* use the following helpers, reading them directly is safe.
|
|
|
|
*/
|
|
|
|
#if BITS_PER_LONG==32 && defined(CONFIG_SMP)
|
|
|
|
#define BTRFS_DEVICE_GETSET_FUNCS(name) \
|
|
|
|
static inline u64 \
|
|
|
|
btrfs_device_get_##name(const struct btrfs_device *dev) \
|
|
|
|
{ \
|
|
|
|
u64 size; \
|
|
|
|
unsigned int seq; \
|
|
|
|
\
|
|
|
|
do { \
|
|
|
|
seq = read_seqcount_begin(&dev->data_seqcount); \
|
|
|
|
size = dev->name; \
|
|
|
|
} while (read_seqcount_retry(&dev->data_seqcount, seq)); \
|
|
|
|
return size; \
|
|
|
|
} \
|
|
|
|
\
|
|
|
|
static inline void \
|
|
|
|
btrfs_device_set_##name(struct btrfs_device *dev, u64 size) \
|
|
|
|
{ \
|
2021-01-21 14:39:10 +03:00
|
|
|
preempt_disable(); \
|
2014-09-03 17:35:38 +04:00
|
|
|
write_seqcount_begin(&dev->data_seqcount); \
|
|
|
|
dev->name = size; \
|
|
|
|
write_seqcount_end(&dev->data_seqcount); \
|
2021-01-21 14:39:10 +03:00
|
|
|
preempt_enable(); \
|
2014-09-03 17:35:38 +04:00
|
|
|
}
|
2019-10-15 22:18:11 +03:00
|
|
|
#elif BITS_PER_LONG==32 && defined(CONFIG_PREEMPTION)
|
2014-09-03 17:35:38 +04:00
|
|
|
#define BTRFS_DEVICE_GETSET_FUNCS(name) \
|
|
|
|
static inline u64 \
|
|
|
|
btrfs_device_get_##name(const struct btrfs_device *dev) \
|
|
|
|
{ \
|
|
|
|
u64 size; \
|
|
|
|
\
|
|
|
|
preempt_disable(); \
|
|
|
|
size = dev->name; \
|
|
|
|
preempt_enable(); \
|
|
|
|
return size; \
|
|
|
|
} \
|
|
|
|
\
|
|
|
|
static inline void \
|
|
|
|
btrfs_device_set_##name(struct btrfs_device *dev, u64 size) \
|
|
|
|
{ \
|
|
|
|
preempt_disable(); \
|
|
|
|
dev->name = size; \
|
|
|
|
preempt_enable(); \
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
#define BTRFS_DEVICE_GETSET_FUNCS(name) \
|
|
|
|
static inline u64 \
|
|
|
|
btrfs_device_get_##name(const struct btrfs_device *dev) \
|
|
|
|
{ \
|
|
|
|
return dev->name; \
|
|
|
|
} \
|
|
|
|
\
|
|
|
|
static inline void \
|
|
|
|
btrfs_device_set_##name(struct btrfs_device *dev, u64 size) \
|
|
|
|
{ \
|
|
|
|
dev->name = size; \
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
BTRFS_DEVICE_GETSET_FUNCS(total_bytes);
|
|
|
|
BTRFS_DEVICE_GETSET_FUNCS(disk_total_bytes);
|
|
|
|
BTRFS_DEVICE_GETSET_FUNCS(bytes_used);
|
|
|
|
|
2020-02-25 06:56:08 +03:00
|
|
|
enum btrfs_chunk_allocation_policy {
|
|
|
|
BTRFS_CHUNK_ALLOC_REGULAR,
|
2021-02-04 13:21:48 +03:00
|
|
|
BTRFS_CHUNK_ALLOC_ZONED,
|
2020-02-25 06:56:08 +03:00
|
|
|
};
|
|
|
|
|
2020-10-28 16:14:46 +03:00
|
|
|
/*
|
|
|
|
* Read policies for mirrored block group profiles, read picks the stripe based
|
|
|
|
* on these policies.
|
|
|
|
*/
|
|
|
|
enum btrfs_read_policy {
|
|
|
|
/* Use process PID to choose the stripe */
|
|
|
|
BTRFS_READ_POLICY_PID,
|
|
|
|
BTRFS_NR_READ_POLICY,
|
|
|
|
};
|
|
|
|
|
2008-03-24 22:02:07 +03:00
|
|
|
struct btrfs_fs_devices {
|
|
|
|
u8 fsid[BTRFS_FSID_SIZE]; /* FS specific uuid */
|
2018-10-30 17:43:23 +03:00
|
|
|
u8 metadata_uuid[BTRFS_FSID_SIZE];
|
2018-10-30 17:43:26 +03:00
|
|
|
bool fsid_change;
|
2018-04-12 05:29:25 +03:00
|
|
|
struct list_head fs_list;
|
2008-03-24 22:02:07 +03:00
|
|
|
|
|
|
|
u64 num_devices;
|
2008-05-14 00:03:06 +04:00
|
|
|
u64 open_devices;
|
2008-11-18 05:11:30 +03:00
|
|
|
u64 rw_devices;
|
2010-12-13 22:56:23 +03:00
|
|
|
u64 missing_devices;
|
2008-11-18 05:11:30 +03:00
|
|
|
u64 total_rw_bytes;
|
2012-06-22 00:03:58 +04:00
|
|
|
u64 total_devices;
|
2018-10-30 17:43:26 +03:00
|
|
|
|
|
|
|
/* Highest generation number of seen devices */
|
|
|
|
u64 latest_generation;
|
|
|
|
|
2008-03-24 22:02:07 +03:00
|
|
|
struct block_device *latest_bdev;
|
2009-06-10 23:17:02 +04:00
|
|
|
|
|
|
|
/* all of the devices in the FS, protected by a mutex
|
|
|
|
* so we can safely walk it to write out the supers without
|
2013-10-25 15:12:02 +04:00
|
|
|
* worrying about add/remove by the multi-device code.
|
|
|
|
* Scrubbing super can kick off supers writing by holding
|
|
|
|
* this mutex lock.
|
2009-06-10 23:17:02 +04:00
|
|
|
*/
|
|
|
|
struct mutex device_list_mutex;
|
2019-05-09 18:11:11 +03:00
|
|
|
|
|
|
|
/* List of all devices, protected by device_list_mutex */
|
2008-03-24 22:02:07 +03:00
|
|
|
struct list_head devices;
|
2008-04-22 17:22:07 +04:00
|
|
|
|
2019-05-09 18:11:11 +03:00
|
|
|
/*
|
|
|
|
* Devices which can satisfy space allocation. Protected by
|
|
|
|
* chunk_mutex
|
|
|
|
*/
|
2008-04-22 17:22:07 +04:00
|
|
|
struct list_head alloc_list;
|
2008-11-18 05:11:30 +03:00
|
|
|
|
2020-07-16 10:25:33 +03:00
|
|
|
struct list_head seed_list;
|
2019-11-13 13:27:27 +03:00
|
|
|
bool seeding;
|
2008-11-18 05:11:30 +03:00
|
|
|
|
|
|
|
int opened;
|
2009-06-10 17:51:32 +04:00
|
|
|
|
|
|
|
/* set when we find or add a device that doesn't have the
|
|
|
|
* nonrot flag set
|
|
|
|
*/
|
2019-11-13 13:27:28 +03:00
|
|
|
bool rotating;
|
2015-03-10 01:38:29 +03:00
|
|
|
|
2015-03-10 01:38:31 +03:00
|
|
|
struct btrfs_fs_info *fs_info;
|
2015-03-10 01:38:29 +03:00
|
|
|
/* sysfs kobjects */
|
2015-08-14 13:32:50 +03:00
|
|
|
struct kobject fsid_kobj;
|
2019-11-21 12:33:30 +03:00
|
|
|
struct kobject *devices_kobj;
|
2020-02-12 12:28:10 +03:00
|
|
|
struct kobject *devinfo_kobj;
|
2015-03-10 01:38:29 +03:00
|
|
|
struct completion kobj_unregister;
|
2020-02-25 06:56:08 +03:00
|
|
|
|
|
|
|
enum btrfs_chunk_allocation_policy chunk_alloc_policy;
|
2020-10-28 16:14:46 +03:00
|
|
|
|
|
|
|
/* Policy used to read the mirrored stripes */
|
|
|
|
enum btrfs_read_policy read_policy;
|
2008-03-24 22:02:07 +03:00
|
|
|
};
|
|
|
|
|
2013-07-25 15:22:34 +04:00
|
|
|
#define BTRFS_BIO_INLINE_CSUM_SIZE 64
|
|
|
|
|
2019-03-08 09:20:03 +03:00
|
|
|
#define BTRFS_MAX_DEVS(info) ((BTRFS_MAX_ITEM_SIZE(info) \
|
|
|
|
- sizeof(struct btrfs_chunk)) \
|
|
|
|
/ sizeof(struct btrfs_stripe) + 1)
|
|
|
|
|
|
|
|
#define BTRFS_MAX_DEVS_SYS_CHUNK ((BTRFS_SYSTEM_CHUNK_ARRAY_SIZE \
|
|
|
|
- 2 * sizeof(struct btrfs_disk_key) \
|
|
|
|
- 2 * sizeof(struct btrfs_chunk)) \
|
|
|
|
/ sizeof(struct btrfs_stripe) + 1)
|
|
|
|
|
2013-05-18 02:30:14 +04:00
|
|
|
/*
|
|
|
|
* we need the mirror number and stripe index to be passed around
|
|
|
|
* the call chain while we are processing end_io (especially errors).
|
|
|
|
* Really, what we need is a btrfs_bio structure that has this info
|
|
|
|
* and is properly sized with its stripe array, but we're not there
|
|
|
|
* quite yet. We have our own btrfs bioset, and all of the bios
|
|
|
|
* we allocate are actually btrfs_io_bios. We'll cram as much of
|
|
|
|
* struct btrfs_bio as we can into this over time.
|
|
|
|
*/
|
|
|
|
struct btrfs_io_bio {
|
2014-09-12 14:43:56 +04:00
|
|
|
unsigned int mirror_num;
|
2020-07-03 11:14:27 +03:00
|
|
|
struct btrfs_device *device;
|
2014-09-12 14:43:56 +04:00
|
|
|
u64 logical;
|
2013-07-25 15:22:34 +04:00
|
|
|
u8 *csum;
|
|
|
|
u8 csum_inline[BTRFS_BIO_INLINE_CSUM_SIZE];
|
2017-05-16 01:33:27 +03:00
|
|
|
struct bvec_iter iter;
|
2017-06-12 18:29:36 +03:00
|
|
|
/*
|
|
|
|
* This member must come last, bio_alloc_bioset will allocate enough
|
|
|
|
* bytes for entire btrfs_io_bio but relies on bio being last.
|
|
|
|
*/
|
2013-05-18 02:30:14 +04:00
|
|
|
struct bio bio;
|
|
|
|
};
|
|
|
|
|
|
|
|
static inline struct btrfs_io_bio *btrfs_io_bio(struct bio *bio)
|
|
|
|
{
|
|
|
|
return container_of(bio, struct btrfs_io_bio, bio);
|
|
|
|
}
|
|
|
|
|
2018-11-22 19:16:49 +03:00
|
|
|
static inline void btrfs_io_bio_free_csum(struct btrfs_io_bio *io_bio)
|
|
|
|
{
|
|
|
|
if (io_bio->csum != io_bio->csum_inline) {
|
|
|
|
kfree(io_bio->csum);
|
|
|
|
io_bio->csum = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-04-10 00:28:12 +04:00
|
|
|
struct btrfs_bio_stripe {
|
|
|
|
struct btrfs_device *dev;
|
|
|
|
u64 physical;
|
2011-03-24 13:24:26 +03:00
|
|
|
u64 length; /* only used for discard mappings */
|
2008-04-10 00:28:12 +04:00
|
|
|
};
|
|
|
|
|
2011-08-04 19:15:33 +04:00
|
|
|
struct btrfs_bio {
|
2017-03-03 11:55:10 +03:00
|
|
|
refcount_t refs;
|
2008-04-10 00:28:12 +04:00
|
|
|
atomic_t stripes_pending;
|
Btrfs: fix use-after-free in the finishing procedure of the device replace
During device replace test, we hit a null pointer deference (It was very easy
to reproduce it by running xfstests' btrfs/011 on the devices with the virtio
scsi driver). There were two bugs that caused this problem:
- We might allocate new chunks on the replaced device after we updated
the mapping tree. And we forgot to replace the source device in those
mapping of the new chunks.
- We might get the mapping information which including the source device
before the mapping information update. And then submit the bio which was
based on that mapping information after we freed the source device.
For the first bug, we can fix it by doing mapping tree update and source
device remove in the same context of the chunk mutex. The chunk mutex is
used to protect the allocable device list, the above method can avoid
the new chunk allocation, and after we remove the source device, all
the new chunks will be allocated on the new device. So it can fix
the first bug.
For the second bug, we need make sure all flighting bios are finished and
no new bios are produced during we are removing the source device. To fix
this problem, we introduced a global @bio_counter, we not only inc/dec
@bio_counter outsize of map_blocks, but also inc it before submitting bio
and dec @bio_counter when ending bios.
Since Raid56 is a little different and device replace dosen't support raid56
yet, it is not addressed in the patch and I add comments to make sure we will
fix it in the future.
Reported-by: Qu Wenruo <quwenruo@cn.fujitsu.com>
Signed-off-by: Wang Shilong <wangsl.fnst@cn.fujitsu.com>
Signed-off-by: Miao Xie <miaox@cn.fujitsu.com>
Signed-off-by: Josef Bacik <jbacik@fb.com>
2014-01-30 12:46:55 +04:00
|
|
|
struct btrfs_fs_info *fs_info;
|
2015-01-20 10:11:43 +03:00
|
|
|
u64 map_type; /* get from map_lookup->type */
|
2008-04-10 00:28:12 +04:00
|
|
|
bio_end_io_t *end_io;
|
2008-08-05 18:13:57 +04:00
|
|
|
struct bio *orig_bio;
|
2008-04-10 00:28:12 +04:00
|
|
|
void *private;
|
2008-04-29 17:38:00 +04:00
|
|
|
atomic_t error;
|
|
|
|
int max_errors;
|
2008-04-10 00:28:12 +04:00
|
|
|
int num_stripes;
|
2011-08-04 19:15:33 +04:00
|
|
|
int mirror_num;
|
2014-11-14 11:06:25 +03:00
|
|
|
int num_tgtdevs;
|
|
|
|
int *tgtdev_map;
|
2015-01-20 10:11:33 +03:00
|
|
|
/*
|
|
|
|
* logical block numbers for the start of each stripe
|
|
|
|
* The last one or two are p/q. These are sorted,
|
|
|
|
* so raid_map[0] is the start of our full stripe
|
|
|
|
*/
|
|
|
|
u64 *raid_map;
|
2008-04-10 00:28:12 +04:00
|
|
|
struct btrfs_bio_stripe stripes[];
|
|
|
|
};
|
|
|
|
|
2011-01-05 13:07:28 +03:00
|
|
|
struct btrfs_device_info {
|
|
|
|
struct btrfs_device *dev;
|
|
|
|
u64 dev_offset;
|
|
|
|
u64 max_avail;
|
btrfs: quasi-round-robin for chunk allocation
In a multi device setup, the chunk allocator currently always allocates
chunks on the devices in the same order. This leads to a very uneven
distribution, especially with RAID1 or RAID10 and an uneven number of
devices.
This patch always sorts the devices before allocating, and allocates the
stripes on the devices with the most available space, as long as there
is enough space available. In a low space situation, it first tries to
maximize striping.
The patch also simplifies the allocator and reduces the checks for
corner cases.
The simplification is done by several means. First, it defines the
properties of each RAID type upfront. These properties are used afterwards
instead of differentiating cases in several places.
Second, the old allocator defined a minimum stripe size for each block
group type, tried to find a large enough chunk, and if this fails just
allocates a smaller one. This is now done in one step. The largest possible
chunk (up to max_chunk_size) is searched and allocated.
Because we now have only one pass, the allocation of the map (struct
map_lookup) is moved down to the point where the number of stripes is
already known. This way we avoid reallocation of the map.
We still avoid allocating stripes that are not a multiple of STRIPE_SIZE.
2011-04-12 14:07:57 +04:00
|
|
|
u64 total_avail;
|
2011-01-05 13:07:28 +03:00
|
|
|
};
|
|
|
|
|
2012-11-21 18:18:10 +04:00
|
|
|
struct btrfs_raid_attr {
|
2019-05-17 12:43:36 +03:00
|
|
|
u8 sub_stripes; /* sub_stripes info for map */
|
|
|
|
u8 dev_stripes; /* stripes per dev */
|
|
|
|
u8 devs_max; /* max devs to use */
|
|
|
|
u8 devs_min; /* min devs needed */
|
|
|
|
u8 tolerated_failures; /* max tolerated fail devs */
|
|
|
|
u8 devs_increment; /* ndevs has to be a multiple of this */
|
|
|
|
u8 ncopies; /* how many copies to data has */
|
|
|
|
u8 nparity; /* number of stripes worth of bytes to store
|
2018-10-05 00:24:42 +03:00
|
|
|
* parity information */
|
2019-05-17 12:43:36 +03:00
|
|
|
u8 mindev_error; /* error code if min devs requisite is unmet */
|
2018-04-25 14:01:42 +03:00
|
|
|
const char raid_name[8]; /* name of the raid */
|
2018-04-25 14:01:43 +03:00
|
|
|
u64 bg_flag; /* block group flag of the raid */
|
2012-11-21 18:18:10 +04:00
|
|
|
};
|
|
|
|
|
2015-09-15 16:08:06 +03:00
|
|
|
extern const struct btrfs_raid_attr btrfs_raid_array[BTRFS_NR_RAID_TYPES];
|
|
|
|
|
Btrfs: add initial tracepoint support for btrfs
Tracepoints can provide insight into why btrfs hits bugs and be greatly
helpful for debugging, e.g
dd-7822 [000] 2121.641088: btrfs_inode_request: root = 5(FS_TREE), gen = 4, ino = 256, blocks = 8, disk_i_size = 0, last_trans = 8, logged_trans = 0
dd-7822 [000] 2121.641100: btrfs_inode_new: root = 5(FS_TREE), gen = 8, ino = 257, blocks = 0, disk_i_size = 0, last_trans = 0, logged_trans = 0
btrfs-transacti-7804 [001] 2146.935420: btrfs_cow_block: root = 2(EXTENT_TREE), refs = 2, orig_buf = 29368320 (orig_level = 0), cow_buf = 29388800 (cow_level = 0)
btrfs-transacti-7804 [001] 2146.935473: btrfs_cow_block: root = 1(ROOT_TREE), refs = 2, orig_buf = 29364224 (orig_level = 0), cow_buf = 29392896 (cow_level = 0)
btrfs-transacti-7804 [001] 2146.972221: btrfs_transaction_commit: root = 1(ROOT_TREE), gen = 8
flush-btrfs-2-7821 [001] 2155.824210: btrfs_chunk_alloc: root = 3(CHUNK_TREE), offset = 1103101952, size = 1073741824, num_stripes = 1, sub_stripes = 0, type = DATA
flush-btrfs-2-7821 [001] 2155.824241: btrfs_cow_block: root = 2(EXTENT_TREE), refs = 2, orig_buf = 29388800 (orig_level = 0), cow_buf = 29396992 (cow_level = 0)
flush-btrfs-2-7821 [001] 2155.824255: btrfs_cow_block: root = 4(DEV_TREE), refs = 2, orig_buf = 29372416 (orig_level = 0), cow_buf = 29401088 (cow_level = 0)
flush-btrfs-2-7821 [000] 2155.824329: btrfs_cow_block: root = 3(CHUNK_TREE), refs = 2, orig_buf = 20971520 (orig_level = 0), cow_buf = 20975616 (cow_level = 0)
btrfs-endio-wri-7800 [001] 2155.898019: btrfs_cow_block: root = 5(FS_TREE), refs = 2, orig_buf = 29384704 (orig_level = 0), cow_buf = 29405184 (cow_level = 0)
btrfs-endio-wri-7800 [001] 2155.898043: btrfs_cow_block: root = 7(CSUM_TREE), refs = 2, orig_buf = 29376512 (orig_level = 0), cow_buf = 29409280 (cow_level = 0)
Here is what I have added:
1) ordere_extent:
btrfs_ordered_extent_add
btrfs_ordered_extent_remove
btrfs_ordered_extent_start
btrfs_ordered_extent_put
These provide critical information to understand how ordered_extents are
updated.
2) extent_map:
btrfs_get_extent
extent_map is used in both read and write cases, and it is useful for tracking
how btrfs specific IO is running.
3) writepage:
__extent_writepage
btrfs_writepage_end_io_hook
Pages are cirtical resourses and produce a lot of corner cases during writeback,
so it is valuable to know how page is written to disk.
4) inode:
btrfs_inode_new
btrfs_inode_request
btrfs_inode_evict
These can show where and when a inode is created, when a inode is evicted.
5) sync:
btrfs_sync_file
btrfs_sync_fs
These show sync arguments.
6) transaction:
btrfs_transaction_commit
In transaction based filesystem, it will be useful to know the generation and
who does commit.
7) back reference and cow:
btrfs_delayed_tree_ref
btrfs_delayed_data_ref
btrfs_delayed_ref_head
btrfs_cow_block
Btrfs natively supports back references, these tracepoints are helpful on
understanding btrfs's COW mechanism.
8) chunk:
btrfs_chunk_alloc
btrfs_chunk_free
Chunk is a link between physical offset and logical offset, and stands for space
infomation in btrfs, and these are helpful on tracing space things.
9) reserved_extent:
btrfs_reserved_extent_alloc
btrfs_reserved_extent_free
These can show how btrfs uses its space.
Signed-off-by: Liu Bo <liubo2009@cn.fujitsu.com>
Signed-off-by: Chris Mason <chris.mason@oracle.com>
2011-03-24 14:18:59 +03:00
|
|
|
struct map_lookup {
|
|
|
|
u64 type;
|
|
|
|
int io_align;
|
|
|
|
int io_width;
|
2016-04-27 03:53:31 +03:00
|
|
|
u64 stripe_len;
|
Btrfs: add initial tracepoint support for btrfs
Tracepoints can provide insight into why btrfs hits bugs and be greatly
helpful for debugging, e.g
dd-7822 [000] 2121.641088: btrfs_inode_request: root = 5(FS_TREE), gen = 4, ino = 256, blocks = 8, disk_i_size = 0, last_trans = 8, logged_trans = 0
dd-7822 [000] 2121.641100: btrfs_inode_new: root = 5(FS_TREE), gen = 8, ino = 257, blocks = 0, disk_i_size = 0, last_trans = 0, logged_trans = 0
btrfs-transacti-7804 [001] 2146.935420: btrfs_cow_block: root = 2(EXTENT_TREE), refs = 2, orig_buf = 29368320 (orig_level = 0), cow_buf = 29388800 (cow_level = 0)
btrfs-transacti-7804 [001] 2146.935473: btrfs_cow_block: root = 1(ROOT_TREE), refs = 2, orig_buf = 29364224 (orig_level = 0), cow_buf = 29392896 (cow_level = 0)
btrfs-transacti-7804 [001] 2146.972221: btrfs_transaction_commit: root = 1(ROOT_TREE), gen = 8
flush-btrfs-2-7821 [001] 2155.824210: btrfs_chunk_alloc: root = 3(CHUNK_TREE), offset = 1103101952, size = 1073741824, num_stripes = 1, sub_stripes = 0, type = DATA
flush-btrfs-2-7821 [001] 2155.824241: btrfs_cow_block: root = 2(EXTENT_TREE), refs = 2, orig_buf = 29388800 (orig_level = 0), cow_buf = 29396992 (cow_level = 0)
flush-btrfs-2-7821 [001] 2155.824255: btrfs_cow_block: root = 4(DEV_TREE), refs = 2, orig_buf = 29372416 (orig_level = 0), cow_buf = 29401088 (cow_level = 0)
flush-btrfs-2-7821 [000] 2155.824329: btrfs_cow_block: root = 3(CHUNK_TREE), refs = 2, orig_buf = 20971520 (orig_level = 0), cow_buf = 20975616 (cow_level = 0)
btrfs-endio-wri-7800 [001] 2155.898019: btrfs_cow_block: root = 5(FS_TREE), refs = 2, orig_buf = 29384704 (orig_level = 0), cow_buf = 29405184 (cow_level = 0)
btrfs-endio-wri-7800 [001] 2155.898043: btrfs_cow_block: root = 7(CSUM_TREE), refs = 2, orig_buf = 29376512 (orig_level = 0), cow_buf = 29409280 (cow_level = 0)
Here is what I have added:
1) ordere_extent:
btrfs_ordered_extent_add
btrfs_ordered_extent_remove
btrfs_ordered_extent_start
btrfs_ordered_extent_put
These provide critical information to understand how ordered_extents are
updated.
2) extent_map:
btrfs_get_extent
extent_map is used in both read and write cases, and it is useful for tracking
how btrfs specific IO is running.
3) writepage:
__extent_writepage
btrfs_writepage_end_io_hook
Pages are cirtical resourses and produce a lot of corner cases during writeback,
so it is valuable to know how page is written to disk.
4) inode:
btrfs_inode_new
btrfs_inode_request
btrfs_inode_evict
These can show where and when a inode is created, when a inode is evicted.
5) sync:
btrfs_sync_file
btrfs_sync_fs
These show sync arguments.
6) transaction:
btrfs_transaction_commit
In transaction based filesystem, it will be useful to know the generation and
who does commit.
7) back reference and cow:
btrfs_delayed_tree_ref
btrfs_delayed_data_ref
btrfs_delayed_ref_head
btrfs_cow_block
Btrfs natively supports back references, these tracepoints are helpful on
understanding btrfs's COW mechanism.
8) chunk:
btrfs_chunk_alloc
btrfs_chunk_free
Chunk is a link between physical offset and logical offset, and stands for space
infomation in btrfs, and these are helpful on tracing space things.
9) reserved_extent:
btrfs_reserved_extent_alloc
btrfs_reserved_extent_free
These can show how btrfs uses its space.
Signed-off-by: Liu Bo <liubo2009@cn.fujitsu.com>
Signed-off-by: Chris Mason <chris.mason@oracle.com>
2011-03-24 14:18:59 +03:00
|
|
|
int num_stripes;
|
|
|
|
int sub_stripes;
|
2018-08-01 05:37:19 +03:00
|
|
|
int verified_stripes; /* For mount time dev extent verification */
|
Btrfs: add initial tracepoint support for btrfs
Tracepoints can provide insight into why btrfs hits bugs and be greatly
helpful for debugging, e.g
dd-7822 [000] 2121.641088: btrfs_inode_request: root = 5(FS_TREE), gen = 4, ino = 256, blocks = 8, disk_i_size = 0, last_trans = 8, logged_trans = 0
dd-7822 [000] 2121.641100: btrfs_inode_new: root = 5(FS_TREE), gen = 8, ino = 257, blocks = 0, disk_i_size = 0, last_trans = 0, logged_trans = 0
btrfs-transacti-7804 [001] 2146.935420: btrfs_cow_block: root = 2(EXTENT_TREE), refs = 2, orig_buf = 29368320 (orig_level = 0), cow_buf = 29388800 (cow_level = 0)
btrfs-transacti-7804 [001] 2146.935473: btrfs_cow_block: root = 1(ROOT_TREE), refs = 2, orig_buf = 29364224 (orig_level = 0), cow_buf = 29392896 (cow_level = 0)
btrfs-transacti-7804 [001] 2146.972221: btrfs_transaction_commit: root = 1(ROOT_TREE), gen = 8
flush-btrfs-2-7821 [001] 2155.824210: btrfs_chunk_alloc: root = 3(CHUNK_TREE), offset = 1103101952, size = 1073741824, num_stripes = 1, sub_stripes = 0, type = DATA
flush-btrfs-2-7821 [001] 2155.824241: btrfs_cow_block: root = 2(EXTENT_TREE), refs = 2, orig_buf = 29388800 (orig_level = 0), cow_buf = 29396992 (cow_level = 0)
flush-btrfs-2-7821 [001] 2155.824255: btrfs_cow_block: root = 4(DEV_TREE), refs = 2, orig_buf = 29372416 (orig_level = 0), cow_buf = 29401088 (cow_level = 0)
flush-btrfs-2-7821 [000] 2155.824329: btrfs_cow_block: root = 3(CHUNK_TREE), refs = 2, orig_buf = 20971520 (orig_level = 0), cow_buf = 20975616 (cow_level = 0)
btrfs-endio-wri-7800 [001] 2155.898019: btrfs_cow_block: root = 5(FS_TREE), refs = 2, orig_buf = 29384704 (orig_level = 0), cow_buf = 29405184 (cow_level = 0)
btrfs-endio-wri-7800 [001] 2155.898043: btrfs_cow_block: root = 7(CSUM_TREE), refs = 2, orig_buf = 29376512 (orig_level = 0), cow_buf = 29409280 (cow_level = 0)
Here is what I have added:
1) ordere_extent:
btrfs_ordered_extent_add
btrfs_ordered_extent_remove
btrfs_ordered_extent_start
btrfs_ordered_extent_put
These provide critical information to understand how ordered_extents are
updated.
2) extent_map:
btrfs_get_extent
extent_map is used in both read and write cases, and it is useful for tracking
how btrfs specific IO is running.
3) writepage:
__extent_writepage
btrfs_writepage_end_io_hook
Pages are cirtical resourses and produce a lot of corner cases during writeback,
so it is valuable to know how page is written to disk.
4) inode:
btrfs_inode_new
btrfs_inode_request
btrfs_inode_evict
These can show where and when a inode is created, when a inode is evicted.
5) sync:
btrfs_sync_file
btrfs_sync_fs
These show sync arguments.
6) transaction:
btrfs_transaction_commit
In transaction based filesystem, it will be useful to know the generation and
who does commit.
7) back reference and cow:
btrfs_delayed_tree_ref
btrfs_delayed_data_ref
btrfs_delayed_ref_head
btrfs_cow_block
Btrfs natively supports back references, these tracepoints are helpful on
understanding btrfs's COW mechanism.
8) chunk:
btrfs_chunk_alloc
btrfs_chunk_free
Chunk is a link between physical offset and logical offset, and stands for space
infomation in btrfs, and these are helpful on tracing space things.
9) reserved_extent:
btrfs_reserved_extent_alloc
btrfs_reserved_extent_free
These can show how btrfs uses its space.
Signed-off-by: Liu Bo <liubo2009@cn.fujitsu.com>
Signed-off-by: Chris Mason <chris.mason@oracle.com>
2011-03-24 14:18:59 +03:00
|
|
|
struct btrfs_bio_stripe stripes[];
|
|
|
|
};
|
|
|
|
|
2011-03-08 16:14:00 +03:00
|
|
|
#define map_lookup_size(n) (sizeof(struct map_lookup) + \
|
|
|
|
(sizeof(struct btrfs_bio_stripe) * (n)))
|
|
|
|
|
2012-01-17 00:04:47 +04:00
|
|
|
struct btrfs_balance_args;
|
2012-01-17 00:04:49 +04:00
|
|
|
struct btrfs_balance_progress;
|
2012-01-17 00:04:47 +04:00
|
|
|
struct btrfs_balance_control {
|
|
|
|
struct btrfs_balance_args data;
|
|
|
|
struct btrfs_balance_args meta;
|
|
|
|
struct btrfs_balance_args sys;
|
|
|
|
|
|
|
|
u64 flags;
|
2012-01-17 00:04:49 +04:00
|
|
|
|
|
|
|
struct btrfs_balance_progress stat;
|
2012-01-17 00:04:47 +04:00
|
|
|
};
|
|
|
|
|
2016-10-27 10:27:36 +03:00
|
|
|
enum btrfs_map_op {
|
|
|
|
BTRFS_MAP_READ,
|
|
|
|
BTRFS_MAP_WRITE,
|
|
|
|
BTRFS_MAP_DISCARD,
|
|
|
|
BTRFS_MAP_GET_READ_MIRRORS,
|
|
|
|
};
|
|
|
|
|
|
|
|
static inline enum btrfs_map_op btrfs_op(struct bio *bio)
|
|
|
|
{
|
|
|
|
switch (bio_op(bio)) {
|
|
|
|
case REQ_OP_DISCARD:
|
|
|
|
return BTRFS_MAP_DISCARD;
|
|
|
|
case REQ_OP_WRITE:
|
2021-02-04 13:21:59 +03:00
|
|
|
case REQ_OP_ZONE_APPEND:
|
2016-10-27 10:27:36 +03:00
|
|
|
return BTRFS_MAP_WRITE;
|
|
|
|
default:
|
|
|
|
WARN_ON_ONCE(1);
|
2020-06-16 21:54:29 +03:00
|
|
|
fallthrough;
|
2016-10-27 10:27:36 +03:00
|
|
|
case REQ_OP_READ:
|
|
|
|
return BTRFS_MAP_READ;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-20 10:11:34 +03:00
|
|
|
void btrfs_get_bbio(struct btrfs_bio *bbio);
|
|
|
|
void btrfs_put_bbio(struct btrfs_bio *bbio);
|
2016-10-27 10:27:36 +03:00
|
|
|
int btrfs_map_block(struct btrfs_fs_info *fs_info, enum btrfs_map_op op,
|
2008-04-10 00:28:12 +04:00
|
|
|
u64 logical, u64 *length,
|
2011-08-04 19:15:33 +04:00
|
|
|
struct btrfs_bio **bbio_ret, int mirror_num);
|
2016-10-27 10:27:36 +03:00
|
|
|
int btrfs_map_sblock(struct btrfs_fs_info *fs_info, enum btrfs_map_op op,
|
2014-10-23 10:42:50 +04:00
|
|
|
u64 logical, u64 *length,
|
2017-03-28 15:45:22 +03:00
|
|
|
struct btrfs_bio **bbio_ret);
|
2021-01-27 16:57:27 +03:00
|
|
|
int btrfs_get_io_geometry(struct btrfs_fs_info *fs_info, struct extent_map *map,
|
|
|
|
enum btrfs_map_op op, u64 logical, u64 len,
|
|
|
|
struct btrfs_io_geometry *io_geom);
|
2016-06-22 04:16:51 +03:00
|
|
|
int btrfs_read_sys_array(struct btrfs_fs_info *fs_info);
|
2016-06-21 17:40:19 +03:00
|
|
|
int btrfs_read_chunk_tree(struct btrfs_fs_info *fs_info);
|
2018-06-20 15:49:06 +03:00
|
|
|
int btrfs_alloc_chunk(struct btrfs_trans_handle *trans, u64 type);
|
2019-05-17 12:43:17 +03:00
|
|
|
void btrfs_mapping_tree_free(struct extent_map_tree *tree);
|
2017-08-23 09:45:59 +03:00
|
|
|
blk_status_t btrfs_map_bio(struct btrfs_fs_info *fs_info, struct bio *bio,
|
2019-07-10 22:28:14 +03:00
|
|
|
int mirror_num);
|
2008-03-24 22:02:07 +03:00
|
|
|
int btrfs_open_devices(struct btrfs_fs_devices *fs_devices,
|
2008-12-02 14:36:09 +03:00
|
|
|
fmode_t flags, void *holder);
|
2018-07-12 09:23:16 +03:00
|
|
|
struct btrfs_device *btrfs_scan_one_device(const char *path,
|
|
|
|
fmode_t flags, void *holder);
|
2019-01-04 08:31:54 +03:00
|
|
|
int btrfs_forget_devices(const char *path);
|
2020-07-15 13:48:48 +03:00
|
|
|
void btrfs_close_devices(struct btrfs_fs_devices *fs_devices);
|
2020-11-06 11:06:33 +03:00
|
|
|
void btrfs_free_extra_devids(struct btrfs_fs_devices *fs_devices);
|
2018-07-20 19:37:50 +03:00
|
|
|
void btrfs_assign_next_active_device(struct btrfs_device *device,
|
|
|
|
struct btrfs_device *this_dev);
|
2018-09-03 12:46:14 +03:00
|
|
|
struct btrfs_device *btrfs_find_device_by_devspec(struct btrfs_fs_info *fs_info,
|
|
|
|
u64 devid,
|
|
|
|
const char *devpath);
|
2013-08-23 14:20:17 +04:00
|
|
|
struct btrfs_device *btrfs_alloc_device(struct btrfs_fs_info *fs_info,
|
|
|
|
const u64 *devid,
|
|
|
|
const u8 *uuid);
|
2018-03-20 17:47:33 +03:00
|
|
|
void btrfs_free_device(struct btrfs_device *device);
|
2016-06-23 01:54:24 +03:00
|
|
|
int btrfs_rm_device(struct btrfs_fs_info *fs_info,
|
2017-02-14 19:55:53 +03:00
|
|
|
const char *device_path, u64 devid);
|
2018-02-19 19:24:15 +03:00
|
|
|
void __exit btrfs_cleanup_fs_uuids(void);
|
2012-11-05 17:59:07 +04:00
|
|
|
int btrfs_num_copies(struct btrfs_fs_info *fs_info, u64 logical, u64 len);
|
2008-04-26 00:53:30 +04:00
|
|
|
int btrfs_grow_device(struct btrfs_trans_handle *trans,
|
|
|
|
struct btrfs_device *device, u64 new_size);
|
2019-01-17 18:32:31 +03:00
|
|
|
struct btrfs_device *btrfs_find_device(struct btrfs_fs_devices *fs_devices,
|
2020-11-03 08:49:43 +03:00
|
|
|
u64 devid, u8 *uuid, u8 *fsid);
|
2008-04-26 00:53:30 +04:00
|
|
|
int btrfs_shrink_device(struct btrfs_device *device, u64 new_size);
|
2017-02-14 19:55:53 +03:00
|
|
|
int btrfs_init_new_device(struct btrfs_fs_info *fs_info, const char *path);
|
2018-05-07 18:44:03 +03:00
|
|
|
int btrfs_balance(struct btrfs_fs_info *fs_info,
|
|
|
|
struct btrfs_balance_control *bctl,
|
2012-01-17 00:04:47 +04:00
|
|
|
struct btrfs_ioctl_balance_args *bargs);
|
2018-11-20 11:12:55 +03:00
|
|
|
void btrfs_describe_block_groups(u64 flags, char *buf, u32 size_buf);
|
2012-06-22 22:24:13 +04:00
|
|
|
int btrfs_resume_balance_async(struct btrfs_fs_info *fs_info);
|
2012-06-22 22:24:12 +04:00
|
|
|
int btrfs_recover_balance(struct btrfs_fs_info *fs_info);
|
2012-01-17 00:04:49 +04:00
|
|
|
int btrfs_pause_balance(struct btrfs_fs_info *fs_info);
|
2012-01-17 00:04:49 +04:00
|
|
|
int btrfs_cancel_balance(struct btrfs_fs_info *fs_info);
|
2013-08-15 19:11:19 +04:00
|
|
|
int btrfs_create_uuid_tree(struct btrfs_fs_info *fs_info);
|
2020-02-18 17:56:08 +03:00
|
|
|
int btrfs_uuid_scan_kthread(void *data);
|
2016-06-23 01:54:24 +03:00
|
|
|
int btrfs_chunk_readonly(struct btrfs_fs_info *fs_info, u64 chunk_offset);
|
2019-03-27 15:24:14 +03:00
|
|
|
int find_free_dev_extent(struct btrfs_device *device, u64 num_bytes,
|
Btrfs: make balance code choose more wisely when relocating
Currently, we can panic the box if the first block group we go to move is of a
type where there is no space left to move those extents. For example, if we
fill the disk up with data, and then we try to balance and we have no room to
move the data nor room to allocate new chunks, we will panic. Change this by
checking to see if we have room to move this chunk around, and if not, return
-ENOSPC and move on to the next chunk. This will make sure we remove block
groups that are moveable, like if we have alot of empty metadata block groups,
and then that way we make room to be able to balance our data chunks as well.
Tested this with an fs that would panic on btrfs-vol -b normally, but no longer
panics with this patch.
V1->V2:
-actually search for a free extent on the device to make sure we can allocate a
chunk if need be.
-fix btrfs_shrink_device to make sure we actually try to relocate all the
chunks, and then if we can't return -ENOSPC so if we are doing a btrfs-vol -r
we don't remove the device with data still on it.
-check to make sure the block group we are going to relocate isn't the last one
in that particular space
-fix a bug in btrfs_shrink_device where we would change the device's size and
not fix it if we fail to do our relocate
Signed-off-by: Josef Bacik <jbacik@redhat.com>
Signed-off-by: Chris Mason <chris.mason@oracle.com>
2009-09-12 00:11:19 +04:00
|
|
|
u64 *start, u64 *max_avail);
|
2012-05-25 18:06:08 +04:00
|
|
|
void btrfs_dev_stat_inc_and_print(struct btrfs_device *dev, int index);
|
2016-06-23 01:54:24 +03:00
|
|
|
int btrfs_get_dev_stats(struct btrfs_fs_info *fs_info,
|
2012-06-22 16:30:39 +04:00
|
|
|
struct btrfs_ioctl_get_dev_stats *stats);
|
2013-05-15 11:48:19 +04:00
|
|
|
void btrfs_init_devices_late(struct btrfs_fs_info *fs_info);
|
2012-05-25 18:06:10 +04:00
|
|
|
int btrfs_init_dev_stats(struct btrfs_fs_info *fs_info);
|
2019-03-20 18:50:38 +03:00
|
|
|
int btrfs_run_dev_stats(struct btrfs_trans_handle *trans);
|
2018-07-20 19:37:48 +03:00
|
|
|
void btrfs_rm_dev_replace_remove_srcdev(struct btrfs_device *srcdev);
|
2019-03-20 18:34:54 +03:00
|
|
|
void btrfs_rm_dev_replace_free_srcdev(struct btrfs_device *srcdev);
|
2018-07-20 19:37:51 +03:00
|
|
|
void btrfs_destroy_dev_replace_tgtdev(struct btrfs_device *tgtdev);
|
2017-03-14 23:33:55 +03:00
|
|
|
int btrfs_is_parity_mirror(struct btrfs_fs_info *fs_info,
|
2017-07-19 10:48:42 +03:00
|
|
|
u64 logical, u64 len);
|
2016-06-23 01:54:24 +03:00
|
|
|
unsigned long btrfs_full_stripe_len(struct btrfs_fs_info *fs_info,
|
2013-01-30 03:40:14 +04:00
|
|
|
u64 logical);
|
2013-06-27 21:22:46 +04:00
|
|
|
int btrfs_finish_chunk_alloc(struct btrfs_trans_handle *trans,
|
2018-07-20 19:37:53 +03:00
|
|
|
u64 chunk_offset, u64 chunk_size);
|
|
|
|
int btrfs_remove_chunk(struct btrfs_trans_handle *trans, u64 chunk_offset);
|
2018-05-17 02:34:31 +03:00
|
|
|
struct extent_map *btrfs_get_chunk_map(struct btrfs_fs_info *fs_info,
|
|
|
|
u64 logical, u64 length);
|
2020-02-13 18:24:32 +03:00
|
|
|
void btrfs_release_disk_super(struct btrfs_super_block *super);
|
2014-07-24 07:37:11 +04:00
|
|
|
|
2012-05-25 18:06:08 +04:00
|
|
|
static inline void btrfs_dev_stat_inc(struct btrfs_device *dev,
|
|
|
|
int index)
|
|
|
|
{
|
|
|
|
atomic_inc(dev->dev_stat_values + index);
|
2017-10-24 13:47:37 +03:00
|
|
|
/*
|
|
|
|
* This memory barrier orders stores updating statistics before stores
|
|
|
|
* updating dev_stats_ccnt.
|
|
|
|
*
|
|
|
|
* It pairs with smp_rmb() in btrfs_run_dev_stats().
|
|
|
|
*/
|
2014-07-24 07:37:11 +04:00
|
|
|
smp_mb__before_atomic();
|
|
|
|
atomic_inc(&dev->dev_stats_ccnt);
|
2012-05-25 18:06:08 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline int btrfs_dev_stat_read(struct btrfs_device *dev,
|
|
|
|
int index)
|
|
|
|
{
|
|
|
|
return atomic_read(dev->dev_stat_values + index);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline int btrfs_dev_stat_read_and_reset(struct btrfs_device *dev,
|
|
|
|
int index)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = atomic_xchg(dev->dev_stat_values + index, 0);
|
2017-10-20 18:10:58 +03:00
|
|
|
/*
|
|
|
|
* atomic_xchg implies a full memory barriers as per atomic_t.txt:
|
|
|
|
* - RMW operations that have a return value are fully ordered;
|
|
|
|
*
|
|
|
|
* This implicit memory barriers is paired with the smp_rmb in
|
|
|
|
* btrfs_run_dev_stats
|
|
|
|
*/
|
2014-07-24 07:37:11 +04:00
|
|
|
atomic_inc(&dev->dev_stats_ccnt);
|
2012-05-25 18:06:08 +04:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void btrfs_dev_stat_set(struct btrfs_device *dev,
|
|
|
|
int index, unsigned long val)
|
|
|
|
{
|
|
|
|
atomic_set(dev->dev_stat_values + index, val);
|
2017-10-24 13:47:37 +03:00
|
|
|
/*
|
|
|
|
* This memory barrier orders stores updating statistics before stores
|
|
|
|
* updating dev_stats_ccnt.
|
|
|
|
*
|
|
|
|
* It pairs with smp_rmb() in btrfs_run_dev_stats().
|
|
|
|
*/
|
2014-07-24 07:37:11 +04:00
|
|
|
smp_mb__before_atomic();
|
|
|
|
atomic_inc(&dev->dev_stats_ccnt);
|
2012-05-25 18:06:08 +04:00
|
|
|
}
|
|
|
|
|
2018-01-30 13:20:45 +03:00
|
|
|
/*
|
|
|
|
* Convert block group flags (BTRFS_BLOCK_GROUP_*) to btrfs_raid_types, which
|
|
|
|
* can be used as index to access btrfs_raid_array[].
|
|
|
|
*/
|
|
|
|
static inline enum btrfs_raid_types btrfs_bg_flags_to_raid_index(u64 flags)
|
|
|
|
{
|
|
|
|
if (flags & BTRFS_BLOCK_GROUP_RAID10)
|
|
|
|
return BTRFS_RAID_RAID10;
|
|
|
|
else if (flags & BTRFS_BLOCK_GROUP_RAID1)
|
|
|
|
return BTRFS_RAID_RAID1;
|
2018-03-03 00:56:53 +03:00
|
|
|
else if (flags & BTRFS_BLOCK_GROUP_RAID1C3)
|
|
|
|
return BTRFS_RAID_RAID1C3;
|
2018-03-03 00:56:53 +03:00
|
|
|
else if (flags & BTRFS_BLOCK_GROUP_RAID1C4)
|
|
|
|
return BTRFS_RAID_RAID1C4;
|
2018-01-30 13:20:45 +03:00
|
|
|
else if (flags & BTRFS_BLOCK_GROUP_DUP)
|
|
|
|
return BTRFS_RAID_DUP;
|
|
|
|
else if (flags & BTRFS_BLOCK_GROUP_RAID0)
|
|
|
|
return BTRFS_RAID_RAID0;
|
|
|
|
else if (flags & BTRFS_BLOCK_GROUP_RAID5)
|
|
|
|
return BTRFS_RAID_RAID5;
|
|
|
|
else if (flags & BTRFS_BLOCK_GROUP_RAID6)
|
|
|
|
return BTRFS_RAID_RAID6;
|
|
|
|
|
|
|
|
return BTRFS_RAID_SINGLE; /* BTRFS_BLOCK_GROUP_SINGLE */
|
|
|
|
}
|
|
|
|
|
2019-03-25 15:31:22 +03:00
|
|
|
void btrfs_commit_device_sizes(struct btrfs_transaction *trans);
|
Btrfs: fix race between fs trimming and block group remove/allocation
Our fs trim operation, which is completely transactionless (doesn't start
or joins an existing transaction) consists of visiting all block groups
and then for each one to iterate its free space entries and perform a
discard operation against the space range represented by the free space
entries. However before performing a discard, the corresponding free space
entry is removed from the free space rbtree, and when the discard completes
it is added back to the free space rbtree.
If a block group remove operation happens while the discard is ongoing (or
before it starts and after a free space entry is hidden), we end up not
waiting for the discard to complete, remove the extent map that maps
logical address to physical addresses and the corresponding chunk metadata
from the the chunk and device trees. After that and before the discard
completes, the current running transaction can finish and a new one start,
allowing for new block groups that map to the same physical addresses to
be allocated and written to.
So fix this by keeping the extent map in memory until the discard completes
so that the same physical addresses aren't reused before it completes.
If the physical locations that are under a discard operation end up being
used for a new metadata block group for example, and dirty metadata extents
are written before the discard finishes (the VM might call writepages() of
our btree inode's i_mapping for example, or an fsync log commit happens) we
end up overwriting metadata with zeroes, which leads to errors from fsck
like the following:
checking extents
Check tree block failed, want=833912832, have=0
Check tree block failed, want=833912832, have=0
Check tree block failed, want=833912832, have=0
Check tree block failed, want=833912832, have=0
Check tree block failed, want=833912832, have=0
read block failed check_tree_block
owner ref check failed [833912832 16384]
Errors found in extent allocation tree or chunk allocation
checking free space cache
checking fs roots
Check tree block failed, want=833912832, have=0
Check tree block failed, want=833912832, have=0
Check tree block failed, want=833912832, have=0
Check tree block failed, want=833912832, have=0
Check tree block failed, want=833912832, have=0
read block failed check_tree_block
root 5 root dir 256 error
root 5 inode 260 errors 2001, no inode item, link count wrong
unresolved ref dir 256 index 0 namelen 8 name foobar_3 filetype 1 errors 6, no dir index, no inode ref
root 5 inode 262 errors 2001, no inode item, link count wrong
unresolved ref dir 256 index 0 namelen 8 name foobar_5 filetype 1 errors 6, no dir index, no inode ref
root 5 inode 263 errors 2001, no inode item, link count wrong
(...)
Signed-off-by: Filipe Manana <fdmanana@suse.com>
Signed-off-by: Chris Mason <clm@fb.com>
2014-11-28 00:14:15 +03:00
|
|
|
|
2019-10-01 20:57:37 +03:00
|
|
|
struct list_head * __attribute_const__ btrfs_get_fs_uuids(void);
|
2017-12-18 12:08:59 +03:00
|
|
|
bool btrfs_check_rw_degradable(struct btrfs_fs_info *fs_info,
|
|
|
|
struct btrfs_device *failing_dev);
|
2020-08-20 18:18:26 +03:00
|
|
|
void btrfs_scratch_superblocks(struct btrfs_fs_info *fs_info,
|
|
|
|
struct block_device *bdev,
|
|
|
|
const char *device_path);
|
btrfs: Introduce a function to check if all chunks a OK for degraded rw mount
Introduce a new function, btrfs_check_rw_degradable(), to check if all
chunks in btrfs is OK for degraded rw mount.
It provides the new basis for accurate btrfs mount/remount and even
runtime degraded mount check other than old one-size-fit-all method.
Btrfs currently uses num_tolerated_disk_barrier_failures to do global
check for tolerated missing device.
Although the one-size-fit-all solution is quite safe, it's too strict
if data and metadata has different duplication level.
For example, if one use Single data and RAID1 metadata for 2 disks, it
means any missing device will make the fs unable to be degraded
mounted.
But in fact, some times all single chunks may be in the existing
device and in that case, we should allow it to be rw degraded mounted.
Such case can be easily reproduced using the following script:
# mkfs.btrfs -f -m raid1 -d sing /dev/sdb /dev/sdc
# wipefs -f /dev/sdc
# mount /dev/sdb -o degraded,rw
If using btrfs-debug-tree to check /dev/sdb, one should find that the
data chunk is only in sdb, so in fact it should allow degraded mount.
This patchset will introduce a new per-chunk degradable check for
btrfs, allow above case to succeed, and it's quite small anyway.
Signed-off-by: Qu Wenruo <quwenruo@cn.fujitsu.com>
Signed-off-by: Anand Jain <anand.jain@oracle.com>
Reviewed-by: David Sterba <dsterba@suse.com>
[ copied text from cover letter with more details about the problem being
solved ]
Signed-off-by: David Sterba <dsterba@suse.com>
2017-03-09 04:34:36 +03:00
|
|
|
|
2018-07-13 21:46:30 +03:00
|
|
|
int btrfs_bg_type_to_factor(u64 flags);
|
2019-05-17 12:43:41 +03:00
|
|
|
const char *btrfs_bg_type_to_raid_name(u64 flags);
|
2018-08-01 05:37:19 +03:00
|
|
|
int btrfs_verify_dev_extents(struct btrfs_fs_info *fs_info);
|
btrfs: zoned: relocate block group to repair IO failure in zoned filesystems
When a bad checksum is found and if the filesystem has a mirror of the
damaged data, we read the correct data from the mirror and writes it to
damaged blocks. This however, violates the sequential write constraints
of a zoned block device.
We can consider three methods to repair an IO failure in zoned filesystems:
(1) Reset and rewrite the damaged zone
(2) Allocate new device extent and replace the damaged device extent to
the new extent
(3) Relocate the corresponding block group
Method (1) is most similar to a behavior done with regular devices.
However, it also wipes non-damaged data in the same device extent, and
so it unnecessary degrades non-damaged data.
Method (2) is much like device replacing but done in the same device. It
is safe because it keeps the device extent until the replacing finish.
However, extending device replacing is non-trivial. It assumes
"src_dev->physical == dst_dev->physical". Also, the extent mapping
replacing function should be extended to support replacing device extent
position in one device.
Method (3) invokes relocation of the damaged block group and is
straightforward to implement. It relocates all the mirrored device
extents, so it potentially is a more costly operation than method (1) or
(2). But it relocates only used extents which reduce the total IO size.
Let's apply method (3) for now. In the future, we can extend device-replace
and apply method (2).
For protecting a block group gets relocated multiple time with multiple
IO errors, this commit introduces "relocating_repair" bit to show it's
now relocating to repair IO failures. Also it uses a new kthread
"btrfs-relocating-repair", not to block IO path with relocating process.
This commit also supports repairing in the scrub process.
Reviewed-by: Josef Bacik <josef@toxicpanda.com>
Signed-off-by: Naohiro Aota <naohiro.aota@wdc.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2021-02-04 13:22:16 +03:00
|
|
|
int btrfs_repair_one_zone(struct btrfs_fs_info *fs_info, u64 logical);
|
2018-07-13 21:46:30 +03:00
|
|
|
|
2008-03-24 22:01:56 +03:00
|
|
|
#endif
|