Skip to content

Commit 00782aa

Browse files
adam900710kdave
authored andcommitted
btrfs: interrupt long running operations if the current process is freezing
[BUG] There is a bug report that running fstrim will prevent the system from hibernation, result the following dmesg: PM: suspend entry (deep) Filesystems sync: 0.060 seconds Freezing user space processes Freezing user space processes failed after 20.007 seconds (1 tasks refusing to freeze, wq_busy=0): task:fstrim state:D stack:0 pid:15564 tgid:15564 ppid:1 flags:0x00004006 Call Trace: <TASK> __schedule+0x381/0x1540 schedule+0x24/0xb0 schedule_timeout+0x1ea/0x2a0 io_schedule_timeout+0x19/0x50 wait_for_completion_io+0x78/0x140 submit_bio_wait+0xaa/0xc0 blkdev_issue_discard+0x65/0xb0 btrfs_issue_discard+0xcf/0x160 [btrfs 7ab35b9b86062a46f6ff578bb32d55ecf8e6bf82] btrfs_discard_extent+0x120/0x2a0 [btrfs 7ab35b9b86062a46f6ff578bb32d55ecf8e6bf82] do_trimming+0xd4/0x220 [btrfs 7ab35b9b86062a46f6ff578bb32d55ecf8e6bf82] trim_bitmaps+0x418/0x520 [btrfs 7ab35b9b86062a46f6ff578bb32d55ecf8e6bf82] btrfs_trim_block_group+0xcb/0x130 [btrfs 7ab35b9b86062a46f6ff578bb32d55ecf8e6bf82] btrfs_trim_fs+0x119/0x460 [btrfs 7ab35b9b86062a46f6ff578bb32d55ecf8e6bf82] btrfs_ioctl_fitrim+0xfb/0x160 [btrfs 7ab35b9b86062a46f6ff578bb32d55ecf8e6bf82] btrfs_ioctl+0x11cc/0x29f0 [btrfs 7ab35b9b86062a46f6ff578bb32d55ecf8e6bf82] __x64_sys_ioctl+0x92/0xd0 do_syscall_64+0x5b/0x80 entry_SYSCALL_64_after_hwframe+0x7c/0xe6 RIP: 0033:0x7f5f3b529f9b RSP: 002b:00007fff279ebc20 EFLAGS: 00000246 ORIG_RAX: 0000000000000010 RAX: ffffffffffffffda RBX: 00007fff279ebd60 RCX: 00007f5f3b529f9b RDX: 00007fff279ebc90 RSI: 00000000c0185879 RDI: 0000000000000003 RBP: 000055748718b2d0 R08: 00005574871899e8 R09: 00007fff279eb010 R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000003 R13: 000055748718ac40 R14: 000055748718b290 R15: 000055748718b290 </TASK> OOM killer enabled. Restarting tasks ... done. random: crng reseeded on system resumption PM: suspend exit PM: suspend entry (s2idle) Filesystems sync: 0.047 seconds [CAUSE] PM code is freezing all user space processes before entering hibernation/suspension, but if a user space process is trapping into the kernel for a long running operation, it will not be frozen since it's still inside kernel. Normally those long running operations check for fatal signals and exit early, but freezing user space processes is not done by signals but a different infrastructure. Unfortunately btrfs only checks fatal signals but not if the current task is being frozen. [FIX] Introduce a helper, btrfs_task_interrupted(), to check both fatal signals and freezing status, and apply to all long running operations, with dedicated error code: - reflink (-EINTR) - fstrim (-ERESTARTSYS) - relocation (-ECANCELD) - llseek (-EINTR) - defrag (-EAGAIN) - fiemap (-EINTR) Reported-by: Rolf Wentland <[email protected]> Link: https://bugzilla.suse.com/show_bug.cgi?id=1229737 Reviewed-by: Josef Bacik <[email protected]> Signed-off-by: Qu Wenruo <[email protected]>
1 parent e325b02 commit 00782aa

File tree

8 files changed

+16
-10
lines changed

8 files changed

+16
-10
lines changed

Diff for: fs/btrfs/defrag.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
#include <linux/types.h>
77
#include <linux/compiler_types.h>
8+
#include "misc.h"
89

910
struct inode;
1011
struct file_ra_state;
@@ -25,7 +26,7 @@ int btrfs_defrag_root(struct btrfs_root *root);
2526

