Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8d19514f authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull btrfs fixes from Chris Mason:
 "We've got corner cases for updating i_size that ceph was hitting,
  error handling for quotas when we run out of space, a very subtle
  snapshot deletion race, a crash while removing devices, and one
  deadlock between subvolume creation and the sb_internal code (thanks
  lockdep)."

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs:
  Btrfs: move d_instantiate outside the transaction during mksubvol
  Btrfs: fix EDQUOT handling in btrfs_delalloc_reserve_metadata
  Btrfs: fix possible stale data exposure
  Btrfs: fix missing i_size update
  Btrfs: fix race between snapshot deletion and getting inode
  Btrfs: fix missing release of the space/qgroup reservation in start_transaction()
  Btrfs: fix wrong sync_writers decrement in btrfs_file_aio_write()
  Btrfs: do not merge logged extents if we've removed them from the tree
  btrfs: don't try to notify udev about missing devices
parents 95436ada 1a65e24b
Loading
Loading
Loading
Loading
+10 −12
Original line number Diff line number Diff line
@@ -4534,7 +4534,7 @@ int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes)
	unsigned nr_extents = 0;
	int extra_reserve = 0;
	enum btrfs_reserve_flush_enum flush = BTRFS_RESERVE_FLUSH_ALL;
	int ret;
	int ret = 0;
	bool delalloc_lock = true;

	/* If we are a free space inode we need to not flush since we will be in
@@ -4579,20 +4579,18 @@ int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes)
	csum_bytes = BTRFS_I(inode)->csum_bytes;
	spin_unlock(&BTRFS_I(inode)->lock);

	if (root->fs_info->quota_enabled) {
	if (root->fs_info->quota_enabled)
		ret = btrfs_qgroup_reserve(root, num_bytes +
					   nr_extents * root->leafsize);
		if (ret) {
			spin_lock(&BTRFS_I(inode)->lock);
			calc_csum_metadata_size(inode, num_bytes, 0);
			spin_unlock(&BTRFS_I(inode)->lock);
			if (delalloc_lock)
				mutex_unlock(&BTRFS_I(inode)->delalloc_mutex);
			return ret;
		}
	}

	ret = reserve_metadata_bytes(root, block_rsv, to_reserve, flush);
	/*
	 * ret != 0 here means the qgroup reservation failed, we go straight to
	 * the shared error handling then.
	 */
	if (ret == 0)
		ret = reserve_metadata_bytes(root, block_rsv,
					     to_reserve, flush);

	if (ret) {
		u64 to_free = 0;
		unsigned dropped;
+2 −1
Original line number Diff line number Diff line
@@ -288,6 +288,7 @@ int unpin_extent_cache(struct extent_map_tree *tree, u64 start, u64 len,
void clear_em_logging(struct extent_map_tree *tree, struct extent_map *em)
{
	clear_bit(EXTENT_FLAG_LOGGING, &em->flags);
	if (em->in_tree)
		try_merge_map(tree, em);
}

+20 −5
Original line number Diff line number Diff line
@@ -293,15 +293,24 @@ static int __btrfs_run_defrag_inode(struct btrfs_fs_info *fs_info,
	struct btrfs_key key;
	struct btrfs_ioctl_defrag_range_args range;
	int num_defrag;
	int index;
	int ret;

	/* get the inode */
	key.objectid = defrag->root;
	btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY);
	key.offset = (u64)-1;

	index = srcu_read_lock(&fs_info->subvol_srcu);

	inode_root = btrfs_read_fs_root_no_name(fs_info, &key);
	if (IS_ERR(inode_root)) {
		kmem_cache_free(btrfs_inode_defrag_cachep, defrag);
		return PTR_ERR(inode_root);
		ret = PTR_ERR(inode_root);
		goto cleanup;
	}
	if (btrfs_root_refs(&inode_root->root_item) == 0) {
		ret = -ENOENT;
		goto cleanup;
	}

	key.objectid = defrag->ino;
@@ -309,9 +318,10 @@ static int __btrfs_run_defrag_inode(struct btrfs_fs_info *fs_info,
	key.offset = 0;
	inode = btrfs_iget(fs_info->sb, &key, inode_root, NULL);
	if (IS_ERR(inode)) {
		kmem_cache_free(btrfs_inode_defrag_cachep, defrag);
		return PTR_ERR(inode);
		ret = PTR_ERR(inode);
		goto cleanup;
	}
	srcu_read_unlock(&fs_info->subvol_srcu, index);

	/* do a chunk of defrag */
	clear_bit(BTRFS_INODE_IN_DEFRAG, &BTRFS_I(inode)->runtime_flags);
@@ -346,6 +356,10 @@ static int __btrfs_run_defrag_inode(struct btrfs_fs_info *fs_info,

	iput(inode);
	return 0;
cleanup:
	srcu_read_unlock(&fs_info->subvol_srcu, index);
	kmem_cache_free(btrfs_inode_defrag_cachep, defrag);
	return ret;
}

/*
@@ -1594,9 +1608,10 @@ static ssize_t btrfs_file_aio_write(struct kiocb *iocb,
		if (err < 0 && num_written > 0)
			num_written = err;
	}
out:

	if (sync)
		atomic_dec(&BTRFS_I(inode)->sync_writers);
out:
	sb_end_write(inode->i_sb);
	current->backing_dev_info = NULL;
	return num_written ? num_written : err;
+4 −1
Original line number Diff line number Diff line
@@ -515,7 +515,6 @@ static noinline int create_subvol(struct btrfs_root *root,

	BUG_ON(ret);

	d_instantiate(dentry, btrfs_lookup_dentry(dir, dentry));
fail:
	if (async_transid) {
		*async_transid = trans->transid;
@@ -525,6 +524,10 @@ static noinline int create_subvol(struct btrfs_root *root,
	}
	if (err && !ret)
		ret = err;

	if (!ret)
		d_instantiate(dentry, btrfs_lookup_dentry(dir, dentry));

	return ret;
}

+10 −3
Original line number Diff line number Diff line
@@ -836,9 +836,16 @@ int btrfs_ordered_update_i_size(struct inode *inode, u64 offset,
	 * if the disk i_size is already at the inode->i_size, or
	 * this ordered extent is inside the disk i_size, we're done
	 */
	if (disk_i_size == i_size || offset <= disk_i_size) {
	if (disk_i_size == i_size)
		goto out;

	/*
	 * We still need to update disk_i_size if outstanding_isize is greater
	 * than disk_i_size.
	 */
	if (offset <= disk_i_size &&
	    (!ordered || ordered->outstanding_isize <= disk_i_size))
		goto out;
	}

	/*
	 * walk backward from this ordered extent to disk_i_size.
@@ -870,7 +877,7 @@ int btrfs_ordered_update_i_size(struct inode *inode, u64 offset,
			break;
		if (test->file_offset >= i_size)
			break;
		if (test->file_offset >= disk_i_size) {
		if (entry_end(test) > disk_i_size) {
			/*
			 * we don't update disk_i_size now, so record this
			 * undealt i_size. Or we will not know the real
Loading