Skip to content

Commit 00aff68

Browse files
committed
Merge tag 'for-5.4-rc6-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux
Pull btrfs fixes from David Sterba: "A few regressions and fixes for stable. Regressions: - fix a race leading to metadata space leak after task received a signal - un-deprecate 2 ioctls, marked as deprecated by mistake Fixes: - fix limit check for number of devices during chunk allocation - fix a race due to double evaluation of i_size_read inside max() macro, can cause a crash - remove wrong device id check in tree-checker" * tag 'for-5.4-rc6-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux: btrfs: un-deprecate ioctls START_SYNC and WAIT_SYNC btrfs: save i_size to avoid double evaluation of i_size_read in compress_file_range Btrfs: fix race leading to metadata space leak after task received signal btrfs: tree-checker: Fix wrong check on max devid btrfs: Consider system chunk array size for new SYSTEM chunks
2 parents 4aba1a7 + a5009d3 commit 00aff68

File tree

5 files changed

+36
-15
lines changed

5 files changed

+36
-15
lines changed

fs/btrfs/inode.c

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -474,6 +474,7 @@ static noinline int compress_file_range(struct async_chunk *async_chunk)
474474
u64 start = async_chunk->start;
475475
u64 end = async_chunk->end;
476476
u64 actual_end;
477+
u64 i_size;
477478
int ret = 0;
478479
struct page **pages = NULL;
479480
unsigned long nr_pages;
@@ -488,7 +489,19 @@ static noinline int compress_file_range(struct async_chunk *async_chunk)
488489
inode_should_defrag(BTRFS_I(inode), start, end, end - start + 1,
489490
SZ_16K);
490491

491-
actual_end = min_t(u64, i_size_read(inode), end + 1);
492+
/*
493+
* We need to save i_size before now because it could change in between
494+
* us evaluating the size and assigning it. This is because we lock and
495+
* unlock the page in truncate and fallocate, and then modify the i_size
496+
* later on.
497+
*
498+
* The barriers are to emulate READ_ONCE, remove that once i_size_read
499+
* does that for us.
500+
*/
501+
barrier();
502+
i_size = i_size_read(inode);
503+
barrier();
504+
actual_end = min_t(u64, i_size, end + 1);
492505
again:
493506
will_compress = 0;
494507
nr_pages = (end >> PAGE_SHIFT) - (start >> PAGE_SHIFT) + 1;

fs/btrfs/ioctl.c

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4195,9 +4195,6 @@ static noinline long btrfs_ioctl_start_sync(struct btrfs_root *root,
41954195
u64 transid;
41964196
int ret;
41974197

4198-
btrfs_warn(root->fs_info,
4199-
"START_SYNC ioctl is deprecated and will be removed in kernel 5.7");
4200-
42014198
trans = btrfs_attach_transaction_barrier(root);
42024199
if (IS_ERR(trans)) {
42034200
if (PTR_ERR(trans) != -ENOENT)
@@ -4225,9 +4222,6 @@ static noinline long btrfs_ioctl_wait_sync(struct btrfs_fs_info *fs_info,
42254222
{
42264223
u64 transid;
42274224

4228-
btrfs_warn(fs_info,
4229-
"WAIT_SYNC ioctl is deprecated and will be removed in kernel 5.7");
4230-
42314225
if (argp) {
42324226
if (copy_from_user(&transid, argp, sizeof(transid)))
42334227
return -EFAULT;

fs/btrfs/space-info.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -893,6 +893,15 @@ static void wait_reserve_ticket(struct btrfs_fs_info *fs_info,
893893
while (ticket->bytes > 0 && ticket->error == 0) {
894894
ret = prepare_to_wait_event(&ticket->wait, &wait, TASK_KILLABLE);
895895
if (ret) {
896+
/*
897+
* Delete us from the list. After we unlock the space
898+
* info, we don't want the async reclaim job to reserve
899+
* space for this ticket. If that would happen, then the
900+
* ticket's task would not known that space was reserved
901+
* despite getting an error, resulting in a space leak
902+
* (bytes_may_use counter of our space_info).
903+
*/
904+
list_del_init(&ticket->list);
896905
ticket->error = -EINTR;
897906
break;
898907
}
@@ -945,12 +954,24 @@ static int handle_reserve_ticket(struct btrfs_fs_info *fs_info,
945954
spin_lock(&space_info->lock);
946955
ret = ticket->error;
947956
if (ticket->bytes || ticket->error) {
957+
/*
958+
* Need to delete here for priority tickets. For regular tickets
959+
* either the async reclaim job deletes the ticket from the list
960+
* or we delete it ourselves at wait_reserve_ticket().
961+
*/
948962
list_del_init(&ticket->list);
949963
if (!ret)
950964
ret = -ENOSPC;
951965
}
952966
spin_unlock(&space_info->lock);
953967
ASSERT(list_empty(&ticket->list));
968+
/*
969+
* Check that we can't have an error set if the reservation succeeded,
970+
* as that would confuse tasks and lead them to error out without
971+
* releasing reserved space (if an error happens the expectation is that
972+
* space wasn't reserved at all).
973+
*/
974+
ASSERT(!(ticket->bytes == 0 && ticket->error));
954975
return ret;
955976
}
956977

fs/btrfs/tree-checker.c

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -686,22 +686,14 @@ static void dev_item_err(const struct extent_buffer *eb, int slot,
686686
static int check_dev_item(struct extent_buffer *leaf,
687687
struct btrfs_key *key, int slot)
688688
{
689-
struct btrfs_fs_info *fs_info = leaf->fs_info;
690689
struct btrfs_dev_item *ditem;
691-
u64 max_devid = max(BTRFS_MAX_DEVS(fs_info), BTRFS_MAX_DEVS_SYS_CHUNK);
692690

693691
if (key->objectid != BTRFS_DEV_ITEMS_OBJECTID) {
694692
dev_item_err(leaf, slot,
695693
"invalid objectid: has=%llu expect=%llu",
696694
key->objectid, BTRFS_DEV_ITEMS_OBJECTID);
697695
return -EUCLEAN;
698696
}
699-
if (key->offset > max_devid) {
700-
dev_item_err(leaf, slot,
701-
"invalid devid: has=%llu expect=[0, %llu]",
702-
key->offset, max_devid);
703-
return -EUCLEAN;
704-
}
705697
ditem = btrfs_item_ptr(leaf, slot, struct btrfs_dev_item);
706698
if (btrfs_device_id(leaf, ditem) != key->offset) {
707699
dev_item_err(leaf, slot,

fs/btrfs/volumes.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4967,6 +4967,7 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
49674967
} else if (type & BTRFS_BLOCK_GROUP_SYSTEM) {
49684968
max_stripe_size = SZ_32M;
49694969
max_chunk_size = 2 * max_stripe_size;
4970+
devs_max = min_t(int, devs_max, BTRFS_MAX_DEVS_SYS_CHUNK);
49704971
} else {
49714972
btrfs_err(info, "invalid chunk type 0x%llx requested",
49724973
type);

0 commit comments

Comments
 (0)