Commit 00aff683 authored by Linus Torvalds's avatar Linus Torvalds

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
parents 4aba1a7e a5009d3a
...@@ -474,6 +474,7 @@ static noinline int compress_file_range(struct async_chunk *async_chunk) ...@@ -474,6 +474,7 @@ static noinline int compress_file_range(struct async_chunk *async_chunk)
u64 start = async_chunk->start; u64 start = async_chunk->start;
u64 end = async_chunk->end; u64 end = async_chunk->end;
u64 actual_end; u64 actual_end;
u64 i_size;
int ret = 0; int ret = 0;
struct page **pages = NULL; struct page **pages = NULL;
unsigned long nr_pages; unsigned long nr_pages;
...@@ -488,7 +489,19 @@ static noinline int compress_file_range(struct async_chunk *async_chunk) ...@@ -488,7 +489,19 @@ static noinline int compress_file_range(struct async_chunk *async_chunk)
inode_should_defrag(BTRFS_I(inode), start, end, end - start + 1, inode_should_defrag(BTRFS_I(inode), start, end, end - start + 1,
SZ_16K); SZ_16K);
actual_end = min_t(u64, i_size_read(inode), end + 1); /*
* We need to save i_size before now because it could change in between
* us evaluating the size and assigning it. This is because we lock and
* unlock the page in truncate and fallocate, and then modify the i_size
* later on.
*
* The barriers are to emulate READ_ONCE, remove that once i_size_read
* does that for us.
*/
barrier();
i_size = i_size_read(inode);
barrier();
actual_end = min_t(u64, i_size, end + 1);
again: again:
will_compress = 0; will_compress = 0;
nr_pages = (end >> PAGE_SHIFT) - (start >> PAGE_SHIFT) + 1; nr_pages = (end >> PAGE_SHIFT) - (start >> PAGE_SHIFT) + 1;
......
...@@ -4195,9 +4195,6 @@ static noinline long btrfs_ioctl_start_sync(struct btrfs_root *root, ...@@ -4195,9 +4195,6 @@ static noinline long btrfs_ioctl_start_sync(struct btrfs_root *root,
u64 transid; u64 transid;
int ret; int ret;
btrfs_warn(root->fs_info,
"START_SYNC ioctl is deprecated and will be removed in kernel 5.7");
trans = btrfs_attach_transaction_barrier(root); trans = btrfs_attach_transaction_barrier(root);
if (IS_ERR(trans)) { if (IS_ERR(trans)) {
if (PTR_ERR(trans) != -ENOENT) if (PTR_ERR(trans) != -ENOENT)
...@@ -4225,9 +4222,6 @@ static noinline long btrfs_ioctl_wait_sync(struct btrfs_fs_info *fs_info, ...@@ -4225,9 +4222,6 @@ static noinline long btrfs_ioctl_wait_sync(struct btrfs_fs_info *fs_info,
{ {
u64 transid; u64 transid;
btrfs_warn(fs_info,
"WAIT_SYNC ioctl is deprecated and will be removed in kernel 5.7");
if (argp) { if (argp) {
if (copy_from_user(&transid, argp, sizeof(transid))) if (copy_from_user(&transid, argp, sizeof(transid)))
return -EFAULT; return -EFAULT;
......
...@@ -893,6 +893,15 @@ static void wait_reserve_ticket(struct btrfs_fs_info *fs_info, ...@@ -893,6 +893,15 @@ static void wait_reserve_ticket(struct btrfs_fs_info *fs_info,
while (ticket->bytes > 0 && ticket->error == 0) { while (ticket->bytes > 0 && ticket->error == 0) {
ret = prepare_to_wait_event(&ticket->wait, &wait, TASK_KILLABLE); ret = prepare_to_wait_event(&ticket->wait, &wait, TASK_KILLABLE);
if (ret) { if (ret) {
/*
* Delete us from the list. After we unlock the space
* info, we don't want the async reclaim job to reserve
* space for this ticket. If that would happen, then the
* ticket's task would not known that space was reserved
* despite getting an error, resulting in a space leak
* (bytes_may_use counter of our space_info).
*/
list_del_init(&ticket->list);
ticket->error = -EINTR; ticket->error = -EINTR;
break; break;
} }
...@@ -945,12 +954,24 @@ static int handle_reserve_ticket(struct btrfs_fs_info *fs_info, ...@@ -945,12 +954,24 @@ static int handle_reserve_ticket(struct btrfs_fs_info *fs_info,
spin_lock(&space_info->lock); spin_lock(&space_info->lock);
ret = ticket->error; ret = ticket->error;
if (ticket->bytes || ticket->error) { if (ticket->bytes || ticket->error) {
/*
* Need to delete here for priority tickets. For regular tickets
* either the async reclaim job deletes the ticket from the list
* or we delete it ourselves at wait_reserve_ticket().
*/
list_del_init(&ticket->list); list_del_init(&ticket->list);
if (!ret) if (!ret)
ret = -ENOSPC; ret = -ENOSPC;
} }
spin_unlock(&space_info->lock); spin_unlock(&space_info->lock);
ASSERT(list_empty(&ticket->list)); ASSERT(list_empty(&ticket->list));
/*
* Check that we can't have an error set if the reservation succeeded,
* as that would confuse tasks and lead them to error out without
* releasing reserved space (if an error happens the expectation is that
* space wasn't reserved at all).
*/
ASSERT(!(ticket->bytes == 0 && ticket->error));
return ret; return ret;
} }
......
...@@ -686,9 +686,7 @@ static void dev_item_err(const struct extent_buffer *eb, int slot, ...@@ -686,9 +686,7 @@ static void dev_item_err(const struct extent_buffer *eb, int slot,
static int check_dev_item(struct extent_buffer *leaf, static int check_dev_item(struct extent_buffer *leaf,
struct btrfs_key *key, int slot) struct btrfs_key *key, int slot)
{ {
struct btrfs_fs_info *fs_info = leaf->fs_info;
struct btrfs_dev_item *ditem; struct btrfs_dev_item *ditem;
u64 max_devid = max(BTRFS_MAX_DEVS(fs_info), BTRFS_MAX_DEVS_SYS_CHUNK);
if (key->objectid != BTRFS_DEV_ITEMS_OBJECTID) { if (key->objectid != BTRFS_DEV_ITEMS_OBJECTID) {
dev_item_err(leaf, slot, dev_item_err(leaf, slot,
...@@ -696,12 +694,6 @@ static int check_dev_item(struct extent_buffer *leaf, ...@@ -696,12 +694,6 @@ static int check_dev_item(struct extent_buffer *leaf,
key->objectid, BTRFS_DEV_ITEMS_OBJECTID); key->objectid, BTRFS_DEV_ITEMS_OBJECTID);
return -EUCLEAN; return -EUCLEAN;
} }
if (key->offset > max_devid) {
dev_item_err(leaf, slot,
"invalid devid: has=%llu expect=[0, %llu]",
key->offset, max_devid);
return -EUCLEAN;
}
ditem = btrfs_item_ptr(leaf, slot, struct btrfs_dev_item); ditem = btrfs_item_ptr(leaf, slot, struct btrfs_dev_item);
if (btrfs_device_id(leaf, ditem) != key->offset) { if (btrfs_device_id(leaf, ditem) != key->offset) {
dev_item_err(leaf, slot, dev_item_err(leaf, slot,
......
...@@ -4967,6 +4967,7 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans, ...@@ -4967,6 +4967,7 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
} else if (type & BTRFS_BLOCK_GROUP_SYSTEM) { } else if (type & BTRFS_BLOCK_GROUP_SYSTEM) {
max_stripe_size = SZ_32M; max_stripe_size = SZ_32M;
max_chunk_size = 2 * max_stripe_size; max_chunk_size = 2 * max_stripe_size;
devs_max = min_t(int, devs_max, BTRFS_MAX_DEVS_SYS_CHUNK);
} else { } else {
btrfs_err(info, "invalid chunk type 0x%llx requested", btrfs_err(info, "invalid chunk type 0x%llx requested",
type); type);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment