diff options
Diffstat (limited to 'fs/btrfs')
| -rw-r--r-- | fs/btrfs/compression.c | 2 | ||||
| -rw-r--r-- | fs/btrfs/extent-tree.c | 11 | ||||
| -rw-r--r-- | fs/btrfs/extent_io.c | 6 | ||||
| -rw-r--r-- | fs/btrfs/free-space-cache.c | 9 | ||||
| -rw-r--r-- | fs/btrfs/scrub.c | 4 | ||||
| -rw-r--r-- | fs/btrfs/transaction.c | 9 | ||||
| -rw-r--r-- | fs/btrfs/volumes.c | 20 | 
7 files changed, 40 insertions, 21 deletions
diff --git a/fs/btrfs/compression.c b/fs/btrfs/compression.c index d286b40a567..86eff48dab7 100644 --- a/fs/btrfs/compression.c +++ b/fs/btrfs/compression.c @@ -405,6 +405,7 @@ int btrfs_submit_compressed_write(struct inode *inode, u64 start,  			bio_put(bio);  			bio = compressed_bio_alloc(bdev, first_byte, GFP_NOFS); +			BUG_ON(!bio);  			bio->bi_private = cb;  			bio->bi_end_io = end_compressed_bio_write;  			bio_add_page(bio, page, PAGE_CACHE_SIZE, 0); @@ -687,6 +688,7 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,  			comp_bio = compressed_bio_alloc(bdev, cur_disk_byte,  							GFP_NOFS); +			BUG_ON(!comp_bio);  			comp_bio->bi_private = cb;  			comp_bio->bi_end_io = end_compressed_bio_read; diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index a84420491c1..2b35f8d14bb 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -529,9 +529,7 @@ static int cache_block_group(struct btrfs_block_group_cache *cache,  	 * allocate blocks for the tree root we can't do the fast caching since  	 * we likely hold important locks.  	 */ -	if (trans && (!trans->transaction->in_commit) && -	    (root && root != root->fs_info->tree_root) && -	    btrfs_test_opt(root, SPACE_CACHE)) { +	if (fs_info->mount_opt & BTRFS_MOUNT_SPACE_CACHE) {  		ret = load_free_space_cache(fs_info, cache);  		spin_lock(&cache->lock); @@ -3152,15 +3150,14 @@ static void set_avail_alloc_bits(struct btrfs_fs_info *fs_info, u64 flags)  /*   * returns target flags in extended format or 0 if restripe for this   * chunk_type is not in progress + * + * should be called with either volume_mutex or balance_lock held   */  static u64 get_restripe_target(struct btrfs_fs_info *fs_info, u64 flags)  {  	struct btrfs_balance_control *bctl = fs_info->balance_ctl;  	u64 target = 0; -	BUG_ON(!mutex_is_locked(&fs_info->volume_mutex) && -	       !spin_is_locked(&fs_info->balance_lock)); -  	if (!bctl)  		return 0; @@ -4205,7 +4202,7 @@ static u64 calc_global_metadata_size(struct btrfs_fs_info *fs_info)  	num_bytes += div64_u64(data_used + meta_used, 50);  	if (num_bytes * 3 > meta_used) -		num_bytes = div64_u64(meta_used, 3) * 2; +		num_bytes = div64_u64(meta_used, 3);  	return ALIGN(num_bytes, fs_info->extent_root->leafsize << 10);  } diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 8d904dd7ea9..cd4b5e40022 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -1937,7 +1937,7 @@ int repair_eb_io_failure(struct btrfs_root *root, struct extent_buffer *eb,  	struct btrfs_mapping_tree *map_tree = &root->fs_info->mapping_tree;  	u64 start = eb->start;  	unsigned long i, num_pages = num_extent_pages(eb->start, eb->len); -	int ret; +	int ret = 0;  	for (i = 0; i < num_pages; i++) {  		struct page *p = extent_buffer_page(eb, i); @@ -2180,6 +2180,10 @@ static int bio_readpage_error(struct bio *failed_bio, struct page *page,  	}  	bio = bio_alloc(GFP_NOFS, 1); +	if (!bio) { +		free_io_failure(inode, failrec, 0); +		return -EIO; +	}  	bio->bi_private = state;  	bio->bi_end_io = failed_bio->bi_end_io;  	bio->bi_sector = failrec->logical >> 9; diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c index e88330d3df5..202008ec367 100644 --- a/fs/btrfs/free-space-cache.c +++ b/fs/btrfs/free-space-cache.c @@ -748,13 +748,6 @@ int load_free_space_cache(struct btrfs_fs_info *fs_info,  	u64 used = btrfs_block_group_used(&block_group->item);  	/* -	 * If we're unmounting then just return, since this does a search on the -	 * normal root and not the commit root and we could deadlock. -	 */ -	if (btrfs_fs_closing(fs_info)) -		return 0; - -	/*  	 * If this block group has been marked to be cleared for one reason or  	 * another then we can't trust the on disk cache, so just return.  	 */ @@ -768,6 +761,8 @@ int load_free_space_cache(struct btrfs_fs_info *fs_info,  	path = btrfs_alloc_path();  	if (!path)  		return 0; +	path->search_commit_root = 1; +	path->skip_locking = 1;  	inode = lookup_free_space_inode(root, block_group, path);  	if (IS_ERR(inode)) { diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index 90acc82046c..bc015f77f3e 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c @@ -1044,6 +1044,8 @@ static int scrub_recheck_block(struct btrfs_fs_info *fs_info,  		BUG_ON(!page->page);  		bio = bio_alloc(GFP_NOFS, 1); +		if (!bio) +			return -EIO;  		bio->bi_bdev = page->bdev;  		bio->bi_sector = page->physical >> 9;  		bio->bi_end_io = scrub_complete_bio_end_io; @@ -1171,6 +1173,8 @@ static int scrub_repair_page_from_good_copy(struct scrub_block *sblock_bad,  		DECLARE_COMPLETION_ONSTACK(complete);  		bio = bio_alloc(GFP_NOFS, 1); +		if (!bio) +			return -EIO;  		bio->bi_bdev = page_bad->bdev;  		bio->bi_sector = page_bad->physical >> 9;  		bio->bi_end_io = scrub_complete_bio_end_io; diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 8da29e8e4de..11b77a59db6 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c @@ -480,6 +480,7 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans,  	struct btrfs_transaction *cur_trans = trans->transaction;  	struct btrfs_fs_info *info = root->fs_info;  	int count = 0; +	int err = 0;  	if (--trans->use_count) {  		trans->block_rsv = trans->orig_rsv; @@ -532,18 +533,18 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans,  	if (current->journal_info == trans)  		current->journal_info = NULL; -	memset(trans, 0, sizeof(*trans)); -	kmem_cache_free(btrfs_trans_handle_cachep, trans);  	if (throttle)  		btrfs_run_delayed_iputs(root);  	if (trans->aborted ||  	    root->fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR) { -		return -EIO; +		err = -EIO;  	} -	return 0; +	memset(trans, 0, sizeof(*trans)); +	kmem_cache_free(btrfs_trans_handle_cachep, trans); +	return err;  }  int btrfs_end_transaction(struct btrfs_trans_handle *trans, diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index a872b48be0a..759d02486d7 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -3833,6 +3833,7 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,  		int sub_stripes = 0;  		u64 stripes_per_dev = 0;  		u32 remaining_stripes = 0; +		u32 last_stripe = 0;  		if (map->type &  		    (BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID10)) { @@ -3846,6 +3847,8 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,  						      stripe_nr_orig,  						      factor,  						      &remaining_stripes); +			div_u64_rem(stripe_nr_end - 1, factor, &last_stripe); +			last_stripe *= sub_stripes;  		}  		for (i = 0; i < num_stripes; i++) { @@ -3858,16 +3861,29 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,  					 BTRFS_BLOCK_GROUP_RAID10)) {  				bbio->stripes[i].length = stripes_per_dev *  							  map->stripe_len; +  				if (i / sub_stripes < remaining_stripes)  					bbio->stripes[i].length +=  						map->stripe_len; + +				/* +				 * Special for the first stripe and +				 * the last stripe: +				 * +				 * |-------|...|-------| +				 *     |----------| +				 *    off     end_off +				 */  				if (i < sub_stripes)  					bbio->stripes[i].length -=  						stripe_offset; -				if ((i / sub_stripes + 1) % -				    sub_stripes == remaining_stripes) + +				if (stripe_index >= last_stripe && +				    stripe_index <= (last_stripe + +						     sub_stripes - 1))  					bbio->stripes[i].length -=  						stripe_end_offset; +  				if (i == sub_stripes - 1)  					stripe_offset = 0;  			} else  |