Skip to content

Commit 7059bdf

Browse files
committed
Merge tag 'for-7.2-rc3-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux
Pull btrfs fixes from David Sterba: - fix root structure leak after relocation error - fix optimization when checksums are read from commit root, fall back to checksum root during relocation - in tree-checker, validate length of inode reference in items - validate properties before setting them - validate free space cache entries on load - transaction abort fixes - fix printing of internal trees as signed numbers - add error messages after critical lzo compression errors * tag 'for-7.2-rc3-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux: btrfs: print-tree: print header owner as signed btrfs: decentralize transaction aborts in create_reloc_root() btrfs: tree-checker: validate INODE_REF's namelen btrfs: lzo: add error message for invalid headers btrfs: fallback to transaction csum tree on a commit root csum miss btrfs: fix root leak if its reloc root is unexpected in merge_reloc_roots() btrfs: reject free space cache with more entries than pages btrfs: fix transaction abort logic in btrfs_fileattr_set() btrfs: validate properties before setting them
2 parents 3b029c0 + c0041b5 commit 7059bdf

8 files changed

Lines changed: 82 additions & 25 deletions

File tree

fs/btrfs/file-item.c

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,7 @@ int btrfs_lookup_bio_sums(struct btrfs_bio *bbio)
358358
const unsigned int nblocks = orig_len >> fs_info->sectorsize_bits;
359359
int ret = 0;
360360
u32 bio_offset = 0;
361+
bool using_commit_root = false;
361362

362363
if ((inode->flags & BTRFS_INODE_NODATASUM) ||
363364
test_bit(BTRFS_FS_STATE_NO_DATA_CSUMS, &fs_info->fs_state))
@@ -431,6 +432,7 @@ int btrfs_lookup_bio_sums(struct btrfs_bio *bbio)
431432
* from across transactions.
432433
*/
433434
if (bbio->csum_search_commit_root) {
435+
using_commit_root = true;
434436
path->search_commit_root = true;
435437
path->skip_locking = true;
436438
down_read(&fs_info->commit_root_sem);
@@ -463,6 +465,28 @@ int btrfs_lookup_bio_sums(struct btrfs_bio *bbio)
463465
* assume this is the case.
464466
*/
465467
if (count == 0) {
468+
/*
469+
* If an extent is relocated in the current transaction
470+
* then relocation writes a new csum without updating
471+
* the extent map generation. Until the next commit, we
472+
* will see a hole in that case, so we need to fallback
473+
* to searching the transaction csum root.
474+
*
475+
* Note that a commit root lookup of a referenced extent can
476+
* only miss, not return a stale csum. A freed extent's csum
477+
* is deleted in the same transaction and its bytenr is not
478+
* reusable until that transaction has committed and the
479+
* extent is unpinned.
480+
*/
481+
if (using_commit_root) {
482+
up_read(&fs_info->commit_root_sem);
483+
using_commit_root = false;
484+
path->search_commit_root = false;
485+
path->skip_locking = false;
486+
btrfs_release_path(path);
487+
continue;
488+
}
489+
466490
memset(csum_dst, 0, csum_size);
467491
count = 1;
468492

@@ -481,7 +505,7 @@ int btrfs_lookup_bio_sums(struct btrfs_bio *bbio)
481505
bio_offset += count * sectorsize;
482506
}
483507

484-
if (bbio->csum_search_commit_root)
508+
if (using_commit_root)
485509
up_read(&fs_info->commit_root_sem);
486510
return ret;
487511
}

fs/btrfs/free-space-cache.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -551,6 +551,9 @@ static int io_ctl_check_crc(struct btrfs_io_ctl *io_ctl, int index)
551551
u32 crc = ~(u32)0;
552552
unsigned offset = 0;
553553

554+
if (index >= io_ctl->num_pages)
555+
return -EIO;
556+
554557
if (index == 0)
555558
offset = sizeof(u32) * io_ctl->num_pages;
556559

