diff options
Diffstat (limited to 'fs/btrfs')
| -rw-r--r-- | fs/btrfs/ctree.h | 3 | ||||
| -rw-r--r-- | fs/btrfs/extent-tree.c | 126 | ||||
| -rw-r--r-- | fs/btrfs/extent_io.c | 51 | ||||
| -rw-r--r-- | fs/btrfs/free-space-cache.c | 2 | ||||
| -rw-r--r-- | fs/btrfs/inode.c | 2 | ||||
| -rw-r--r-- | fs/btrfs/ioctl.c | 2 | ||||
| -rw-r--r-- | fs/btrfs/scrub.c | 5 | ||||
| -rw-r--r-- | fs/btrfs/super.c | 6 | ||||
| -rw-r--r-- | fs/btrfs/volumes.c | 2 | 
9 files changed, 120 insertions, 79 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 04a5dfcee5a..50634abef9b 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -2369,6 +2369,9 @@ int btrfs_block_rsv_check(struct btrfs_root *root,  int btrfs_block_rsv_refill(struct btrfs_root *root,  			  struct btrfs_block_rsv *block_rsv,  			  u64 min_reserved); +int btrfs_block_rsv_refill_noflush(struct btrfs_root *root, +				   struct btrfs_block_rsv *block_rsv, +				   u64 min_reserved);  int btrfs_block_rsv_migrate(struct btrfs_block_rsv *src_rsv,  			    struct btrfs_block_rsv *dst_rsv,  			    u64 num_bytes); diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 930ae894973..2ad813674d7 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -3888,9 +3888,9 @@ int btrfs_block_rsv_check(struct btrfs_root *root,  	return ret;  } -int btrfs_block_rsv_refill(struct btrfs_root *root, -			  struct btrfs_block_rsv *block_rsv, -			  u64 min_reserved) +static inline int __btrfs_block_rsv_refill(struct btrfs_root *root, +					   struct btrfs_block_rsv *block_rsv, +					   u64 min_reserved, int flush)  {  	u64 num_bytes = 0;  	int ret = -ENOSPC; @@ -3909,7 +3909,7 @@ int btrfs_block_rsv_refill(struct btrfs_root *root,  	if (!ret)  		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, 0);  		return 0; @@ -3918,6 +3918,20 @@ int btrfs_block_rsv_refill(struct btrfs_root *root,  	return ret;  } +int btrfs_block_rsv_refill(struct btrfs_root *root, +			   struct btrfs_block_rsv *block_rsv, +			   u64 min_reserved) +{ +	return __btrfs_block_rsv_refill(root, block_rsv, min_reserved, 1); +} + +int btrfs_block_rsv_refill_noflush(struct btrfs_root *root, +				   struct btrfs_block_rsv *block_rsv, +				   u64 min_reserved) +{ +	return __btrfs_block_rsv_refill(root, block_rsv, min_reserved, 0); +} +  int btrfs_block_rsv_migrate(struct btrfs_block_rsv *src_rsv,  			    struct btrfs_block_rsv *dst_rsv,  			    u64 num_bytes) @@ -5093,11 +5107,11 @@ static noinline int find_free_extent(struct btrfs_trans_handle *trans,  	struct btrfs_root *root = orig_root->fs_info->extent_root;  	struct btrfs_free_cluster *last_ptr = NULL;  	struct btrfs_block_group_cache *block_group = NULL; +	struct btrfs_block_group_cache *used_block_group;  	int empty_cluster = 2 * 1024 * 1024;  	int allowed_chunk_alloc = 0;  	int done_chunk_alloc = 0;  	struct btrfs_space_info *space_info; -	int last_ptr_loop = 0;  	int loop = 0;  	int index = 0;  	int alloc_type = (data & BTRFS_BLOCK_GROUP_DATA) ? @@ -5159,6 +5173,7 @@ static noinline int find_free_extent(struct btrfs_trans_handle *trans,  ideal_cache:  		block_group = btrfs_lookup_block_group(root->fs_info,  						       search_start); +		used_block_group = block_group;  		/*  		 * we don't want to use the block group if it doesn't match our  		 * allocation bits, or if its not cached. @@ -5196,6 +5211,7 @@ search:  		u64 offset;  		int cached; +		used_block_group = block_group;  		btrfs_get_block_group(block_group);  		search_start = block_group->key.objectid; @@ -5265,84 +5281,73 @@ alloc:  		spin_lock(&block_group->free_space_ctl->tree_lock);  		if (cached &&  		    block_group->free_space_ctl->free_space < -		    num_bytes + empty_size) { +		    num_bytes + empty_cluster + empty_size) {  			spin_unlock(&block_group->free_space_ctl->tree_lock);  			goto loop;  		}  		spin_unlock(&block_group->free_space_ctl->tree_lock);  		/* -		 * Ok we want to try and use the cluster allocator, so lets look -		 * there, unless we are on LOOP_NO_EMPTY_SIZE, since we will -		 * have tried the cluster allocator plenty of times at this -		 * point and not have found anything, so we are likely way too -		 * fragmented for the clustering stuff to find anything, so lets -		 * just skip it and let the allocator find whatever block it can -		 * find +		 * Ok we want to try and use the cluster allocator, so +		 * lets look there  		 */ -		if (last_ptr && loop < LOOP_NO_EMPTY_SIZE) { +		if (last_ptr) {  			/*  			 * the refill lock keeps out other  			 * people trying to start a new cluster  			 */  			spin_lock(&last_ptr->refill_lock); -			if (last_ptr->block_group && -			    (last_ptr->block_group->ro || -			    !block_group_bits(last_ptr->block_group, data))) { -				offset = 0; +			used_block_group = last_ptr->block_group; +			if (used_block_group != block_group && +			    (!used_block_group || +			     used_block_group->ro || +			     !block_group_bits(used_block_group, data))) { +				used_block_group = block_group;  				goto refill_cluster;  			} -			offset = btrfs_alloc_from_cluster(block_group, last_ptr, -						 num_bytes, search_start); +			if (used_block_group != block_group) +				btrfs_get_block_group(used_block_group); + +			offset = btrfs_alloc_from_cluster(used_block_group, +			  last_ptr, num_bytes, used_block_group->key.objectid);  			if (offset) {  				/* we have a block, we're done */  				spin_unlock(&last_ptr->refill_lock);  				goto checks;  			} -			spin_lock(&last_ptr->lock); -			/* -			 * whoops, this cluster doesn't actually point to -			 * this block group.  Get a ref on the block -			 * group is does point to and try again -			 */ -			if (!last_ptr_loop && last_ptr->block_group && -			    last_ptr->block_group != block_group && -			    index <= -				 get_block_group_index(last_ptr->block_group)) { - -				btrfs_put_block_group(block_group); -				block_group = last_ptr->block_group; -				btrfs_get_block_group(block_group); -				spin_unlock(&last_ptr->lock); -				spin_unlock(&last_ptr->refill_lock); - -				last_ptr_loop = 1; -				search_start = block_group->key.objectid; -				/* -				 * we know this block group is properly -				 * in the list because -				 * btrfs_remove_block_group, drops the -				 * cluster before it removes the block -				 * group from the list -				 */ -				goto have_block_group; +			WARN_ON(last_ptr->block_group != used_block_group); +			if (used_block_group != block_group) { +				btrfs_put_block_group(used_block_group); +				used_block_group = block_group;  			} -			spin_unlock(&last_ptr->lock);  refill_cluster: +			BUG_ON(used_block_group != block_group); +			/* If we are on LOOP_NO_EMPTY_SIZE, we can't +			 * set up a new clusters, so lets just skip it +			 * and let the allocator find whatever block +			 * it can find.  If we reach this point, we +			 * will have tried the cluster allocator +			 * plenty of times and not have found +			 * anything, so we are likely way too +			 * fragmented for the clustering stuff to find +			 * anything.  */ +			if (loop >= LOOP_NO_EMPTY_SIZE) { +				spin_unlock(&last_ptr->refill_lock); +				goto unclustered_alloc; +			} +  			/*  			 * this cluster didn't work out, free it and  			 * start over  			 */  			btrfs_return_cluster_to_free_space(NULL, last_ptr); -			last_ptr_loop = 0; -  			/* allocate a cluster in this block group */  			ret = btrfs_find_space_cluster(trans, root,  					       block_group, last_ptr, -					       offset, num_bytes, +					       search_start, num_bytes,  					       empty_cluster + empty_size);  			if (ret == 0) {  				/* @@ -5378,6 +5383,7 @@ refill_cluster:  			goto loop;  		} +unclustered_alloc:  		offset = btrfs_find_space_for_alloc(block_group, search_start,  						    num_bytes, empty_size);  		/* @@ -5404,14 +5410,14 @@ checks:  		search_start = stripe_align(root, offset);  		/* move on to the next group */  		if (search_start + num_bytes >= search_end) { -			btrfs_add_free_space(block_group, offset, num_bytes); +			btrfs_add_free_space(used_block_group, offset, num_bytes);  			goto loop;  		}  		/* move on to the next group */  		if (search_start + num_bytes > -		    block_group->key.objectid + block_group->key.offset) { -			btrfs_add_free_space(block_group, offset, num_bytes); +		    used_block_group->key.objectid + used_block_group->key.offset) { +			btrfs_add_free_space(used_block_group, offset, num_bytes);  			goto loop;  		} @@ -5419,14 +5425,14 @@ checks:  		ins->offset = num_bytes;  		if (offset < search_start) -			btrfs_add_free_space(block_group, offset, +			btrfs_add_free_space(used_block_group, offset,  					     search_start - offset);  		BUG_ON(offset > search_start); -		ret = btrfs_update_reserved_bytes(block_group, num_bytes, +		ret = btrfs_update_reserved_bytes(used_block_group, num_bytes,  						  alloc_type);  		if (ret == -EAGAIN) { -			btrfs_add_free_space(block_group, offset, num_bytes); +			btrfs_add_free_space(used_block_group, offset, num_bytes);  			goto loop;  		} @@ -5435,15 +5441,19 @@ checks:  		ins->offset = num_bytes;  		if (offset < search_start) -			btrfs_add_free_space(block_group, offset, +			btrfs_add_free_space(used_block_group, offset,  					     search_start - offset);  		BUG_ON(offset > search_start); +		if (used_block_group != block_group) +			btrfs_put_block_group(used_block_group);  		btrfs_put_block_group(block_group);  		break;  loop:  		failed_cluster_refill = false;  		failed_alloc = false;  		BUG_ON(index != get_block_group_index(block_group)); +		if (used_block_group != block_group) +			btrfs_put_block_group(used_block_group);  		btrfs_put_block_group(block_group);  	}  	up_read(&space_info->groups_sem); diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 9472d3de5e5..49f3c9dc09f 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -935,8 +935,10 @@ again:  	node = tree_search(tree, start);  	if (!node) {  		prealloc = alloc_extent_state_atomic(prealloc); -		if (!prealloc) -			return -ENOMEM; +		if (!prealloc) { +			err = -ENOMEM; +			goto out; +		}  		err = insert_state(tree, prealloc, start, end, &bits);  		prealloc = NULL;  		BUG_ON(err == -EEXIST); @@ -992,8 +994,10 @@ hit_next:  	 */  	if (state->start < start) {  		prealloc = alloc_extent_state_atomic(prealloc); -		if (!prealloc) -			return -ENOMEM; +		if (!prealloc) { +			err = -ENOMEM; +			goto out; +		}  		err = split_state(tree, state, prealloc, start);  		BUG_ON(err == -EEXIST);  		prealloc = NULL; @@ -1024,8 +1028,10 @@ hit_next:  			this_end = last_start - 1;  		prealloc = alloc_extent_state_atomic(prealloc); -		if (!prealloc) -			return -ENOMEM; +		if (!prealloc) { +			err = -ENOMEM; +			goto out; +		}  		/*  		 * Avoid to free 'prealloc' if it can be merged with @@ -1051,8 +1057,10 @@ hit_next:  	 */  	if (state->start <= end && state->end > end) {  		prealloc = alloc_extent_state_atomic(prealloc); -		if (!prealloc) -			return -ENOMEM; +		if (!prealloc) { +			err = -ENOMEM; +			goto out; +		}  		err = split_state(tree, state, prealloc, end + 1);  		BUG_ON(err == -EEXIST); @@ -2287,14 +2295,20 @@ static void end_bio_extent_readpage(struct bio *bio, int err)  		if (!uptodate) {  			int failed_mirror;  			failed_mirror = (int)(unsigned long)bio->bi_bdev; -			if (tree->ops && tree->ops->readpage_io_failed_hook) -				ret = tree->ops->readpage_io_failed_hook( -						bio, page, start, end, -						failed_mirror, state); -			else -				ret = bio_readpage_error(bio, page, start, end, -							 failed_mirror, NULL); +			/* +			 * The generic bio_readpage_error handles errors the +			 * following way: If possible, new read requests are +			 * created and submitted and will end up in +			 * end_bio_extent_readpage as well (if we're lucky, not +			 * in the !uptodate case). In that case it returns 0 and +			 * we just go on with the next page in our bio. If it +			 * can't handle the error it will return -EIO and we +			 * remain responsible for that page. +			 */ +			ret = bio_readpage_error(bio, page, start, end, +							failed_mirror, NULL);  			if (ret == 0) { +error_handled:  				uptodate =  					test_bit(BIO_UPTODATE, &bio->bi_flags);  				if (err) @@ -2302,6 +2316,13 @@ static void end_bio_extent_readpage(struct bio *bio, int err)  				uncache_state(&cached);  				continue;  			} +			if (tree->ops && tree->ops->readpage_io_failed_hook) { +				ret = tree->ops->readpage_io_failed_hook( +							bio, page, start, end, +							failed_mirror, state); +				if (ret == 0) +					goto error_handled; +			}  		}  		if (uptodate) { diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c index 6e5b7e46369..ec23d43d0c3 100644 --- a/fs/btrfs/free-space-cache.c +++ b/fs/btrfs/free-space-cache.c @@ -1470,6 +1470,7 @@ static void add_new_bitmap(struct btrfs_free_space_ctl *ctl,  {  	info->offset = offset_to_bitmap(ctl, offset);  	info->bytes = 0; +	INIT_LIST_HEAD(&info->list);  	link_free_space(ctl, info);  	ctl->total_bitmaps++; @@ -2319,6 +2320,7 @@ again:  	if (!found) {  		start = i; +		cluster->max_size = 0;  		found = true;  	} diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 526dd51a196..2c984f7d4c2 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -3490,7 +3490,7 @@ void btrfs_evict_inode(struct inode *inode)  	 * doing the truncate.  	 */  	while (1) { -		ret = btrfs_block_rsv_refill(root, rsv, min_size); +		ret = btrfs_block_rsv_refill_noflush(root, rsv, min_size);  		/*  		 * Try and steal from the global reserve since we will diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index a90e749ed6d..72d461656f6 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -1278,7 +1278,7 @@ static noinline int btrfs_ioctl_resize(struct btrfs_root *root,  		}  		ret = btrfs_grow_device(trans, device, new_size);  		btrfs_commit_transaction(trans, root); -	} else { +	} else if (new_size < old_size) {  		ret = btrfs_shrink_device(device, new_size);  	} diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index fab420db512..c27bcb67f33 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c @@ -256,6 +256,11 @@ static int scrub_print_warning_inode(u64 inum, u64 offset, u64 root, void *ctx)  	btrfs_release_path(swarn->path);  	ipath = init_ipath(4096, local_root, swarn->path); +	if (IS_ERR(ipath)) { +		ret = PTR_ERR(ipath); +		ipath = NULL; +		goto err; +	}  	ret = paths_from_inode(inum, ipath);  	if (ret < 0) diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 17ee7fc5e64..e28ad4baf48 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -1057,7 +1057,7 @@ static int btrfs_calc_avail_data_space(struct btrfs_root *root, u64 *free_bytes)  	int i = 0, nr_devices;  	int ret; -	nr_devices = fs_info->fs_devices->rw_devices; +	nr_devices = fs_info->fs_devices->open_devices;  	BUG_ON(!nr_devices);  	devices_info = kmalloc(sizeof(*devices_info) * nr_devices, @@ -1079,8 +1079,8 @@ static int btrfs_calc_avail_data_space(struct btrfs_root *root, u64 *free_bytes)  	else  		min_stripe_size = BTRFS_STRIPE_LEN; -	list_for_each_entry(device, &fs_devices->alloc_list, dev_alloc_list) { -		if (!device->in_fs_metadata) +	list_for_each_entry(device, &fs_devices->devices, dev_list) { +		if (!device->in_fs_metadata || !device->bdev)  			continue;  		avail_space = device->total_bytes - device->bytes_used; diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index c37433d3cd8..0a8c8f8304b 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -1611,7 +1611,7 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path)  	if ((sb->s_flags & MS_RDONLY) && !root->fs_info->fs_devices->seeding)  		return -EINVAL; -	bdev = blkdev_get_by_path(device_path, FMODE_EXCL, +	bdev = blkdev_get_by_path(device_path, FMODE_WRITE | FMODE_EXCL,  				  root->fs_info->bdev_holder);  	if (IS_ERR(bdev))  		return PTR_ERR(bdev);  |