diff options
Diffstat (limited to 'fs/btrfs')
| -rw-r--r-- | fs/btrfs/ctree.h | 4 | ||||
| -rw-r--r-- | fs/btrfs/dir-item.c | 2 | ||||
| -rw-r--r-- | fs/btrfs/disk-io.c | 10 | ||||
| -rw-r--r-- | fs/btrfs/extent-tree.c | 7 | ||||
| -rw-r--r-- | fs/btrfs/extent_io.c | 126 | ||||
| -rw-r--r-- | fs/btrfs/hash.c | 5 | ||||
| -rw-r--r-- | fs/btrfs/inode.c | 6 | 
7 files changed, 143 insertions, 17 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 643c70d2b2e6..4f8f75d9e839 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -2563,7 +2563,7 @@ u64 btrfs_csum_bytes_to_leaves(struct btrfs_fs_info *fs_info, u64 csum_bytes);  static inline u64 btrfs_calc_trans_metadata_size(struct btrfs_fs_info *fs_info,  						 unsigned num_items)  { -	return fs_info->nodesize * BTRFS_MAX_LEVEL * 2 * num_items; +	return (u64)fs_info->nodesize * BTRFS_MAX_LEVEL * 2 * num_items;  }  /* @@ -2573,7 +2573,7 @@ static inline u64 btrfs_calc_trans_metadata_size(struct btrfs_fs_info *fs_info,  static inline u64 btrfs_calc_trunc_metadata_size(struct btrfs_fs_info *fs_info,  						 unsigned num_items)  { -	return fs_info->nodesize * BTRFS_MAX_LEVEL * num_items; +	return (u64)fs_info->nodesize * BTRFS_MAX_LEVEL * num_items;  }  int btrfs_should_throttle_delayed_refs(struct btrfs_trans_handle *trans, diff --git a/fs/btrfs/dir-item.c b/fs/btrfs/dir-item.c index 60a750678a82..c24d615e3d7f 100644 --- a/fs/btrfs/dir-item.c +++ b/fs/btrfs/dir-item.c @@ -468,7 +468,7 @@ int verify_dir_item(struct btrfs_fs_info *fs_info,  	if (btrfs_dir_name_len(leaf, dir_item) > namelen) {  		btrfs_crit(fs_info, "invalid dir item name len: %u", -		       (unsigned)btrfs_dir_data_len(leaf, dir_item)); +		       (unsigned)btrfs_dir_name_len(leaf, dir_item));  		return 1;  	} diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 8685d67185d0..5f678dcb20e6 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -3467,10 +3467,12 @@ static int write_dev_supers(struct btrfs_device *device,  		 * we fua the first super.  The others we allow  		 * to go down lazy.  		 */ -		if (i == 0) -			ret = btrfsic_submit_bh(REQ_OP_WRITE, REQ_FUA, bh); -		else +		if (i == 0) { +			ret = btrfsic_submit_bh(REQ_OP_WRITE, +						REQ_SYNC | REQ_FUA, bh); +		} else {  			ret = btrfsic_submit_bh(REQ_OP_WRITE, REQ_SYNC, bh); +		}  		if (ret)  			errors++;  	} @@ -3535,7 +3537,7 @@ static int write_dev_flush(struct btrfs_device *device, int wait)  	bio->bi_end_io = btrfs_end_empty_barrier;  	bio->bi_bdev = device->bdev; -	bio->bi_opf = REQ_OP_WRITE | REQ_PREFLUSH; +	bio->bi_opf = REQ_OP_WRITE | REQ_SYNC | REQ_PREFLUSH;  	init_completion(&device->flush_wait);  	bio->bi_private = &device->flush_wait;  	device->flush_bio = bio; diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index e390451c72e6..33d979e9ea2a 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -3993,6 +3993,7 @@ static int update_space_info(struct btrfs_fs_info *info, u64 flags,  				    info->space_info_kobj, "%s",  				    alloc_name(found->flags));  	if (ret) { +		percpu_counter_destroy(&found->total_bytes_pinned);  		kfree(found);  		return ret;  	} @@ -4844,7 +4845,7 @@ static int may_commit_transaction(struct btrfs_fs_info *fs_info,  	spin_unlock(&delayed_rsv->lock);  commit: -	trans = btrfs_join_transaction(fs_info->fs_root); +	trans = btrfs_join_transaction(fs_info->extent_root);  	if (IS_ERR(trans))  		return -ENOSPC; @@ -4862,7 +4863,7 @@ static int flush_space(struct btrfs_fs_info *fs_info,  		       struct btrfs_space_info *space_info, u64 num_bytes,  		       u64 orig_bytes, int state)  { -	struct btrfs_root *root = fs_info->fs_root; +	struct btrfs_root *root = fs_info->extent_root;  	struct btrfs_trans_handle *trans;  	int nr;  	int ret = 0; @@ -5062,7 +5063,7 @@ static void priority_reclaim_metadata_space(struct btrfs_fs_info *fs_info,  	int flush_state = FLUSH_DELAYED_ITEMS_NR;  	spin_lock(&space_info->lock); -	to_reclaim = btrfs_calc_reclaim_metadata_size(fs_info->fs_root, +	to_reclaim = btrfs_calc_reclaim_metadata_size(fs_info->extent_root,  						      space_info);  	if (!to_reclaim) {  		spin_unlock(&space_info->lock); diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index d8da3edf2ac3..d3619e010005 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -2458,7 +2458,7 @@ void end_extent_writepage(struct page *page, int err, u64 start, u64 end)  	if (!uptodate) {  		ClearPageUptodate(page);  		SetPageError(page); -		ret = ret < 0 ? ret : -EIO; +		ret = err < 0 ? err : -EIO;  		mapping_set_error(page->mapping, ret);  	}  } @@ -4377,6 +4377,123 @@ static struct extent_map *get_extent_skip_holes(struct inode *inode,  	return NULL;  } +/* + * To cache previous fiemap extent + * + * Will be used for merging fiemap extent + */ +struct fiemap_cache { +	u64 offset; +	u64 phys; +	u64 len; +	u32 flags; +	bool cached; +}; + +/* + * Helper to submit fiemap extent. + * + * Will try to merge current fiemap extent specified by @offset, @phys, + * @len and @flags with cached one. + * And only when we fails to merge, cached one will be submitted as + * fiemap extent. + * + * Return value is the same as fiemap_fill_next_extent(). + */ +static int emit_fiemap_extent(struct fiemap_extent_info *fieinfo, +				struct fiemap_cache *cache, +				u64 offset, u64 phys, u64 len, u32 flags) +{ +	int ret = 0; + +	if (!cache->cached) +		goto assign; + +	/* +	 * Sanity check, extent_fiemap() should have ensured that new +	 * fiemap extent won't overlap with cahced one. +	 * Not recoverable. +	 * +	 * NOTE: Physical address can overlap, due to compression +	 */ +	if (cache->offset + cache->len > offset) { +		WARN_ON(1); +		return -EINVAL; +	} + +	/* +	 * Only merges fiemap extents if +	 * 1) Their logical addresses are continuous +	 * +	 * 2) Their physical addresses are continuous +	 *    So truly compressed (physical size smaller than logical size) +	 *    extents won't get merged with each other +	 * +	 * 3) Share same flags except FIEMAP_EXTENT_LAST +	 *    So regular extent won't get merged with prealloc extent +	 */ +	if (cache->offset + cache->len  == offset && +	    cache->phys + cache->len == phys  && +	    (cache->flags & ~FIEMAP_EXTENT_LAST) == +			(flags & ~FIEMAP_EXTENT_LAST)) { +		cache->len += len; +		cache->flags |= flags; +		goto try_submit_last; +	} + +	/* Not mergeable, need to submit cached one */ +	ret = fiemap_fill_next_extent(fieinfo, cache->offset, cache->phys, +				      cache->len, cache->flags); +	cache->cached = false; +	if (ret) +		return ret; +assign: +	cache->cached = true; +	cache->offset = offset; +	cache->phys = phys; +	cache->len = len; +	cache->flags = flags; +try_submit_last: +	if (cache->flags & FIEMAP_EXTENT_LAST) { +		ret = fiemap_fill_next_extent(fieinfo, cache->offset, +				cache->phys, cache->len, cache->flags); +		cache->cached = false; +	} +	return ret; +} + +/* + * Sanity check for fiemap cache + * + * All fiemap cache should be submitted by emit_fiemap_extent() + * Iteration should be terminated either by last fiemap extent or + * fieinfo->fi_extents_max. + * So no cached fiemap should exist. + */ +static int check_fiemap_cache(struct btrfs_fs_info *fs_info, +			       struct fiemap_extent_info *fieinfo, +			       struct fiemap_cache *cache) +{ +	int ret; + +	if (!cache->cached) +		return 0; + +	/* Small and recoverbale problem, only to info developer */ +#ifdef CONFIG_BTRFS_DEBUG +	WARN_ON(1); +#endif +	btrfs_warn(fs_info, +		   "unhandled fiemap cache detected: offset=%llu phys=%llu len=%llu flags=0x%x", +		   cache->offset, cache->phys, cache->len, cache->flags); +	ret = fiemap_fill_next_extent(fieinfo, cache->offset, cache->phys, +				      cache->len, cache->flags); +	cache->cached = false; +	if (ret > 0) +		ret = 0; +	return ret; +} +  int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,  		__u64 start, __u64 len, get_extent_t *get_extent)  { @@ -4394,6 +4511,7 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,  	struct extent_state *cached_state = NULL;  	struct btrfs_path *path;  	struct btrfs_root *root = BTRFS_I(inode)->root; +	struct fiemap_cache cache = { 0 };  	int end = 0;  	u64 em_start = 0;  	u64 em_len = 0; @@ -4573,8 +4691,8 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,  			flags |= FIEMAP_EXTENT_LAST;  			end = 1;  		} -		ret = fiemap_fill_next_extent(fieinfo, em_start, disko, -					      em_len, flags); +		ret = emit_fiemap_extent(fieinfo, &cache, em_start, disko, +					   em_len, flags);  		if (ret) {  			if (ret == 1)  				ret = 0; @@ -4582,6 +4700,8 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,  		}  	}  out_free: +	if (!ret) +		ret = check_fiemap_cache(root->fs_info, fieinfo, &cache);  	free_extent_map(em);  out:  	btrfs_free_path(path); diff --git a/fs/btrfs/hash.c b/fs/btrfs/hash.c index a97fdc156a03..baacc1866861 100644 --- a/fs/btrfs/hash.c +++ b/fs/btrfs/hash.c @@ -38,6 +38,7 @@ u32 btrfs_crc32c(u32 crc, const void *address, unsigned int length)  {  	SHASH_DESC_ON_STACK(shash, tfm);  	u32 *ctx = (u32 *)shash_desc_ctx(shash); +	u32 retval;  	int err;  	shash->tfm = tfm; @@ -47,5 +48,7 @@ u32 btrfs_crc32c(u32 crc, const void *address, unsigned int length)  	err = crypto_shash_update(shash, address, length);  	BUG_ON(err); -	return *ctx; +	retval = *ctx; +	barrier_data(ctx); +	return retval;  } diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 17cbe9306faf..ef3c98c527c1 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -2952,7 +2952,7 @@ static int btrfs_finish_ordered_io(struct btrfs_ordered_extent *ordered_extent)  	ret = test_range_bit(io_tree, ordered_extent->file_offset,  			ordered_extent->file_offset + ordered_extent->len - 1, -			EXTENT_DEFRAG, 1, cached_state); +			EXTENT_DEFRAG, 0, cached_state);  	if (ret) {  		u64 last_snapshot = btrfs_root_last_snapshot(&root->root_item);  		if (0 && last_snapshot >= BTRFS_I(inode)->generation) @@ -7483,8 +7483,8 @@ bool btrfs_page_exists_in_range(struct inode *inode, loff_t start, loff_t end)  	int found = false;  	void **pagep = NULL;  	struct page *page = NULL; -	int start_idx; -	int end_idx; +	unsigned long start_idx; +	unsigned long end_idx;  	start_idx = start >> PAGE_SHIFT;  | 
