btrfs: btrfs_check_shared should manage its own transaction
authorEdmund Nadolski <enadolski@suse.com>
Thu, 29 Jun 2017 03:56:58 +0000 (21:56 -0600)
committerDavid Sterba <dsterba@suse.com>
Wed, 16 Aug 2017 12:19:53 +0000 (14:19 +0200)
Commit afce772e87c3 ("btrfs: fix check_shared for fiemap ioctl") added
transaction semantics around calls to btrfs_check_shared() in order to
provide accurate accounting of delayed refs. The transaction management
should be done inside btrfs_check_shared(), so that callers do not need
to manage transactions individually.

Signed-off-by: Edmund Nadolski <enadolski@suse.com>
Signed-off-by: Jeff Mahoney <jeffm@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/backref.c
fs/btrfs/backref.h
fs/btrfs/extent_io.c

index 3725277f6e08353573c907b28328e7d754e90804..35cfa388dc0bab640f6dce31fb167582b6520bd5 100644 (file)
@@ -1580,20 +1580,21 @@ int btrfs_find_all_roots(struct btrfs_trans_handle *trans,
 /**
  * btrfs_check_shared - tell us whether an extent is shared
  *
- * @trans: optional trans handle
- *
  * btrfs_check_shared uses the backref walking code but will short
  * circuit as soon as it finds a root or inode that doesn't match the
  * one passed in. This provides a significant performance benefit for
  * callers (such as fiemap) which want to know whether the extent is
  * shared but do not need a ref count.
  *
+ * This attempts to allocate a transaction in order to account for
+ * delayed refs, but continues on even when the alloc fails.
+ *
  * Return: 0 if extent is not shared, 1 if it is shared, < 0 on error.
  */
-int btrfs_check_shared(struct btrfs_trans_handle *trans,
-                      struct btrfs_fs_info *fs_info, u64 root_objectid,
-                      u64 inum, u64 bytenr)
+int btrfs_check_shared(struct btrfs_root *root, u64 inum, u64 bytenr)
 {
+       struct btrfs_fs_info *fs_info = root->fs_info;
+       struct btrfs_trans_handle *trans;
        struct ulist *tmp = NULL;
        struct ulist *roots = NULL;
        struct ulist_iterator uiter;
@@ -1609,14 +1610,18 @@ int btrfs_check_shared(struct btrfs_trans_handle *trans,
                return -ENOMEM;
        }
 
-       if (trans)
-               btrfs_get_tree_mod_seq(fs_info, &elem);
-       else
+       trans = btrfs_join_transaction(root);
+       if (IS_ERR(trans)) {
+               trans = NULL;
                down_read(&fs_info->commit_root_sem);
+       } else {
+               btrfs_get_tree_mod_seq(fs_info, &elem);
+       }
+
        ULIST_ITER_INIT(&uiter);
        while (1) {
                ret = find_parent_nodes(trans, fs_info, bytenr, elem.seq, tmp,
-                                       roots, NULL, root_objectid, inum, 1);
+                                       roots, NULL, root->objectid, inum, 1);
                if (ret == BACKREF_FOUND_SHARED) {
                        /* this is the only condition under which we return 1 */
                        ret = 1;
@@ -1631,10 +1636,13 @@ int btrfs_check_shared(struct btrfs_trans_handle *trans,
                bytenr = node->val;
                cond_resched();
        }
-       if (trans)
+
+       if (trans) {
                btrfs_put_tree_mod_seq(fs_info, &elem);
-       else
+               btrfs_end_transaction(trans);
+       } else {
                up_read(&fs_info->commit_root_sem);
+       }
        ulist_free(tmp);
        ulist_free(roots);
        return ret;
index 9c41fbac30091f39bad52a3f21ebf6e931db364b..f9428aaaa77afb53bfd0b41c8d867c82ee8e5c5b 100644 (file)
@@ -68,9 +68,7 @@ int btrfs_find_one_extref(struct btrfs_root *root, u64 inode_objectid,
                          u64 start_off, struct btrfs_path *path,
                          struct btrfs_inode_extref **ret_extref,
                          u64 *found_off);
-int btrfs_check_shared(struct btrfs_trans_handle *trans,
-                      struct btrfs_fs_info *fs_info, u64 root_objectid,
-                      u64 inum, u64 bytenr);
+int btrfs_check_shared(struct btrfs_root *root, u64 inum, u64 bytenr);
 
 int __init btrfs_prelim_ref_init(void);
 void btrfs_prelim_ref_exit(void);
index d6f761b4fae0f70692386d5d30cc34f83f1778e2..7dd1b2dc7c6855cfac8d3a79329f1768a7a37136 100644 (file)
@@ -20,7 +20,6 @@
 #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;
@@ -4606,24 +4605,11 @@ 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
@@ -4631,11 +4617,9 @@ 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(trans, root->fs_info,
-                                       root->objectid,
-                                       btrfs_ino(BTRFS_I(inode)), bytenr);
-                       if (trans)
-                               btrfs_end_transaction(trans);
+                       ret = btrfs_check_shared(root,
+                                                btrfs_ino(BTRFS_I(inode)),
+                                                bytenr);
                        if (ret < 0)
                                goto out_free;
                        if (ret)