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

Commit c1f42467 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs:
  btrfs: rename the option to nospace_cache
  Btrfs: handle bio_add_page failure gracefully in scrub
  Btrfs: fix deadlock caused by the race between relocation
  Btrfs: only map pages if we know we need them when reading the space cache
  Btrfs: fix orphan backref nodes
  Btrfs: Abstract similar code for btrfs_block_rsv_add{, _noflush}
  Btrfs: fix unreleased path in btrfs_orphan_cleanup()
  Btrfs: fix no reserved space for writing out inode cache
  Btrfs: fix nocow when deleting the item
  Btrfs: tweak the delayed inode reservations again
  Btrfs: rework error handling in btrfs_mount()
  Btrfs: close devices on all error paths in open_ctree()
  Btrfs: avoid null dereference and leaks when bailing from open_ctree()
  Btrfs: fix subvol_name leak on error in btrfs_mount()
  Btrfs: fix memory leak in btrfs_parse_early_options()
  Btrfs: fix our reservations for updating an inode when completing io
  Btrfs: fix oops on NULL trans handle in btrfs_truncate
  btrfs: fix double-free 'tree_root' in 'btrfs_mount()'
parents fe10e6f4 8965593e
Loading
Loading
Loading
Loading
+1 −3
Original line number Diff line number Diff line
@@ -147,14 +147,12 @@ struct btrfs_inode {
	 * the btrfs file release call will add this inode to the
	 * ordered operations list so that we make sure to flush out any
	 * new data the application may have written before commit.
	 *
	 * yes, its silly to have a single bitflag, but we might grow more
	 * of these.
	 */
	unsigned ordered_data_close:1;
	unsigned orphan_meta_reserved:1;
	unsigned dummy_inode:1;
	unsigned in_defrag:1;
	unsigned delalloc_meta_reserved:1;

	/*
	 * always compress this one file
+57 −1
Original line number Diff line number Diff line
@@ -617,12 +617,14 @@ static void btrfs_delayed_item_release_metadata(struct btrfs_root *root,
static int btrfs_delayed_inode_reserve_metadata(
					struct btrfs_trans_handle *trans,
					struct btrfs_root *root,
					struct inode *inode,
					struct btrfs_delayed_node *node)
{
	struct btrfs_block_rsv *src_rsv;
	struct btrfs_block_rsv *dst_rsv;
	u64 num_bytes;
	int ret;
	int release = false;

	src_rsv = trans->block_rsv;
	dst_rsv = &root->fs_info->delayed_block_rsv;
@@ -652,12 +654,65 @@ static int btrfs_delayed_inode_reserve_metadata(
		if (!ret)
			node->bytes_reserved = num_bytes;
		return ret;
	} else if (src_rsv == &root->fs_info->delalloc_block_rsv) {
		spin_lock(&BTRFS_I(inode)->lock);
		if (BTRFS_I(inode)->delalloc_meta_reserved) {
			BTRFS_I(inode)->delalloc_meta_reserved = 0;
			spin_unlock(&BTRFS_I(inode)->lock);
			release = true;
			goto migrate;
		}
		spin_unlock(&BTRFS_I(inode)->lock);

		/* Ok we didn't have space pre-reserved.  This shouldn't happen
		 * too often but it can happen if we do delalloc to an existing
		 * inode which gets dirtied because of the time update, and then
		 * isn't touched again until after the transaction commits and
		 * then we try to write out the data.  First try to be nice and
		 * reserve something strictly for us.  If not be a pain and try
		 * to steal from the delalloc block rsv.
		 */
		ret = btrfs_block_rsv_add_noflush(root, dst_rsv, num_bytes);
		if (!ret)
			goto out;

		ret = btrfs_block_rsv_migrate(src_rsv, dst_rsv, num_bytes);
		if (!ret)
			goto out;

		/*
		 * Ok this is a problem, let's just steal from the global rsv
		 * since this really shouldn't happen that often.
		 */
		WARN_ON(1);
		ret = btrfs_block_rsv_migrate(&root->fs_info->global_block_rsv,
					      dst_rsv, num_bytes);
		goto out;
	}

migrate:
	ret = btrfs_block_rsv_migrate(src_rsv, dst_rsv, num_bytes);

out:
	/*
	 * Migrate only takes a reservation, it doesn't touch the size of the
	 * block_rsv.  This is to simplify people who don't normally have things
	 * migrated from their block rsv.  If they go to release their
	 * reservation, that will decrease the size as well, so if migrate
	 * reduced size we'd end up with a negative size.  But for the
	 * delalloc_meta_reserved stuff we will only know to drop 1 reservation,
	 * but we could in fact do this reserve/migrate dance several times
	 * between the time we did the original reservation and we'd clean it
	 * up.  So to take care of this, release the space for the meta
	 * reservation here.  I think it may be time for a documentation page on
	 * how block rsvs. work.
	 */
	if (!ret)
		node->bytes_reserved = num_bytes;

	if (release)
		btrfs_block_rsv_release(root, src_rsv, num_bytes);

	return ret;
}

@@ -1708,7 +1763,8 @@ int btrfs_delayed_update_inode(struct btrfs_trans_handle *trans,
		goto release_node;
	}

	ret = btrfs_delayed_inode_reserve_metadata(trans, root, delayed_node);
	ret = btrfs_delayed_inode_reserve_metadata(trans, root, inode,
						   delayed_node);
	if (ret)
		goto release_node;

+18 −24
Original line number Diff line number Diff line
@@ -1890,31 +1890,32 @@ struct btrfs_root *open_ctree(struct super_block *sb,
	u64 features;
	struct btrfs_key location;
	struct buffer_head *bh;
	struct btrfs_root *extent_root = kzalloc(sizeof(struct btrfs_root),
						 GFP_NOFS);
	struct btrfs_root *csum_root = kzalloc(sizeof(struct btrfs_root),
						 GFP_NOFS);
	struct btrfs_super_block *disk_super;
	struct btrfs_root *tree_root = btrfs_sb(sb);
	struct btrfs_fs_info *fs_info = NULL;
	struct btrfs_root *chunk_root = kzalloc(sizeof(struct btrfs_root),
						GFP_NOFS);
	struct btrfs_root *dev_root = kzalloc(sizeof(struct btrfs_root),
					      GFP_NOFS);
	struct btrfs_fs_info *fs_info = tree_root->fs_info;
	struct btrfs_root *extent_root;
	struct btrfs_root *csum_root;
	struct btrfs_root *chunk_root;
	struct btrfs_root *dev_root;
	struct btrfs_root *log_tree_root;

	int ret;
	int err = -EINVAL;
	int num_backups_tried = 0;
	int backup_index = 0;

	struct btrfs_super_block *disk_super;
	extent_root = fs_info->extent_root =
		kzalloc(sizeof(struct btrfs_root), GFP_NOFS);
	csum_root = fs_info->csum_root =
		kzalloc(sizeof(struct btrfs_root), GFP_NOFS);
	chunk_root = fs_info->chunk_root =
		kzalloc(sizeof(struct btrfs_root), GFP_NOFS);
	dev_root = fs_info->dev_root =
		kzalloc(sizeof(struct btrfs_root), GFP_NOFS);

	if (!extent_root || !tree_root || !tree_root->fs_info ||
	    !chunk_root || !dev_root || !csum_root) {
	if (!extent_root || !csum_root || !chunk_root || !dev_root) {
		err = -ENOMEM;
		goto fail;
	}
	fs_info = tree_root->fs_info;

	ret = init_srcu_struct(&fs_info->subvol_srcu);
	if (ret) {
@@ -1954,12 +1955,6 @@ struct btrfs_root *open_ctree(struct super_block *sb,
	mutex_init(&fs_info->reloc_mutex);

	init_completion(&fs_info->kobj_unregister);
	fs_info->tree_root = tree_root;
	fs_info->extent_root = extent_root;
	fs_info->csum_root = csum_root;
	fs_info->chunk_root = chunk_root;
	fs_info->dev_root = dev_root;
	fs_info->fs_devices = fs_devices;
	INIT_LIST_HEAD(&fs_info->dirty_cowonly_roots);
	INIT_LIST_HEAD(&fs_info->space_info);
	btrfs_mapping_init(&fs_info->mapping_tree);
@@ -2465,21 +2460,20 @@ fail_sb_buffer:
	btrfs_stop_workers(&fs_info->caching_workers);
fail_alloc:
fail_iput:
	btrfs_mapping_tree_free(&fs_info->mapping_tree);

	invalidate_inode_pages2(fs_info->btree_inode->i_mapping);
	iput(fs_info->btree_inode);

	btrfs_close_devices(fs_info->fs_devices);
	btrfs_mapping_tree_free(&fs_info->mapping_tree);
fail_bdi:
	bdi_destroy(&fs_info->bdi);
fail_srcu:
	cleanup_srcu_struct(&fs_info->subvol_srcu);
fail:
	btrfs_close_devices(fs_info->fs_devices);
	free_fs_info(fs_info);
	return ERR_PTR(err);

recovery_tree_root:

	if (!btrfs_test_opt(tree_root, RECOVERY))
		goto fail_tree_roots;

+31 −19
Original line number Diff line number Diff line
@@ -3797,16 +3797,16 @@ void btrfs_free_block_rsv(struct btrfs_root *root,
	kfree(rsv);
}

int btrfs_block_rsv_add(struct btrfs_root *root,
static inline int __block_rsv_add(struct btrfs_root *root,
				  struct btrfs_block_rsv *block_rsv,
			u64 num_bytes)
				  u64 num_bytes, int flush)
{
	int ret;

	if (num_bytes == 0)
		return 0;

	ret = reserve_metadata_bytes(root, block_rsv, num_bytes, 1);
	ret = reserve_metadata_bytes(root, block_rsv, num_bytes, flush);
	if (!ret) {
		block_rsv_add_bytes(block_rsv, num_bytes, 1);
		return 0;
@@ -3815,22 +3815,18 @@ int btrfs_block_rsv_add(struct btrfs_root *root,
	return ret;
}

int btrfs_block_rsv_add_noflush(struct btrfs_root *root,
int btrfs_block_rsv_add(struct btrfs_root *root,
			struct btrfs_block_rsv *block_rsv,
			u64 num_bytes)
{
	int ret;

	if (num_bytes == 0)
		return 0;

	ret = reserve_metadata_bytes(root, block_rsv, num_bytes, 0);
	if (!ret) {
		block_rsv_add_bytes(block_rsv, num_bytes, 1);
		return 0;
	return __block_rsv_add(root, block_rsv, num_bytes, 1);
}

	return ret;
int btrfs_block_rsv_add_noflush(struct btrfs_root *root,
				struct btrfs_block_rsv *block_rsv,
				u64 num_bytes)
{
	return __block_rsv_add(root, block_rsv, num_bytes, 0);
}

int btrfs_block_rsv_check(struct btrfs_root *root,
@@ -4064,23 +4060,30 @@ int btrfs_snap_reserve_metadata(struct btrfs_trans_handle *trans,
 */
static unsigned drop_outstanding_extent(struct inode *inode)
{
	unsigned drop_inode_space = 0;
	unsigned dropped_extents = 0;

	BUG_ON(!BTRFS_I(inode)->outstanding_extents);
	BTRFS_I(inode)->outstanding_extents--;

	if (BTRFS_I(inode)->outstanding_extents == 0 &&
	    BTRFS_I(inode)->delalloc_meta_reserved) {
		drop_inode_space = 1;
		BTRFS_I(inode)->delalloc_meta_reserved = 0;
	}

	/*
	 * If we have more or the same amount of outsanding extents than we have
	 * reserved then we need to leave the reserved extents count alone.
	 */
	if (BTRFS_I(inode)->outstanding_extents >=
	    BTRFS_I(inode)->reserved_extents)
		return 0;
		return drop_inode_space;

	dropped_extents = BTRFS_I(inode)->reserved_extents -
		BTRFS_I(inode)->outstanding_extents;
	BTRFS_I(inode)->reserved_extents -= dropped_extents;
	return dropped_extents;
	return dropped_extents + drop_inode_space;
}

/**
@@ -4166,9 +4169,18 @@ int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes)
		nr_extents = BTRFS_I(inode)->outstanding_extents -
			BTRFS_I(inode)->reserved_extents;
		BTRFS_I(inode)->reserved_extents += nr_extents;
	}

		to_reserve = btrfs_calc_trans_metadata_size(root, nr_extents);
	/*
	 * Add an item to reserve for updating the inode when we complete the
	 * delalloc io.
	 */
	if (!BTRFS_I(inode)->delalloc_meta_reserved) {
		nr_extents++;
		BTRFS_I(inode)->delalloc_meta_reserved = 1;
	}

	to_reserve = btrfs_calc_trans_metadata_size(root, nr_extents);
	to_reserve += calc_csum_metadata_size(inode, num_bytes, 1);
	spin_unlock(&BTRFS_I(inode)->lock);

+10 −7
Original line number Diff line number Diff line
@@ -537,6 +537,13 @@ static int io_ctl_read_entry(struct io_ctl *io_ctl,
			    struct btrfs_free_space *entry, u8 *type)
{
	struct btrfs_free_space_entry *e;
	int ret;

	if (!io_ctl->cur) {
		ret = io_ctl_check_crc(io_ctl, io_ctl->index);
		if (ret)
			return ret;
	}

	e = io_ctl->cur;
	entry->offset = le64_to_cpu(e->offset);
@@ -550,10 +557,7 @@ static int io_ctl_read_entry(struct io_ctl *io_ctl,

	io_ctl_unmap_page(io_ctl);

	if (io_ctl->index >= io_ctl->num_pages)
	return 0;

	return io_ctl_check_crc(io_ctl, io_ctl->index);
}

static int io_ctl_read_bitmap(struct io_ctl *io_ctl,
@@ -561,9 +565,6 @@ static int io_ctl_read_bitmap(struct io_ctl *io_ctl,
{
	int ret;

	if (io_ctl->cur && io_ctl->cur != io_ctl->orig)
		io_ctl_unmap_page(io_ctl);

	ret = io_ctl_check_crc(io_ctl, io_ctl->index);
	if (ret)
		return ret;
@@ -699,6 +700,8 @@ int __load_free_space_cache(struct btrfs_root *root, struct inode *inode,
		num_entries--;
	}

	io_ctl_unmap_page(&io_ctl);

	/*
	 * We add the bitmaps at the end of the entries in order that
	 * the bitmap entries are added to the cache.
Loading