Skip to content

Commit fd2ff27

Browse files
committed
Merge tag 'for-5.13-rc4-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux
Pull btrfs fixes from David Sterba: "Error handling improvements, caught by error injection: - handle errors during checksum deletion - set error on mapping when ordered extent io cannot be finished - inode link count fixup in tree-log - missing return value checks for inode updates in tree-log - abort transaction in rename exchange if adding second reference fails Fixes: - fix fsync failure after writes to prealloc extents - fix deadlock when cloning inline extents and low on available space - fix compressed writes that cross stripe boundary" * tag 'for-5.13-rc4-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux: MAINTAINERS: add btrfs IRC link btrfs: fix deadlock when cloning inline extents and low on available space btrfs: fix fsync failure and transaction abort after writes to prealloc extents btrfs: abort in rename_exchange if we fail to insert the second ref btrfs: check error value from btrfs_update_inode in tree log btrfs: fixup error handling in fixup_inode_link_counts btrfs: mark ordered extent and inode with error if we fail to finish btrfs: return errors from btrfs_del_csums in cleanup_ref_head btrfs: fix error handling in btrfs_del_csums btrfs: fix compressed writes that cross stripe boundary
2 parents 324c92e + 503d1ac commit fd2ff27

File tree

7 files changed

+148
-58
lines changed

7 files changed

+148
-58
lines changed

MAINTAINERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3877,6 +3877,7 @@ L: [email protected]
38773877
S: Maintained
38783878
W: http://btrfs.wiki.kernel.org/
38793879
Q: http://patchwork.kernel.org/project/linux-btrfs/list/
3880+
C: irc://irc.libera.chat/btrfs
38803881
T: git git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux.git
38813882
F: Documentation/filesystems/btrfs.rst
38823883
F: fs/btrfs/