fs/btrfs/ioctl.c

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,7 @@ int btrfs_fileattr_set(struct mnt_idmap *idmap,
289289
int ret;
290290
const char *comp = NULL;
291291
u32 inode_flags;
292+
bool prop_set = false;
292293

293294
if (btrfs_root_readonly(root))
294295
return -EROFS;
@@ -401,16 +402,15 @@ int btrfs_fileattr_set(struct mnt_idmap *idmap,
401402
if (comp) {
402403
ret = btrfs_set_prop(trans, inode, "btrfs.compression",
403404
comp, strlen(comp), 0);
404-
if (unlikely(ret)) {
405-
btrfs_abort_transaction(trans, ret);
405+
if (ret)
406406
goto out_end_trans;
407-
}
407+
prop_set = true;
408408
} else {
409409
ret = btrfs_set_prop(trans, inode, "btrfs.compression", NULL, 0, 0);
410-
if (unlikely(ret && ret != -ENODATA)) {
411-
btrfs_abort_transaction(trans, ret);
410+
prop_set = (ret == 0);
411+
/* If ret == -ENODATA ignore and proceed to update inode item. */
412+
if (ret && ret != -ENODATA)
412413
goto out_end_trans;
413-
}
414414
}
415415

416416
update_flags:
@@ -420,6 +420,12 @@ int btrfs_fileattr_set(struct mnt_idmap *idmap,
420420
inode_inc_iversion(&inode->vfs_inode);
421421
inode_set_ctime_current(&inode->vfs_inode);
422422
ret = btrfs_update_inode(trans, inode);
423+
/*
424+
* If we set a property or deleted one, we must abort if we fail to
425+
* update the inode, to avoid persisting an inconsistent state.
426+
*/
427+
if (unlikely(ret && prop_set))
428+
btrfs_abort_transaction(trans, ret);
423429

424430
out_end_trans:
425431
btrfs_end_transaction(trans);

fs/btrfs/lzo.c

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -552,17 +552,26 @@ int lzo_decompress(struct list_head *ws, const u8 *data_in,
552552
size_t max_segment_len = workspace_buf_length(fs_info);
553553
int ret;
554554

555-
if (unlikely(srclen < LZO_LEN || srclen > max_segment_len + LZO_LEN * 2))
555+
if (unlikely(srclen < LZO_LEN || srclen > max_segment_len + LZO_LEN * 2)) {
556+
btrfs_err(fs_info, "invalid lzo header length, has %zu expect (%u, %zu)",
557+
srclen, LZO_LEN, max_segment_len + LZO_LEN * 2);
556558
return -EUCLEAN;
559+
}
557560

558561
in_len = get_unaligned_le32(data_in);
559-
if (unlikely(in_len != srclen))
562+
if (unlikely(in_len != srclen)) {
563+
btrfs_err(fs_info, "invalid lzo header length, has %zu expect %zu",
564+
in_len, srclen);
560565
return -EUCLEAN;
566+
}
561567
data_in += LZO_LEN;
562568

563569
in_len = get_unaligned_le32(data_in);
564-
if (unlikely(in_len != srclen - LZO_LEN * 2))
570+
if (unlikely(in_len != srclen - LZO_LEN * 2)) {
571+
btrfs_err(fs_info, "invalid lzo segment length, has %zu expect %zu",
572+
in_len, srclen - LZO_LEN * 2);
565573
return -EUCLEAN;
574+
}
566575
data_in += LZO_LEN;
567576

568577
out_len = sectorsize;

fs/btrfs/print-tree.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -449,9 +449,9 @@ void btrfs_print_leaf(const struct extent_buffer *l)
449449
nr = btrfs_header_nritems(l);
450450

451451
btrfs_info(fs_info,
452-
"leaf %llu gen %llu total ptrs %d free space %d owner %llu",
452+
"leaf %llu gen %llu total ptrs %d free space %d owner %lld",
453453
btrfs_header_bytenr(l), btrfs_header_generation(l), nr,
454-
btrfs_leaf_free_space(l), btrfs_header_owner(l));
454+
btrfs_leaf_free_space(l), (s64)btrfs_header_owner(l));
455455
print_eb_refs_lock(l);
456456
for (i = 0 ; i < nr ; i++) {
457457
char key_buf[KEY_TYPE_BUF_SIZE];
@@ -600,10 +600,10 @@ void btrfs_print_tree(const struct extent_buffer *c, bool follow)
600600
return;
601601
}
602602
btrfs_info(fs_info,
603-
"node %llu level %d gen %llu total ptrs %d free spc %u owner %llu",
603+
"node %llu level %d gen %llu total ptrs %d free spc %u owner %lld",
604604
btrfs_header_bytenr(c), level, btrfs_header_generation(c),
605605
nr, (u32)BTRFS_NODEPTRS_PER_BLOCK(fs_info) - nr,
606-
btrfs_header_owner(c));
606+
(s64)btrfs_header_owner(c));
607607
print_eb_refs_lock(c);
608608
for (i = 0; i < nr; i++) {
609609
btrfs_node_key_to_cpu(c, &key, i);

fs/btrfs/props.c

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -127,14 +127,24 @@ int btrfs_set_prop(struct btrfs_trans_handle *trans, struct btrfs_inode *inode,
127127
return ret;
128128
}
129129

130+
ret = handler->validate(inode, value, value_len);
131+
if (ret)
132+
return ret;
130133
ret = btrfs_setxattr(trans, &inode->vfs_inode, handler->xattr_name, value,
131134
value_len, flags);
132135
if (ret)
133136
return ret;
134137
ret = handler->apply(inode, value, value_len);
135-
if (ret) {
136-
btrfs_setxattr(trans, &inode->vfs_inode, handler->xattr_name, NULL,
137-
0, flags);
138+
/* We validated before, so it should not fail here. */
139+
ASSERT(ret == 0);
140+
if (unlikely(ret)) {
141+
int ret2;
142+
143+
/* Try to delete xattr, if not possible abort transaction. */
144+
ret2 = btrfs_setxattr(trans, &inode->vfs_inode, handler->xattr_name,
145+
NULL, 0, flags);
146+
if (unlikely(ret2))
147+
btrfs_abort_transaction(trans, ret2);
138148
return ret;
139149
}
140150

fs/btrfs/relocation.c

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -719,21 +719,19 @@ static struct btrfs_root *create_reloc_root(struct btrfs_trans_handle *trans,
719719

720720
ret = btrfs_insert_root(trans, fs_info->tree_root,
721721
&root_key, root_item);
722-
if (ret)
723-
goto abort;
722+
if (unlikely(ret)) {
723+
btrfs_abort_transaction(trans, ret);
724+
return ERR_PTR(ret);
725+
}
724726

725727
reloc_root = btrfs_read_tree_root(fs_info->tree_root, &root_key);
726728
if (IS_ERR(reloc_root)) {
727-
ret = PTR_ERR(reloc_root);
728-
goto abort;
729+
btrfs_abort_transaction(trans, PTR_ERR(reloc_root));
730+
return ERR_CAST(reloc_root);
729731
}
730732
set_bit(BTRFS_ROOT_SHAREABLE, &reloc_root->state);
731733
btrfs_set_root_last_trans(reloc_root, trans->transid);
732734
return reloc_root;
733-
734-
abort:
735-
btrfs_abort_transaction(trans, ret);
736-
return ERR_PTR(ret);
737735
}
738736

739737
/*
@@ -1912,6 +1910,7 @@ void merge_reloc_roots(struct reloc_control *rc)
19121910
* corruption, e.g. bad reloc tree key offset.
19131911
*/
19141912
ret = -EINVAL;
1913+
btrfs_put_root(root);
19151914
goto out;
19161915
}
19171916
ret = merge_reloc_root(rc, root);

fs/btrfs/tree-checker.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1923,6 +1923,12 @@ static int check_inode_ref(struct extent_buffer *leaf,
19231923

19241924
iref = (struct btrfs_inode_ref *)ptr;
19251925
namelen = btrfs_inode_ref_name_len(leaf, iref);
1926+
if (unlikely(namelen == 0 || namelen > BTRFS_NAME_LEN)) {
1927+
inode_ref_err(leaf, slot,
1928+
"invalid inode ref name length, has %u expect [1, %u]",
1929+
namelen, BTRFS_NAME_LEN);
1930+
return -EUCLEAN;
1931+
}
19261932
if (unlikely(ptr + sizeof(*iref) + namelen > end)) {
19271933
inode_ref_err(leaf, slot,
19281934
"inode ref overflow, ptr %lu end %lu namelen %u",

0 commit comments

Comments
 (0)