2627
static inline int btrfs_defrag_cancelled(struct btrfs_fs_info *fs_info)
2728
{
28-
return signal_pending(current);
29+
return signal_pending(current) || btrfs_task_interrupted();
2930
}
3031

3132
#endif

Diff for: fs/btrfs/extent-tree.c

+1-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
*/
55

66
#include <linux/sched.h>
7-
#include <linux/sched/signal.h>
87
#include <linux/pagemap.h>
98
#include <linux/writeback.h>
109
#include <linux/blkdev.h>
@@ -6459,7 +6458,7 @@ static int btrfs_trim_free_extents(struct btrfs_device *device, u64 *trimmed)
64596458
start += len;
64606459
*trimmed += bytes;
64616460

6462-
if (fatal_signal_pending(current)) {
6461+
if (btrfs_task_interrupted()) {
64636462
ret = -ERESTARTSYS;
64646463
break;
64656464
}

Diff for: fs/btrfs/fiemap.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -794,7 +794,7 @@ static int extent_fiemap(struct btrfs_inode *inode,
794794

795795
prev_extent_end = extent_end;
796796
next_item:
797-
if (fatal_signal_pending(current)) {
797+
if (btrfs_task_interrupted()) {
798798
ret = -EINTR;
799799
goto out_unlock;
800800
}

Diff for: fs/btrfs/file.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -3676,7 +3676,7 @@ static loff_t find_desired_extent(struct file *file, loff_t offset, int whence)
36763676
start = extent_end;
36773677
last_extent_end = extent_end;
36783678
path->slots[0]++;
3679-
if (fatal_signal_pending(current)) {
3679+
if (btrfs_task_interrupted()) {
36803680
ret = -EINTR;
36813681
goto out;
36823682
}

Diff for: fs/btrfs/free-space-cache.c

+2-3
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55

66
#include <linux/pagemap.h>
77
#include <linux/sched.h>
8-
#include <linux/sched/signal.h>
98
#include <linux/slab.h>
109
#include <linux/math64.h>
1110
#include <linux/ratelimit.h>
@@ -3809,7 +3808,7 @@ static int trim_no_bitmap(struct btrfs_block_group *block_group,
38093808
if (async && *total_trimmed)
38103809
break;
38113810

3812-
if (fatal_signal_pending(current)) {
3811+
if (btrfs_task_interrupted()) {
38133812
ret = -ERESTARTSYS;
38143813
break;
38153814
}
@@ -4000,7 +3999,7 @@ static int trim_bitmaps(struct btrfs_block_group *block_group,
40003999
}
40014000
block_group->discard_cursor = start;
40024001

4003-
if (fatal_signal_pending(current)) {
4002+
if (btrfs_task_interrupted()) {
40044003
if (start != offset)
40054004
reset_trimming_bitmap(ctl, offset);
40064005
ret = -ERESTARTSYS;

Diff for: fs/btrfs/misc.h

+7
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
#include <linux/wait.h>
1010
#include <linux/math64.h>
1111
#include <linux/rbtree.h>
12+
#include <linux/sched/signal.h>
13+
#include <linux/freezer.h>
1214

1315
/*
1416
* Enumerate bits using enum autoincrement. Define the @name as the n-th bit.
@@ -163,4 +165,9 @@ static inline bool bitmap_test_range_all_zero(const unsigned long *addr,
163165
return (found_set == start + nbits);
164166
}
165167

168+
static inline bool btrfs_task_interrupted(void)
169+
{
170+
return fatal_signal_pending(current) || freezing(current);
171+
}
172+
166173
#endif

Diff for: fs/btrfs/reflink.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -564,7 +564,7 @@ static int btrfs_clone(struct inode *src, struct inode *inode,
564564
btrfs_release_path(path);
565565
key.offset = prev_extent_end;
566566

567-
if (fatal_signal_pending(current)) {
567+
if (btrfs_task_interrupted()) {
568568
ret = -EINTR;
569569
goto out;
570570
}

Diff for: fs/btrfs/relocation.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -2936,7 +2936,7 @@ noinline int btrfs_should_cancel_balance(const struct btrfs_fs_info *fs_info)
29362936
{
29372937
return atomic_read(&fs_info->balance_cancel_req) ||
29382938
atomic_read(&fs_info->reloc_cancel_req) ||
2939-
fatal_signal_pending(current);
2939+
btrfs_task_interrupted();
29402940
}
29412941
ALLOW_ERROR_INJECTION(btrfs_should_cancel_balance, TRUE);
29422942

0 commit comments

Comments
 (0)