fs/btrfs/compression.c

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -457,18 +457,25 @@ blk_status_t btrfs_submit_compressed_write(struct btrfs_inode *inode, u64 start,
457457
bytes_left = compressed_len;
458458
for (pg_index = 0; pg_index < cb->nr_pages; pg_index++) {
459459
int submit = 0;
460-
int len;
460+
int len = 0;
461461

462462
page = compressed_pages[pg_index];
463463
page->mapping = inode->vfs_inode.i_mapping;
464464
if (bio->bi_iter.bi_size)
465465
submit = btrfs_bio_fits_in_stripe(page, PAGE_SIZE, bio,
466466
0);
467467

468-
if (pg_index == 0 && use_append)
469-
len = bio_add_zone_append_page(bio, page, PAGE_SIZE, 0);
470-
else
471-
len = bio_add_page(bio, page, PAGE_SIZE, 0);
468+
/*
469+
* Page can only be added to bio if the current bio fits in
470+
* stripe.
471+
*/
472+
if (!submit) {
473+
if (pg_index == 0 && use_append)
474+
len = bio_add_zone_append_page(bio, page,
475+
PAGE_SIZE, 0);
476+
else
477+
len = bio_add_page(bio, page, PAGE_SIZE, 0);
478+
}
472479

473480
page->mapping = NULL;
474481
if (submit || len < PAGE_SIZE) {

fs/btrfs/extent-tree.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1868,7 +1868,7 @@ static int cleanup_ref_head(struct btrfs_trans_handle *trans,
18681868
trace_run_delayed_ref_head(fs_info, head, 0);
18691869
btrfs_delayed_ref_unlock(head);
18701870
btrfs_put_delayed_ref_head(head);
1871-
return 0;
1871+
return ret;
18721872
}
18731873

18741874
static struct btrfs_delayed_ref_head *btrfs_obtain_ref_head(

fs/btrfs/file-item.c

Lines changed: 81 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -788,7 +788,7 @@ int btrfs_del_csums(struct btrfs_trans_handle *trans,
788788
u64 end_byte = bytenr + len;
789789
u64 csum_end;
790790
struct extent_buffer *leaf;
791-
int ret;
791+
int ret = 0;
792792
const u32 csum_size = fs_info->csum_size;
793793
u32 blocksize_bits = fs_info->sectorsize_bits;
794794

@@ -806,6 +806,7 @@ int btrfs_del_csums(struct btrfs_trans_handle *trans,
806806

807807
ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
808808
if (ret > 0) {
809+
ret = 0;
809810
if (path->slots[0] == 0)
810811
break;
811812
path->slots[0]--;
@@ -862,7 +863,7 @@ int btrfs_del_csums(struct btrfs_trans_handle *trans,
862863
ret = btrfs_del_items(trans, root, path,
863864
path->slots[0], del_nr);
864865
if (ret)
865-
goto out;
866+
break;
866867
if (key.offset == bytenr)
867868
break;
868869
} else if (key.offset < bytenr && csum_end > end_byte) {
@@ -906,8 +907,9 @@ int btrfs_del_csums(struct btrfs_trans_handle *trans,
906907
ret = btrfs_split_item(trans, root, path, &key, offset);
907908
if (ret && ret != -EAGAIN) {
908909
btrfs_abort_transaction(trans, ret);
909-
goto out;
910+
break;
910911
}
912+
ret = 0;
911913

912914
key.offset = end_byte - 1;
913915
} else {
@@ -917,12 +919,41 @@ int btrfs_del_csums(struct btrfs_trans_handle *trans,
917919
}
918920
btrfs_release_path(path);
919921
}
920-
ret = 0;
921-
out:
922922
btrfs_free_path(path);
923923
return ret;
924924
}
925925

926+
static int find_next_csum_offset(struct btrfs_root *root,
927+
struct btrfs_path *path,
928+
u64 *next_offset)
929+
{
930+
const u32 nritems = btrfs_header_nritems(path->nodes[0]);
931+
struct btrfs_key found_key;
932+
int slot = path->slots[0] + 1;
933+
int ret;
934+
935+
if (nritems == 0 || slot >= nritems) {
936+
ret = btrfs_next_leaf(root, path);
937+
if (ret < 0) {
938+
return ret;
939+
} else if (ret > 0) {
940+
*next_offset = (u64)-1;
941+
return 0;
942+
}
943+
slot = path->slots[0];
944+
}
945+
946+
btrfs_item_key_to_cpu(path->nodes[0], &found_key, slot);
947+
948+
if (found_key.objectid != BTRFS_EXTENT_CSUM_OBJECTID ||
949+
found_key.type != BTRFS_EXTENT_CSUM_KEY)
950+
*next_offset = (u64)-1;
951+
else
952+
*next_offset = found_key.offset;
953+
954+
return 0;
955+
}
956+
926957
int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans,
927958
struct btrfs_root *root,
928959
struct btrfs_ordered_sum *sums)
@@ -938,7 +969,6 @@ int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans,
938969
u64 total_bytes = 0;
939970
u64 csum_offset;
940971
u64 bytenr;
941-
u32 nritems;
942972
u32 ins_size;
943973
int index = 0;
944974
int found_next;
@@ -981,26 +1011,10 @@ int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans,
9811011
goto insert;
9821012
}
9831013
} else {
984-
int slot = path->slots[0] + 1;
985-
/* we didn't find a csum item, insert one */
986-
nritems = btrfs_header_nritems(path->nodes[0]);
987-
if (!nritems || (path->slots[0] >= nritems - 1)) {
988-
ret = btrfs_next_leaf(root, path);
989-
if (ret < 0) {
990-
goto out;
991-
} else if (ret > 0) {
992-
found_next = 1;
993-
goto insert;
994-
}
995-
slot = path->slots[0];
996-
}
997-
btrfs_item_key_to_cpu(path->nodes[0], &found_key, slot);
998-
if (found_key.objectid != BTRFS_EXTENT_CSUM_OBJECTID ||
999-
found_key.type != BTRFS_EXTENT_CSUM_KEY) {
1000-
found_next = 1;
1001-
goto insert;
1002-
}
1003-
next_offset = found_key.offset;
1014+
/* We didn't find a csum item, insert one. */
1015+
ret = find_next_csum_offset(root, path, &next_offset);
1016+
if (ret < 0)
1017+
goto out;
10041018
found_next = 1;
10051019
goto insert;
10061020
}
@@ -1056,8 +1070,48 @@ int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans,
10561070
tmp = sums->len - total_bytes;
10571071
tmp >>= fs_info->sectorsize_bits;
10581072
WARN_ON(tmp < 1);
1073+
extend_nr = max_t(int, 1, tmp);
1074+
1075+
/*
1076+
* A log tree can already have checksum items with a subset of
1077+
* the checksums we are trying to log. This can happen after
1078+
* doing a sequence of partial writes into prealloc extents and
1079+
* fsyncs in between, with a full fsync logging a larger subrange
1080+
* of an extent for which a previous fast fsync logged a smaller
1081+
* subrange. And this happens in particular due to merging file
1082+
* extent items when we complete an ordered extent for a range
1083+
* covered by a prealloc extent - this is done at
1084+
* btrfs_mark_extent_written().
1085+
*
1086+
* So if we try to extend the previous checksum item, which has
1087+
* a range that ends at the start of the range we want to insert,
1088+
* make sure we don't extend beyond the start offset of the next
1089+
* checksum item. If we are at the last item in the leaf, then
1090+
* forget the optimization of extending and add a new checksum
1091+
* item - it is not worth the complexity of releasing the path,
1092+
* getting the first key for the next leaf, repeat the btree
1093+
* search, etc, because log trees are temporary anyway and it
1094+
* would only save a few bytes of leaf space.
1095+
*/
1096+
if (root->root_key.objectid == BTRFS_TREE_LOG_OBJECTID) {
1097+
if (path->slots[0] + 1 >=
1098+
btrfs_header_nritems(path->nodes[0])) {
1099+
ret = find_next_csum_offset(root, path, &next_offset);
1100+
if (ret < 0)
1101+
goto out;
1102+
found_next = 1;
1103+
goto insert;
1104+
}
1105+
1106+
ret = find_next_csum_offset(root, path, &next_offset);
1107+
if (ret < 0)
1108+
goto out;
1109+
1110+
tmp = (next_offset - bytenr) >> fs_info->sectorsize_bits;
1111+
if (tmp <= INT_MAX)
1112+
extend_nr = min_t(int, extend_nr, tmp);
1113+
}
10591114

1060-
extend_nr = max_t(int, 1, (int)tmp);
10611115
diff = (csum_offset + extend_nr) * csum_size;
10621116
diff = min(diff,
10631117
MAX_CSUM_ITEMS(fs_info, csum_size) * csum_size);

fs/btrfs/inode.c

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3000,6 +3000,18 @@ static int btrfs_finish_ordered_io(struct btrfs_ordered_extent *ordered_extent)
30003000
if (ret || truncated) {
30013001
u64 unwritten_start = start;
30023002

3003+
/*
3004+
* If we failed to finish this ordered extent for any reason we
3005+
* need to make sure BTRFS_ORDERED_IOERR is set on the ordered
3006+
* extent, and mark the inode with the error if it wasn't
3007+
* already set. Any error during writeback would have already
3008+
* set the mapping error, so we need to set it if we're the ones
3009+
* marking this ordered extent as failed.
3010+
*/
3011+
if (ret && !test_and_set_bit(BTRFS_ORDERED_IOERR,
3012+
&ordered_extent->flags))
3013+
mapping_set_error(ordered_extent->inode->i_mapping, -EIO);
3014+
30033015
if (truncated)
30043016
unwritten_start += logical_len;
30053017
clear_extent_uptodate(io_tree, unwritten_start, end, NULL);
@@ -9076,6 +9088,7 @@ static int btrfs_rename_exchange(struct inode *old_dir,
90769088
int ret2;
90779089
bool root_log_pinned = false;
90789090
bool dest_log_pinned = false;
9091+
bool need_abort = false;
90799092

90809093
/* we only allow rename subvolume link between subvolumes */
90819094
if (old_ino != BTRFS_FIRST_FREE_OBJECTID && root != dest)
@@ -9135,6 +9148,7 @@ static int btrfs_rename_exchange(struct inode *old_dir,
91359148
old_idx);
91369149
if (ret)
91379150
goto out_fail;
9151+
need_abort = true;
91389152
}
91399153

91409154
/* And now for the dest. */
@@ -9150,8 +9164,11 @@ static int btrfs_rename_exchange(struct inode *old_dir,
91509164
new_ino,
91519165
btrfs_ino(BTRFS_I(old_dir)),
91529166
new_idx);
9153-
if (ret)
9167+
if (ret) {
9168+
if (need_abort)
9169+
btrfs_abort_transaction(trans, ret);
91549170
goto out_fail;
9171+
}
91559172
}
91569173

91579174
/* Update inode version and ctime/mtime. */

fs/btrfs/reflink.c

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -203,10 +203,7 @@ static int clone_copy_inline_extent(struct inode *dst,
203203
* inline extent's data to the page.
204204
*/
205205
ASSERT(key.offset > 0);
206-
ret = copy_inline_to_page(BTRFS_I(dst), new_key->offset,
207-
inline_data, size, datal,
208-
comp_type);
209-
goto out;
206+
goto copy_to_page;
210207
}
211208
} else if (i_size_read(dst) <= datal) {
212209
struct btrfs_file_extent_item *ei;
@@ -222,13 +219,10 @@ static int clone_copy_inline_extent(struct inode *dst,
222219
BTRFS_FILE_EXTENT_INLINE)
223220
goto copy_inline_extent;
224221

225-
ret = copy_inline_to_page(BTRFS_I(dst), new_key->offset,
226-
inline_data, size, datal, comp_type);
227-
goto out;
222+
goto copy_to_page;
228223
}
229224

230225
copy_inline_extent:
231-
ret = 0;
232226
/*
233227
* We have no extent items, or we have an extent at offset 0 which may
234228
* or may not be inlined. All these cases are dealt the same way.
@@ -240,11 +234,13 @@ static int clone_copy_inline_extent(struct inode *dst,
240234
* clone. Deal with all these cases by copying the inline extent
241235
* data into the respective page at the destination inode.
242236
*/
243-
ret = copy_inline_to_page(BTRFS_I(dst), new_key->offset,
244-
inline_data, size, datal, comp_type);
245-
goto out;
237+
goto copy_to_page;
246238
}
247239

240+
/*
241+
* Release path before starting a new transaction so we don't hold locks
242+
* that would confuse lockdep.
243+
*/
248244
btrfs_release_path(path);
249245
/*
250246
* If we end up here it means were copy the inline extent into a leaf
@@ -281,11 +277,6 @@ static int clone_copy_inline_extent(struct inode *dst,
281277
ret = btrfs_inode_set_file_extent_range(BTRFS_I(dst), 0, aligned_end);
282278
out:
283279
if (!ret && !trans) {
284-
/*
285-
* Release path before starting a new transaction so we don't
286-
* hold locks that would confuse lockdep.
287-
*/
288-
btrfs_release_path(path);
289280
/*
290281
* No transaction here means we copied the inline extent into a
291282
* page of the destination inode.
@@ -306,6 +297,21 @@ static int clone_copy_inline_extent(struct inode *dst,
306297
*trans_out = trans;
307298

308299
return ret;
300+
301+
copy_to_page:
302+
/*
303+
* Release our path because we don't need it anymore and also because
304+
* copy_inline_to_page() needs to reserve data and metadata, which may
305+
* need to flush delalloc when we are low on available space and
306+
* therefore cause a deadlock if writeback of an inline extent needs to
307+
* write to the same leaf or an ordered extent completion needs to write
308+
* to the same leaf.
309+
*/
310+
btrfs_release_path(path);
311+
312+
ret = copy_inline_to_page(BTRFS_I(dst), new_key->offset,
313+
inline_data, size, datal, comp_type);
314+
goto out;
309315
}
310316

311317
/**

0 commit comments

Comments
 (0)