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

Commit a061fc8d authored by Chris Mason's avatar Chris Mason
Browse files

Btrfs: Add support for online device removal



This required a few structural changes to the code that manages bdev pointers:

The VFS super block now gets an anon-bdev instead of a pointer to the
lowest bdev.  This allows us to avoid swapping the super block bdev pointer
around at run time.

The code to read in the super block no longer goes through the extent
buffer interface.  Things got ugly keeping the mapping constant.

Signed-off-by: default avatarChris Mason <chris.mason@oracle.com>
parent 5d9cd9ec
Loading
Loading
Loading
Loading
+2 −1
Original line number Original line Diff line number Diff line
@@ -505,7 +505,7 @@ struct btrfs_fs_info {
	u64 alloc_start;
	u64 alloc_start;
	struct btrfs_transaction *running_transaction;
	struct btrfs_transaction *running_transaction;
	struct btrfs_super_block super_copy;
	struct btrfs_super_block super_copy;
	struct extent_buffer *sb_buffer;
	struct btrfs_super_block super_for_commit;
	struct block_device *__bdev;
	struct block_device *__bdev;
	struct super_block *sb;
	struct super_block *sb;
	struct inode *btree_inode;
	struct inode *btree_inode;
@@ -1208,6 +1208,7 @@ BTRFS_SETGET_STACK_FUNCS(root_limit, struct btrfs_root_item, byte_limit, 64);


/* struct btrfs_super_block */
/* struct btrfs_super_block */
BTRFS_SETGET_STACK_FUNCS(super_bytenr, struct btrfs_super_block, bytenr, 64);
BTRFS_SETGET_STACK_FUNCS(super_bytenr, struct btrfs_super_block, bytenr, 64);
BTRFS_SETGET_STACK_FUNCS(super_flags, struct btrfs_super_block, flags, 64);
BTRFS_SETGET_STACK_FUNCS(super_generation, struct btrfs_super_block,
BTRFS_SETGET_STACK_FUNCS(super_generation, struct btrfs_super_block,
			 generation, 64);
			 generation, 64);
BTRFS_SETGET_STACK_FUNCS(super_root, struct btrfs_super_block, root, 64);
BTRFS_SETGET_STACK_FUNCS(super_root, struct btrfs_super_block, root, 64);
+46 −55
Original line number Original line Diff line number Diff line
@@ -78,9 +78,13 @@ struct extent_map *btree_get_extent(struct inode *inode, struct page *page,


	spin_lock(&em_tree->lock);
	spin_lock(&em_tree->lock);
	em = lookup_extent_mapping(em_tree, start, len);
	em = lookup_extent_mapping(em_tree, start, len);
	if (em) {
		em->bdev =
			BTRFS_I(inode)->root->fs_info->fs_devices->latest_bdev;
		spin_unlock(&em_tree->lock);
		spin_unlock(&em_tree->lock);
	if (em)
		goto out;
		goto out;
	}
	spin_unlock(&em_tree->lock);


	em = alloc_extent_map(GFP_NOFS);
	em = alloc_extent_map(GFP_NOFS);
	if (!em) {
	if (!em) {
@@ -90,7 +94,7 @@ struct extent_map *btree_get_extent(struct inode *inode, struct page *page,
	em->start = 0;
	em->start = 0;
	em->len = (u64)-1;
	em->len = (u64)-1;
	em->block_start = 0;
	em->block_start = 0;
	em->bdev = inode->i_sb->s_bdev;
	em->bdev = BTRFS_I(inode)->root->fs_info->fs_devices->latest_bdev;


	spin_lock(&em_tree->lock);
	spin_lock(&em_tree->lock);
	ret = add_extent_mapping(em_tree, em);
	ret = add_extent_mapping(em_tree, em);
@@ -435,11 +439,6 @@ static int __btree_submit_bio_hook(struct inode *inode, int rw, struct bio *bio,
	ret = btrfs_bio_wq_end_io(root->fs_info, bio, 1);
	ret = btrfs_bio_wq_end_io(root->fs_info, bio, 1);
	BUG_ON(ret);
	BUG_ON(ret);


	if (offset == BTRFS_SUPER_INFO_OFFSET) {
		bio->bi_bdev = root->fs_info->fs_devices->latest_bdev;
		submit_bio(rw, bio);
		return 0;
	}
	return btrfs_map_bio(BTRFS_I(inode)->root, rw, bio, mirror_num);
	return btrfs_map_bio(BTRFS_I(inode)->root, rw, bio, mirror_num);
}
}


@@ -587,7 +586,6 @@ static int close_all_devices(struct btrfs_fs_info *fs_info)
	list = &fs_info->fs_devices->devices;
	list = &fs_info->fs_devices->devices;
	list_for_each(next, list) {
	list_for_each(next, list) {
		device = list_entry(next, struct btrfs_device, dev_list);
		device = list_entry(next, struct btrfs_device, dev_list);
		if (device->bdev && device->bdev != fs_info->sb->s_bdev)
		close_bdev_excl(device->bdev);
		close_bdev_excl(device->bdev);
		device->bdev = NULL;
		device->bdev = NULL;
	}
	}
@@ -1118,6 +1116,7 @@ struct btrfs_root *open_ctree(struct super_block *sb,
	u32 leafsize;
	u32 leafsize;
	u32 blocksize;
	u32 blocksize;
	u32 stripesize;
	u32 stripesize;
	struct buffer_head *bh;
	struct btrfs_root *extent_root = kmalloc(sizeof(struct btrfs_root),
	struct btrfs_root *extent_root = kmalloc(sizeof(struct btrfs_root),
						 GFP_NOFS);
						 GFP_NOFS);
	struct btrfs_root *tree_root = kmalloc(sizeof(struct btrfs_root),
	struct btrfs_root *tree_root = kmalloc(sizeof(struct btrfs_root),
@@ -1153,7 +1152,6 @@ struct btrfs_root *open_ctree(struct super_block *sb,
	spin_lock_init(&fs_info->new_trans_lock);
	spin_lock_init(&fs_info->new_trans_lock);


	init_completion(&fs_info->kobj_unregister);
	init_completion(&fs_info->kobj_unregister);
	sb_set_blocksize(sb, BTRFS_SUPER_INFO_SIZE);
	fs_info->tree_root = tree_root;
	fs_info->tree_root = tree_root;
	fs_info->extent_root = extent_root;
	fs_info->extent_root = extent_root;
	fs_info->chunk_root = chunk_root;
	fs_info->chunk_root = chunk_root;
@@ -1170,6 +1168,9 @@ struct btrfs_root *open_ctree(struct super_block *sb,
	fs_info->btree_inode->i_ino = 1;
	fs_info->btree_inode->i_ino = 1;
	fs_info->btree_inode->i_nlink = 1;
	fs_info->btree_inode->i_nlink = 1;


	sb->s_blocksize = 4096;
	sb->s_blocksize_bits = blksize_bits(4096);

	/*
	/*
	 * we set the i_size on the btree inode to the max possible int.
	 * we set the i_size on the btree inode to the max possible int.
	 * the real end of the address space is determined by all of
	 * the real end of the address space is determined by all of
@@ -1229,19 +1230,16 @@ struct btrfs_root *open_ctree(struct super_block *sb,
	__setup_root(4096, 4096, 4096, 4096, tree_root,
	__setup_root(4096, 4096, 4096, 4096, tree_root,
		     fs_info, BTRFS_ROOT_TREE_OBJECTID);
		     fs_info, BTRFS_ROOT_TREE_OBJECTID);


	fs_info->sb_buffer = read_tree_block(tree_root,
					     BTRFS_SUPER_INFO_OFFSET,
					     4096);


	if (!fs_info->sb_buffer)
	bh = __bread(fs_devices->latest_bdev,
		     BTRFS_SUPER_INFO_OFFSET / 4096, 4096);
	if (!bh)
		goto fail_iput;
		goto fail_iput;


	read_extent_buffer(fs_info->sb_buffer, &fs_info->super_copy, 0,
	memcpy(&fs_info->super_copy, bh->b_data, sizeof(fs_info->super_copy));
			   sizeof(fs_info->super_copy));
	brelse(bh);


	read_extent_buffer(fs_info->sb_buffer, fs_info->fsid,
	memcpy(fs_info->fsid, fs_info->super_copy.fsid, BTRFS_FSID_SIZE);
			   (unsigned long)btrfs_super_fsid(fs_info->sb_buffer),
			   BTRFS_FSID_SIZE);


	disk_super = &fs_info->super_copy;
	disk_super = &fs_info->super_copy;
	if (!btrfs_super_root(disk_super))
	if (!btrfs_super_root(disk_super))
@@ -1263,7 +1261,9 @@ struct btrfs_root *open_ctree(struct super_block *sb,
	tree_root->leafsize = leafsize;
	tree_root->leafsize = leafsize;
	tree_root->sectorsize = sectorsize;
	tree_root->sectorsize = sectorsize;
	tree_root->stripesize = stripesize;
	tree_root->stripesize = stripesize;
	sb_set_blocksize(sb, sectorsize);

	sb->s_blocksize = sectorsize;
	sb->s_blocksize_bits = blksize_bits(sectorsize);


	if (strncmp((char *)(&disk_super->magic), BTRFS_MAGIC,
	if (strncmp((char *)(&disk_super->magic), BTRFS_MAGIC,
		    sizeof(disk_super->magic))) {
		    sizeof(disk_super->magic))) {
@@ -1339,7 +1339,6 @@ struct btrfs_root *open_ctree(struct super_block *sb,
fail_sys_array:
fail_sys_array:
	mutex_unlock(&fs_info->fs_mutex);
	mutex_unlock(&fs_info->fs_mutex);
fail_sb_buffer:
fail_sb_buffer:
	free_extent_buffer(fs_info->sb_buffer);
	extent_io_tree_empty_lru(&BTRFS_I(fs_info->btree_inode)->io_tree);
	extent_io_tree_empty_lru(&BTRFS_I(fs_info->btree_inode)->io_tree);
fail_iput:
fail_iput:
	iput(fs_info->btree_inode);
	iput(fs_info->btree_inode);
@@ -1380,41 +1379,44 @@ int write_all_supers(struct btrfs_root *root)
	struct list_head *cur;
	struct list_head *cur;
	struct list_head *head = &root->fs_info->fs_devices->devices;
	struct list_head *head = &root->fs_info->fs_devices->devices;
	struct btrfs_device *dev;
	struct btrfs_device *dev;
	struct extent_buffer *sb;
	struct btrfs_super_block *sb;
	struct btrfs_dev_item *dev_item;
	struct btrfs_dev_item *dev_item;
	struct buffer_head *bh;
	struct buffer_head *bh;
	int ret;
	int ret;
	int do_barriers;
	int do_barriers;
	int max_errors;
	int max_errors;
	int total_errors = 0;
	int total_errors = 0;
	u32 crc;
	u64 flags;


	max_errors = btrfs_super_num_devices(&root->fs_info->super_copy) - 1;
	max_errors = btrfs_super_num_devices(&root->fs_info->super_copy) - 1;
	do_barriers = !btrfs_test_opt(root, NOBARRIER);
	do_barriers = !btrfs_test_opt(root, NOBARRIER);


	sb = root->fs_info->sb_buffer;
	sb = &root->fs_info->super_for_commit;
	dev_item = (struct btrfs_dev_item *)offsetof(struct btrfs_super_block,
	dev_item = &sb->dev_item;
						      dev_item);
	list_for_each(cur, head) {
	list_for_each(cur, head) {
		dev = list_entry(cur, struct btrfs_device, dev_list);
		dev = list_entry(cur, struct btrfs_device, dev_list);
		btrfs_set_device_type(sb, dev_item, dev->type);
		btrfs_set_stack_device_type(dev_item, dev->type);
		btrfs_set_device_id(sb, dev_item, dev->devid);
		btrfs_set_stack_device_id(dev_item, dev->devid);
		btrfs_set_device_total_bytes(sb, dev_item, dev->total_bytes);
		btrfs_set_stack_device_total_bytes(dev_item, dev->total_bytes);
		btrfs_set_device_bytes_used(sb, dev_item, dev->bytes_used);
		btrfs_set_stack_device_bytes_used(dev_item, dev->bytes_used);
		btrfs_set_device_io_align(sb, dev_item, dev->io_align);
		btrfs_set_stack_device_io_align(dev_item, dev->io_align);
		btrfs_set_device_io_width(sb, dev_item, dev->io_width);
		btrfs_set_stack_device_io_width(dev_item, dev->io_width);
		btrfs_set_device_sector_size(sb, dev_item, dev->sector_size);
		btrfs_set_stack_device_sector_size(dev_item, dev->sector_size);
		write_extent_buffer(sb, dev->uuid,
		memcpy(dev_item->uuid, dev->uuid, BTRFS_UUID_SIZE);
				    (unsigned long)btrfs_device_uuid(dev_item),
		flags = btrfs_super_flags(sb);
				    BTRFS_UUID_SIZE);
		btrfs_set_super_flags(sb, flags | BTRFS_HEADER_FLAG_WRITTEN);


		btrfs_set_header_flag(sb, BTRFS_HEADER_FLAG_WRITTEN);

		csum_tree_block(root, sb, 0);
		crc = ~(u32)0;

		crc = btrfs_csum_data(root, (char *)sb + BTRFS_CSUM_SIZE, crc,
		bh = __getblk(dev->bdev, BTRFS_SUPER_INFO_OFFSET /
				      BTRFS_SUPER_INFO_SIZE - BTRFS_CSUM_SIZE);
			      root->fs_info->sb->s_blocksize,
		btrfs_csum_final(crc, sb->csum);

		bh = __getblk(dev->bdev, BTRFS_SUPER_INFO_OFFSET / 4096,
			      BTRFS_SUPER_INFO_SIZE);
			      BTRFS_SUPER_INFO_SIZE);


		read_extent_buffer(sb, bh->b_data, 0, BTRFS_SUPER_INFO_SIZE);
		memcpy(bh->b_data, sb, BTRFS_SUPER_INFO_SIZE);
		dev->pending_io = bh;
		dev->pending_io = bh;


		get_bh(bh);
		get_bh(bh);
@@ -1483,15 +1485,6 @@ int write_ctree_super(struct btrfs_trans_handle *trans, struct btrfs_root
	int ret;
	int ret;


	ret = write_all_supers(root);
	ret = write_all_supers(root);
#if 0
	if (!btrfs_test_opt(root, NOBARRIER))
		blkdev_issue_flush(sb->s_bdev, NULL);
	set_extent_buffer_dirty(&BTRFS_I(btree_inode)->io_tree, super);
	ret = sync_page_range_nolock(btree_inode, btree_inode->i_mapping,
				     super->start, super->len);
	if (!btrfs_test_opt(root, NOBARRIER))
		blkdev_issue_flush(sb->s_bdev, NULL);
#endif
	return ret;
	return ret;
}
}


@@ -1570,8 +1563,6 @@ int close_ctree(struct btrfs_root *root)
	if (root->fs_info->dev_root->node);
	if (root->fs_info->dev_root->node);
		free_extent_buffer(root->fs_info->dev_root->node);
		free_extent_buffer(root->fs_info->dev_root->node);


	free_extent_buffer(fs_info->sb_buffer);

	btrfs_free_block_groups(root->fs_info);
	btrfs_free_block_groups(root->fs_info);
	del_fs_roots(fs_info);
	del_fs_roots(fs_info);


@@ -1652,7 +1643,7 @@ void btrfs_throttle(struct btrfs_root *root)
{
{
	struct backing_dev_info *bdi;
	struct backing_dev_info *bdi;


	bdi = root->fs_info->sb->s_bdev->bd_inode->i_mapping->backing_dev_info;
	bdi = &root->fs_info->bdi;
	if (root->fs_info->throttles && bdi_write_congested(bdi)) {
	if (root->fs_info->throttles && bdi_write_congested(bdi)) {
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18)
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18)
		congestion_wait(WRITE, HZ/20);
		congestion_wait(WRITE, HZ/20);
+113 −26
Original line number Original line Diff line number Diff line
@@ -147,6 +147,8 @@ struct btrfs_block_group_cache *btrfs_lookup_block_group(struct
	u64 end;
	u64 end;
	int ret;
	int ret;


	bytenr = max_t(u64, bytenr,
		       BTRFS_SUPER_INFO_OFFSET + BTRFS_SUPER_INFO_SIZE);
	block_group_cache = &info->block_group_cache;
	block_group_cache = &info->block_group_cache;
	ret = find_first_extent_bit(block_group_cache,
	ret = find_first_extent_bit(block_group_cache,
				    bytenr, &start, &end,
				    bytenr, &start, &end,
@@ -1059,16 +1061,25 @@ static void set_avail_alloc_bits(struct btrfs_fs_info *fs_info, u64 flags)
	}
	}
}
}


static u64 reduce_alloc_profile(u64 flags)
static u64 reduce_alloc_profile(struct btrfs_root *root, u64 flags)
{
{
	u64 num_devices = root->fs_info->fs_devices->num_devices;

	if (num_devices == 1)
		flags &= ~(BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_RAID0);
	if (num_devices < 4)
		flags &= ~BTRFS_BLOCK_GROUP_RAID10;

	if ((flags & BTRFS_BLOCK_GROUP_DUP) &&
	if ((flags & BTRFS_BLOCK_GROUP_DUP) &&
	    (flags & (BTRFS_BLOCK_GROUP_RAID1 |
	    (flags & (BTRFS_BLOCK_GROUP_RAID1 |
		      BTRFS_BLOCK_GROUP_RAID10)))
		      BTRFS_BLOCK_GROUP_RAID10))) {
		flags &= ~BTRFS_BLOCK_GROUP_DUP;
		flags &= ~BTRFS_BLOCK_GROUP_DUP;
	}


	if ((flags & BTRFS_BLOCK_GROUP_RAID1) &&
	if ((flags & BTRFS_BLOCK_GROUP_RAID1) &&
	    (flags & BTRFS_BLOCK_GROUP_RAID10))
	    (flags & BTRFS_BLOCK_GROUP_RAID10)) {
		flags &= ~BTRFS_BLOCK_GROUP_RAID1;
		flags &= ~BTRFS_BLOCK_GROUP_RAID1;
	}


	if ((flags & BTRFS_BLOCK_GROUP_RAID0) &&
	if ((flags & BTRFS_BLOCK_GROUP_RAID0) &&
	    ((flags & BTRFS_BLOCK_GROUP_RAID1) |
	    ((flags & BTRFS_BLOCK_GROUP_RAID1) |
@@ -1078,7 +1089,6 @@ static u64 reduce_alloc_profile(u64 flags)
	return flags;
	return flags;
}
}



static int do_chunk_alloc(struct btrfs_trans_handle *trans,
static int do_chunk_alloc(struct btrfs_trans_handle *trans,
			  struct btrfs_root *extent_root, u64 alloc_bytes,
			  struct btrfs_root *extent_root, u64 alloc_bytes,
			  u64 flags)
			  u64 flags)
@@ -1089,7 +1099,7 @@ static int do_chunk_alloc(struct btrfs_trans_handle *trans,
	u64 num_bytes;
	u64 num_bytes;
	int ret;
	int ret;


	flags = reduce_alloc_profile(flags);
	flags = reduce_alloc_profile(extent_root, flags);


	space_info = __find_space_info(extent_root->fs_info, flags);
	space_info = __find_space_info(extent_root->fs_info, flags);
	if (!space_info) {
	if (!space_info) {
@@ -1169,6 +1179,21 @@ static int update_block_group(struct btrfs_trans_handle *trans,
	return 0;
	return 0;
}
}


static u64 first_logical_byte(struct btrfs_root *root, u64 search_start)
{
	u64 start;
	u64 end;
	int ret;
	ret = find_first_extent_bit(&root->fs_info->block_group_cache,
				    search_start, &start, &end,
				    BLOCK_GROUP_DATA | BLOCK_GROUP_METADATA |
				    BLOCK_GROUP_SYSTEM);
	if (ret)
		return 0;
	return start;
}


static int update_pinned_extents(struct btrfs_root *root,
static int update_pinned_extents(struct btrfs_root *root,
				u64 bytenr, u64 num, int pin)
				u64 bytenr, u64 num, int pin)
{
{
@@ -1185,16 +1210,25 @@ static int update_pinned_extents(struct btrfs_root *root,
	}
	}
	while (num > 0) {
	while (num > 0) {
		cache = btrfs_lookup_block_group(fs_info, bytenr);
		cache = btrfs_lookup_block_group(fs_info, bytenr);
		WARN_ON(!cache);
		if (!cache) {
			u64 first = first_logical_byte(root, bytenr);
			WARN_ON(first < bytenr);
			len = min(first - bytenr, num);
		} else {
			len = min(num, cache->key.offset -
			len = min(num, cache->key.offset -
				  (bytenr - cache->key.objectid));
				  (bytenr - cache->key.objectid));
		}
		if (pin) {
		if (pin) {
			if (cache) {
				cache->pinned += len;
				cache->pinned += len;
				cache->space_info->bytes_pinned += len;
				cache->space_info->bytes_pinned += len;
			}
			fs_info->total_pinned += len;
			fs_info->total_pinned += len;
		} else {
		} else {
			if (cache) {
				cache->pinned -= len;
				cache->pinned -= len;
				cache->space_info->bytes_pinned -= len;
				cache->space_info->bytes_pinned -= len;
			}
			fs_info->total_pinned -= len;
			fs_info->total_pinned -= len;
		}
		}
		bytenr += len;
		bytenr += len;
@@ -1547,7 +1581,7 @@ static int noinline find_free_extent(struct btrfs_trans_handle *trans,
				     int data)
				     int data)
{
{
	int ret;
	int ret;
	u64 orig_search_start = search_start;
	u64 orig_search_start;
	struct btrfs_root * root = orig_root->fs_info->extent_root;
	struct btrfs_root * root = orig_root->fs_info->extent_root;
	struct btrfs_fs_info *info = root->fs_info;
	struct btrfs_fs_info *info = root->fs_info;
	u64 total_needed = num_bytes;
	u64 total_needed = num_bytes;
@@ -1577,6 +1611,9 @@ static int noinline find_free_extent(struct btrfs_trans_handle *trans,
		}
		}
	}
	}


	search_start = max(search_start, first_logical_byte(root, 0));
	orig_search_start = search_start;

	if (search_end == (u64)-1)
	if (search_end == (u64)-1)
		search_end = btrfs_super_total_bytes(&info->super_copy);
		search_end = btrfs_super_total_bytes(&info->super_copy);


@@ -1751,7 +1788,7 @@ int btrfs_alloc_extent(struct btrfs_trans_handle *trans,
		data = BTRFS_BLOCK_GROUP_METADATA | alloc_profile;
		data = BTRFS_BLOCK_GROUP_METADATA | alloc_profile;
	}
	}
again:
again:
	data = reduce_alloc_profile(data);
	data = reduce_alloc_profile(root, data);
	if (root->ref_cows) {
	if (root->ref_cows) {
		if (!(data & BTRFS_BLOCK_GROUP_METADATA)) {
		if (!(data & BTRFS_BLOCK_GROUP_METADATA)) {
			ret = do_chunk_alloc(trans, root->fs_info->extent_root,
			ret = do_chunk_alloc(trans, root->fs_info->extent_root,
@@ -2309,6 +2346,7 @@ static int noinline relocate_inode_pages(struct inode *inode, u64 start,
	struct file_ra_state *ra;
	struct file_ra_state *ra;
	unsigned long total_read = 0;
	unsigned long total_read = 0;
	unsigned long ra_pages;
	unsigned long ra_pages;
	struct btrfs_trans_handle *trans;


	ra = kzalloc(sizeof(*ra), GFP_NOFS);
	ra = kzalloc(sizeof(*ra), GFP_NOFS);


@@ -2326,9 +2364,13 @@ static int noinline relocate_inode_pages(struct inode *inode, u64 start,
				       calc_ra(i, last_index, ra_pages));
				       calc_ra(i, last_index, ra_pages));
		}
		}
		total_read++;
		total_read++;
		if (((u64)i << PAGE_CACHE_SHIFT) > inode->i_size)
			goto truncate_racing;

		page = grab_cache_page(inode->i_mapping, i);
		page = grab_cache_page(inode->i_mapping, i);
		if (!page)
		if (!page) {
			goto out_unlock;
			goto out_unlock;
		}
		if (!PageUptodate(page)) {
		if (!PageUptodate(page)) {
			btrfs_readpage(NULL, page);
			btrfs_readpage(NULL, page);
			lock_page(page);
			lock_page(page);
@@ -2350,20 +2392,33 @@ static int noinline relocate_inode_pages(struct inode *inode, u64 start,


		lock_extent(io_tree, page_start, page_end, GFP_NOFS);
		lock_extent(io_tree, page_start, page_end, GFP_NOFS);


		set_page_dirty(page);
		set_extent_delalloc(io_tree, page_start,
		set_extent_delalloc(io_tree, page_start,
				    page_end, GFP_NOFS);
				    page_end, GFP_NOFS);
		set_page_dirty(page);


		unlock_extent(io_tree, page_start, page_end, GFP_NOFS);
		unlock_extent(io_tree, page_start, page_end, GFP_NOFS);
		unlock_page(page);
		unlock_page(page);
		page_cache_release(page);
		page_cache_release(page);
		balance_dirty_pages_ratelimited_nr(inode->i_mapping, 1);
	}
	}
	balance_dirty_pages_ratelimited_nr(inode->i_mapping,
					   total_read);


out_unlock:
out_unlock:
	kfree(ra);
	kfree(ra);
	trans = btrfs_start_transaction(BTRFS_I(inode)->root, 1);
	if (trans) {
		btrfs_add_ordered_inode(inode);
		btrfs_end_transaction(trans, BTRFS_I(inode)->root);
		mark_inode_dirty(inode);
	}
	mutex_unlock(&inode->i_mutex);
	mutex_unlock(&inode->i_mutex);
	return 0;
	return 0;

truncate_racing:
	vmtruncate(inode, inode->i_size);
	balance_dirty_pages_ratelimited_nr(inode->i_mapping,
					   total_read);
	goto out_unlock;
}
}


/*
/*
@@ -2466,6 +2521,27 @@ static int noinline relocate_one_reference(struct btrfs_root *extent_root,
	return 0;
	return 0;
}
}


static int noinline del_extent_zero(struct btrfs_root *extent_root,
				    struct btrfs_path *path,
				    struct btrfs_key *extent_key)
{
	int ret;
	struct btrfs_trans_handle *trans;

	trans = btrfs_start_transaction(extent_root, 1);
	ret = btrfs_search_slot(trans, extent_root, extent_key, path, -1, 1);
	if (ret > 0) {
		ret = -EIO;
		goto out;
	}
	if (ret < 0)
		goto out;
	ret = btrfs_del_item(trans, extent_root, path);
out:
	btrfs_end_transaction(trans, extent_root);
	return ret;
}

static int noinline relocate_one_extent(struct btrfs_root *extent_root,
static int noinline relocate_one_extent(struct btrfs_root *extent_root,
					struct btrfs_path *path,
					struct btrfs_path *path,
					struct btrfs_key *extent_key)
					struct btrfs_key *extent_key)
@@ -2477,6 +2553,10 @@ static int noinline relocate_one_extent(struct btrfs_root *extent_root,
	u32 item_size;
	u32 item_size;
	int ret = 0;
	int ret = 0;


	if (extent_key->objectid == 0) {
		ret = del_extent_zero(extent_root, path, extent_key);
		goto out;
	}
	key.objectid = extent_key->objectid;
	key.objectid = extent_key->objectid;
	key.type = BTRFS_EXTENT_REF_KEY;
	key.type = BTRFS_EXTENT_REF_KEY;
	key.offset = 0;
	key.offset = 0;
@@ -2490,15 +2570,24 @@ static int noinline relocate_one_extent(struct btrfs_root *extent_root,
		ret = 0;
		ret = 0;
		leaf = path->nodes[0];
		leaf = path->nodes[0];
		nritems = btrfs_header_nritems(leaf);
		nritems = btrfs_header_nritems(leaf);
		if (path->slots[0] == nritems)
		if (path->slots[0] == nritems) {
			ret = btrfs_next_leaf(extent_root, path);
			if (ret > 0) {
				ret = 0;
				goto out;
			}
			if (ret < 0)
				goto out;
				goto out;
		}


		btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
		btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
		if (found_key.objectid != extent_key->objectid)
		if (found_key.objectid != extent_key->objectid) {
			break;
			break;
		}


		if (found_key.type != BTRFS_EXTENT_REF_KEY)
		if (found_key.type != BTRFS_EXTENT_REF_KEY) {
			break;
			break;
		}


		key.offset = found_key.offset + 1;
		key.offset = found_key.offset + 1;
		item_size = btrfs_item_size_nr(leaf, path->slots[0]);
		item_size = btrfs_item_size_nr(leaf, path->slots[0]);
@@ -2519,7 +2608,7 @@ static u64 update_block_group_flags(struct btrfs_root *root, u64 flags)
	u64 stripped = BTRFS_BLOCK_GROUP_RAID0 |
	u64 stripped = BTRFS_BLOCK_GROUP_RAID0 |
		BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_RAID10;
		BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_RAID10;


	num_devices = btrfs_super_num_devices(&root->fs_info->super_copy);
	num_devices = root->fs_info->fs_devices->num_devices;
	if (num_devices == 1) {
	if (num_devices == 1) {
		stripped |= BTRFS_BLOCK_GROUP_DUP;
		stripped |= BTRFS_BLOCK_GROUP_DUP;
		stripped = flags & ~stripped;
		stripped = flags & ~stripped;
@@ -2535,9 +2624,6 @@ static u64 update_block_group_flags(struct btrfs_root *root, u64 flags)
		return flags;
		return flags;
	} else {
	} else {
		/* they already had raid on here, just return */
		/* they already had raid on here, just return */
		if ((flags & BTRFS_BLOCK_GROUP_DUP) &&
		    (flags & BTRFS_BLOCK_GROUP_RAID1)) {
		}
		if (flags & stripped)
		if (flags & stripped)
			return flags;
			return flags;


@@ -2570,7 +2656,7 @@ int btrfs_shrink_extent_tree(struct btrfs_root *root, u64 shrink_start)
	struct extent_buffer *leaf;
	struct extent_buffer *leaf;
	u32 nritems;
	u32 nritems;
	int ret;
	int ret;
	int progress = 0;
	int progress;


	shrink_block_group = btrfs_lookup_block_group(root->fs_info,
	shrink_block_group = btrfs_lookup_block_group(root->fs_info,
						      shrink_start);
						      shrink_start);
@@ -2597,6 +2683,7 @@ int btrfs_shrink_extent_tree(struct btrfs_root *root, u64 shrink_start)
	shrink_block_group->ro = 1;
	shrink_block_group->ro = 1;


	total_found = 0;
	total_found = 0;
	progress = 0;
	key.objectid = shrink_start;
	key.objectid = shrink_start;
	key.offset = 0;
	key.offset = 0;
	key.type = 0;
	key.type = 0;
+26 −1
Original line number Original line Diff line number Diff line
@@ -2194,6 +2194,8 @@ struct extent_map *btrfs_get_extent(struct inode *inode, struct page *page,
again:
again:
	spin_lock(&em_tree->lock);
	spin_lock(&em_tree->lock);
	em = lookup_extent_mapping(em_tree, start, len);
	em = lookup_extent_mapping(em_tree, start, len);
	if (em)
		em->bdev = root->fs_info->fs_devices->latest_bdev;
	spin_unlock(&em_tree->lock);
	spin_unlock(&em_tree->lock);


	if (em) {
	if (em) {
@@ -2212,7 +2214,7 @@ struct extent_map *btrfs_get_extent(struct inode *inode, struct page *page,


	em->start = EXTENT_MAP_HOLE;
	em->start = EXTENT_MAP_HOLE;
	em->len = (u64)-1;
	em->len = (u64)-1;
	em->bdev = inode->i_sb->s_bdev;
	em->bdev = root->fs_info->fs_devices->latest_bdev;
	ret = btrfs_lookup_file_extent(trans, root, path,
	ret = btrfs_lookup_file_extent(trans, root, path,
				       objectid, start, trans != NULL);
				       objectid, start, trans != NULL);
	if (ret < 0) {
	if (ret < 0) {
@@ -3101,6 +3103,27 @@ long btrfs_ioctl_add_dev(struct btrfs_root *root, void __user *arg)
	return ret;
	return ret;
}
}


long btrfs_ioctl_rm_dev(struct btrfs_root *root, void __user *arg)
{
	struct btrfs_ioctl_vol_args *vol_args;
	int ret;

	vol_args = kmalloc(sizeof(*vol_args), GFP_NOFS);

	if (!vol_args)
		return -ENOMEM;

	if (copy_from_user(vol_args, arg, sizeof(*vol_args))) {
		ret = -EFAULT;
		goto out;
	}
	ret = btrfs_rm_device(root, vol_args->name);

out:
	kfree(vol_args);
	return ret;
}

int dup_item_to_inode(struct btrfs_trans_handle *trans,
int dup_item_to_inode(struct btrfs_trans_handle *trans,
		       struct btrfs_root *root,
		       struct btrfs_root *root,
		       struct btrfs_path *path,
		       struct btrfs_path *path,
@@ -3294,6 +3317,8 @@ long btrfs_ioctl(struct file *file, unsigned int
		return btrfs_ioctl_resize(root, (void __user *)arg);
		return btrfs_ioctl_resize(root, (void __user *)arg);
	case BTRFS_IOC_ADD_DEV:
	case BTRFS_IOC_ADD_DEV:
		return btrfs_ioctl_add_dev(root, (void __user *)arg);
		return btrfs_ioctl_add_dev(root, (void __user *)arg);
	case BTRFS_IOC_RM_DEV:
		return btrfs_ioctl_rm_dev(root, (void __user *)arg);
	case BTRFS_IOC_BALANCE:
	case BTRFS_IOC_BALANCE:
		return btrfs_balance(root->fs_info->dev_root);
		return btrfs_balance(root->fs_info->dev_root);
	case BTRFS_IOC_CLONE:
	case BTRFS_IOC_CLONE:
+8 −27
Original line number Original line Diff line number Diff line
@@ -315,24 +315,12 @@ static void btrfs_write_super(struct super_block *sb)
	sb->s_dirt = 0;
	sb->s_dirt = 0;
}
}


/*
static int btrfs_test_super(struct super_block *s, void *data)
 * This is almost a copy of get_sb_bdev in fs/super.c.
 * We need the local copy to allow direct mounting of
 * subvolumes, but this could be easily integrated back
 * into the generic version.  --hch
 */

/* start copy & paste */
static int set_bdev_super(struct super_block *s, void *data)
{
{
	s->s_bdev = data;
	struct btrfs_fs_devices *test_fs_devices = data;
	s->s_dev = s->s_bdev->bd_dev;
	struct btrfs_root *root = btrfs_sb(s);
	return 0;
}


static int test_bdev_super(struct super_block *s, void *data)
	return root->fs_info->fs_devices == test_fs_devices;
{
	return (void *)s->s_bdev == data;
}
}


int btrfs_get_sb_bdev(struct file_system_type *fs_type,
int btrfs_get_sb_bdev(struct file_system_type *fs_type,
@@ -354,14 +342,9 @@ int btrfs_get_sb_bdev(struct file_system_type *fs_type,
		return error;
		return error;


	bdev = fs_devices->lowest_bdev;
	bdev = fs_devices->lowest_bdev;
	/*
	btrfs_lock_volumes();
	 * once the super is inserted into the list by sget, s_umount
	s = sget(fs_type, btrfs_test_super, set_anon_super, fs_devices);
	 * will protect the lockfs code from trying to start a snapshot
	btrfs_unlock_volumes();
	 * while we are mounting
	 */
	down(&bdev->bd_mount_sem);
	s = sget(fs_type, test_bdev_super, set_bdev_super, bdev);
	up(&bdev->bd_mount_sem);
	if (IS_ERR(s))
	if (IS_ERR(s))
		goto error_s;
		goto error_s;


@@ -373,13 +356,11 @@ int btrfs_get_sb_bdev(struct file_system_type *fs_type,
			goto error_bdev;
			goto error_bdev;
		}
		}


		close_bdev_excl(bdev);
	} else {
	} else {
		char b[BDEVNAME_SIZE];
		char b[BDEVNAME_SIZE];


		s->s_flags = flags;
		s->s_flags = flags;
		strlcpy(s->s_id, bdevname(bdev, b), sizeof(s->s_id));
		strlcpy(s->s_id, bdevname(bdev, b), sizeof(s->s_id));
		sb_set_blocksize(s, block_size(bdev));
		error = btrfs_fill_super(s, fs_devices, data,
		error = btrfs_fill_super(s, fs_devices, data,
					 flags & MS_SILENT ? 1 : 0);
					 flags & MS_SILENT ? 1 : 0);
		if (error) {
		if (error) {
@@ -458,7 +439,7 @@ static struct file_system_type btrfs_fs_type = {
	.owner		= THIS_MODULE,
	.owner		= THIS_MODULE,
	.name		= "btrfs",
	.name		= "btrfs",
	.get_sb		= btrfs_get_sb,
	.get_sb		= btrfs_get_sb,
	.kill_sb	= kill_block_super,
	.kill_sb	= kill_anon_super,
	.fs_flags	= FS_REQUIRES_DEV,
	.fs_flags	= FS_REQUIRES_DEV,
};
};


Loading