2018-04-04 01:16:55 +08:00
|
|
|
/* SPDX-License-Identifier: GPL-2.0 */
|
2008-03-25 03:01:56 +08:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2007 Oracle. All rights reserved.
|
|
|
|
*/
|
|
|
|
|
2018-04-04 01:16:55 +08:00
|
|
|
#ifndef BTRFS_VOLUMES_H
|
|
|
|
#define BTRFS_VOLUMES_H
|
2008-04-04 04:29:03 +08:00
|
|
|
|
2011-01-05 18:07:28 +08:00
|
|
|
#include <linux/sort.h>
|
2013-01-29 14:04:50 +08:00
|
|
|
#include <linux/btrfs.h>
|
2008-06-12 04:50:36 +08:00
|
|
|
#include "async-thread.h"
|
2022-10-27 03:08:17 +08:00
|
|
|
#include "messages.h"
|
2022-11-15 17:44:04 +08:00
|
|
|
#include "tree-checker.h"
|
2022-11-13 09:32:07 +08:00
|
|
|
#include "rcu-string.h"
|
2008-04-10 04:28:12 +08:00
|
|
|
|
2018-07-03 17:10:05 +08:00
|
|
|
#define BTRFS_MAX_DATA_CHUNK_SIZE (10ULL * SZ_1G)
|
|
|
|
|
2014-09-03 21:35:43 +08:00
|
|
|
extern struct mutex uuid_mutex;
|
|
|
|
|
2023-02-17 13:36:58 +08:00
|
|
|
#define BTRFS_STRIPE_LEN SZ_64K
|
|
|
|
#define BTRFS_STRIPE_LEN_SHIFT (16)
|
|
|
|
#define BTRFS_STRIPE_LEN_MASK (BTRFS_STRIPE_LEN - 1)
|
|
|
|
|
|
|
|
static_assert(const_ilog2(BTRFS_STRIPE_LEN) == BTRFS_STRIPE_LEN_SHIFT);
|
2011-01-05 18:07:28 +08:00
|
|
|
|
2022-04-20 16:08:28 +08:00
|
|
|
/* Used by sanity check for btrfs_raid_types. */
|
|
|
|
#define const_ffs(n) (__builtin_ctzll(n) + 1)
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The conversion from BTRFS_BLOCK_GROUP_* bits to btrfs_raid_type requires
|
|
|
|
* RAID0 always to be the lowest profile bit.
|
|
|
|
* Although it's part of on-disk format and should never change, do extra
|
|
|
|
* compile-time sanity checks.
|
|
|
|
*/
|
|
|
|
static_assert(const_ffs(BTRFS_BLOCK_GROUP_RAID0) <
|
|
|
|
const_ffs(BTRFS_BLOCK_GROUP_PROFILE_MASK & ~BTRFS_BLOCK_GROUP_RAID0));
|
|
|
|
static_assert(const_ilog2(BTRFS_BLOCK_GROUP_RAID0) >
|
|
|
|
ilog2(BTRFS_BLOCK_GROUP_TYPE_MASK));
|
|
|
|
|
|
|
|
/* ilog2() can handle both constants and variables */
|
|
|
|
#define BTRFS_BG_FLAG_TO_INDEX(profile) \
|
|
|
|
ilog2((profile) >> (ilog2(BTRFS_BLOCK_GROUP_RAID0) - 1))
|
|
|
|
|
2022-04-20 16:08:27 +08:00
|
|
|
enum btrfs_raid_types {
|
2022-04-20 16:08:28 +08:00
|
|
|
/* SINGLE is the special one as it doesn't have on-disk bit. */
|
|
|
|
BTRFS_RAID_SINGLE = 0,
|
|
|
|
|
|
|
|
BTRFS_RAID_RAID0 = BTRFS_BG_FLAG_TO_INDEX(BTRFS_BLOCK_GROUP_RAID0),
|
|
|
|
BTRFS_RAID_RAID1 = BTRFS_BG_FLAG_TO_INDEX(BTRFS_BLOCK_GROUP_RAID1),
|
|
|
|
BTRFS_RAID_DUP = BTRFS_BG_FLAG_TO_INDEX(BTRFS_BLOCK_GROUP_DUP),
|
|
|
|
BTRFS_RAID_RAID10 = BTRFS_BG_FLAG_TO_INDEX(BTRFS_BLOCK_GROUP_RAID10),
|
|
|
|
BTRFS_RAID_RAID5 = BTRFS_BG_FLAG_TO_INDEX(BTRFS_BLOCK_GROUP_RAID5),
|
|
|
|
BTRFS_RAID_RAID6 = BTRFS_BG_FLAG_TO_INDEX(BTRFS_BLOCK_GROUP_RAID6),
|
|
|
|
BTRFS_RAID_RAID1C3 = BTRFS_BG_FLAG_TO_INDEX(BTRFS_BLOCK_GROUP_RAID1C3),
|
|
|
|
BTRFS_RAID_RAID1C4 = BTRFS_BG_FLAG_TO_INDEX(BTRFS_BLOCK_GROUP_RAID1C4),
|
|
|
|
|
2022-04-20 16:08:27 +08:00
|
|
|
BTRFS_NR_RAID_TYPES
|
|
|
|
};
|
|
|
|
|
2014-09-03 21:35:38 +08: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 19:39:10 +08:00
|
|
|
#define btrfs_device_data_ordered_init(device) \
|
|
|
|
seqcount_init(&device->data_seqcount)
|
2014-09-03 21:35:38 +08:00
|
|
|
#else
|
2021-01-21 19:39:10 +08:00
|
|
|
#define btrfs_device_data_ordered_init(device) do { } while (0)
|
2014-09-03 21:35:38 +08:00
|
|
|
#endif
|
|
|
|
|
2017-12-04 12:54:52 +08:00
|
|
|
#define BTRFS_DEV_STATE_WRITEABLE (0)
|
2017-12-04 12:54:53 +08:00
|
|
|
#define BTRFS_DEV_STATE_IN_FS_METADATA (1)
|
2017-12-04 12:54:54 +08:00
|
|
|
#define BTRFS_DEV_STATE_MISSING (2)
|
2017-12-04 12:54:55 +08:00
|
|
|
#define BTRFS_DEV_STATE_REPLACE_TGT (3)
|
2017-12-04 12:54:56 +08: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 18:55:24 +08:00
|
|
|
#define BTRFS_DEV_STATE_NO_READA (5)
|
2017-12-04 12:54:52 +08:00
|
|
|
|
2020-11-10 19:26:07 +08:00
|
|
|
struct btrfs_zoned_device_info;
|
|
|
|
|
2008-03-25 03:01:56 +08:00
|
|
|
struct btrfs_device {
|
2019-05-09 23:11:11 +08:00
|
|
|
struct list_head dev_list; /* device_list_mutex */
|
|
|
|
struct list_head dev_alloc_list; /* chunk mutex */
|
2019-03-25 20:31:22 +08:00
|
|
|
struct list_head post_commit_list; /* chunk mutex */
|
2008-11-18 10:11:30 +08:00
|
|
|
struct btrfs_fs_devices *fs_devices;
|
2016-06-23 06:54:56 +08:00
|
|
|
struct btrfs_fs_info *fs_info;
|
2009-04-21 03:50:09 +08:00
|
|
|
|
2019-12-05 04:19:01 +08:00
|
|
|
struct rcu_string __rcu *name;
|
2014-07-24 11:37:10 +08:00
|
|
|
|
|
|
|
u64 generation;
|
|
|
|
|
2023-09-27 17:34:26 +08:00
|
|
|
struct bdev_handle *bdev_handle;
|
2014-07-24 11:37:10 +08:00
|
|
|
struct block_device *bdev;
|
|
|
|
|
2020-11-10 19:26:07 +08:00
|
|
|
struct btrfs_zoned_device_info *zone_info;
|
|
|
|
|
2022-01-12 13:06:01 +08:00
|
|
|
/*
|
|
|
|
* Device's major-minor number. Must be set even if the device is not
|
|
|
|
* opened (bdev == NULL), unless the device is missing.
|
|
|
|
*/
|
|
|
|
dev_t devt;
|
2017-12-04 12:54:52 +08:00
|
|
|
unsigned long dev_state;
|
2017-08-23 14:45:59 +08:00
|
|
|
blk_status_t last_flush_error;
|
2008-04-22 21:22:07 +08:00
|
|
|
|
2014-09-03 21:35:38 +08:00
|
|
|
#ifdef __BTRFS_NEED_DEVICE_DATA_ORDERED
|
2021-01-21 19:39:10 +08:00
|
|
|
seqcount_t data_seqcount;
|
2014-09-03 21:35:38 +08:00
|
|
|
#endif
|
|
|
|
|
2008-03-25 03:01:56 +08:00
|
|
|
/* the internal btrfs device id */
|
|
|
|
u64 devid;
|
|
|
|
|
2014-07-24 11:37:12 +08:00
|
|
|
/* size of the device in memory */
|
2008-03-25 03:01:56 +08:00
|
|
|
u64 total_bytes;
|
|
|
|
|
2014-07-24 11:37:12 +08:00
|
|
|
/* size of the device on disk */
|
2009-04-27 19:29:03 +08:00
|
|
|
u64 disk_total_bytes;
|
|
|
|
|
2008-03-25 03:01:56 +08: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 12:27:33 +08:00
|
|
|
/* type and info about this device */
|
|
|
|
u64 type;
|
2008-03-25 03:01:56 +08:00
|
|
|
|
|
|
|
/* minimal io size for this device */
|
|
|
|
u32 sector_size;
|
|
|
|
|
|
|
|
/* physical drive uuid (or lvm uuid) */
|
2008-04-16 03:41:47 +08:00
|
|
|
u8 uuid[BTRFS_UUID_SIZE];
|
2008-06-12 04:50:36 +08:00
|
|
|
|
2014-09-03 21:35:33 +08:00
|
|
|
/*
|
|
|
|
* size of the device on the current transaction
|
|
|
|
*
|
|
|
|
* This variant is update when committing the transaction,
|
2019-03-25 20:31:22 +08:00
|
|
|
* and protected by chunk mutex
|
2014-09-03 21:35:33 +08:00
|
|
|
*/
|
|
|
|
u64 commit_total_bytes;
|
|
|
|
|
2014-09-03 21:35:34 +08:00
|
|
|
/* bytes used on the current transaction */
|
|
|
|
u64 commit_bytes_used;
|
2014-09-03 21:35:33 +08:00
|
|
|
|
2022-04-06 14:12:24 +08:00
|
|
|
/* Bio used for flushing device barriers */
|
|
|
|
struct bio flush_bio;
|
2013-10-31 12:27:33 +08:00
|
|
|
struct completion flush_wait;
|
|
|
|
|
2011-03-08 21:14:00 +08:00
|
|
|
/* per-device scrub information */
|
2018-01-03 16:08:30 +08:00
|
|
|
struct scrub_ctx *scrub_ctx;
|
2011-03-08 21:14:00 +08:00
|
|
|
|
2012-05-25 22:06:08 +08:00
|
|
|
/* disk I/O failure stats. For detailed description refer to
|
|
|
|
* enum btrfs_dev_stat_values in ioctl.h */
|
2012-05-25 22:06:10 +08:00
|
|
|
int dev_stats_valid;
|
2014-07-24 11:37:11 +08:00
|
|
|
|
|
|
|
/* Counter to record the change of device stats */
|
|
|
|
atomic_t dev_stats_ccnt;
|
2012-05-25 22:06:08 +08:00
|
|
|
atomic_t dev_stat_values[BTRFS_DEV_STAT_VALUES_MAX];
|
2019-03-27 20:24:12 +08:00
|
|
|
|
|
|
|
struct extent_io_tree alloc_state;
|
2020-01-06 19:38:31 +08:00
|
|
|
|
|
|
|
struct completion kobj_unregister;
|
|
|
|
/* For sysfs/FSID/devinfo/devid/ */
|
|
|
|
struct kobject devid_kobj;
|
2019-10-09 19:58:13 +08:00
|
|
|
|
|
|
|
/* Bandwidth limit for scrub, in bytes */
|
|
|
|
u64 scrub_speed_max;
|
2008-03-25 03:01:56 +08:00
|
|
|
};
|
|
|
|
|
2022-09-15 07:04:43 +08:00
|
|
|
/*
|
|
|
|
* Block group or device which contains an active swapfile. Used for preventing
|
|
|
|
* unsafe operations while a swapfile is active.
|
|
|
|
*
|
|
|
|
* These are sorted on (ptr, inode) (note that a block group or device can
|
|
|
|
* contain more than one swapfile). We compare the pointer values because we
|
|
|
|
* don't actually care what the object is, we just need a quick check whether
|
|
|
|
* the object exists in the rbtree.
|
|
|
|
*/
|
|
|
|
struct btrfs_swapfile_pin {
|
|
|
|
struct rb_node node;
|
|
|
|
void *ptr;
|
|
|
|
struct inode *inode;
|
|
|
|
/*
|
|
|
|
* If true, ptr points to a struct btrfs_block_group. Otherwise, ptr
|
|
|
|
* points to a struct btrfs_device.
|
|
|
|
*/
|
|
|
|
bool is_block_group;
|
|
|
|
/*
|
|
|
|
* Only used when 'is_block_group' is true and it is the number of
|
|
|
|
* extents used by a swapfile for this block group ('ptr' field).
|
|
|
|
*/
|
|
|
|
int bg_extent_count;
|
|
|
|
};
|
|
|
|
|
2014-09-03 21:35:38 +08: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 19:39:10 +08:00
|
|
|
preempt_disable(); \
|
2014-09-03 21:35:38 +08:00
|
|
|
write_seqcount_begin(&dev->data_seqcount); \
|
|
|
|
dev->name = size; \
|
|
|
|
write_seqcount_end(&dev->data_seqcount); \
|
2021-01-21 19:39:10 +08:00
|
|
|
preempt_enable(); \
|
2014-09-03 21:35:38 +08:00
|
|
|
}
|
2019-10-16 03:18:11 +08:00
|
|
|
#elif BITS_PER_LONG==32 && defined(CONFIG_PREEMPTION)
|
2014-09-03 21:35:38 +08: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 11:56:08 +08:00
|
|
|
enum btrfs_chunk_allocation_policy {
|
|
|
|
BTRFS_CHUNK_ALLOC_REGULAR,
|
2021-02-04 18:21:48 +08:00
|
|
|
BTRFS_CHUNK_ALLOC_ZONED,
|
2020-02-25 11:56:08 +08:00
|
|
|
};
|
|
|
|
|
2020-10-28 21:14:46 +08: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-25 03:02:07 +08:00
|
|
|
struct btrfs_fs_devices {
|
|
|
|
u8 fsid[BTRFS_FSID_SIZE]; /* FS specific uuid */
|
2023-05-24 20:02:38 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* UUID written into the btree blocks:
|
|
|
|
*
|
|
|
|
* - If metadata_uuid != fsid then super block must have
|
|
|
|
* BTRFS_FEATURE_INCOMPAT_METADATA_UUID flag set.
|
|
|
|
*
|
|
|
|
* - Following shall be true at all times:
|
|
|
|
* - metadata_uuid == btrfs_header::fsid
|
|
|
|
* - metadata_uuid == btrfs_dev_item::fsid
|
2023-09-07 00:16:41 +08:00
|
|
|
*
|
|
|
|
* - Relations between fsid and metadata_uuid in sb and fs_devices:
|
|
|
|
* - Normal:
|
|
|
|
* fs_devices->fsid == fs_devices->metadata_uuid == sb->fsid
|
|
|
|
* sb->metadata_uuid == 0
|
|
|
|
*
|
|
|
|
* - When the BTRFS_FEATURE_INCOMPAT_METADATA_UUID flag is set:
|
|
|
|
* fs_devices->fsid == sb->fsid
|
|
|
|
* fs_devices->metadata_uuid == sb->metadata_uuid
|
2023-10-04 23:00:24 +08:00
|
|
|
*
|
|
|
|
* - When in-memory fs_devices->temp_fsid is true
|
|
|
|
* fs_devices->fsid = random
|
|
|
|
* fs_devices->metadata_uuid == sb->fsid
|
2023-05-24 20:02:38 +08:00
|
|
|
*/
|
2018-10-30 22:43:23 +08:00
|
|
|
u8 metadata_uuid[BTRFS_FSID_SIZE];
|
2023-05-24 20:02:38 +08:00
|
|
|
|
2018-04-12 10:29:25 +08:00
|
|
|
struct list_head fs_list;
|
2008-03-25 03:02:07 +08:00
|
|
|
|
2021-10-06 04:12:40 +08:00
|
|
|
/*
|
|
|
|
* Number of devices under this fsid including missing and
|
|
|
|
* replace-target device and excludes seed devices.
|
|
|
|
*/
|
2008-03-25 03:02:07 +08:00
|
|
|
u64 num_devices;
|
2021-10-06 04:12:40 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* The number of devices that successfully opened, including
|
|
|
|
* replace-target, excludes seed devices.
|
|
|
|
*/
|
2008-05-14 04:03:06 +08:00
|
|
|
u64 open_devices;
|
2021-10-06 04:12:40 +08:00
|
|
|
|
|
|
|
/* The number of devices that are under the chunk allocation list. */
|
2008-11-18 10:11:30 +08:00
|
|
|
u64 rw_devices;
|
2021-10-06 04:12:40 +08:00
|
|
|
|
|
|
|
/* Count of missing devices under this fsid excluding seed device. */
|
2010-12-14 03:56:23 +08:00
|
|
|
u64 missing_devices;
|
2008-11-18 10:11:30 +08:00
|
|
|
u64 total_rw_bytes;
|
2021-10-06 04:12:40 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Count of devices from btrfs_super_block::num_devices for this fsid,
|
|
|
|
* which includes the seed device, excludes the transient replace-target
|
|
|
|
* device.
|
|
|
|
*/
|
2012-06-22 04:03:58 +08:00
|
|
|
u64 total_devices;
|
2018-10-30 22:43:26 +08:00
|
|
|
|
|
|
|
/* Highest generation number of seen devices */
|
|
|
|
u64 latest_generation;
|
|
|
|
|
2021-08-24 13:05:19 +08:00
|
|
|
/*
|
|
|
|
* The mount device or a device with highest generation after removal
|
|
|
|
* or replace.
|
|
|
|
*/
|
|
|
|
struct btrfs_device *latest_dev;
|
2009-06-11 03:17:02 +08:00
|
|
|
|
2023-05-24 20:02:43 +08:00
|
|
|
/*
|
|
|
|
* All of the devices in the filesystem, protected by a mutex so we can
|
|
|
|
* safely walk it to write out the super blocks without worrying about
|
|
|
|
* adding/removing by the multi-device code. Scrubbing super block can
|
|
|
|
* kick off supers writing by holding this mutex lock.
|
2009-06-11 03:17:02 +08:00
|
|
|
*/
|
|
|
|
struct mutex device_list_mutex;
|
2019-05-09 23:11:11 +08:00
|
|
|
|
|
|
|
/* List of all devices, protected by device_list_mutex */
|
2008-03-25 03:02:07 +08:00
|
|
|
struct list_head devices;
|
2008-04-22 21:22:07 +08:00
|
|
|
|
2023-05-24 20:02:43 +08:00
|
|
|
/* Devices which can satisfy space allocation. Protected by * chunk_mutex. */
|
2008-04-22 21:22:07 +08:00
|
|
|
struct list_head alloc_list;
|
2008-11-18 10:11:30 +08:00
|
|
|
|
2020-07-16 15:25:33 +08:00
|
|
|
struct list_head seed_list;
|
2008-11-18 10:11:30 +08:00
|
|
|
|
2023-05-24 20:02:43 +08:00
|
|
|
/* Count fs-devices opened. */
|
2008-11-18 10:11:30 +08:00
|
|
|
int opened;
|
2009-06-10 21:51:32 +08:00
|
|
|
|
2023-05-24 20:02:43 +08:00
|
|
|
/* Set when we find or add a device that doesn't have the nonrot flag set. */
|
2019-11-13 18:27:28 +08:00
|
|
|
bool rotating;
|
2023-05-24 20:02:43 +08:00
|
|
|
/* Devices support TRIM/discard commands. */
|
2022-07-27 02:54:10 +08:00
|
|
|
bool discardable;
|
2023-05-24 20:02:43 +08:00
|
|
|
/* The filesystem is a seed filesystem. */
|
2023-05-24 20:02:35 +08:00
|
|
|
bool seeding;
|
2023-09-28 09:09:47 +08:00
|
|
|
/* The mount needs to use a randomly generated fsid. */
|
|
|
|
bool temp_fsid;
|
2015-03-10 06:38:29 +08:00
|
|
|
|
2015-03-10 06:38:31 +08:00
|
|
|
struct btrfs_fs_info *fs_info;
|
2015-03-10 06:38:29 +08:00
|
|
|
/* sysfs kobjects */
|
2015-08-14 18:32:50 +08:00
|
|
|
struct kobject fsid_kobj;
|
2019-11-21 17:33:30 +08:00
|
|
|
struct kobject *devices_kobj;
|
2020-02-12 17:28:10 +08:00
|
|
|
struct kobject *devinfo_kobj;
|
2015-03-10 06:38:29 +08:00
|
|
|
struct completion kobj_unregister;
|
2020-02-25 11:56:08 +08:00
|
|
|
|
|
|
|
enum btrfs_chunk_allocation_policy chunk_alloc_policy;
|
2020-10-28 21:14:46 +08:00
|
|
|
|
2023-05-24 20:02:43 +08:00
|
|
|
/* Policy used to read the mirrored stripes. */
|
2020-10-28 21:14:46 +08:00
|
|
|
enum btrfs_read_policy read_policy;
|
2008-03-25 03:02:07 +08:00
|
|
|
};
|
|
|
|
|
2019-03-08 14:20:03 +08: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)
|
|
|
|
|
2021-09-15 15:17:16 +08:00
|
|
|
struct btrfs_io_stripe {
|
2008-04-10 04:28:12 +08:00
|
|
|
struct btrfs_device *dev;
|
2023-09-15 00:06:58 +08:00
|
|
|
/* Block mapping. */
|
|
|
|
u64 physical;
|
|
|
|
u64 length;
|
2023-09-15 00:07:01 +08:00
|
|
|
bool is_scrub;
|
2023-09-15 00:06:58 +08:00
|
|
|
/* For the endio handler. */
|
|
|
|
struct btrfs_io_context *bioc;
|
2022-06-03 14:57:25 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
struct btrfs_discard_stripe {
|
|
|
|
struct btrfs_device *dev;
|
|
|
|
u64 physical;
|
|
|
|
u64 length;
|
2008-04-10 04:28:12 +08:00
|
|
|
};
|
|
|
|
|
2021-09-15 15:17:16 +08:00
|
|
|
/*
|
|
|
|
* Context for IO subsmission for device stripe.
|
|
|
|
*
|
|
|
|
* - Track the unfinished mirrors for mirror based profiles
|
|
|
|
* Mirror based profiles are SINGLE/DUP/RAID1/RAID10.
|
|
|
|
*
|
|
|
|
* - Contain the logical -> physical mapping info
|
|
|
|
* Used by submit_stripe_bio() for mapping logical bio
|
|
|
|
* into physical device address.
|
|
|
|
*
|
|
|
|
* - Contain device replace info
|
|
|
|
* Used by handle_ops_on_dev_replace() to copy logical bios
|
|
|
|
* into the new device.
|
|
|
|
*
|
|
|
|
* - Contain RAID56 full stripe logical bytenrs
|
|
|
|
*/
|
|
|
|
struct btrfs_io_context {
|
2017-03-03 16:55:10 +08:00
|
|
|
refcount_t refs;
|
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 16:46:55 +08:00
|
|
|
struct btrfs_fs_info *fs_info;
|
btrfs: use a dedicated data structure for chunk maps
Currently we abuse the extent_map structure for two purposes:
1) To actually represent extents for inodes;
2) To represent chunk mappings.
This is odd and has several disadvantages:
1) To create a chunk map, we need to do two memory allocations: one for
an extent_map structure and another one for a map_lookup structure, so
more potential for an allocation failure and more complicated code to
manage and link two structures;
2) For a chunk map we actually only use 3 fields (24 bytes) of the
respective extent map structure: the 'start' field to have the logical
start address of the chunk, the 'len' field to have the chunk's size,
and the 'orig_block_len' field to contain the chunk's stripe size.
Besides wasting a memory, it's also odd and not intuitive at all to
have the stripe size in a field named 'orig_block_len'.
We are also using 'block_len' of the extent_map structure to contain
the chunk size, so we have 2 fields for the same value, 'len' and
'block_len', which is pointless;
3) When an extent map is associated to a chunk mapping, we set the bit
EXTENT_FLAG_FS_MAPPING on its flags and then make its member named
'map_lookup' point to the associated map_lookup structure. This means
that for an extent map associated to an inode extent, we are not using
this 'map_lookup' pointer, so wasting 8 bytes (on a 64 bits platform);
4) Extent maps associated to a chunk mapping are never merged or split so
it's pointless to use the existing extent map infrastructure.
So add a dedicated data structure named 'btrfs_chunk_map' to represent
chunk mappings, this is basically the existing map_lookup structure with
some extra fields:
1) 'start' to contain the chunk logical address;
2) 'chunk_len' to contain the chunk's length;
3) 'stripe_size' for the stripe size;
4) 'rb_node' for insertion into a rb tree;
5) 'refs' for reference counting.
This way we do a single memory allocation for chunk mappings and we don't
waste memory for them with unused/unnecessary fields from an extent_map.
We also save 8 bytes from the extent_map structure by removing the
'map_lookup' pointer, so the size of struct extent_map is reduced from
144 bytes down to 136 bytes, and we can now have 30 extents map per 4K
page instead of 28.
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>
2023-11-21 21:38:38 +08:00
|
|
|
/* Taken from struct btrfs_chunk_map::type. */
|
|
|
|
u64 map_type;
|
2008-08-05 22:13:57 +08:00
|
|
|
struct bio *orig_bio;
|
2008-04-29 21:38:00 +08:00
|
|
|
atomic_t error;
|
2023-02-07 12:26:13 +08:00
|
|
|
u16 max_errors;
|
|
|
|
|
2023-09-15 00:06:58 +08:00
|
|
|
u64 logical;
|
|
|
|
u64 size;
|
|
|
|
/* Raid stripe tree ordered entry. */
|
|
|
|
struct list_head rst_ordered_entry;
|
|
|
|
|
2023-02-07 12:26:13 +08:00
|
|
|
/*
|
|
|
|
* The total number of stripes, including the extra duplicated
|
|
|
|
* stripe for replace.
|
|
|
|
*/
|
|
|
|
u16 num_stripes;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The mirror_num of this bioc.
|
|
|
|
*
|
|
|
|
* This is for reads which use 0 as mirror_num, thus we should return a
|
|
|
|
* valid mirror_num (>0) for the reader.
|
|
|
|
*/
|
|
|
|
u16 mirror_num;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The following two members are for dev-replace case only.
|
|
|
|
*
|
btrfs: use an efficient way to represent source of duplicated stripes
For btrfs dev-replace, we have to duplicate writes to the source
device into the target device.
For non-RAID56, all writes into the same mapped ranges are sharing the
same content, thus they don't really need to bother anything.
(E.g. in btrfs_submit_bio() for non-RAID56 range we just submit the
same write to all involved devices).
But for RAID56, all stripes contain different content, thus we must
have a clear mapping of which stripe is duplicated from which original
stripe.
Currently we use a complex way using tgtdev_map[] array, e.g:
num_tgtdevs = 1
tgtdev_map[0] = 0 <- Means stripes[0] is not involved in replace.
tgtdev_map[1] = 3 <- Means stripes[1] is involved in replace,
and it's duplicated to stripes[3].
tgtdev_map[2] = 0 <- Means stripes[2] is not involved in replace.
But this is wasting some space, and ignores one important thing for
dev-replace, there is at most one running replace.
Thus we can change it to a fixed array to represent the mapping:
replace_nr_stripes = 1
replace_stripe_src = 1 <- Means stripes[1] is involved in replace.
thus the extra stripe is a copy of
stripes[1]
By this we can save some space for bioc on RAID56 chunks with many
devices. And we get rid of one variable sized array from bioc.
Thus the patch involves the following changes:
- Replace @num_tgtdevs and @tgtdev_map[] with @replace_nr_stripes
and @replace_stripe_src.
@num_tgtdevs is just renamed to @replace_nr_stripes.
While the mapping is completely changed.
- Add extra ASSERT()s for RAID56 code
- Only add two more extra stripes for dev-replace cases.
As we have an upper limit on how many dev-replace stripes we can have.
- Unify the behavior of handle_ops_on_dev_replace()
Previously handle_ops_on_dev_replace() go two different paths for
WRITE and GET_READ_MIRRORS.
Now unify them by always going the WRITE path first (with at most 2
replace stripes), then if we're doing GET_READ_MIRRORS and we have 2
extra stripes, just drop one stripe.
- Remove the @real_stripes argument from alloc_btrfs_io_context()
As we don't need the old variable length array any more.
Signed-off-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2023-02-07 12:26:14 +08:00
|
|
|
* @replace_nr_stripes: Number of duplicated stripes which need to be
|
2023-02-07 12:26:13 +08:00
|
|
|
* written to replace target.
|
|
|
|
* Should be <= 2 (2 for DUP, otherwise <= 1).
|
btrfs: use an efficient way to represent source of duplicated stripes
For btrfs dev-replace, we have to duplicate writes to the source
device into the target device.
For non-RAID56, all writes into the same mapped ranges are sharing the
same content, thus they don't really need to bother anything.
(E.g. in btrfs_submit_bio() for non-RAID56 range we just submit the
same write to all involved devices).
But for RAID56, all stripes contain different content, thus we must
have a clear mapping of which stripe is duplicated from which original
stripe.
Currently we use a complex way using tgtdev_map[] array, e.g:
num_tgtdevs = 1
tgtdev_map[0] = 0 <- Means stripes[0] is not involved in replace.
tgtdev_map[1] = 3 <- Means stripes[1] is involved in replace,
and it's duplicated to stripes[3].
tgtdev_map[2] = 0 <- Means stripes[2] is not involved in replace.
But this is wasting some space, and ignores one important thing for
dev-replace, there is at most one running replace.
Thus we can change it to a fixed array to represent the mapping:
replace_nr_stripes = 1
replace_stripe_src = 1 <- Means stripes[1] is involved in replace.
thus the extra stripe is a copy of
stripes[1]
By this we can save some space for bioc on RAID56 chunks with many
devices. And we get rid of one variable sized array from bioc.
Thus the patch involves the following changes:
- Replace @num_tgtdevs and @tgtdev_map[] with @replace_nr_stripes
and @replace_stripe_src.
@num_tgtdevs is just renamed to @replace_nr_stripes.
While the mapping is completely changed.
- Add extra ASSERT()s for RAID56 code
- Only add two more extra stripes for dev-replace cases.
As we have an upper limit on how many dev-replace stripes we can have.
- Unify the behavior of handle_ops_on_dev_replace()
Previously handle_ops_on_dev_replace() go two different paths for
WRITE and GET_READ_MIRRORS.
Now unify them by always going the WRITE path first (with at most 2
replace stripes), then if we're doing GET_READ_MIRRORS and we have 2
extra stripes, just drop one stripe.
- Remove the @real_stripes argument from alloc_btrfs_io_context()
As we don't need the old variable length array any more.
Signed-off-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2023-02-07 12:26:14 +08:00
|
|
|
* @replace_stripe_src: The array indicates where the duplicated stripes
|
|
|
|
* are from.
|
2023-02-07 12:26:13 +08:00
|
|
|
*
|
btrfs: use an efficient way to represent source of duplicated stripes
For btrfs dev-replace, we have to duplicate writes to the source
device into the target device.
For non-RAID56, all writes into the same mapped ranges are sharing the
same content, thus they don't really need to bother anything.
(E.g. in btrfs_submit_bio() for non-RAID56 range we just submit the
same write to all involved devices).
But for RAID56, all stripes contain different content, thus we must
have a clear mapping of which stripe is duplicated from which original
stripe.
Currently we use a complex way using tgtdev_map[] array, e.g:
num_tgtdevs = 1
tgtdev_map[0] = 0 <- Means stripes[0] is not involved in replace.
tgtdev_map[1] = 3 <- Means stripes[1] is involved in replace,
and it's duplicated to stripes[3].
tgtdev_map[2] = 0 <- Means stripes[2] is not involved in replace.
But this is wasting some space, and ignores one important thing for
dev-replace, there is at most one running replace.
Thus we can change it to a fixed array to represent the mapping:
replace_nr_stripes = 1
replace_stripe_src = 1 <- Means stripes[1] is involved in replace.
thus the extra stripe is a copy of
stripes[1]
By this we can save some space for bioc on RAID56 chunks with many
devices. And we get rid of one variable sized array from bioc.
Thus the patch involves the following changes:
- Replace @num_tgtdevs and @tgtdev_map[] with @replace_nr_stripes
and @replace_stripe_src.
@num_tgtdevs is just renamed to @replace_nr_stripes.
While the mapping is completely changed.
- Add extra ASSERT()s for RAID56 code
- Only add two more extra stripes for dev-replace cases.
As we have an upper limit on how many dev-replace stripes we can have.
- Unify the behavior of handle_ops_on_dev_replace()
Previously handle_ops_on_dev_replace() go two different paths for
WRITE and GET_READ_MIRRORS.
Now unify them by always going the WRITE path first (with at most 2
replace stripes), then if we're doing GET_READ_MIRRORS and we have 2
extra stripes, just drop one stripe.
- Remove the @real_stripes argument from alloc_btrfs_io_context()
As we don't need the old variable length array any more.
Signed-off-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2023-02-07 12:26:14 +08:00
|
|
|
* The @replace_stripe_src[] array is mostly for RAID56 cases.
|
2023-02-07 12:26:13 +08:00
|
|
|
* As non-RAID56 stripes share the same contents of the mapped range,
|
|
|
|
* thus no need to bother where the duplicated ones are from.
|
|
|
|
*
|
|
|
|
* But for RAID56 case, all stripes contain different contents, thus
|
|
|
|
* we need a way to know the mapping.
|
|
|
|
*
|
|
|
|
* There is an example for the two members, using a RAID5 write:
|
|
|
|
*
|
|
|
|
* num_stripes: 4 (3 + 1 duplicated write)
|
|
|
|
* stripes[0]: dev = devid 1, physical = X
|
|
|
|
* stripes[1]: dev = devid 2, physical = Y
|
|
|
|
* stripes[2]: dev = devid 3, physical = Z
|
|
|
|
* stripes[3]: dev = devid 0, physical = Y
|
|
|
|
*
|
btrfs: use an efficient way to represent source of duplicated stripes
For btrfs dev-replace, we have to duplicate writes to the source
device into the target device.
For non-RAID56, all writes into the same mapped ranges are sharing the
same content, thus they don't really need to bother anything.
(E.g. in btrfs_submit_bio() for non-RAID56 range we just submit the
same write to all involved devices).
But for RAID56, all stripes contain different content, thus we must
have a clear mapping of which stripe is duplicated from which original
stripe.
Currently we use a complex way using tgtdev_map[] array, e.g:
num_tgtdevs = 1
tgtdev_map[0] = 0 <- Means stripes[0] is not involved in replace.
tgtdev_map[1] = 3 <- Means stripes[1] is involved in replace,
and it's duplicated to stripes[3].
tgtdev_map[2] = 0 <- Means stripes[2] is not involved in replace.
But this is wasting some space, and ignores one important thing for
dev-replace, there is at most one running replace.
Thus we can change it to a fixed array to represent the mapping:
replace_nr_stripes = 1
replace_stripe_src = 1 <- Means stripes[1] is involved in replace.
thus the extra stripe is a copy of
stripes[1]
By this we can save some space for bioc on RAID56 chunks with many
devices. And we get rid of one variable sized array from bioc.
Thus the patch involves the following changes:
- Replace @num_tgtdevs and @tgtdev_map[] with @replace_nr_stripes
and @replace_stripe_src.
@num_tgtdevs is just renamed to @replace_nr_stripes.
While the mapping is completely changed.
- Add extra ASSERT()s for RAID56 code
- Only add two more extra stripes for dev-replace cases.
As we have an upper limit on how many dev-replace stripes we can have.
- Unify the behavior of handle_ops_on_dev_replace()
Previously handle_ops_on_dev_replace() go two different paths for
WRITE and GET_READ_MIRRORS.
Now unify them by always going the WRITE path first (with at most 2
replace stripes), then if we're doing GET_READ_MIRRORS and we have 2
extra stripes, just drop one stripe.
- Remove the @real_stripes argument from alloc_btrfs_io_context()
As we don't need the old variable length array any more.
Signed-off-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2023-02-07 12:26:14 +08:00
|
|
|
* replace_nr_stripes = 1
|
|
|
|
* replace_stripe_src = 1 <- Means stripes[1] is involved in replace.
|
|
|
|
* The duplicated stripe index would be
|
|
|
|
* (@num_stripes - 1).
|
|
|
|
*
|
|
|
|
* Note, that we can still have cases replace_nr_stripes = 2 for DUP.
|
|
|
|
* In that case, all stripes share the same content, thus we don't
|
|
|
|
* need to bother @replace_stripe_src value at all.
|
2023-02-07 12:26:13 +08:00
|
|
|
*/
|
btrfs: use an efficient way to represent source of duplicated stripes
For btrfs dev-replace, we have to duplicate writes to the source
device into the target device.
For non-RAID56, all writes into the same mapped ranges are sharing the
same content, thus they don't really need to bother anything.
(E.g. in btrfs_submit_bio() for non-RAID56 range we just submit the
same write to all involved devices).
But for RAID56, all stripes contain different content, thus we must
have a clear mapping of which stripe is duplicated from which original
stripe.
Currently we use a complex way using tgtdev_map[] array, e.g:
num_tgtdevs = 1
tgtdev_map[0] = 0 <- Means stripes[0] is not involved in replace.
tgtdev_map[1] = 3 <- Means stripes[1] is involved in replace,
and it's duplicated to stripes[3].
tgtdev_map[2] = 0 <- Means stripes[2] is not involved in replace.
But this is wasting some space, and ignores one important thing for
dev-replace, there is at most one running replace.
Thus we can change it to a fixed array to represent the mapping:
replace_nr_stripes = 1
replace_stripe_src = 1 <- Means stripes[1] is involved in replace.
thus the extra stripe is a copy of
stripes[1]
By this we can save some space for bioc on RAID56 chunks with many
devices. And we get rid of one variable sized array from bioc.
Thus the patch involves the following changes:
- Replace @num_tgtdevs and @tgtdev_map[] with @replace_nr_stripes
and @replace_stripe_src.
@num_tgtdevs is just renamed to @replace_nr_stripes.
While the mapping is completely changed.
- Add extra ASSERT()s for RAID56 code
- Only add two more extra stripes for dev-replace cases.
As we have an upper limit on how many dev-replace stripes we can have.
- Unify the behavior of handle_ops_on_dev_replace()
Previously handle_ops_on_dev_replace() go two different paths for
WRITE and GET_READ_MIRRORS.
Now unify them by always going the WRITE path first (with at most 2
replace stripes), then if we're doing GET_READ_MIRRORS and we have 2
extra stripes, just drop one stripe.
- Remove the @real_stripes argument from alloc_btrfs_io_context()
As we don't need the old variable length array any more.
Signed-off-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2023-02-07 12:26:14 +08:00
|
|
|
u16 replace_nr_stripes;
|
|
|
|
s16 replace_stripe_src;
|
2015-01-20 15:11:33 +08:00
|
|
|
/*
|
2023-02-17 13:37:03 +08:00
|
|
|
* Logical bytenr of the full stripe start, only for RAID56 cases.
|
|
|
|
*
|
|
|
|
* When this value is set to other than (u64)-1, the stripes[] should
|
|
|
|
* follow this pattern:
|
|
|
|
*
|
|
|
|
* (real_stripes = num_stripes - replace_nr_stripes)
|
|
|
|
* (data_stripes = (is_raid6) ? (real_stripes - 2) : (real_stripes - 1))
|
|
|
|
*
|
|
|
|
* stripes[0]: The first data stripe
|
|
|
|
* stripes[1]: The second data stripe
|
|
|
|
* ...
|
|
|
|
* stripes[data_stripes - 1]: The last data stripe
|
|
|
|
* stripes[data_stripes]: The P stripe
|
|
|
|
* stripes[data_stripes + 1]: The Q stripe (only for RAID6).
|
2015-01-20 15:11:33 +08:00
|
|
|
*/
|
2023-02-17 13:37:03 +08:00
|
|
|
u64 full_stripe_logical;
|
2021-09-15 15:17:16 +08:00
|
|
|
struct btrfs_io_stripe stripes[];
|
2008-04-10 04:28:12 +08:00
|
|
|
};
|
|
|
|
|
2011-01-05 18:07:28 +08: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 18:07:57 +08:00
|
|
|
u64 total_avail;
|
2011-01-05 18:07:28 +08:00
|
|
|
};
|
|
|
|
|
2012-11-21 22:18:10 +08:00
|
|
|
struct btrfs_raid_attr {
|
2019-05-17 17:43:36 +08: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 05:24:42 +08:00
|
|
|
* parity information */
|
2019-05-17 17:43:36 +08:00
|
|
|
u8 mindev_error; /* error code if min devs requisite is unmet */
|
2018-04-25 19:01:42 +08:00
|
|
|
const char raid_name[8]; /* name of the raid */
|
2018-04-25 19:01:43 +08:00
|
|
|
u64 bg_flag; /* block group flag of the raid */
|
2012-11-21 22:18:10 +08:00
|
|
|
};
|
|
|
|
|
2015-09-15 21:08:06 +08:00
|
|
|
extern const struct btrfs_raid_attr btrfs_raid_array[BTRFS_NR_RAID_TYPES];
|
|
|
|
|
btrfs: use a dedicated data structure for chunk maps
Currently we abuse the extent_map structure for two purposes:
1) To actually represent extents for inodes;
2) To represent chunk mappings.
This is odd and has several disadvantages:
1) To create a chunk map, we need to do two memory allocations: one for
an extent_map structure and another one for a map_lookup structure, so
more potential for an allocation failure and more complicated code to
manage and link two structures;
2) For a chunk map we actually only use 3 fields (24 bytes) of the
respective extent map structure: the 'start' field to have the logical
start address of the chunk, the 'len' field to have the chunk's size,
and the 'orig_block_len' field to contain the chunk's stripe size.
Besides wasting a memory, it's also odd and not intuitive at all to
have the stripe size in a field named 'orig_block_len'.
We are also using 'block_len' of the extent_map structure to contain
the chunk size, so we have 2 fields for the same value, 'len' and
'block_len', which is pointless;
3) When an extent map is associated to a chunk mapping, we set the bit
EXTENT_FLAG_FS_MAPPING on its flags and then make its member named
'map_lookup' point to the associated map_lookup structure. This means
that for an extent map associated to an inode extent, we are not using
this 'map_lookup' pointer, so wasting 8 bytes (on a 64 bits platform);
4) Extent maps associated to a chunk mapping are never merged or split so
it's pointless to use the existing extent map infrastructure.
So add a dedicated data structure named 'btrfs_chunk_map' to represent
chunk mappings, this is basically the existing map_lookup structure with
some extra fields:
1) 'start' to contain the chunk logical address;
2) 'chunk_len' to contain the chunk's length;
3) 'stripe_size' for the stripe size;
4) 'rb_node' for insertion into a rb tree;
5) 'refs' for reference counting.
This way we do a single memory allocation for chunk mappings and we don't
waste memory for them with unused/unnecessary fields from an extent_map.
We also save 8 bytes from the extent_map structure by removing the
'map_lookup' pointer, so the size of struct extent_map is reduced from
144 bytes down to 136 bytes, and we can now have 30 extents map per 4K
page instead of 28.
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>
2023-11-21 21:38:38 +08:00
|
|
|
struct btrfs_chunk_map {
|
|
|
|
struct rb_node rb_node;
|
|
|
|
/* For mount time dev extent verification. */
|
|
|
|
int verified_stripes;
|
|
|
|
refcount_t refs;
|
|
|
|
u64 start;
|
|
|
|
u64 chunk_len;
|
|
|
|
u64 stripe_size;
|
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 19:18:59 +08:00
|
|
|
u64 type;
|
|
|
|
int io_align;
|
|
|
|
int io_width;
|
|
|
|
int num_stripes;
|
|
|
|
int sub_stripes;
|
2021-09-15 15:17:16 +08:00
|
|
|
struct btrfs_io_stripe stripes[];
|
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 19:18:59 +08:00
|
|
|
};
|
|
|
|
|
btrfs: use a dedicated data structure for chunk maps
Currently we abuse the extent_map structure for two purposes:
1) To actually represent extents for inodes;
2) To represent chunk mappings.
This is odd and has several disadvantages:
1) To create a chunk map, we need to do two memory allocations: one for
an extent_map structure and another one for a map_lookup structure, so
more potential for an allocation failure and more complicated code to
manage and link two structures;
2) For a chunk map we actually only use 3 fields (24 bytes) of the
respective extent map structure: the 'start' field to have the logical
start address of the chunk, the 'len' field to have the chunk's size,
and the 'orig_block_len' field to contain the chunk's stripe size.
Besides wasting a memory, it's also odd and not intuitive at all to
have the stripe size in a field named 'orig_block_len'.
We are also using 'block_len' of the extent_map structure to contain
the chunk size, so we have 2 fields for the same value, 'len' and
'block_len', which is pointless;
3) When an extent map is associated to a chunk mapping, we set the bit
EXTENT_FLAG_FS_MAPPING on its flags and then make its member named
'map_lookup' point to the associated map_lookup structure. This means
that for an extent map associated to an inode extent, we are not using
this 'map_lookup' pointer, so wasting 8 bytes (on a 64 bits platform);
4) Extent maps associated to a chunk mapping are never merged or split so
it's pointless to use the existing extent map infrastructure.
So add a dedicated data structure named 'btrfs_chunk_map' to represent
chunk mappings, this is basically the existing map_lookup structure with
some extra fields:
1) 'start' to contain the chunk logical address;
2) 'chunk_len' to contain the chunk's length;
3) 'stripe_size' for the stripe size;
4) 'rb_node' for insertion into a rb tree;
5) 'refs' for reference counting.
This way we do a single memory allocation for chunk mappings and we don't
waste memory for them with unused/unnecessary fields from an extent_map.
We also save 8 bytes from the extent_map structure by removing the
'map_lookup' pointer, so the size of struct extent_map is reduced from
144 bytes down to 136 bytes, and we can now have 30 extents map per 4K
page instead of 28.
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>
2023-11-21 21:38:38 +08:00
|
|
|
#define btrfs_chunk_map_size(n) (sizeof(struct btrfs_chunk_map) + \
|
|
|
|
(sizeof(struct btrfs_io_stripe) * (n)))
|
|
|
|
|
|
|
|
static inline void btrfs_free_chunk_map(struct btrfs_chunk_map *map)
|
|
|
|
{
|
|
|
|
if (map && refcount_dec_and_test(&map->refs)) {
|
|
|
|
ASSERT(RB_EMPTY_NODE(&map->rb_node));
|
|
|
|
kfree(map);
|
|
|
|
}
|
|
|
|
}
|
2011-03-08 21:14:00 +08:00
|
|
|
|
2012-01-17 04:04:47 +08:00
|
|
|
struct btrfs_balance_args;
|
2012-01-17 04:04:49 +08:00
|
|
|
struct btrfs_balance_progress;
|
2012-01-17 04:04:47 +08: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 04:04:49 +08:00
|
|
|
|
|
|
|
struct btrfs_balance_progress stat;
|
2012-01-17 04:04:47 +08:00
|
|
|
};
|
|
|
|
|
2021-10-06 04:12:42 +08:00
|
|
|
/*
|
|
|
|
* Search for a given device by the set parameters
|
|
|
|
*/
|
|
|
|
struct btrfs_dev_lookup_args {
|
|
|
|
u64 devid;
|
|
|
|
u8 *uuid;
|
|
|
|
u8 *fsid;
|
|
|
|
bool missing;
|
|
|
|
};
|
|
|
|
|
|
|
|
/* We have to initialize to -1 because BTRFS_DEV_REPLACE_DEVID is 0 */
|
|
|
|
#define BTRFS_DEV_LOOKUP_ARGS_INIT { .devid = (u64)-1 }
|
|
|
|
|
|
|
|
#define BTRFS_DEV_LOOKUP_ARGS(name) \
|
|
|
|
struct btrfs_dev_lookup_args name = BTRFS_DEV_LOOKUP_ARGS_INIT
|
|
|
|
|
2016-10-27 15:27:36 +08:00
|
|
|
enum btrfs_map_op {
|
|
|
|
BTRFS_MAP_READ,
|
|
|
|
BTRFS_MAP_WRITE,
|
|
|
|
BTRFS_MAP_GET_READ_MIRRORS,
|
|
|
|
};
|
|
|
|
|
|
|
|
static inline enum btrfs_map_op btrfs_op(struct bio *bio)
|
|
|
|
{
|
|
|
|
switch (bio_op(bio)) {
|
|
|
|
case REQ_OP_WRITE:
|
2021-02-04 18:21:59 +08:00
|
|
|
case REQ_OP_ZONE_APPEND:
|
2016-10-27 15:27:36 +08:00
|
|
|
return BTRFS_MAP_WRITE;
|
|
|
|
default:
|
|
|
|
WARN_ON_ONCE(1);
|
2020-06-17 02:54:29 +08:00
|
|
|
fallthrough;
|
2016-10-27 15:27:36 +08:00
|
|
|
case REQ_OP_READ:
|
|
|
|
return BTRFS_MAP_READ;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-27 03:08:17 +08:00
|
|
|
static inline unsigned long btrfs_chunk_item_size(int num_stripes)
|
|
|
|
{
|
|
|
|
ASSERT(num_stripes);
|
|
|
|
return sizeof(struct btrfs_chunk) +
|
|
|
|
sizeof(struct btrfs_stripe) * (num_stripes - 1);
|
|
|
|
}
|
|
|
|
|
2023-06-22 14:42:40 +08:00
|
|
|
/*
|
2023-12-06 02:26:39 +08:00
|
|
|
* Do the type safe conversion from stripe_nr to offset inside the chunk.
|
2023-06-22 14:42:40 +08:00
|
|
|
*
|
|
|
|
* @stripe_nr is u32, with left shift it can overflow u32 for chunks larger
|
|
|
|
* than 4G. This does the proper type cast to avoid overflow.
|
|
|
|
*/
|
|
|
|
static inline u64 btrfs_stripe_nr_to_offset(u32 stripe_nr)
|
|
|
|
{
|
|
|
|
return (u64)stripe_nr << BTRFS_STRIPE_LEN_SHIFT;
|
|
|
|
}
|
|
|
|
|
2021-09-15 15:17:16 +08:00
|
|
|
void btrfs_get_bioc(struct btrfs_io_context *bioc);
|
|
|
|
void btrfs_put_bioc(struct btrfs_io_context *bioc);
|
2016-10-27 15:27:36 +08:00
|
|
|
int btrfs_map_block(struct btrfs_fs_info *fs_info, enum btrfs_map_op op,
|
2008-04-10 04:28:12 +08:00
|
|
|
u64 logical, u64 *length,
|
2023-05-31 12:17:37 +08:00
|
|
|
struct btrfs_io_context **bioc_ret,
|
2023-09-17 18:06:21 +08:00
|
|
|
struct btrfs_io_stripe *smap, int *mirror_num_ret);
|
2023-03-20 10:12:49 +08:00
|
|
|
int btrfs_map_repair_block(struct btrfs_fs_info *fs_info,
|
|
|
|
struct btrfs_io_stripe *smap, u64 logical,
|
|
|
|
u32 length, int mirror_num);
|
2022-06-03 14:57:25 +08:00
|
|
|
struct btrfs_discard_stripe *btrfs_map_discard(struct btrfs_fs_info *fs_info,
|
|
|
|
u64 logical, u64 *length_ret,
|
|
|
|
u32 *num_stripes);
|
2016-06-22 09:16:51 +08:00
|
|
|
int btrfs_read_sys_array(struct btrfs_fs_info *fs_info);
|
2016-06-21 22:40:19 +08:00
|
|
|
int btrfs_read_chunk_tree(struct btrfs_fs_info *fs_info);
|
2021-08-18 18:41:19 +08:00
|
|
|
struct btrfs_block_group *btrfs_create_chunk(struct btrfs_trans_handle *trans,
|
btrfs: rework chunk allocation to avoid exhaustion of the system chunk array
Commit eafa4fd0ad0607 ("btrfs: fix exhaustion of the system chunk array
due to concurrent allocations") fixed a problem that resulted in
exhausting the system chunk array in the superblock when there are many
tasks allocating chunks in parallel. Basically too many tasks enter the
first phase of chunk allocation without previous tasks having finished
their second phase of allocation, resulting in too many system chunks
being allocated. That was originally observed when running the fallocate
tests of stress-ng on a PowerPC machine, using a node size of 64K.
However that commit also introduced a deadlock where a task in phase 1 of
the chunk allocation waited for another task that had allocated a system
chunk to finish its phase 2, but that other task was waiting on an extent
buffer lock held by the first task, therefore resulting in both tasks not
making any progress. That change was later reverted by a patch with the
subject "btrfs: fix deadlock with concurrent chunk allocations involving
system chunks", since there is no simple and short solution to address it
and the deadlock is relatively easy to trigger on zoned filesystems, while
the system chunk array exhaustion is not so common.
This change reworks the chunk allocation to avoid the system chunk array
exhaustion. It accomplishes that by making the first phase of chunk
allocation do the updates of the device items in the chunk btree and the
insertion of the new chunk item in the chunk btree. This is done while
under the protection of the chunk mutex (fs_info->chunk_mutex), in the
same critical section that checks for available system space, allocates
a new system chunk if needed and reserves system chunk space. This way
we do not have chunk space reserved until the second phase completes.
The same logic is applied to chunk removal as well, since it keeps
reserved system space long after it is done updating the chunk btree.
For direct allocation of system chunks, the previous behaviour remains,
because otherwise we would deadlock on extent buffers of the chunk btree.
Changes to the chunk btree are by large done by chunk allocation and chunk
removal, which first reserve chunk system space and then later do changes
to the chunk btree. The other remaining cases are uncommon and correspond
to adding a device, removing a device and resizing a device. All these
other cases do not pre-reserve system space, they modify the chunk btree
right away, so they don't hold reserved space for a long period like chunk
allocation and chunk removal do.
The diff of this change is huge, but more than half of it is just addition
of comments describing both how things work regarding chunk allocation and
removal, including both the new behavior and the parts of the old behavior
that did not change.
CC: stable@vger.kernel.org # 5.12+
Tested-by: Shin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com>
Tested-by: Naohiro Aota <naohiro.aota@wdc.com>
Signed-off-by: Filipe Manana <fdmanana@suse.com>
Tested-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2021-06-29 21:43:06 +08:00
|
|
|
u64 type);
|
btrfs: use a dedicated data structure for chunk maps
Currently we abuse the extent_map structure for two purposes:
1) To actually represent extents for inodes;
2) To represent chunk mappings.
This is odd and has several disadvantages:
1) To create a chunk map, we need to do two memory allocations: one for
an extent_map structure and another one for a map_lookup structure, so
more potential for an allocation failure and more complicated code to
manage and link two structures;
2) For a chunk map we actually only use 3 fields (24 bytes) of the
respective extent map structure: the 'start' field to have the logical
start address of the chunk, the 'len' field to have the chunk's size,
and the 'orig_block_len' field to contain the chunk's stripe size.
Besides wasting a memory, it's also odd and not intuitive at all to
have the stripe size in a field named 'orig_block_len'.
We are also using 'block_len' of the extent_map structure to contain
the chunk size, so we have 2 fields for the same value, 'len' and
'block_len', which is pointless;
3) When an extent map is associated to a chunk mapping, we set the bit
EXTENT_FLAG_FS_MAPPING on its flags and then make its member named
'map_lookup' point to the associated map_lookup structure. This means
that for an extent map associated to an inode extent, we are not using
this 'map_lookup' pointer, so wasting 8 bytes (on a 64 bits platform);
4) Extent maps associated to a chunk mapping are never merged or split so
it's pointless to use the existing extent map infrastructure.
So add a dedicated data structure named 'btrfs_chunk_map' to represent
chunk mappings, this is basically the existing map_lookup structure with
some extra fields:
1) 'start' to contain the chunk logical address;
2) 'chunk_len' to contain the chunk's length;
3) 'stripe_size' for the stripe size;
4) 'rb_node' for insertion into a rb tree;
5) 'refs' for reference counting.
This way we do a single memory allocation for chunk mappings and we don't
waste memory for them with unused/unnecessary fields from an extent_map.
We also save 8 bytes from the extent_map structure by removing the
'map_lookup' pointer, so the size of struct extent_map is reduced from
144 bytes down to 136 bytes, and we can now have 30 extents map per 4K
page instead of 28.
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>
2023-11-21 21:38:38 +08:00
|
|
|
void btrfs_mapping_tree_free(struct btrfs_fs_info *fs_info);
|
2008-03-25 03:02:07 +08:00
|
|
|
int btrfs_open_devices(struct btrfs_fs_devices *fs_devices,
|
2023-06-08 19:02:55 +08:00
|
|
|
blk_mode_t flags, void *holder);
|
2023-09-09 00:31:55 +08:00
|
|
|
struct btrfs_device *btrfs_scan_one_device(const char *path, blk_mode_t flags,
|
|
|
|
bool mount_arg_dev);
|
2022-01-12 13:06:00 +08:00
|
|
|
int btrfs_forget_devices(dev_t devt);
|
2020-07-15 18:48:48 +08:00
|
|
|
void btrfs_close_devices(struct btrfs_fs_devices *fs_devices);
|
2020-11-06 16:06:33 +08:00
|
|
|
void btrfs_free_extra_devids(struct btrfs_fs_devices *fs_devices);
|
2018-07-21 00:37:50 +08:00
|
|
|
void btrfs_assign_next_active_device(struct btrfs_device *device,
|
|
|
|
struct btrfs_device *this_dev);
|
2018-09-03 17:46:14 +08:00
|
|
|
struct btrfs_device *btrfs_find_device_by_devspec(struct btrfs_fs_info *fs_info,
|
|
|
|
u64 devid,
|
|
|
|
const char *devpath);
|
2021-10-06 04:12:43 +08:00
|
|
|
int btrfs_get_dev_args_from_path(struct btrfs_fs_info *fs_info,
|
|
|
|
struct btrfs_dev_lookup_args *args,
|
|
|
|
const char *path);
|
2013-08-23 18:20:17 +08:00
|
|
|
struct btrfs_device *btrfs_alloc_device(struct btrfs_fs_info *fs_info,
|
2022-11-07 23:07:17 +08:00
|
|
|
const u64 *devid, const u8 *uuid,
|
|
|
|
const char *path);
|
2021-10-06 04:12:43 +08:00
|
|
|
void btrfs_put_dev_args_from_path(struct btrfs_dev_lookup_args *args);
|
2016-06-23 06:54:24 +08:00
|
|
|
int btrfs_rm_device(struct btrfs_fs_info *fs_info,
|
btrfs: use btrfs_get_dev_args_from_path in dev removal ioctls
For device removal and replace we call btrfs_find_device_by_devspec,
which if we give it a device path and nothing else will call
btrfs_get_dev_args_from_path, which opens the block device and reads the
super block and then looks up our device based on that.
However at this point we're holding the sb write "lock", so reading the
block device pulls in the dependency of ->open_mutex, which produces the
following lockdep splat
======================================================
WARNING: possible circular locking dependency detected
5.14.0-rc2+ #405 Not tainted
------------------------------------------------------
losetup/11576 is trying to acquire lock:
ffff9bbe8cded938 ((wq_completion)loop0){+.+.}-{0:0}, at: flush_workqueue+0x67/0x5e0
but task is already holding lock:
ffff9bbe88e4fc68 (&lo->lo_mutex){+.+.}-{3:3}, at: __loop_clr_fd+0x41/0x660 [loop]
which lock already depends on the new lock.
the existing dependency chain (in reverse order) is:
-> #4 (&lo->lo_mutex){+.+.}-{3:3}:
__mutex_lock+0x7d/0x750
lo_open+0x28/0x60 [loop]
blkdev_get_whole+0x25/0xf0
blkdev_get_by_dev.part.0+0x168/0x3c0
blkdev_open+0xd2/0xe0
do_dentry_open+0x161/0x390
path_openat+0x3cc/0xa20
do_filp_open+0x96/0x120
do_sys_openat2+0x7b/0x130
__x64_sys_openat+0x46/0x70
do_syscall_64+0x38/0x90
entry_SYSCALL_64_after_hwframe+0x44/0xae
-> #3 (&disk->open_mutex){+.+.}-{3:3}:
__mutex_lock+0x7d/0x750
blkdev_get_by_dev.part.0+0x56/0x3c0
blkdev_get_by_path+0x98/0xa0
btrfs_get_bdev_and_sb+0x1b/0xb0
btrfs_find_device_by_devspec+0x12b/0x1c0
btrfs_rm_device+0x127/0x610
btrfs_ioctl+0x2a31/0x2e70
__x64_sys_ioctl+0x80/0xb0
do_syscall_64+0x38/0x90
entry_SYSCALL_64_after_hwframe+0x44/0xae
-> #2 (sb_writers#12){.+.+}-{0:0}:
lo_write_bvec+0xc2/0x240 [loop]
loop_process_work+0x238/0xd00 [loop]
process_one_work+0x26b/0x560
worker_thread+0x55/0x3c0
kthread+0x140/0x160
ret_from_fork+0x1f/0x30
-> #1 ((work_completion)(&lo->rootcg_work)){+.+.}-{0:0}:
process_one_work+0x245/0x560
worker_thread+0x55/0x3c0
kthread+0x140/0x160
ret_from_fork+0x1f/0x30
-> #0 ((wq_completion)loop0){+.+.}-{0:0}:
__lock_acquire+0x10ea/0x1d90
lock_acquire+0xb5/0x2b0
flush_workqueue+0x91/0x5e0
drain_workqueue+0xa0/0x110
destroy_workqueue+0x36/0x250
__loop_clr_fd+0x9a/0x660 [loop]
block_ioctl+0x3f/0x50
__x64_sys_ioctl+0x80/0xb0
do_syscall_64+0x38/0x90
entry_SYSCALL_64_after_hwframe+0x44/0xae
other info that might help us debug this:
Chain exists of:
(wq_completion)loop0 --> &disk->open_mutex --> &lo->lo_mutex
Possible unsafe locking scenario:
CPU0 CPU1
---- ----
lock(&lo->lo_mutex);
lock(&disk->open_mutex);
lock(&lo->lo_mutex);
lock((wq_completion)loop0);
*** DEADLOCK ***
1 lock held by losetup/11576:
#0: ffff9bbe88e4fc68 (&lo->lo_mutex){+.+.}-{3:3}, at: __loop_clr_fd+0x41/0x660 [loop]
stack backtrace:
CPU: 0 PID: 11576 Comm: losetup Not tainted 5.14.0-rc2+ #405
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.13.0-2.fc32 04/01/2014
Call Trace:
dump_stack_lvl+0x57/0x72
check_noncircular+0xcf/0xf0
? stack_trace_save+0x3b/0x50
__lock_acquire+0x10ea/0x1d90
lock_acquire+0xb5/0x2b0
? flush_workqueue+0x67/0x5e0
? lockdep_init_map_type+0x47/0x220
flush_workqueue+0x91/0x5e0
? flush_workqueue+0x67/0x5e0
? verify_cpu+0xf0/0x100
drain_workqueue+0xa0/0x110
destroy_workqueue+0x36/0x250
__loop_clr_fd+0x9a/0x660 [loop]
? blkdev_ioctl+0x8d/0x2a0
block_ioctl+0x3f/0x50
__x64_sys_ioctl+0x80/0xb0
do_syscall_64+0x38/0x90
entry_SYSCALL_64_after_hwframe+0x44/0xae
RIP: 0033:0x7f31b02404cb
Instead what we want to do is populate our device lookup args before we
grab any locks, and then pass these args into btrfs_rm_device(). From
there we can find the device and do the appropriate removal.
Suggested-by: Anand Jain <anand.jain@oracle.com>
Reviewed-by: Anand Jain <anand.jain@oracle.com>
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2021-10-06 04:12:44 +08:00
|
|
|
struct btrfs_dev_lookup_args *args,
|
2023-09-27 17:34:26 +08:00
|
|
|
struct bdev_handle **bdev_handle);
|
2018-02-20 00:24:15 +08:00
|
|
|
void __exit btrfs_cleanup_fs_uuids(void);
|
2012-11-05 21:59:07 +08:00
|
|
|
int btrfs_num_copies(struct btrfs_fs_info *fs_info, u64 logical, u64 len);
|
2008-04-26 04:53:30 +08:00
|
|
|
int btrfs_grow_device(struct btrfs_trans_handle *trans,
|
|
|
|
struct btrfs_device *device, u64 new_size);
|
2021-10-06 04:12:42 +08:00
|
|
|
struct btrfs_device *btrfs_find_device(const struct btrfs_fs_devices *fs_devices,
|
|
|
|
const struct btrfs_dev_lookup_args *args);
|
2008-04-26 04:53:30 +08:00
|
|
|
int btrfs_shrink_device(struct btrfs_device *device, u64 new_size);
|
2017-02-15 00:55:53 +08:00
|
|
|
int btrfs_init_new_device(struct btrfs_fs_info *fs_info, const char *path);
|
2018-05-07 23:44:03 +08:00
|
|
|
int btrfs_balance(struct btrfs_fs_info *fs_info,
|
|
|
|
struct btrfs_balance_control *bctl,
|
2012-01-17 04:04:47 +08:00
|
|
|
struct btrfs_ioctl_balance_args *bargs);
|
2018-11-20 16:12:55 +08:00
|
|
|
void btrfs_describe_block_groups(u64 flags, char *buf, u32 size_buf);
|
2012-06-23 02:24:13 +08:00
|
|
|
int btrfs_resume_balance_async(struct btrfs_fs_info *fs_info);
|
2012-06-23 02:24:12 +08:00
|
|
|
int btrfs_recover_balance(struct btrfs_fs_info *fs_info);
|
2012-01-17 04:04:49 +08:00
|
|
|
int btrfs_pause_balance(struct btrfs_fs_info *fs_info);
|
2021-04-19 15:41:02 +08:00
|
|
|
int btrfs_relocate_chunk(struct btrfs_fs_info *fs_info, u64 chunk_offset);
|
2012-01-17 04:04:49 +08:00
|
|
|
int btrfs_cancel_balance(struct btrfs_fs_info *fs_info);
|
2013-08-15 23:11:19 +08:00
|
|
|
int btrfs_create_uuid_tree(struct btrfs_fs_info *fs_info);
|
2020-02-18 22:56:08 +08:00
|
|
|
int btrfs_uuid_scan_kthread(void *data);
|
2021-08-24 13:27:42 +08:00
|
|
|
bool btrfs_chunk_writeable(struct btrfs_fs_info *fs_info, u64 chunk_offset);
|
2012-05-25 22:06:08 +08:00
|
|
|
void btrfs_dev_stat_inc_and_print(struct btrfs_device *dev, int index);
|
2016-06-23 06:54:24 +08:00
|
|
|
int btrfs_get_dev_stats(struct btrfs_fs_info *fs_info,
|
2012-06-22 20:30:39 +08:00
|
|
|
struct btrfs_ioctl_get_dev_stats *stats);
|
2022-11-04 22:12:34 +08:00
|
|
|
int btrfs_init_devices_late(struct btrfs_fs_info *fs_info);
|
2012-05-25 22:06:10 +08:00
|
|
|
int btrfs_init_dev_stats(struct btrfs_fs_info *fs_info);
|
2019-03-20 23:50:38 +08:00
|
|
|
int btrfs_run_dev_stats(struct btrfs_trans_handle *trans);
|
2018-07-21 00:37:48 +08:00
|
|
|
void btrfs_rm_dev_replace_remove_srcdev(struct btrfs_device *srcdev);
|
2019-03-20 23:34:54 +08:00
|
|
|
void btrfs_rm_dev_replace_free_srcdev(struct btrfs_device *srcdev);
|
2018-07-21 00:37:51 +08:00
|
|
|
void btrfs_destroy_dev_replace_tgtdev(struct btrfs_device *tgtdev);
|
2017-03-15 04:33:55 +08:00
|
|
|
int btrfs_is_parity_mirror(struct btrfs_fs_info *fs_info,
|
2017-07-19 15:48:42 +08:00
|
|
|
u64 logical, u64 len);
|
2016-06-23 06:54:24 +08:00
|
|
|
unsigned long btrfs_full_stripe_len(struct btrfs_fs_info *fs_info,
|
2013-01-30 07:40:14 +08:00
|
|
|
u64 logical);
|
btrfs: use a dedicated data structure for chunk maps
Currently we abuse the extent_map structure for two purposes:
1) To actually represent extents for inodes;
2) To represent chunk mappings.
This is odd and has several disadvantages:
1) To create a chunk map, we need to do two memory allocations: one for
an extent_map structure and another one for a map_lookup structure, so
more potential for an allocation failure and more complicated code to
manage and link two structures;
2) For a chunk map we actually only use 3 fields (24 bytes) of the
respective extent map structure: the 'start' field to have the logical
start address of the chunk, the 'len' field to have the chunk's size,
and the 'orig_block_len' field to contain the chunk's stripe size.
Besides wasting a memory, it's also odd and not intuitive at all to
have the stripe size in a field named 'orig_block_len'.
We are also using 'block_len' of the extent_map structure to contain
the chunk size, so we have 2 fields for the same value, 'len' and
'block_len', which is pointless;
3) When an extent map is associated to a chunk mapping, we set the bit
EXTENT_FLAG_FS_MAPPING on its flags and then make its member named
'map_lookup' point to the associated map_lookup structure. This means
that for an extent map associated to an inode extent, we are not using
this 'map_lookup' pointer, so wasting 8 bytes (on a 64 bits platform);
4) Extent maps associated to a chunk mapping are never merged or split so
it's pointless to use the existing extent map infrastructure.
So add a dedicated data structure named 'btrfs_chunk_map' to represent
chunk mappings, this is basically the existing map_lookup structure with
some extra fields:
1) 'start' to contain the chunk logical address;
2) 'chunk_len' to contain the chunk's length;
3) 'stripe_size' for the stripe size;
4) 'rb_node' for insertion into a rb tree;
5) 'refs' for reference counting.
This way we do a single memory allocation for chunk mappings and we don't
waste memory for them with unused/unnecessary fields from an extent_map.
We also save 8 bytes from the extent_map structure by removing the
'map_lookup' pointer, so the size of struct extent_map is reduced from
144 bytes down to 136 bytes, and we can now have 30 extents map per 4K
page instead of 28.
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>
2023-11-21 21:38:38 +08:00
|
|
|
u64 btrfs_calc_stripe_length(const struct btrfs_chunk_map *map);
|
2022-05-13 16:34:30 +08:00
|
|
|
int btrfs_nr_parity_stripes(u64 type);
|
btrfs: rework chunk allocation to avoid exhaustion of the system chunk array
Commit eafa4fd0ad0607 ("btrfs: fix exhaustion of the system chunk array
due to concurrent allocations") fixed a problem that resulted in
exhausting the system chunk array in the superblock when there are many
tasks allocating chunks in parallel. Basically too many tasks enter the
first phase of chunk allocation without previous tasks having finished
their second phase of allocation, resulting in too many system chunks
being allocated. That was originally observed when running the fallocate
tests of stress-ng on a PowerPC machine, using a node size of 64K.
However that commit also introduced a deadlock where a task in phase 1 of
the chunk allocation waited for another task that had allocated a system
chunk to finish its phase 2, but that other task was waiting on an extent
buffer lock held by the first task, therefore resulting in both tasks not
making any progress. That change was later reverted by a patch with the
subject "btrfs: fix deadlock with concurrent chunk allocations involving
system chunks", since there is no simple and short solution to address it
and the deadlock is relatively easy to trigger on zoned filesystems, while
the system chunk array exhaustion is not so common.
This change reworks the chunk allocation to avoid the system chunk array
exhaustion. It accomplishes that by making the first phase of chunk
allocation do the updates of the device items in the chunk btree and the
insertion of the new chunk item in the chunk btree. This is done while
under the protection of the chunk mutex (fs_info->chunk_mutex), in the
same critical section that checks for available system space, allocates
a new system chunk if needed and reserves system chunk space. This way
we do not have chunk space reserved until the second phase completes.
The same logic is applied to chunk removal as well, since it keeps
reserved system space long after it is done updating the chunk btree.
For direct allocation of system chunks, the previous behaviour remains,
because otherwise we would deadlock on extent buffers of the chunk btree.
Changes to the chunk btree are by large done by chunk allocation and chunk
removal, which first reserve chunk system space and then later do changes
to the chunk btree. The other remaining cases are uncommon and correspond
to adding a device, removing a device and resizing a device. All these
other cases do not pre-reserve system space, they modify the chunk btree
right away, so they don't hold reserved space for a long period like chunk
allocation and chunk removal do.
The diff of this change is huge, but more than half of it is just addition
of comments describing both how things work regarding chunk allocation and
removal, including both the new behavior and the parts of the old behavior
that did not change.
CC: stable@vger.kernel.org # 5.12+
Tested-by: Shin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com>
Tested-by: Naohiro Aota <naohiro.aota@wdc.com>
Signed-off-by: Filipe Manana <fdmanana@suse.com>
Tested-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2021-06-29 21:43:06 +08:00
|
|
|
int btrfs_chunk_alloc_add_chunk_item(struct btrfs_trans_handle *trans,
|
|
|
|
struct btrfs_block_group *bg);
|
2018-07-21 00:37:53 +08:00
|
|
|
int btrfs_remove_chunk(struct btrfs_trans_handle *trans, u64 chunk_offset);
|
btrfs: use a dedicated data structure for chunk maps
Currently we abuse the extent_map structure for two purposes:
1) To actually represent extents for inodes;
2) To represent chunk mappings.
This is odd and has several disadvantages:
1) To create a chunk map, we need to do two memory allocations: one for
an extent_map structure and another one for a map_lookup structure, so
more potential for an allocation failure and more complicated code to
manage and link two structures;
2) For a chunk map we actually only use 3 fields (24 bytes) of the
respective extent map structure: the 'start' field to have the logical
start address of the chunk, the 'len' field to have the chunk's size,
and the 'orig_block_len' field to contain the chunk's stripe size.
Besides wasting a memory, it's also odd and not intuitive at all to
have the stripe size in a field named 'orig_block_len'.
We are also using 'block_len' of the extent_map structure to contain
the chunk size, so we have 2 fields for the same value, 'len' and
'block_len', which is pointless;
3) When an extent map is associated to a chunk mapping, we set the bit
EXTENT_FLAG_FS_MAPPING on its flags and then make its member named
'map_lookup' point to the associated map_lookup structure. This means
that for an extent map associated to an inode extent, we are not using
this 'map_lookup' pointer, so wasting 8 bytes (on a 64 bits platform);
4) Extent maps associated to a chunk mapping are never merged or split so
it's pointless to use the existing extent map infrastructure.
So add a dedicated data structure named 'btrfs_chunk_map' to represent
chunk mappings, this is basically the existing map_lookup structure with
some extra fields:
1) 'start' to contain the chunk logical address;
2) 'chunk_len' to contain the chunk's length;
3) 'stripe_size' for the stripe size;
4) 'rb_node' for insertion into a rb tree;
5) 'refs' for reference counting.
This way we do a single memory allocation for chunk mappings and we don't
waste memory for them with unused/unnecessary fields from an extent_map.
We also save 8 bytes from the extent_map structure by removing the
'map_lookup' pointer, so the size of struct extent_map is reduced from
144 bytes down to 136 bytes, and we can now have 30 extents map per 4K
page instead of 28.
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>
2023-11-21 21:38:38 +08:00
|
|
|
|
|
|
|
#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
|
|
|
|
struct btrfs_chunk_map *btrfs_alloc_chunk_map(int num_stripes, gfp_t gfp);
|
|
|
|
int btrfs_add_chunk_map(struct btrfs_fs_info *fs_info, struct btrfs_chunk_map *map);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
struct btrfs_chunk_map *btrfs_clone_chunk_map(struct btrfs_chunk_map *map, gfp_t gfp);
|
|
|
|
struct btrfs_chunk_map *btrfs_find_chunk_map(struct btrfs_fs_info *fs_info,
|
|
|
|
u64 logical, u64 length);
|
|
|
|
struct btrfs_chunk_map *btrfs_find_chunk_map_nolock(struct btrfs_fs_info *fs_info,
|
|
|
|
u64 logical, u64 length);
|
|
|
|
struct btrfs_chunk_map *btrfs_get_chunk_map(struct btrfs_fs_info *fs_info,
|
|
|
|
u64 logical, u64 length);
|
|
|
|
void btrfs_remove_chunk_map(struct btrfs_fs_info *fs_info, struct btrfs_chunk_map *map);
|
2020-02-13 23:24:32 +08:00
|
|
|
void btrfs_release_disk_super(struct btrfs_super_block *super);
|
2014-07-24 11:37:11 +08:00
|
|
|
|
2012-05-25 22:06:08 +08:00
|
|
|
static inline void btrfs_dev_stat_inc(struct btrfs_device *dev,
|
|
|
|
int index)
|
|
|
|
{
|
|
|
|
atomic_inc(dev->dev_stat_values + index);
|
2017-10-24 18:47:37 +08: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 11:37:11 +08:00
|
|
|
smp_mb__before_atomic();
|
|
|
|
atomic_inc(&dev->dev_stats_ccnt);
|
2012-05-25 22:06:08 +08: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 23:10:58 +08: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 11:37:11 +08:00
|
|
|
atomic_inc(&dev->dev_stats_ccnt);
|
2012-05-25 22:06:08 +08: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 18:47:37 +08: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 11:37:11 +08:00
|
|
|
smp_mb__before_atomic();
|
|
|
|
atomic_inc(&dev->dev_stats_ccnt);
|
2012-05-25 22:06:08 +08:00
|
|
|
}
|
|
|
|
|
2022-11-13 09:32:07 +08:00
|
|
|
static inline const char *btrfs_dev_name(const struct btrfs_device *device)
|
|
|
|
{
|
|
|
|
if (!device || test_bit(BTRFS_DEV_STATE_MISSING, &device->dev_state))
|
|
|
|
return "<missing disk>";
|
|
|
|
else
|
|
|
|
return rcu_str_deref(device->name);
|
|
|
|
}
|
|
|
|
|
2019-03-25 20:31:22 +08: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 05:14:15 +08:00
|
|
|
|
2019-10-02 01:57:37 +08:00
|
|
|
struct list_head * __attribute_const__ btrfs_get_fs_uuids(void);
|
2017-12-18 17:08:59 +08:00
|
|
|
bool btrfs_check_rw_degradable(struct btrfs_fs_info *fs_info,
|
|
|
|
struct btrfs_device *failing_dev);
|
2020-08-20 23:18:26 +08: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 09:34:36 +08:00
|
|
|
|
2021-07-26 20:15:19 +08:00
|
|
|
enum btrfs_raid_types __attribute_const__ btrfs_bg_flags_to_raid_index(u64 flags);
|
2018-07-14 02:46:30 +08:00
|
|
|
int btrfs_bg_type_to_factor(u64 flags);
|
2019-05-17 17:43:41 +08:00
|
|
|
const char *btrfs_bg_type_to_raid_name(u64 flags);
|
2018-08-01 10:37:19 +08:00
|
|
|
int btrfs_verify_dev_extents(struct btrfs_fs_info *fs_info);
|
2021-12-07 22:28:36 +08:00
|
|
|
bool btrfs_repair_one_zone(struct btrfs_fs_info *fs_info, u64 logical);
|
2018-07-14 02:46:30 +08:00
|
|
|
|
2022-09-15 07:04:40 +08:00
|
|
|
bool btrfs_pinned_by_swapfile(struct btrfs_fs_info *fs_info, void *ptr);
|
2023-07-31 19:16:32 +08:00
|
|
|
u8 *btrfs_sb_fsid_ptr(struct btrfs_super_block *sb);
|
2022-09-15 07:04:40 +08:00
|
|
|
|
2008-03-25 03:01:56 +08:00
|
|
|
#endif
|