Skip to content

Commit 2e3c251

Browse files
adam900710kdave
authored andcommitted
btrfs: extent_io: add proper error handling to lock_extent_buffer_for_io()
This function needs some extra checks on locked pages and eb. For error handling we need to unlock locked pages and the eb. There is a rare >0 return value branch, where all pages get locked while write bio is not flushed. Thankfully it's handled by the only caller, btree_write_cache_pages(), as later write_one_eb() call will trigger submit_one_bio(). So there shouldn't be any problem. Signed-off-by: Qu Wenruo <[email protected]> Reviewed-by: David Sterba <[email protected]> Signed-off-by: David Sterba <[email protected]>
1 parent 02c6db4 commit 2e3c251

File tree

1 file changed

+22
-5
lines changed

1 file changed

+22
-5
lines changed

fs/btrfs/extent_io.c

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3492,19 +3492,27 @@ void wait_on_extent_buffer_writeback(struct extent_buffer *eb)
34923492
TASK_UNINTERRUPTIBLE);
34933493
}
34943494

3495+
/*
3496+
* Lock eb pages and flush the bio if we can't the locks
3497+
*
3498+
* Return 0 if nothing went wrong
3499+
* Return >0 is same as 0, except bio is not submitted
3500+
* Return <0 if something went wrong, no page is locked
3501+
*/
34953502
static noinline_for_stack int
34963503
lock_extent_buffer_for_io(struct extent_buffer *eb,
34973504
struct btrfs_fs_info *fs_info,
34983505
struct extent_page_data *epd)
34993506
{
3500-
int i, num_pages;
3507+
int i, num_pages, failed_page_nr;
35013508
int flush = 0;
35023509
int ret = 0;
35033510

35043511
if (!btrfs_try_tree_write_lock(eb)) {
3505-
flush = 1;
35063512
ret = flush_write_bio(epd);
3507-
BUG_ON(ret < 0);
3513+
if (ret < 0)
3514+
return ret;
3515+
flush = 1;
35083516
btrfs_tree_lock(eb);
35093517
}
35103518

@@ -3514,7 +3522,8 @@ lock_extent_buffer_for_io(struct extent_buffer *eb,
35143522
return 0;
35153523
if (!flush) {
35163524
ret = flush_write_bio(epd);
3517-
BUG_ON(ret < 0);
3525+
if (ret < 0)
3526+
return ret;
35183527
flush = 1;
35193528
}
35203529
while (1) {
@@ -3556,14 +3565,22 @@ lock_extent_buffer_for_io(struct extent_buffer *eb,
35563565
if (!trylock_page(p)) {
35573566
if (!flush) {
35583567
ret = flush_write_bio(epd);
3559-
BUG_ON(ret < 0);
3568+
if (ret < 0) {
3569+
failed_page_nr = i;
3570+
goto err_unlock;
3571+
}
35603572
flush = 1;
35613573
}
35623574
lock_page(p);
35633575
}
35643576
}
35653577

35663578
return ret;
3579+
err_unlock:
3580+
/* Unlock already locked pages */
3581+
for (i = 0; i < failed_page_nr; i++)
3582+
unlock_page(eb->pages[i]);
3583+
return ret;
35673584
}
35683585

35693586
static void end_extent_buffer_writeback(struct extent_buffer *eb)

0 commit comments

Comments
 (0)