mirror of
https://github.com/Fishwaldo/linux-bl808.git
synced 2025-06-17 20:25:19 +00:00
btrfs: fix check_shared for fiemap ioctl
Only in the case of different root_id or different object_id, check_shared identified extent as the shared. However, If a extent was referred by different offset of same file, it should also be identified as shared. In addition, check_shared's loop scale is at least n^3, so if a extent has too many references, even causes soft hang up. First, add all delayed_ref to the ref_tree and calculate the unqiue_refs, if the unique_refs is greater than one, return BACKREF_FOUND_SHARED. Then individually add the on-disk reference(inline/keyed) to the ref_tree and calculate the unique_refs of the ref_tree to check if the unique_refs is greater than one.Because once there are two references to return SHARED, so the time complexity is close to the constant. Reported-by: Tsutomu Itoh <t-itoh@jp.fujitsu.com> Signed-off-by: Lu Fengqi <lufq.fnst@cn.fujitsu.com> Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
parent
b0de6c4c81
commit
afce772e87
2 changed files with 369 additions and 10 deletions
|
@ -20,6 +20,7 @@
|
|||
#include "locking.h"
|
||||
#include "rcu-string.h"
|
||||
#include "backref.h"
|
||||
#include "transaction.h"
|
||||
|
||||
static struct kmem_cache *extent_state_cache;
|
||||
static struct kmem_cache *extent_buffer_cache;
|
||||
|
@ -4487,11 +4488,24 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
|
|||
flags |= (FIEMAP_EXTENT_DELALLOC |
|
||||
FIEMAP_EXTENT_UNKNOWN);
|
||||
} else if (fieinfo->fi_extents_max) {
|
||||
struct btrfs_trans_handle *trans;
|
||||
|
||||
u64 bytenr = em->block_start -
|
||||
(em->start - em->orig_start);
|
||||
|
||||
disko = em->block_start + offset_in_extent;
|
||||
|
||||
/*
|
||||
* We need a trans handle to get delayed refs
|
||||
*/
|
||||
trans = btrfs_join_transaction(root);
|
||||
/*
|
||||
* It's OK if we can't start a trans we can still check
|
||||
* from commit_root
|
||||
*/
|
||||
if (IS_ERR(trans))
|
||||
trans = NULL;
|
||||
|
||||
/*
|
||||
* As btrfs supports shared space, this information
|
||||
* can be exported to userspace tools via
|
||||
|
@ -4499,9 +4513,11 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
|
|||
* then we're just getting a count and we can skip the
|
||||
* lookup stuff.
|
||||
*/
|
||||
ret = btrfs_check_shared(NULL, root->fs_info,
|
||||
ret = btrfs_check_shared(trans, root->fs_info,
|
||||
root->objectid,
|
||||
btrfs_ino(inode), bytenr);
|
||||
if (trans)
|
||||
btrfs_end_transaction(trans, root);
|
||||
if (ret < 0)
|
||||
goto out_free;
|
||||
if (ret)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue