]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/commitdiff
Merge branch 'for-4.14' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 9 Sep 2017 20:27:51 +0000 (13:27 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 9 Sep 2017 20:27:51 +0000 (13:27 -0700)
Pull btrfs updates from David Sterba:
 "The changes range through all types: cleanups, core chagnes, sanity
  checks, fixes, other user visible changes, detailed list below:

   - deprecated: user transaction ioctl

   - mount option ssd does not change allocation alignments

   - degraded read-write mount is allowed if all the raid profile
     constraints are met, now based on more accurate check

   - defrag: do not reset compression afterwards; the NOCOMPRESS flag
     can be now overriden by defrag

   - prep work for better extent reference tracking (related to the
     qgroup slowness with balance)

   - prep work for compression heuristics

   - memory allocation reductions (may help latencies on a loaded
     system)

   - better accounting for io waiting states

   - error handling improvements (removed BUGs)

   - added more sanity checks for shared refs

   - fix readdir vs pagefault deadlock under some circumstances

   - fix for 'no-hole' mode, certain combination of compressed and
     inline extents

   - send: fix emission of invalid clone operations

   - fixup file mode if setting acls fail

   - more fixes from fuzzing

   - oher cleanups"

* 'for-4.14' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux: (104 commits)
  btrfs: submit superblock io with REQ_META and REQ_PRIO
  btrfs: remove unnecessary memory barrier in btrfs_direct_IO
  btrfs: remove superfluous chunk_tree argument from btrfs_alloc_dev_extent
  btrfs: Remove chunk_objectid parameter of btrfs_alloc_dev_extent
  btrfs: pass fs_info to btrfs_del_root instead of tree_root
  Btrfs: add one more sanity check for shared ref type
  Btrfs: remove BUG_ON in __add_tree_block
  Btrfs: remove BUG() in add_data_reference
  Btrfs: remove BUG() in print_extent_item
  Btrfs: remove BUG() in btrfs_extent_inline_ref_size
  Btrfs: convert to use btrfs_get_extent_inline_ref_type
  Btrfs: add a helper to retrive extent inline ref type
  btrfs: scrub: simplify scrub worker initialization
  btrfs: scrub: clean up division in scrub_find_csum
  btrfs: scrub: clean up division in __scrub_mark_bitmap
  btrfs: scrub: use bool for flush_all_writes
  btrfs: preserve i_mode if __btrfs_set_acl() fails
  btrfs: Remove extraneous chunk_objectid variable
  btrfs: Remove chunk_objectid argument from btrfs_make_block_group
  btrfs: Remove extra parentheses from condition in copy_items()
  ...

40 files changed:
fs/btrfs/acl.c
fs/btrfs/async-thread.c
fs/btrfs/async-thread.h
fs/btrfs/backref.c
fs/btrfs/backref.h
fs/btrfs/btrfs_inode.h
fs/btrfs/check-integrity.c
fs/btrfs/compression.c
fs/btrfs/compression.h
fs/btrfs/ctree.c
fs/btrfs/ctree.h
fs/btrfs/delayed-inode.c
fs/btrfs/dev-replace.c
fs/btrfs/disk-io.c
fs/btrfs/disk-io.h
fs/btrfs/extent-tree.c
fs/btrfs/extent_io.c
fs/btrfs/extent_io.h
fs/btrfs/file.c
fs/btrfs/free-space-cache.c
fs/btrfs/free-space-tree.c
fs/btrfs/free-space-tree.h
fs/btrfs/inode.c
fs/btrfs/ioctl.c
fs/btrfs/print-tree.c
fs/btrfs/print-tree.h
fs/btrfs/props.c
fs/btrfs/qgroup.c
fs/btrfs/relocation.c
fs/btrfs/root-tree.c
fs/btrfs/scrub.c
fs/btrfs/send.c
fs/btrfs/struct-funcs.c
fs/btrfs/super.c
fs/btrfs/tests/btrfs-tests.c
fs/btrfs/tests/free-space-tree-tests.c
fs/btrfs/tree-log.c
fs/btrfs/volumes.c
fs/btrfs/volumes.h
include/trace/events/btrfs.h

index 8d8370ddb6b29655f05ffe2855bd78f9937c7363..1ba49ebe67da39f6daf0a9a6f0ff63fff8554935 100644 (file)
@@ -114,13 +114,17 @@ out:
 int btrfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
 {
        int ret;
+       umode_t old_mode = inode->i_mode;
 
        if (type == ACL_TYPE_ACCESS && acl) {
                ret = posix_acl_update_mode(inode, &inode->i_mode, &acl);
                if (ret)
                        return ret;
        }
-       return __btrfs_set_acl(NULL, inode, acl, type);
+       ret = __btrfs_set_acl(NULL, inode, acl, type);
+       if (ret)
+               inode->i_mode = old_mode;
+       return ret;
 }
 
 /*
index ff0b0be92d6122402f02c039eed8e4599fdce4df..e00c8a9fd5bbc0182f27c3cf3e60027a293f077f 100644 (file)
@@ -75,18 +75,18 @@ void btrfs_##name(struct work_struct *arg)                          \
 }
 
 struct btrfs_fs_info *
-btrfs_workqueue_owner(struct __btrfs_workqueue *wq)
+btrfs_workqueue_owner(const struct __btrfs_workqueue *wq)
 {
        return wq->fs_info;
 }
 
 struct btrfs_fs_info *
-btrfs_work_owner(struct btrfs_work *work)
+btrfs_work_owner(const struct btrfs_work *work)
 {
        return work->wq->fs_info;
 }
 
-bool btrfs_workqueue_normal_congested(struct btrfs_workqueue *wq)
+bool btrfs_workqueue_normal_congested(const struct btrfs_workqueue *wq)
 {
        /*
         * We could compare wq->normal->pending with num_online_cpus()
index 1f9597355c9d974ef11489afbed69d4a7df087d9..fc957e00cef144385e8368a44cfc418b412eadc0 100644 (file)
@@ -82,7 +82,7 @@ void btrfs_queue_work(struct btrfs_workqueue *wq,
 void btrfs_destroy_workqueue(struct btrfs_workqueue *wq);
 void btrfs_workqueue_set_max(struct btrfs_workqueue *wq, int max);
 void btrfs_set_work_high_priority(struct btrfs_work *work);
-struct btrfs_fs_info *btrfs_work_owner(struct btrfs_work *work);
-struct btrfs_fs_info *btrfs_workqueue_owner(struct __btrfs_workqueue *wq);
-bool btrfs_workqueue_normal_congested(struct btrfs_workqueue *wq);
+struct btrfs_fs_info *btrfs_work_owner(const struct btrfs_work *work);
+struct btrfs_fs_info *btrfs_workqueue_owner(const struct __btrfs_workqueue *wq);
+bool btrfs_workqueue_normal_congested(const struct btrfs_workqueue *wq);
 #endif
index f723c11bb763b1ebd028d08d5a45151f6d897c8c..b517ef1477ea5634d5ae9910e1c5a7f2b2becc7a 100644 (file)
@@ -18,6 +18,7 @@
 
 #include <linux/mm.h>
 #include <linux/rbtree.h>
+#include <trace/events/btrfs.h>
 #include "ctree.h"
 #include "disk-io.h"
 #include "backref.h"
 #include "delayed-ref.h"
 #include "locking.h"
 
-enum merge_mode {
-       MERGE_IDENTICAL_KEYS = 1,
-       MERGE_IDENTICAL_PARENTS,
-};
-
 /* Just an arbitrary number so we can be sure this happened */
 #define BACKREF_FOUND_SHARED 6
 
@@ -40,269 +36,11 @@ struct extent_inode_elem {
        struct extent_inode_elem *next;
 };
 
-/*
- * ref_root is used as the root of the ref tree that hold a collection
- * of unique references.
- */
-struct ref_root {
-       struct rb_root rb_root;
-
-       /*
-        * The unique_refs represents the number of ref_nodes with a positive
-        * count stored in the tree. Even if a ref_node (the count is greater
-        * than one) is added, the unique_refs will only increase by one.
-        */
-       unsigned int unique_refs;
-};
-
-/* ref_node is used to store a unique reference to the ref tree. */
-struct ref_node {
-       struct rb_node rb_node;
-
-       /* For NORMAL_REF, otherwise all these fields should be set to 0 */
-       u64 root_id;
-       u64 object_id;
-       u64 offset;
-
-       /* For SHARED_REF, otherwise parent field should be set to 0 */
-       u64 parent;
-
-       /* Ref to the ref_mod of btrfs_delayed_ref_node */
-       int ref_mod;
-};
-
-/* Dynamically allocate and initialize a ref_root */
-static struct ref_root *ref_root_alloc(void)
-{
-       struct ref_root *ref_tree;
-
-       ref_tree = kmalloc(sizeof(*ref_tree), GFP_NOFS);
-       if (!ref_tree)
-               return NULL;
-
-       ref_tree->rb_root = RB_ROOT;
-       ref_tree->unique_refs = 0;
-
-       return ref_tree;
-}
-
-/* Free all nodes in the ref tree, and reinit ref_root */
-static void ref_root_fini(struct ref_root *ref_tree)
-{
-       struct ref_node *node;
-       struct rb_node *next;
-
-       while ((next = rb_first(&ref_tree->rb_root)) != NULL) {
-               node = rb_entry(next, struct ref_node, rb_node);
-               rb_erase(next, &ref_tree->rb_root);
-               kfree(node);
-       }
-
-       ref_tree->rb_root = RB_ROOT;
-       ref_tree->unique_refs = 0;
-}
-
-static void ref_root_free(struct ref_root *ref_tree)
-{
-       if (!ref_tree)
-               return;
-
-       ref_root_fini(ref_tree);
-       kfree(ref_tree);
-}
-
-/*
- * Compare ref_node with (root_id, object_id, offset, parent)
- *
- * The function compares two ref_node a and b. It returns an integer less
- * than, equal to, or greater than zero , respectively, to be less than, to
- * equal, or be greater than b.
- */
-static int ref_node_cmp(struct ref_node *a, struct ref_node *b)
-{
-       if (a->root_id < b->root_id)
-               return -1;
-       else if (a->root_id > b->root_id)
-               return 1;
-
-       if (a->object_id < b->object_id)
-               return -1;
-       else if (a->object_id > b->object_id)
-               return 1;
-
-       if (a->offset < b->offset)
-               return -1;
-       else if (a->offset > b->offset)
-               return 1;
-
-       if (a->parent < b->parent)
-               return -1;
-       else if (a->parent > b->parent)
-               return 1;
-
-       return 0;
-}
-
-/*
- * Search ref_node with (root_id, object_id, offset, parent) in the tree
- *
- * if found, the pointer of the ref_node will be returned;
- * if not found, NULL will be returned and pos will point to the rb_node for
- * insert, pos_parent will point to pos'parent for insert;
-*/
-static struct ref_node *__ref_tree_search(struct ref_root *ref_tree,
-                                         struct rb_node ***pos,
-                                         struct rb_node **pos_parent,
-                                         u64 root_id, u64 object_id,
-                                         u64 offset, u64 parent)
-{
-       struct ref_node *cur = NULL;
-       struct ref_node entry;
-       int ret;
-
-       entry.root_id = root_id;
-       entry.object_id = object_id;
-       entry.offset = offset;
-       entry.parent = parent;
-
-       *pos = &ref_tree->rb_root.rb_node;
-
-       while (**pos) {
-               *pos_parent = **pos;
-               cur = rb_entry(*pos_parent, struct ref_node, rb_node);
-
-               ret = ref_node_cmp(cur, &entry);
-               if (ret > 0)
-                       *pos = &(**pos)->rb_left;
-               else if (ret < 0)
-                       *pos = &(**pos)->rb_right;
-               else
-                       return cur;
-       }
-
-       return NULL;
-}
-
-/*
- * Insert a ref_node to the ref tree
- * @pos used for specifiy the position to insert
- * @pos_parent for specifiy pos's parent
- *
- * success, return 0;
- * ref_node already exists, return -EEXIST;
-*/
-static int ref_tree_insert(struct ref_root *ref_tree, struct rb_node **pos,
-                          struct rb_node *pos_parent, struct ref_node *ins)
-{
-       struct rb_node **p = NULL;
-       struct rb_node *parent = NULL;
-       struct ref_node *cur = NULL;
-
-       if (!pos) {
-               cur = __ref_tree_search(ref_tree, &p, &parent, ins->root_id,
-                                       ins->object_id, ins->offset,
-                                       ins->parent);
-               if (cur)
-                       return -EEXIST;
-       } else {
-               p = pos;
-               parent = pos_parent;
-       }
-
-       rb_link_node(&ins->rb_node, parent, p);
-       rb_insert_color(&ins->rb_node, &ref_tree->rb_root);
-
-       return 0;
-}
-
-/* Erase and free ref_node, caller should update ref_root->unique_refs */
-static void ref_tree_remove(struct ref_root *ref_tree, struct ref_node *node)
-{
-       rb_erase(&node->rb_node, &ref_tree->rb_root);
-       kfree(node);
-}
-
-/*
- * Update ref_root->unique_refs
- *
- * Call __ref_tree_search
- *     1. if ref_node doesn't exist, ref_tree_insert this node, and update
- *     ref_root->unique_refs:
- *             if ref_node->ref_mod > 0, ref_root->unique_refs++;
- *             if ref_node->ref_mod < 0, do noting;
- *
- *     2. if ref_node is found, then get origin ref_node->ref_mod, and update
- *     ref_node->ref_mod.
- *             if ref_node->ref_mod is equal to 0,then call ref_tree_remove
- *
- *             according to origin_mod and new_mod, update ref_root->items
- *             +----------------+--------------+-------------+
- *             |                |new_count <= 0|new_count > 0|
- *             +----------------+--------------+-------------+
- *             |origin_count < 0|       0      |      1      |
- *             +----------------+--------------+-------------+
- *             |origin_count > 0|      -1      |      0      |
- *             +----------------+--------------+-------------+
- *
- * In case of allocation failure, -ENOMEM is returned and the ref_tree stays
- * unaltered.
- * Success, return 0
- */
-static int ref_tree_add(struct ref_root *ref_tree, u64 root_id, u64 object_id,
-                       u64 offset, u64 parent, int count)
-{
-       struct ref_node *node = NULL;
-       struct rb_node **pos = NULL;
-       struct rb_node *pos_parent = NULL;
-       int origin_count;
-       int ret;
-
-       if (!count)
-               return 0;
-
-       node = __ref_tree_search(ref_tree, &pos, &pos_parent, root_id,
-                                object_id, offset, parent);
-       if (node == NULL) {
-               node = kmalloc(sizeof(*node), GFP_NOFS);
-               if (!node)
-                       return -ENOMEM;
-
-               node->root_id = root_id;
-               node->object_id = object_id;
-               node->offset = offset;
-               node->parent = parent;
-               node->ref_mod = count;
-
-               ret = ref_tree_insert(ref_tree, pos, pos_parent, node);
-               ASSERT(!ret);
-               if (ret) {
-                       kfree(node);
-                       return ret;
-               }
-
-               ref_tree->unique_refs += node->ref_mod > 0 ? 1 : 0;
-
-               return 0;
-       }
-
-       origin_count = node->ref_mod;
-       node->ref_mod += count;
-
-       if (node->ref_mod > 0)
-               ref_tree->unique_refs += origin_count > 0 ? 0 : 1;
-       else if (node->ref_mod <= 0)
-               ref_tree->unique_refs += origin_count > 0 ? -1 : 0;
-
-       if (!node->ref_mod)
-               ref_tree_remove(ref_tree, node);
-
-       return 0;
-}
-
-static int check_extent_in_eb(struct btrfs_key *key, struct extent_buffer *eb,
-                               struct btrfs_file_extent_item *fi,
-                               u64 extent_item_pos,
-                               struct extent_inode_elem **eie)
+static int check_extent_in_eb(const struct btrfs_key *key,
+                             const struct extent_buffer *eb,
+                             const struct btrfs_file_extent_item *fi,
+                             u64 extent_item_pos,
+                             struct extent_inode_elem **eie)
 {
        u64 offset = 0;
        struct extent_inode_elem *e;
@@ -344,9 +82,9 @@ static void free_inode_elem_list(struct extent_inode_elem *eie)
        }
 }
 
-static int find_extent_in_eb(struct extent_buffer *eb, u64 wanted_disk_byte,
-                               u64 extent_item_pos,
-                               struct extent_inode_elem **eie)
+static int find_extent_in_eb(const struct extent_buffer *eb,
+                            u64 wanted_disk_byte, u64 extent_item_pos,
+                            struct extent_inode_elem **eie)
 {
        u64 disk_byte;
        struct btrfs_key key;
@@ -383,26 +121,44 @@ static int find_extent_in_eb(struct extent_buffer *eb, u64 wanted_disk_byte,
        return 0;
 }
 
+struct preftree {
+       struct rb_root root;
+       unsigned int count;
+};
+
+#define PREFTREE_INIT  { .root = RB_ROOT, .count = 0 }
+
+struct preftrees {
+       struct preftree direct;    /* BTRFS_SHARED_[DATA|BLOCK]_REF_KEY */
+       struct preftree indirect;  /* BTRFS_[TREE_BLOCK|EXTENT_DATA]_REF_KEY */
+       struct preftree indirect_missing_keys;
+};
+
 /*
- * this structure records all encountered refs on the way up to the root
+ * Checks for a shared extent during backref search.
+ *
+ * The share_count tracks prelim_refs (direct and indirect) having a
+ * ref->count >0:
+ *  - incremented when a ref->count transitions to >0
+ *  - decremented when a ref->count transitions to <1
  */
-struct __prelim_ref {
-       struct list_head list;
-       u64 root_id;
-       struct btrfs_key key_for_search;
-       int level;
-       int count;
-       struct extent_inode_elem *inode_list;
-       u64 parent;
-       u64 wanted_disk_byte;
+struct share_check {
+       u64 root_objectid;
+       u64 inum;
+       int share_count;
 };
 
+static inline int extent_is_shared(struct share_check *sc)
+{
+       return (sc && sc->share_count > 1) ? BACKREF_FOUND_SHARED : 0;
+}
+
 static struct kmem_cache *btrfs_prelim_ref_cache;
 
 int __init btrfs_prelim_ref_init(void)
 {
        btrfs_prelim_ref_cache = kmem_cache_create("btrfs_prelim_ref",
-                                       sizeof(struct __prelim_ref),
+                                       sizeof(struct prelim_ref),
                                        0,
                                        SLAB_MEM_SPREAD,
                                        NULL);
@@ -416,6 +172,134 @@ void btrfs_prelim_ref_exit(void)
        kmem_cache_destroy(btrfs_prelim_ref_cache);
 }
 
+static void free_pref(struct prelim_ref *ref)
+{
+       kmem_cache_free(btrfs_prelim_ref_cache, ref);
+}
+
+/*
+ * Return 0 when both refs are for the same block (and can be merged).
+ * A -1 return indicates ref1 is a 'lower' block than ref2, while 1
+ * indicates a 'higher' block.
+ */
+static int prelim_ref_compare(struct prelim_ref *ref1,
+                             struct prelim_ref *ref2)
+{
+       if (ref1->level < ref2->level)
+               return -1;
+       if (ref1->level > ref2->level)
+               return 1;
+       if (ref1->root_id < ref2->root_id)
+               return -1;
+       if (ref1->root_id > ref2->root_id)
+               return 1;
+       if (ref1->key_for_search.type < ref2->key_for_search.type)
+               return -1;
+       if (ref1->key_for_search.type > ref2->key_for_search.type)
+               return 1;
+       if (ref1->key_for_search.objectid < ref2->key_for_search.objectid)
+               return -1;
+       if (ref1->key_for_search.objectid > ref2->key_for_search.objectid)
+               return 1;
+       if (ref1->key_for_search.offset < ref2->key_for_search.offset)
+               return -1;
+       if (ref1->key_for_search.offset > ref2->key_for_search.offset)
+               return 1;
+       if (ref1->parent < ref2->parent)
+               return -1;
+       if (ref1->parent > ref2->parent)
+               return 1;
+
+       return 0;
+}
+
+void update_share_count(struct share_check *sc, int oldcount, int newcount)
+{
+       if ((!sc) || (oldcount == 0 && newcount < 1))
+               return;
+
+       if (oldcount > 0 && newcount < 1)
+               sc->share_count--;
+       else if (oldcount < 1 && newcount > 0)
+               sc->share_count++;
+}
+
+/*
+ * Add @newref to the @root rbtree, merging identical refs.
+ *
+ * Callers should assume that newref has been freed after calling.
+ */
+static void prelim_ref_insert(const struct btrfs_fs_info *fs_info,
+                             struct preftree *preftree,
+                             struct prelim_ref *newref,
+                             struct share_check *sc)
+{
+       struct rb_root *root;
+       struct rb_node **p;
+       struct rb_node *parent = NULL;
+       struct prelim_ref *ref;
+       int result;
+
+       root = &preftree->root;
+       p = &root->rb_node;
+
+       while (*p) {
+               parent = *p;
+               ref = rb_entry(parent, struct prelim_ref, rbnode);
+               result = prelim_ref_compare(ref, newref);
+               if (result < 0) {
+                       p = &(*p)->rb_left;
+               } else if (result > 0) {
+                       p = &(*p)->rb_right;
+               } else {
+                       /* Identical refs, merge them and free @newref */
+                       struct extent_inode_elem *eie = ref->inode_list;
+
+                       while (eie && eie->next)
+                               eie = eie->next;
+
+                       if (!eie)
+                               ref->inode_list = newref->inode_list;
+                       else
+                               eie->next = newref->inode_list;
+                       trace_btrfs_prelim_ref_merge(fs_info, ref, newref,
+                                                    preftree->count);
+                       /*
+                        * A delayed ref can have newref->count < 0.
+                        * The ref->count is updated to follow any
+                        * BTRFS_[ADD|DROP]_DELAYED_REF actions.
+                        */
+                       update_share_count(sc, ref->count,
+                                          ref->count + newref->count);
+                       ref->count += newref->count;
+                       free_pref(newref);
+                       return;
+               }
+       }
+
+       update_share_count(sc, 0, newref->count);
+       preftree->count++;
+       trace_btrfs_prelim_ref_insert(fs_info, newref, NULL, preftree->count);
+       rb_link_node(&newref->rbnode, parent, p);
+       rb_insert_color(&newref->rbnode, root);
+}
+
+/*
+ * Release the entire tree.  We don't care about internal consistency so
+ * just free everything and then reset the tree root.
+ */
+static void prelim_release(struct preftree *preftree)
+{
+       struct prelim_ref *ref, *next_ref;
+
+       rbtree_postorder_for_each_entry_safe(ref, next_ref, &preftree->root,
+                                            rbnode)
+               free_pref(ref);
+
+       preftree->root = RB_ROOT;
+       preftree->count = 0;
+}
+
 /*
  * the rules for all callers of this function are:
  * - obtaining the parent is the goal
@@ -448,19 +332,19 @@ void btrfs_prelim_ref_exit(void)
  *
  * - column 1, 3: we've the parent -> done
  * - column 2:    we take the first key from the block to find the parent
- *                (see __add_missing_keys)
+ *                (see add_missing_keys)
  * - column 4:    we use the key to find the parent
  *
  * additional information that's available but not required to find the parent
  * block might help in merging entries to gain some speed.
  */
-
-static int __add_prelim_ref(struct list_head *head, u64 root_id,
-                           struct btrfs_key *key, int level,
-                           u64 parent, u64 wanted_disk_byte, int count,
-                           gfp_t gfp_mask)
+static int add_prelim_ref(const struct btrfs_fs_info *fs_info,
+                         struct preftree *preftree, u64 root_id,
+                         const struct btrfs_key *key, int level, u64 parent,
+                         u64 wanted_disk_byte, int count,
+                         struct share_check *sc, gfp_t gfp_mask)
 {
-       struct __prelim_ref *ref;
+       struct prelim_ref *ref;
 
        if (root_id == BTRFS_DATA_RELOC_TREE_OBJECTID)
                return 0;
@@ -503,13 +387,37 @@ static int __add_prelim_ref(struct list_head *head, u64 root_id,
        ref->count = count;
        ref->parent = parent;
        ref->wanted_disk_byte = wanted_disk_byte;
-       list_add_tail(&ref->list, head);
+       prelim_ref_insert(fs_info, preftree, ref, sc);
+       return extent_is_shared(sc);
+}
 
-       return 0;
+/* direct refs use root == 0, key == NULL */
+static int add_direct_ref(const struct btrfs_fs_info *fs_info,
+                         struct preftrees *preftrees, int level, u64 parent,
+                         u64 wanted_disk_byte, int count,
+                         struct share_check *sc, gfp_t gfp_mask)
+{
+       return add_prelim_ref(fs_info, &preftrees->direct, 0, NULL, level,
+                             parent, wanted_disk_byte, count, sc, gfp_mask);
+}
+
+/* indirect refs use parent == 0 */
+static int add_indirect_ref(const struct btrfs_fs_info *fs_info,
+                           struct preftrees *preftrees, u64 root_id,
+                           const struct btrfs_key *key, int level,
+                           u64 wanted_disk_byte, int count,
+                           struct share_check *sc, gfp_t gfp_mask)
+{
+       struct preftree *tree = &preftrees->indirect;
+
+       if (!key)
+               tree = &preftrees->indirect_missing_keys;
+       return add_prelim_ref(fs_info, tree, root_id, key, level, 0,
+                             wanted_disk_byte, count, sc, gfp_mask);
 }
 
 static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path,
-                          struct ulist *parents, struct __prelim_ref *ref,
+                          struct ulist *parents, struct prelim_ref *ref,
                           int level, u64 time_seq, const u64 *extent_item_pos,
                           u64 total_refs)
 {
@@ -599,11 +507,10 @@ next:
  * resolve an indirect backref in the form (root_id, key, level)
  * to a logical address
  */
-static int __resolve_indirect_ref(struct btrfs_fs_info *fs_info,
-                                 struct btrfs_path *path, u64 time_seq,
-                                 struct __prelim_ref *ref,
-                                 struct ulist *parents,
-                                 const u64 *extent_item_pos, u64 total_refs)
+static int resolve_indirect_ref(struct btrfs_fs_info *fs_info,
+                               struct btrfs_path *path, u64 time_seq,
+                               struct prelim_ref *ref, struct ulist *parents,
+                               const u64 *extent_item_pos, u64 total_refs)
 {
        struct btrfs_root *root;
        struct btrfs_key root_key;
@@ -681,52 +588,90 @@ out:
        return ret;
 }
 
+static struct extent_inode_elem *
+unode_aux_to_inode_list(struct ulist_node *node)
+{
+       if (!node)
+               return NULL;
+       return (struct extent_inode_elem *)(uintptr_t)node->aux;
+}
+
 /*
- * resolve all indirect backrefs from the list
+ * We maintain three seperate rbtrees: one for direct refs, one for
+ * indirect refs which have a key, and one for indirect refs which do not
+ * have a key. Each tree does merge on insertion.
+ *
+ * Once all of the references are located, we iterate over the tree of
+ * indirect refs with missing keys. An appropriate key is located and
+ * the ref is moved onto the tree for indirect refs. After all missing
+ * keys are thus located, we iterate over the indirect ref tree, resolve
+ * each reference, and then insert the resolved reference onto the
+ * direct tree (merging there too).
+ *
+ * New backrefs (i.e., for parent nodes) are added to the appropriate
+ * rbtree as they are encountered. The new backrefs are subsequently
+ * resolved as above.
  */
-static int __resolve_indirect_refs(struct btrfs_fs_info *fs_info,
-                                  struct btrfs_path *path, u64 time_seq,
-                                  struct list_head *head,
-                                  const u64 *extent_item_pos, u64 total_refs,
-                                  u64 root_objectid)
+static int resolve_indirect_refs(struct btrfs_fs_info *fs_info,
+                                struct btrfs_path *path, u64 time_seq,
+                                struct preftrees *preftrees,
+                                const u64 *extent_item_pos, u64 total_refs,
+                                struct share_check *sc)
 {
        int err;
        int ret = 0;
-       struct __prelim_ref *ref;
-       struct __prelim_ref *ref_safe;
-       struct __prelim_ref *new_ref;
        struct ulist *parents;
        struct ulist_node *node;
        struct ulist_iterator uiter;
+       struct rb_node *rnode;
 
        parents = ulist_alloc(GFP_NOFS);
        if (!parents)
                return -ENOMEM;
 
        /*
-        * _safe allows us to insert directly after the current item without
-        * iterating over the newly inserted items.
-        * we're also allowed to re-assign ref during iteration.
+        * We could trade memory usage for performance here by iterating
+        * the tree, allocating new refs for each insertion, and then
+        * freeing the entire indirect tree when we're done.  In some test
+        * cases, the tree can grow quite large (~200k objects).
         */
-       list_for_each_entry_safe(ref, ref_safe, head, list) {
-               if (ref->parent)        /* already direct */
-                       continue;
-               if (ref->count == 0)
+       while ((rnode = rb_first(&preftrees->indirect.root))) {
+               struct prelim_ref *ref;
+
+               ref = rb_entry(rnode, struct prelim_ref, rbnode);
+               if (WARN(ref->parent,
+                        "BUG: direct ref found in indirect tree")) {
+                       ret = -EINVAL;
+                       goto out;
+               }
+
+               rb_erase(&ref->rbnode, &preftrees->indirect.root);
+               preftrees->indirect.count--;
+
+               if (ref->count == 0) {
+                       free_pref(ref);
                        continue;
-               if (root_objectid && ref->root_id != root_objectid) {
+               }
+
+               if (sc && sc->root_objectid &&
+                   ref->root_id != sc->root_objectid) {
+                       free_pref(ref);
                        ret = BACKREF_FOUND_SHARED;
                        goto out;
                }
-               err = __resolve_indirect_ref(fs_info, path, time_seq, ref,
-                                            parents, extent_item_pos,
-                                            total_refs);
+               err = resolve_indirect_ref(fs_info, path, time_seq, ref,
+                                          parents, extent_item_pos,
+                                          total_refs);
                /*
                 * we can only tolerate ENOENT,otherwise,we should catch error
                 * and return directly.
                 */
                if (err == -ENOENT) {
+                       prelim_ref_insert(fs_info, &preftrees->direct, ref,
+                                         NULL);
                        continue;
                } else if (err) {
+                       free_pref(ref);
                        ret = err;
                        goto out;
                }
@@ -735,68 +680,65 @@ static int __resolve_indirect_refs(struct btrfs_fs_info *fs_info,
                ULIST_ITER_INIT(&uiter);
                node = ulist_next(parents, &uiter);
                ref->parent = node ? node->val : 0;
-               ref->inode_list = node ?
-                       (struct extent_inode_elem *)(uintptr_t)node->aux : NULL;
+               ref->inode_list = unode_aux_to_inode_list(node);
 
-               /* additional parents require new refs being added here */
+               /* Add a prelim_ref(s) for any other parent(s). */
                while ((node = ulist_next(parents, &uiter))) {
+                       struct prelim_ref *new_ref;
+
                        new_ref = kmem_cache_alloc(btrfs_prelim_ref_cache,
                                                   GFP_NOFS);
                        if (!new_ref) {
+                               free_pref(ref);
                                ret = -ENOMEM;
                                goto out;
                        }
                        memcpy(new_ref, ref, sizeof(*ref));
                        new_ref->parent = node->val;
-                       new_ref->inode_list = (struct extent_inode_elem *)
-                                                       (uintptr_t)node->aux;
-                       list_add(&new_ref->list, &ref->list);
+                       new_ref->inode_list = unode_aux_to_inode_list(node);
+                       prelim_ref_insert(fs_info, &preftrees->direct,
+                                         new_ref, NULL);
                }
+
+               /*
+                * Now it's a direct ref, put it in the the direct tree. We must
+                * do this last because the ref could be merged/freed here.
+                */
+               prelim_ref_insert(fs_info, &preftrees->direct, ref, NULL);
+
                ulist_reinit(parents);
+               cond_resched();
        }
 out:
        ulist_free(parents);
        return ret;
 }
 
-static inline int ref_for_same_block(struct __prelim_ref *ref1,
-                                    struct __prelim_ref *ref2)
-{
-       if (ref1->level != ref2->level)
-               return 0;
-       if (ref1->root_id != ref2->root_id)
-               return 0;
-       if (ref1->key_for_search.type != ref2->key_for_search.type)
-               return 0;
-       if (ref1->key_for_search.objectid != ref2->key_for_search.objectid)
-               return 0;
-       if (ref1->key_for_search.offset != ref2->key_for_search.offset)
-               return 0;
-       if (ref1->parent != ref2->parent)
-               return 0;
-
-       return 1;
-}
-
 /*
  * read tree blocks and add keys where required.
  */
-static int __add_missing_keys(struct btrfs_fs_info *fs_info,
-                             struct list_head *head)
+static int add_missing_keys(struct btrfs_fs_info *fs_info,
+                           struct preftrees *preftrees)
 {
-       struct __prelim_ref *ref;
+       struct prelim_ref *ref;
        struct extent_buffer *eb;
+       struct preftree *tree = &preftrees->indirect_missing_keys;
+       struct rb_node *node;
 
-       list_for_each_entry(ref, head, list) {
-               if (ref->parent)
-                       continue;
-               if (ref->key_for_search.type)
-                       continue;
+       while ((node = rb_first(&tree->root))) {
+               ref = rb_entry(node, struct prelim_ref, rbnode);
+               rb_erase(node, &tree->root);
+
+               BUG_ON(ref->parent);    /* should not be a direct ref */
+               BUG_ON(ref->key_for_search.type);
                BUG_ON(!ref->wanted_disk_byte);
+
                eb = read_tree_block(fs_info, ref->wanted_disk_byte, 0);
                if (IS_ERR(eb)) {
+                       free_pref(ref);
                        return PTR_ERR(eb);
                } else if (!extent_buffer_uptodate(eb)) {
+                       free_pref(ref);
                        free_extent_buffer(eb);
                        return -EIO;
                }
@@ -807,73 +749,33 @@ static int __add_missing_keys(struct btrfs_fs_info *fs_info,
                        btrfs_node_key_to_cpu(eb, &ref->key_for_search, 0);
                btrfs_tree_read_unlock(eb);
                free_extent_buffer(eb);
+               prelim_ref_insert(fs_info, &preftrees->indirect, ref, NULL);
+               cond_resched();
        }
        return 0;
 }
 
-/*
- * merge backrefs and adjust counts accordingly
- *
- *    FIXME: For MERGE_IDENTICAL_KEYS, if we add more keys in __add_prelim_ref
- *           then we can merge more here. Additionally, we could even add a key
- *           range for the blocks we looked into to merge even more (-> replace
- *           unresolved refs by those having a parent).
- */
-static void __merge_refs(struct list_head *head, enum merge_mode mode)
-{
-       struct __prelim_ref *pos1;
-
-       list_for_each_entry(pos1, head, list) {
-               struct __prelim_ref *pos2 = pos1, *tmp;
-
-               list_for_each_entry_safe_continue(pos2, tmp, head, list) {
-                       struct __prelim_ref *ref1 = pos1, *ref2 = pos2;
-                       struct extent_inode_elem *eie;
-
-                       if (!ref_for_same_block(ref1, ref2))
-                               continue;
-                       if (mode == MERGE_IDENTICAL_KEYS) {
-                               if (!ref1->parent && ref2->parent)
-                                       swap(ref1, ref2);
-                       } else {
-                               if (ref1->parent != ref2->parent)
-                                       continue;
-                       }
-
-                       eie = ref1->inode_list;
-                       while (eie && eie->next)
-                               eie = eie->next;
-                       if (eie)
-                               eie->next = ref2->inode_list;
-                       else
-                               ref1->inode_list = ref2->inode_list;
-                       ref1->count += ref2->count;
-
-                       list_del(&ref2->list);
-                       kmem_cache_free(btrfs_prelim_ref_cache, ref2);
-                       cond_resched();
-               }
-
-       }
-}
-
 /*
  * add all currently queued delayed refs from this head whose seq nr is
  * smaller or equal that seq to the list
  */
-static int __add_delayed_refs(struct btrfs_delayed_ref_head *head, u64 seq,
-                             struct list_head *prefs, u64 *total_refs,
-                             u64 inum)
+static int add_delayed_refs(const struct btrfs_fs_info *fs_info,
+                           struct btrfs_delayed_ref_head *head, u64 seq,
+                           struct preftrees *preftrees, u64 *total_refs,
+                           struct share_check *sc)
 {
        struct btrfs_delayed_ref_node *node;
        struct btrfs_delayed_extent_op *extent_op = head->extent_op;
        struct btrfs_key key;
-       struct btrfs_key op_key = {0};
-       int sgn;
+       struct btrfs_key tmp_op_key;
+       struct btrfs_key *op_key = NULL;
+       int count;
        int ret = 0;
 
-       if (extent_op && extent_op->update_key)
-               btrfs_disk_key_to_cpu(&op_key, &extent_op->key);
+       if (extent_op && extent_op->update_key) {
+               btrfs_disk_key_to_cpu(&tmp_op_key, &extent_op->key);
+               op_key = &tmp_op_key;
+       }
 
        spin_lock(&head->lock);
        list_for_each_entry(node, &head->ref_list, list) {
@@ -886,36 +788,40 @@ static int __add_delayed_refs(struct btrfs_delayed_ref_head *head, u64 seq,
                        WARN_ON(1);
                        continue;
                case BTRFS_ADD_DELAYED_REF:
-                       sgn = 1;
+                       count = node->ref_mod;
                        break;
                case BTRFS_DROP_DELAYED_REF:
-                       sgn = -1;
+                       count = node->ref_mod * -1;
                        break;
                default:
                        BUG_ON(1);
                }
-               *total_refs += (node->ref_mod * sgn);
+               *total_refs += count;
                switch (node->type) {
                case BTRFS_TREE_BLOCK_REF_KEY: {
+                       /* NORMAL INDIRECT METADATA backref */
                        struct btrfs_delayed_tree_ref *ref;
 
                        ref = btrfs_delayed_node_to_tree_ref(node);
-                       ret = __add_prelim_ref(prefs, ref->root, &op_key,
-                                              ref->level + 1, 0, node->bytenr,
-                                              node->ref_mod * sgn, GFP_ATOMIC);
+                       ret = add_indirect_ref(fs_info, preftrees, ref->root,
+                                              &tmp_op_key, ref->level + 1,
+                                              node->bytenr, count, sc,
+                                              GFP_ATOMIC);
                        break;
                }
                case BTRFS_SHARED_BLOCK_REF_KEY: {
+                       /* SHARED DIRECT METADATA backref */
                        struct btrfs_delayed_tree_ref *ref;
 
                        ref = btrfs_delayed_node_to_tree_ref(node);
-                       ret = __add_prelim_ref(prefs, 0, NULL,
-                                              ref->level + 1, ref->parent,
-                                              node->bytenr,
-                                              node->ref_mod * sgn, GFP_ATOMIC);
+
+                       ret = add_direct_ref(fs_info, preftrees, ref->level + 1,
+                                            ref->parent, node->bytenr, count,
+                                            sc, GFP_ATOMIC);
                        break;
                }
                case BTRFS_EXTENT_DATA_REF_KEY: {
+                       /* NORMAL INDIRECT DATA backref */
                        struct btrfs_delayed_data_ref *ref;
                        ref = btrfs_delayed_node_to_data_ref(node);
 
@@ -927,42 +833,53 @@ static int __add_delayed_refs(struct btrfs_delayed_ref_head *head, u64 seq,
                         * Found a inum that doesn't match our known inum, we
                         * know it's shared.
                         */
-                       if (inum && ref->objectid != inum) {
+                       if (sc && sc->inum && ref->objectid != sc->inum) {
                                ret = BACKREF_FOUND_SHARED;
-                               break;
+                               goto out;
                        }
 
-                       ret = __add_prelim_ref(prefs, ref->root, &key, 0, 0,
-                                              node->bytenr,
-                                              node->ref_mod * sgn, GFP_ATOMIC);
+                       ret = add_indirect_ref(fs_info, preftrees, ref->root,
+                                              &key, 0, node->bytenr, count, sc,
+                                              GFP_ATOMIC);
                        break;
                }
                case BTRFS_SHARED_DATA_REF_KEY: {
+                       /* SHARED DIRECT FULL backref */
                        struct btrfs_delayed_data_ref *ref;
 
                        ref = btrfs_delayed_node_to_data_ref(node);
-                       ret = __add_prelim_ref(prefs, 0, NULL, 0,
-                                              ref->parent, node->bytenr,
-                                              node->ref_mod * sgn, GFP_ATOMIC);
+
+                       ret = add_direct_ref(fs_info, preftrees, 0, ref->parent,
+                                            node->bytenr, count, sc,
+                                            GFP_ATOMIC);
                        break;
                }
                default:
                        WARN_ON(1);
                }
-               if (ret)
+               /*
+                * We must ignore BACKREF_FOUND_SHARED until all delayed
+                * refs have been checked.
+                */
+               if (ret && (ret != BACKREF_FOUND_SHARED))
                        break;
        }
+       if (!ret)
+               ret = extent_is_shared(sc);
+out:
        spin_unlock(&head->lock);
        return ret;
 }
 
 /*
  * add all inline backrefs for bytenr to the list
+ *
+ * Returns 0 on success, <0 on error, or BACKREF_FOUND_SHARED.
  */
-static int __add_inline_refs(struct btrfs_path *path, u64 bytenr,
-                            int *info_level, struct list_head *prefs,
-                            struct ref_root *ref_tree,
-                            u64 *total_refs, u64 inum)
+static int add_inline_refs(const struct btrfs_fs_info *fs_info,
+                          struct btrfs_path *path, u64 bytenr,
+                          int *info_level, struct preftrees *preftrees,
+                          u64 *total_refs, struct share_check *sc)
 {
        int ret = 0;
        int slot;
@@ -1012,14 +929,18 @@ static int __add_inline_refs(struct btrfs_path *path, u64 bytenr,
                int type;
 
                iref = (struct btrfs_extent_inline_ref *)ptr;
-               type = btrfs_extent_inline_ref_type(leaf, iref);
+               type = btrfs_get_extent_inline_ref_type(leaf, iref,
+                                                       BTRFS_REF_TYPE_ANY);
+               if (type == BTRFS_REF_TYPE_INVALID)
+                       return -EINVAL;
+
                offset = btrfs_extent_inline_ref_offset(leaf, iref);
 
                switch (type) {
                case BTRFS_SHARED_BLOCK_REF_KEY:
-                       ret = __add_prelim_ref(prefs, 0, NULL,
-                                               *info_level + 1, offset,
-                                               bytenr, 1, GFP_NOFS);
+                       ret = add_direct_ref(fs_info, preftrees,
+                                            *info_level + 1, offset,
+                                            bytenr, 1, NULL, GFP_NOFS);
                        break;
                case BTRFS_SHARED_DATA_REF_KEY: {
                        struct btrfs_shared_data_ref *sdref;
@@ -1027,21 +948,15 @@ static int __add_inline_refs(struct btrfs_path *path, u64 bytenr,
 
                        sdref = (struct btrfs_shared_data_ref *)(iref + 1);
                        count = btrfs_shared_data_ref_count(leaf, sdref);
-                       ret = __add_prelim_ref(prefs, 0, NULL, 0, offset,
-                                              bytenr, count, GFP_NOFS);
-                       if (ref_tree) {
-                               if (!ret)
-                                       ret = ref_tree_add(ref_tree, 0, 0, 0,
-                                                          bytenr, count);
-                               if (!ret && ref_tree->unique_refs > 1)
-                                       ret = BACKREF_FOUND_SHARED;
-                       }
+
+                       ret = add_direct_ref(fs_info, preftrees, 0, offset,
+                                            bytenr, count, sc, GFP_NOFS);
                        break;
                }
                case BTRFS_TREE_BLOCK_REF_KEY:
-                       ret = __add_prelim_ref(prefs, offset, NULL,
-                                              *info_level + 1, 0,
-                                              bytenr, 1, GFP_NOFS);
+                       ret = add_indirect_ref(fs_info, preftrees, offset,
+                                              NULL, *info_level + 1,
+                                              bytenr, 1, NULL, GFP_NOFS);
                        break;
                case BTRFS_EXTENT_DATA_REF_KEY: {
                        struct btrfs_extent_data_ref *dref;
@@ -1055,23 +970,16 @@ static int __add_inline_refs(struct btrfs_path *path, u64 bytenr,
                        key.type = BTRFS_EXTENT_DATA_KEY;
                        key.offset = btrfs_extent_data_ref_offset(leaf, dref);
 
-                       if (inum && key.objectid != inum) {
+                       if (sc && sc->inum && key.objectid != sc->inum) {
                                ret = BACKREF_FOUND_SHARED;
                                break;
                        }
 
                        root = btrfs_extent_data_ref_root(leaf, dref);
-                       ret = __add_prelim_ref(prefs, root, &key, 0, 0,
-                                              bytenr, count, GFP_NOFS);
-                       if (ref_tree) {
-                               if (!ret)
-                                       ret = ref_tree_add(ref_tree, root,
-                                                          key.objectid,
-                                                          key.offset, 0,
-                                                          count);
-                               if (!ret && ref_tree->unique_refs > 1)
-                                       ret = BACKREF_FOUND_SHARED;
-                       }
+
+                       ret = add_indirect_ref(fs_info, preftrees, root,
+                                              &key, 0, bytenr, count,
+                                              sc, GFP_NOFS);
                        break;
                }
                default:
@@ -1087,11 +995,13 @@ static int __add_inline_refs(struct btrfs_path *path, u64 bytenr,
 
 /*
  * add all non-inline backrefs for bytenr to the list
+ *
+ * Returns 0 on success, <0 on error, or BACKREF_FOUND_SHARED.
  */
-static int __add_keyed_refs(struct btrfs_fs_info *fs_info,
-                           struct btrfs_path *path, u64 bytenr,
-                           int info_level, struct list_head *prefs,
-                           struct ref_root *ref_tree, u64 inum)
+static int add_keyed_refs(struct btrfs_fs_info *fs_info,
+                         struct btrfs_path *path, u64 bytenr,
+                         int info_level, struct preftrees *preftrees,
+                         struct share_check *sc)
 {
        struct btrfs_root *extent_root = fs_info->extent_root;
        int ret;
@@ -1121,34 +1031,32 @@ static int __add_keyed_refs(struct btrfs_fs_info *fs_info,
 
                switch (key.type) {
                case BTRFS_SHARED_BLOCK_REF_KEY:
-                       ret = __add_prelim_ref(prefs, 0, NULL,
-                                               info_level + 1, key.offset,
-                                               bytenr, 1, GFP_NOFS);
+                       /* SHARED DIRECT METADATA backref */
+                       ret = add_direct_ref(fs_info, preftrees,
+                                            info_level + 1, key.offset,
+                                            bytenr, 1, NULL, GFP_NOFS);
                        break;
                case BTRFS_SHARED_DATA_REF_KEY: {
+                       /* SHARED DIRECT FULL backref */
                        struct btrfs_shared_data_ref *sdref;
                        int count;
 
                        sdref = btrfs_item_ptr(leaf, slot,
                                              struct btrfs_shared_data_ref);
                        count = btrfs_shared_data_ref_count(leaf, sdref);
-                       ret = __add_prelim_ref(prefs, 0, NULL, 0, key.offset,
-                                               bytenr, count, GFP_NOFS);
-                       if (ref_tree) {
-                               if (!ret)
-                                       ret = ref_tree_add(ref_tree, 0, 0, 0,
-                                                          bytenr, count);
-                               if (!ret && ref_tree->unique_refs > 1)
-                                       ret = BACKREF_FOUND_SHARED;
-                       }
+                       ret = add_direct_ref(fs_info, preftrees, 0,
+                                            key.offset, bytenr, count,
+                                            sc, GFP_NOFS);
                        break;
                }
                case BTRFS_TREE_BLOCK_REF_KEY:
-                       ret = __add_prelim_ref(prefs, key.offset, NULL,
-                                              info_level + 1, 0,
-                                              bytenr, 1, GFP_NOFS);
+                       /* NORMAL INDIRECT METADATA backref */
+                       ret = add_indirect_ref(fs_info, preftrees, key.offset,
+                                              NULL, info_level + 1, bytenr,
+                                              1, NULL, GFP_NOFS);
                        break;
                case BTRFS_EXTENT_DATA_REF_KEY: {
+                       /* NORMAL INDIRECT DATA backref */
                        struct btrfs_extent_data_ref *dref;
                        int count;
                        u64 root;
@@ -1161,23 +1069,15 @@ static int __add_keyed_refs(struct btrfs_fs_info *fs_info,
                        key.type = BTRFS_EXTENT_DATA_KEY;
                        key.offset = btrfs_extent_data_ref_offset(leaf, dref);
 
-                       if (inum && key.objectid != inum) {
+                       if (sc && sc->inum && key.objectid != sc->inum) {
                                ret = BACKREF_FOUND_SHARED;
                                break;
                        }
 
                        root = btrfs_extent_data_ref_root(leaf, dref);
-                       ret = __add_prelim_ref(prefs, root, &key, 0, 0,
-                                              bytenr, count, GFP_NOFS);
-                       if (ref_tree) {
-                               if (!ret)
-                                       ret = ref_tree_add(ref_tree, root,
-                                                          key.objectid,
-                                                          key.offset, 0,
-                                                          count);
-                               if (!ret && ref_tree->unique_refs > 1)
-                                       ret = BACKREF_FOUND_SHARED;
-                       }
+                       ret = add_indirect_ref(fs_info, preftrees, root,
+                                              &key, 0, bytenr, count,
+                                              sc, GFP_NOFS);
                        break;
                }
                default:
@@ -1197,15 +1097,15 @@ static int __add_keyed_refs(struct btrfs_fs_info *fs_info,
  * indirect refs to their parent bytenr.
  * When roots are found, they're added to the roots list
  *
- * NOTE: This can return values > 0
- *
  * If time_seq is set to SEQ_LAST, it will not search delayed_refs, and behave
  * much like trans == NULL case, the difference only lies in it will not
  * commit root.
  * The special case is for qgroup to search roots in commit_transaction().
  *
- * If check_shared is set to 1, any extent has more than one ref item, will
- * be returned BACKREF_FOUND_SHARED immediately.
+ * @sc - if !NULL, then immediately return BACKREF_FOUND_SHARED when a
+ * shared extent is detected.
+ *
+ * Otherwise this returns 0 for success and <0 for an error.
  *
  * FIXME some caching might speed things up
  */
@@ -1213,7 +1113,7 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans,
                             struct btrfs_fs_info *fs_info, u64 bytenr,
                             u64 time_seq, struct ulist *refs,
                             struct ulist *roots, const u64 *extent_item_pos,
-                            u64 root_objectid, u64 inum, int check_shared)
+                            struct share_check *sc)
 {
        struct btrfs_key key;
        struct btrfs_path *path;
@@ -1221,15 +1121,16 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans,
        struct btrfs_delayed_ref_head *head;
        int info_level = 0;
        int ret;
-       struct list_head prefs_delayed;
-       struct list_head prefs;
-       struct __prelim_ref *ref;
+       struct prelim_ref *ref;
+       struct rb_node *node;
        struct extent_inode_elem *eie = NULL;
-       struct ref_root *ref_tree = NULL;
+       /* total of both direct AND indirect refs! */
        u64 total_refs = 0;
-
-       INIT_LIST_HEAD(&prefs);
-       INIT_LIST_HEAD(&prefs_delayed);
+       struct preftrees preftrees = {
+               .direct = PREFTREE_INIT,
+               .indirect = PREFTREE_INIT,
+               .indirect_missing_keys = PREFTREE_INIT
+       };
 
        key.objectid = bytenr;
        key.offset = (u64)-1;
@@ -1257,18 +1158,6 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans,
 again:
        head = NULL;
 
-       if (check_shared) {
-               if (!ref_tree) {
-                       ref_tree = ref_root_alloc();
-                       if (!ref_tree) {
-                               ret = -ENOMEM;
-                               goto out;
-                       }
-               } else {
-                       ref_root_fini(ref_tree);
-               }
-       }
-
        ret = btrfs_search_slot(trans, fs_info->extent_root, &key, path, 0, 0);
        if (ret < 0)
                goto out;
@@ -1304,45 +1193,14 @@ again:
                                goto again;
                        }
                        spin_unlock(&delayed_refs->lock);
-                       ret = __add_delayed_refs(head, time_seq,
-                                                &prefs_delayed, &total_refs,
-                                                inum);
+                       ret = add_delayed_refs(fs_info, head, time_seq,
+                                              &preftrees, &total_refs, sc);
                        mutex_unlock(&head->mutex);
                        if (ret)
                                goto out;
                } else {
                        spin_unlock(&delayed_refs->lock);
                }
-
-               if (check_shared && !list_empty(&prefs_delayed)) {
-                       /*
-                        * Add all delay_ref to the ref_tree and check if there
-                        * are multiple ref items added.
-                        */
-                       list_for_each_entry(ref, &prefs_delayed, list) {
-                               if (ref->key_for_search.type) {
-                                       ret = ref_tree_add(ref_tree,
-                                               ref->root_id,
-                                               ref->key_for_search.objectid,
-                                               ref->key_for_search.offset,
-                                               0, ref->count);
-                                       if (ret)
-                                               goto out;
-                               } else {
-                                       ret = ref_tree_add(ref_tree, 0, 0, 0,
-                                                    ref->parent, ref->count);
-                                       if (ret)
-                                               goto out;
-                               }
-
-                       }
-
-                       if (ref_tree->unique_refs > 1) {
-                               ret = BACKREF_FOUND_SHARED;
-                               goto out;
-                       }
-
-               }
        }
 
        if (path->slots[0]) {
@@ -1356,42 +1214,48 @@ again:
                if (key.objectid == bytenr &&
                    (key.type == BTRFS_EXTENT_ITEM_KEY ||
                     key.type == BTRFS_METADATA_ITEM_KEY)) {
-                       ret = __add_inline_refs(path, bytenr,
-                                               &info_level, &prefs,
-                                               ref_tree, &total_refs,
-                                               inum);
+                       ret = add_inline_refs(fs_info, path, bytenr,
+                                             &info_level, &preftrees,
+                                             &total_refs, sc);
                        if (ret)
                                goto out;
-                       ret = __add_keyed_refs(fs_info, path, bytenr,
-                                              info_level, &prefs,
-                                              ref_tree, inum);
+                       ret = add_keyed_refs(fs_info, path, bytenr, info_level,
+                                            &preftrees, sc);
                        if (ret)
                                goto out;
                }
        }
-       btrfs_release_path(path);
 
-       list_splice_init(&prefs_delayed, &prefs);
+       btrfs_release_path(path);
 
-       ret = __add_missing_keys(fs_info, &prefs);
+       ret = add_missing_keys(fs_info, &preftrees);
        if (ret)
                goto out;
 
-       __merge_refs(&prefs, MERGE_IDENTICAL_KEYS);
+       WARN_ON(!RB_EMPTY_ROOT(&preftrees.indirect_missing_keys.root));
 
-       ret = __resolve_indirect_refs(fs_info, path, time_seq, &prefs,
-                                     extent_item_pos, total_refs,
-                                     root_objectid);
+       ret = resolve_indirect_refs(fs_info, path, time_seq, &preftrees,
+                                   extent_item_pos, total_refs, sc);
        if (ret)
                goto out;
 
-       __merge_refs(&prefs, MERGE_IDENTICAL_PARENTS);
+       WARN_ON(!RB_EMPTY_ROOT(&preftrees.indirect.root));
 
-       while (!list_empty(&prefs)) {
-               ref = list_first_entry(&prefs, struct __prelim_ref, list);
+       /*
+        * This walks the tree of merged and resolved refs. Tree blocks are
+        * read in as needed. Unique entries are added to the ulist, and
+        * the list of found roots is updated.
+        *
+        * We release the entire tree in one go before returning.
+        */
+       node = rb_first(&preftrees.direct.root);
+       while (node) {
+               ref = rb_entry(node, struct prelim_ref, rbnode);
+               node = rb_next(&ref->rbnode);
                WARN_ON(ref->count < 0);
                if (roots && ref->count && ref->root_id && ref->parent == 0) {
-                       if (root_objectid && ref->root_id != root_objectid) {
+                       if (sc && sc->root_objectid &&
+                           ref->root_id != sc->root_objectid) {
                                ret = BACKREF_FOUND_SHARED;
                                goto out;
                        }
@@ -1442,24 +1306,16 @@ again:
                        }
                        eie = NULL;
                }
-               list_del(&ref->list);
-               kmem_cache_free(btrfs_prelim_ref_cache, ref);
+               cond_resched();
        }
 
 out:
        btrfs_free_path(path);
-       ref_root_free(ref_tree);
-       while (!list_empty(&prefs)) {
-               ref = list_first_entry(&prefs, struct __prelim_ref, list);
-               list_del(&ref->list);
-               kmem_cache_free(btrfs_prelim_ref_cache, ref);
-       }
-       while (!list_empty(&prefs_delayed)) {
-               ref = list_first_entry(&prefs_delayed, struct __prelim_ref,
-                                      list);
-               list_del(&ref->list);
-               kmem_cache_free(btrfs_prelim_ref_cache, ref);
-       }
+
+       prelim_release(&preftrees.direct);
+       prelim_release(&preftrees.indirect);
+       prelim_release(&preftrees.indirect_missing_keys);
+
        if (ret < 0)
                free_inode_elem_list(eie);
        return ret;
@@ -1475,7 +1331,7 @@ static void free_leaf_list(struct ulist *blocks)
        while ((node = ulist_next(blocks, &uiter))) {
                if (!node->aux)
                        continue;
-               eie = (struct extent_inode_elem *)(uintptr_t)node->aux;
+               eie = unode_aux_to_inode_list(node);
                free_inode_elem_list(eie);
                node->aux = 0;
        }
@@ -1503,7 +1359,7 @@ static int btrfs_find_all_leafs(struct btrfs_trans_handle *trans,
                return -ENOMEM;
 
        ret = find_parent_nodes(trans, fs_info, bytenr, time_seq,
-                               *leafs, NULL, extent_item_pos, 0, 0, 0);
+                               *leafs, NULL, extent_item_pos, NULL);
        if (ret < 0 && ret != -ENOENT) {
                free_leaf_list(*leafs);
                return ret;
@@ -1525,9 +1381,9 @@ static int btrfs_find_all_leafs(struct btrfs_trans_handle *trans,
  *
  * returns 0 on success, < 0 on error.
  */
-static int __btrfs_find_all_roots(struct btrfs_trans_handle *trans,
-                                 struct btrfs_fs_info *fs_info, u64 bytenr,
-                                 u64 time_seq, struct ulist **roots)
+static int btrfs_find_all_roots_safe(struct btrfs_trans_handle *trans,
+                                    struct btrfs_fs_info *fs_info, u64 bytenr,
+                                    u64 time_seq, struct ulist **roots)
 {
        struct ulist *tmp;
        struct ulist_node *node = NULL;
@@ -1546,7 +1402,7 @@ static int __btrfs_find_all_roots(struct btrfs_trans_handle *trans,
        ULIST_ITER_INIT(&uiter);
        while (1) {
                ret = find_parent_nodes(trans, fs_info, bytenr, time_seq,
-                                       tmp, *roots, NULL, 0, 0, 0);
+                                       tmp, *roots, NULL, NULL);
                if (ret < 0 && ret != -ENOENT) {
                        ulist_free(tmp);
                        ulist_free(*roots);
@@ -1571,7 +1427,8 @@ int btrfs_find_all_roots(struct btrfs_trans_handle *trans,
 
        if (!trans)
                down_read(&fs_info->commit_root_sem);
-       ret = __btrfs_find_all_roots(trans, fs_info, bytenr, time_seq, roots);
+       ret = btrfs_find_all_roots_safe(trans, fs_info, bytenr,
+                                       time_seq, roots);
        if (!trans)
                up_read(&fs_info->commit_root_sem);
        return ret;
@@ -1580,26 +1437,32 @@ 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;
        struct ulist_node *node;
        struct seq_list elem = SEQ_LIST_INIT(elem);
        int ret = 0;
+       struct share_check shared = {
+               .root_objectid = root->objectid,
+               .inum = inum,
+               .share_count = 0,
+       };
 
        tmp = ulist_alloc(GFP_NOFS);
        roots = ulist_alloc(GFP_NOFS);
@@ -1609,14 +1472,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, &shared);
                if (ret == BACKREF_FOUND_SHARED) {
                        /* this is the only condition under which we return 1 */
                        ret = 1;
@@ -1631,10 +1498,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;
@@ -1649,7 +1519,7 @@ int btrfs_find_one_extref(struct btrfs_root *root, u64 inode_objectid,
        struct btrfs_key key;
        struct btrfs_key found_key;
        struct btrfs_inode_extref *extref;
-       struct extent_buffer *leaf;
+       const struct extent_buffer *leaf;
        unsigned long ptr;
 
        key.objectid = inode_objectid;
@@ -1806,7 +1676,7 @@ int extent_from_logical(struct btrfs_fs_info *fs_info, u64 logical,
        u64 flags;
        u64 size = 0;
        u32 item_size;
-       struct extent_buffer *eb;
+       const struct extent_buffer *eb;
        struct btrfs_extent_item *ei;
        struct btrfs_key key;
 
@@ -1870,15 +1740,17 @@ int extent_from_logical(struct btrfs_fs_info *fs_info, u64 logical,
  * helper function to iterate extent inline refs. ptr must point to a 0 value
  * for the first call and may be modified. it is used to track state.
  * if more refs exist, 0 is returned and the next call to
- * __get_extent_inline_ref must pass the modified ptr parameter to get the
+ * get_extent_inline_ref must pass the modified ptr parameter to get the
  * next ref. after the last ref was processed, 1 is returned.
  * returns <0 on error
  */
-static int __get_extent_inline_ref(unsigned long *ptr, struct extent_buffer *eb,
-                                  struct btrfs_key *key,
-                                  struct btrfs_extent_item *ei, u32 item_size,
-                                  struct btrfs_extent_inline_ref **out_eiref,
-                                  int *out_type)
+static int get_extent_inline_ref(unsigned long *ptr,
+                                const struct extent_buffer *eb,
+                                const struct btrfs_key *key,
+                                const struct btrfs_extent_item *ei,
+                                u32 item_size,
+                                struct btrfs_extent_inline_ref **out_eiref,
+                                int *out_type)
 {
        unsigned long end;
        u64 flags;
@@ -1908,7 +1780,10 @@ static int __get_extent_inline_ref(unsigned long *ptr, struct extent_buffer *eb,
 
        end = (unsigned long)ei + item_size;
        *out_eiref = (struct btrfs_extent_inline_ref *)(*ptr);
-       *out_type = btrfs_extent_inline_ref_type(eb, *out_eiref);
+       *out_type = btrfs_get_extent_inline_ref_type(eb, *out_eiref,
+                                                    BTRFS_REF_TYPE_ANY);
+       if (*out_type == BTRFS_REF_TYPE_INVALID)
+               return -EINVAL;
 
        *ptr += btrfs_extent_inline_ref_size(*out_type);
        WARN_ON(*ptr > end);
@@ -1921,7 +1796,7 @@ static int __get_extent_inline_ref(unsigned long *ptr, struct extent_buffer *eb,
 /*
  * reads the tree block backref for an extent. tree level and root are returned
  * through out_level and out_root. ptr must point to a 0 value for the first
- * call and may be modified (see __get_extent_inline_ref comment).
+ * call and may be modified (see get_extent_inline_ref comment).
  * returns 0 if data was provided, 1 if there was no more data to provide or
  * <0 on error.
  */
@@ -1937,7 +1812,7 @@ int tree_backref_for_extent(unsigned long *ptr, struct extent_buffer *eb,
                return 1;
 
        while (1) {
-               ret = __get_extent_inline_ref(ptr, eb, key, ei, item_size,
+               ret = get_extent_inline_ref(ptr, eb, key, ei, item_size,
                                              &eiref, &type);
                if (ret < 0)
                        return ret;
@@ -2034,8 +1909,8 @@ int iterate_extent_inodes(struct btrfs_fs_info *fs_info,
 
        ULIST_ITER_INIT(&ref_uiter);
        while (!ret && (ref_node = ulist_next(refs, &ref_uiter))) {
-               ret = __btrfs_find_all_roots(trans, fs_info, ref_node->val,
-                                            tree_mod_seq_elem.seq, &roots);
+               ret = btrfs_find_all_roots_safe(trans, fs_info, ref_node->val,
+                                               tree_mod_seq_elem.seq, &roots);
                if (ret)
                        break;
                ULIST_ITER_INIT(&root_uiter);
index 9c41fbac30091f39bad52a3f21ebf6e931db364b..e410335841aacfb0f672f90292cd9c8c621054ee 100644 (file)
@@ -68,10 +68,20 @@ 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);
+
+struct prelim_ref {
+       struct rb_node rbnode;
+       u64 root_id;
+       struct btrfs_key key_for_search;
+       int level;
+       int count;
+       struct extent_inode_elem *inode_list;
+       u64 parent;
+       u64 wanted_disk_byte;
+};
+
 #endif
index d87ac27a5f2b4cbf2e415e6a34ac88f66647b008..eccadb5f62a5ed60929f173d814698d266f4e27c 100644 (file)
@@ -179,9 +179,14 @@ struct btrfs_inode {
        unsigned reserved_extents;
 
        /*
-        * always compress this one file
+        * Cached values of inode properties
         */
-       unsigned force_compress;
+       unsigned prop_compress;         /* per-file compression algorithm */
+       /*
+        * Force compression on the file using the defrag ioctl, could be
+        * different from prop_compress and takes precedence if set
+        */
+       unsigned defrag_compress;
 
        struct btrfs_delayed_node *delayed_node;
 
@@ -207,7 +212,7 @@ struct btrfs_inode {
 
 extern unsigned char btrfs_filetype_table[];
 
-static inline struct btrfs_inode *BTRFS_I(struct inode *inode)
+static inline struct btrfs_inode *BTRFS_I(const struct inode *inode)
 {
        return container_of(inode, struct btrfs_inode, vfs_inode);
 }
@@ -231,7 +236,7 @@ static inline void btrfs_insert_inode_hash(struct inode *inode)
        __insert_inode_hash(inode, h);
 }
 
-static inline u64 btrfs_ino(struct btrfs_inode *inode)
+static inline u64 btrfs_ino(const struct btrfs_inode *inode)
 {
        u64 ino = inode->location.objectid;
 
index fb07e3c22b9aaa7362861cd3451ee27f184a7d77..7d5a9b51f0d7a81fa7d5adf9900e4fcc744a80c0 100644 (file)
@@ -791,12 +791,12 @@ static int btrfsic_process_superblock_dev_mirror(
        dev_bytenr = btrfs_sb_offset(superblock_mirror_num);
        if (dev_bytenr + BTRFS_SUPER_INFO_SIZE > device->commit_total_bytes)
                return -1;
-       bh = __bread(superblock_bdev, dev_bytenr / 4096,
+       bh = __bread(superblock_bdev, dev_bytenr / BTRFS_BDEV_BLOCKSIZE,
                     BTRFS_SUPER_INFO_SIZE);
        if (NULL == bh)
                return -1;
        super_tmp = (struct btrfs_super_block *)
-           (bh->b_data + (dev_bytenr & 4095));
+           (bh->b_data + (dev_bytenr & (BTRFS_BDEV_BLOCKSIZE - 1)));
 
        if (btrfs_super_bytenr(super_tmp) != dev_bytenr ||
            btrfs_super_magic(super_tmp) != BTRFS_MAGIC ||
@@ -1728,7 +1728,7 @@ static int btrfsic_test_for_metadata(struct btrfsic_state *state,
        num_pages = state->metablock_size >> PAGE_SHIFT;
        h = (struct btrfs_header *)datav[0];
 
-       if (memcmp(h->fsid, fs_info->fsid, BTRFS_UUID_SIZE))
+       if (memcmp(h->fsid, fs_info->fsid, BTRFS_FSID_SIZE))
                return 1;
 
        for (i = 0; i < num_pages; i++) {
@@ -2753,7 +2753,7 @@ int btrfsic_submit_bh(int op, int op_flags, struct buffer_head *bh)
            (op == REQ_OP_WRITE) && bh->b_size > 0) {
                u64 dev_bytenr;
 
-               dev_bytenr = 4096 * bh->b_blocknr;
+               dev_bytenr = BTRFS_BDEV_BLOCKSIZE * bh->b_blocknr;
                if (dev_state->state->print_mask &
                    BTRFSIC_PRINT_MASK_SUBMIT_BIO_BH)
                        pr_info("submit_bh(op=0x%x,0x%x, blocknr=%llu (bytenr %llu), size=%zu, data=%p, bdev=%p)\n",
index d2ef9ac2a63038e279239012fdec7de0cf9573e3..883ecc58fd0dabeda45dd05557c503bd47a71902 100644 (file)
@@ -825,7 +825,7 @@ static void free_workspace(int type, struct list_head *workspace)
        int *free_ws                    = &btrfs_comp_ws[idx].free_ws;
 
        spin_lock(ws_lock);
-       if (*free_ws < num_online_cpus()) {
+       if (*free_ws <= num_online_cpus()) {
                list_add(workspace, idle_ws);
                (*free_ws)++;
                spin_unlock(ws_lock);
@@ -1047,3 +1047,36 @@ int btrfs_decompress_buf2page(const char *buf, unsigned long buf_start,
 
        return 1;
 }
+
+/*
+ * Compression heuristic.
+ *
+ * For now is's a naive and optimistic 'return true', we'll extend the logic to
+ * quickly (compared to direct compression) detect data characteristics
+ * (compressible/uncompressible) to avoid wasting CPU time on uncompressible
+ * data.
+ *
+ * The following types of analysis can be performed:
+ * - detect mostly zero data
+ * - detect data with low "byte set" size (text, etc)
+ * - detect data with low/high "core byte" set
+ *
+ * Return non-zero if the compression should be done, 0 otherwise.
+ */
+int btrfs_compress_heuristic(struct inode *inode, u64 start, u64 end)
+{
+       u64 index = start >> PAGE_SHIFT;
+       u64 end_index = end >> PAGE_SHIFT;
+       struct page *page;
+       int ret = 1;
+
+       while (index <= end_index) {
+               page = find_get_page(inode->i_mapping, index);
+               kmap(page);
+               kunmap(page);
+               put_page(page);
+               index++;
+       }
+
+       return ret;
+}
index 87f6d3332163e2949465a9b85f8c7c73d963e584..3b1b0ac15fdcf22a1a751d5bde97dfe0225019d6 100644 (file)
@@ -100,7 +100,6 @@ enum btrfs_compression_type {
        BTRFS_COMPRESS_ZLIB  = 1,
        BTRFS_COMPRESS_LZO   = 2,
        BTRFS_COMPRESS_TYPES = 2,
-       BTRFS_COMPRESS_LAST  = 3,
 };
 
 struct btrfs_compress_op {
@@ -129,4 +128,6 @@ struct btrfs_compress_op {
 extern const struct btrfs_compress_op btrfs_zlib_compress;
 extern const struct btrfs_compress_op btrfs_lzo_compress;
 
+int btrfs_compress_heuristic(struct inode *inode, u64 start, u64 end);
+
 #endif
index 3f4daa9d6e2cc8df872e9cf6141eaaf89a4155f9..6d49db7d86be29c1fa256b60a7ee9beab3d9b1ed 100644 (file)
@@ -4650,7 +4650,7 @@ void btrfs_truncate_item(struct btrfs_fs_info *fs_info,
        btrfs_mark_buffer_dirty(leaf);
 
        if (btrfs_leaf_free_space(fs_info, leaf) < 0) {
-               btrfs_print_leaf(fs_info, leaf);
+               btrfs_print_leaf(leaf);
                BUG();
        }
 }
@@ -4679,7 +4679,7 @@ void btrfs_extend_item(struct btrfs_fs_info *fs_info, struct btrfs_path *path,
        data_end = leaf_data_end(fs_info, leaf);
 
        if (btrfs_leaf_free_space(fs_info, leaf) < data_size) {
-               btrfs_print_leaf(fs_info, leaf);
+               btrfs_print_leaf(leaf);
                BUG();
        }
        slot = path->slots[0];
@@ -4687,7 +4687,7 @@ void btrfs_extend_item(struct btrfs_fs_info *fs_info, struct btrfs_path *path,
 
        BUG_ON(slot < 0);
        if (slot >= nritems) {
-               btrfs_print_leaf(fs_info, leaf);
+               btrfs_print_leaf(leaf);
                btrfs_crit(fs_info, "slot %d too large, nritems %d",
                           slot, nritems);
                BUG_ON(1);
@@ -4718,7 +4718,7 @@ void btrfs_extend_item(struct btrfs_fs_info *fs_info, struct btrfs_path *path,
        btrfs_mark_buffer_dirty(leaf);
 
        if (btrfs_leaf_free_space(fs_info, leaf) < 0) {
-               btrfs_print_leaf(fs_info, leaf);
+               btrfs_print_leaf(leaf);
                BUG();
        }
 }
@@ -4757,7 +4757,7 @@ void setup_items_for_insert(struct btrfs_root *root, struct btrfs_path *path,
        data_end = leaf_data_end(fs_info, leaf);
 
        if (btrfs_leaf_free_space(fs_info, leaf) < total_size) {
-               btrfs_print_leaf(fs_info, leaf);
+               btrfs_print_leaf(leaf);
                btrfs_crit(fs_info, "not enough freespace need %u have %d",
                           total_size, btrfs_leaf_free_space(fs_info, leaf));
                BUG();
@@ -4767,7 +4767,7 @@ void setup_items_for_insert(struct btrfs_root *root, struct btrfs_path *path,
                unsigned int old_data = btrfs_item_end_nr(leaf, slot);
 
                if (old_data < data_end) {
-                       btrfs_print_leaf(fs_info, leaf);
+                       btrfs_print_leaf(leaf);
                        btrfs_crit(fs_info, "slot %d old_data %d data_end %d",
                                   slot, old_data, data_end);
                        BUG_ON(1);
@@ -4811,7 +4811,7 @@ void setup_items_for_insert(struct btrfs_root *root, struct btrfs_path *path,
        btrfs_mark_buffer_dirty(leaf);
 
        if (btrfs_leaf_free_space(fs_info, leaf) < 0) {
-               btrfs_print_leaf(fs_info, leaf);
+               btrfs_print_leaf(leaf);
                BUG();
        }
 }
index 3f3eb7b17cac5c84be5883a5577b547eb8847b90..2add002662f4bbb3104f3127f394d2ebc03d65a9 100644 (file)
@@ -470,8 +470,8 @@ struct btrfs_block_rsv {
 
 /*
  * free clusters are used to claim free space in relatively large chunks,
- * allowing us to do less seeky writes.  They are used for all metadata
- * allocations and data allocations in ssd mode.
+ * allowing us to do less seeky writes. They are used for all metadata
+ * allocations. In ssd_spread mode they are also used for data allocations.
  */
 struct btrfs_free_cluster {
        spinlock_t lock;
@@ -558,7 +558,6 @@ struct btrfs_block_group_cache {
        u64 bytes_super;
        u64 flags;
        u64 cache_generation;
-       u32 sectorsize;
 
        /*
         * If the free space extent count exceeds this number, convert the block
@@ -968,7 +967,7 @@ struct btrfs_fs_info {
 
        struct reloc_control *reloc_ctl;
 
-       /* data_alloc_cluster is only used in ssd mode */
+       /* data_alloc_cluster is only used in ssd_spread mode */
        struct btrfs_free_cluster data_alloc_cluster;
 
        /* all metadata allocations go through this cluster */
@@ -1072,8 +1071,6 @@ struct btrfs_fs_info {
        /* next backup root to be overwritten */
        int backup_root_index;
 
-       int num_tolerated_disk_barrier_failures;
-
        /* device replace state */
        struct btrfs_dev_replace dev_replace;
 
@@ -1261,12 +1258,17 @@ struct btrfs_root {
         */
        int send_in_progress;
        struct btrfs_subvolume_writers *subv_writers;
-       atomic_t will_be_snapshoted;
+       atomic_t will_be_snapshotted;
 
        /* For qgroup metadata space reserve */
        atomic64_t qgroup_meta_rsv;
 };
 
+struct btrfs_file_private {
+       struct btrfs_trans_handle *trans;
+       void *filldir_buf;
+};
+
 static inline u32 btrfs_inode_sectorsize(const struct inode *inode)
 {
        return btrfs_sb(inode->i_sb)->sectorsize;
@@ -1435,7 +1437,7 @@ do {                                                                   \
 #define BTRFS_INODE_ROOT_ITEM_INIT     (1 << 31)
 
 struct btrfs_map_token {
-       struct extent_buffer *eb;
+       const struct extent_buffer *eb;
        char *kaddr;
        unsigned long offset;
 };
@@ -1469,18 +1471,19 @@ static inline void btrfs_init_map_token (struct btrfs_map_token *token)
                           sizeof(((type *)0)->member)))
 
 #define DECLARE_BTRFS_SETGET_BITS(bits)                                        \
-u##bits btrfs_get_token_##bits(struct extent_buffer *eb, void *ptr,    \
-                              unsigned long off,                       \
-                              struct btrfs_map_token *token);          \
-void btrfs_set_token_##bits(struct extent_buffer *eb, void *ptr,       \
+u##bits btrfs_get_token_##bits(const struct extent_buffer *eb,         \
+                              const void *ptr, unsigned long off,      \
+                              struct btrfs_map_token *token);          \
+void btrfs_set_token_##bits(struct extent_buffer *eb, const void *ptr, \
                            unsigned long off, u##bits val,             \
                            struct btrfs_map_token *token);             \
-static inline u##bits btrfs_get_##bits(struct extent_buffer *eb, void *ptr, \
+static inline u##bits btrfs_get_##bits(const struct extent_buffer *eb, \
+                                      const void *ptr,                 \
                                       unsigned long off)               \
 {                                                                      \
        return btrfs_get_token_##bits(eb, ptr, off, NULL);              \
 }                                                                      \
-static inline void btrfs_set_##bits(struct extent_buffer *eb, void *ptr, \
+static inline void btrfs_set_##bits(struct extent_buffer *eb, void *ptr,\
                                    unsigned long off, u##bits val)     \
 {                                                                      \
        btrfs_set_token_##bits(eb, ptr, off, val, NULL);                        \
@@ -1492,7 +1495,8 @@ DECLARE_BTRFS_SETGET_BITS(32)
 DECLARE_BTRFS_SETGET_BITS(64)
 
 #define BTRFS_SETGET_FUNCS(name, type, member, bits)                   \
-static inline u##bits btrfs_##name(struct extent_buffer *eb, type *s)  \
+static inline u##bits btrfs_##name(const struct extent_buffer *eb,     \
+                                  const type *s)                       \
 {                                                                      \
        BUILD_BUG_ON(sizeof(u##bits) != sizeof(((type *)0))->member);   \
        return btrfs_get_##bits(eb, s, offsetof(type, member));         \
@@ -1503,7 +1507,8 @@ static inline void btrfs_set_##name(struct extent_buffer *eb, type *s,    \
        BUILD_BUG_ON(sizeof(u##bits) != sizeof(((type *)0))->member);   \
        btrfs_set_##bits(eb, s, offsetof(type, member), val);           \
 }                                                                      \
-static inline u##bits btrfs_token_##name(struct extent_buffer *eb, type *s, \
+static inline u##bits btrfs_token_##name(const struct extent_buffer *eb,\
+                                        const type *s,                 \
                                         struct btrfs_map_token *token) \
 {                                                                      \
        BUILD_BUG_ON(sizeof(u##bits) != sizeof(((type *)0))->member);   \
@@ -1518,9 +1523,9 @@ static inline void btrfs_set_token_##name(struct extent_buffer *eb,       \
 }
 
 #define BTRFS_SETGET_HEADER_FUNCS(name, type, member, bits)            \
-static inline u##bits btrfs_##name(struct extent_buffer *eb)           \
+static inline u##bits btrfs_##name(const struct extent_buffer *eb)     \
 {                                                                      \
-       type *p = page_address(eb->pages[0]);                           \
+       const type *p = page_address(eb->pages[0]);                     \
        u##bits res = le##bits##_to_cpu(p->member);                     \
        return res;                                                     \
 }                                                                      \
@@ -1532,7 +1537,7 @@ static inline void btrfs_set_##name(struct extent_buffer *eb,             \
 }
 
 #define BTRFS_SETGET_STACK_FUNCS(name, type, member, bits)             \
-static inline u##bits btrfs_##name(type *s)                            \
+static inline u##bits btrfs_##name(const type *s)                      \
 {                                                                      \
        return le##bits##_to_cpu(s->member);                            \
 }                                                                      \
@@ -1799,7 +1804,6 @@ static inline u32 btrfs_extent_inline_ref_size(int type)
        if (type == BTRFS_EXTENT_DATA_REF_KEY)
                return sizeof(struct btrfs_extent_data_ref) +
                       offsetof(struct btrfs_extent_inline_ref, offset);
-       BUG();
        return 0;
 }
 
@@ -1857,7 +1861,7 @@ static inline unsigned long btrfs_node_key_ptr_offset(int nr)
                sizeof(struct btrfs_key_ptr) * nr;
 }
 
-void btrfs_node_key(struct extent_buffer *eb,
+void btrfs_node_key(const struct extent_buffer *eb,
                    struct btrfs_disk_key *disk_key, int nr);
 
 static inline void btrfs_set_node_key(struct extent_buffer *eb,
@@ -1886,28 +1890,28 @@ static inline struct btrfs_item *btrfs_item_nr(int nr)
        return (struct btrfs_item *)btrfs_item_nr_offset(nr);
 }
 
-static inline u32 btrfs_item_end(struct extent_buffer *eb,
+static inline u32 btrfs_item_end(const struct extent_buffer *eb,
                                 struct btrfs_item *item)
 {
        return btrfs_item_offset(eb, item) + btrfs_item_size(eb, item);
 }
 
-static inline u32 btrfs_item_end_nr(struct extent_buffer *eb, int nr)
+static inline u32 btrfs_item_end_nr(const struct extent_buffer *eb, int nr)
 {
        return btrfs_item_end(eb, btrfs_item_nr(nr));
 }
 
-static inline u32 btrfs_item_offset_nr(struct extent_buffer *eb, int nr)
+static inline u32 btrfs_item_offset_nr(const struct extent_buffer *eb, int nr)
 {
        return btrfs_item_offset(eb, btrfs_item_nr(nr));
 }
 
-static inline u32 btrfs_item_size_nr(struct extent_buffer *eb, int nr)
+static inline u32 btrfs_item_size_nr(const struct extent_buffer *eb, int nr)
 {
        return btrfs_item_size(eb, btrfs_item_nr(nr));
 }
 
-static inline void btrfs_item_key(struct extent_buffer *eb,
+static inline void btrfs_item_key(const struct extent_buffer *eb,
                           struct btrfs_disk_key *disk_key, int nr)
 {
        struct btrfs_item *item = btrfs_item_nr(nr);
@@ -1943,8 +1947,8 @@ BTRFS_SETGET_STACK_FUNCS(stack_dir_name_len, struct btrfs_dir_item,
 BTRFS_SETGET_STACK_FUNCS(stack_dir_transid, struct btrfs_dir_item,
                         transid, 64);
 
-static inline void btrfs_dir_item_key(struct extent_buffer *eb,
-                                     struct btrfs_dir_item *item,
+static inline void btrfs_dir_item_key(const struct extent_buffer *eb,
+                                     const struct btrfs_dir_item *item,
                                      struct btrfs_disk_key *key)
 {
        read_eb_member(eb, item, struct btrfs_dir_item, location, key);
@@ -1952,7 +1956,7 @@ static inline void btrfs_dir_item_key(struct extent_buffer *eb,
 
 static inline void btrfs_set_dir_item_key(struct extent_buffer *eb,
                                          struct btrfs_dir_item *item,
-                                         struct btrfs_disk_key *key)
+                                         const struct btrfs_disk_key *key)
 {
        write_eb_member(eb, item, struct btrfs_dir_item, location, key);
 }
@@ -1964,8 +1968,8 @@ BTRFS_SETGET_FUNCS(free_space_bitmaps, struct btrfs_free_space_header,
 BTRFS_SETGET_FUNCS(free_space_generation, struct btrfs_free_space_header,
                   generation, 64);
 
-static inline void btrfs_free_space_key(struct extent_buffer *eb,
-                                       struct btrfs_free_space_header *h,
+static inline void btrfs_free_space_key(const struct extent_buffer *eb,
+                                       const struct btrfs_free_space_header *h,
                                        struct btrfs_disk_key *key)
 {
        read_eb_member(eb, h, struct btrfs_free_space_header, location, key);
@@ -1973,7 +1977,7 @@ static inline void btrfs_free_space_key(struct extent_buffer *eb,
 
 static inline void btrfs_set_free_space_key(struct extent_buffer *eb,
                                            struct btrfs_free_space_header *h,
-                                           struct btrfs_disk_key *key)
+                                           const struct btrfs_disk_key *key)
 {
        write_eb_member(eb, h, struct btrfs_free_space_header, location, key);
 }
@@ -2000,25 +2004,25 @@ static inline void btrfs_cpu_key_to_disk(struct btrfs_disk_key *disk,
        disk->objectid = cpu_to_le64(cpu->objectid);
 }
 
-static inline void btrfs_node_key_to_cpu(struct extent_buffer *eb,
-                                 struct btrfs_key *key, int nr)
+static inline void btrfs_node_key_to_cpu(const struct extent_buffer *eb,
+                                        struct btrfs_key *key, int nr)
 {
        struct btrfs_disk_key disk_key;
        btrfs_node_key(eb, &disk_key, nr);
        btrfs_disk_key_to_cpu(key, &disk_key);
 }
 
-static inline void btrfs_item_key_to_cpu(struct extent_buffer *eb,
-                                 struct btrfs_key *key, int nr)
+static inline void btrfs_item_key_to_cpu(const struct extent_buffer *eb,
+                                        struct btrfs_key *key, int nr)
 {
        struct btrfs_disk_key disk_key;
        btrfs_item_key(eb, &disk_key, nr);
        btrfs_disk_key_to_cpu(key, &disk_key);
 }
 
-static inline void btrfs_dir_item_key_to_cpu(struct extent_buffer *eb,
-                                     struct btrfs_dir_item *item,
-                                     struct btrfs_key *key)
+static inline void btrfs_dir_item_key_to_cpu(const struct extent_buffer *eb,
+                                            const struct btrfs_dir_item *item,
+                                            struct btrfs_key *key)
 {
        struct btrfs_disk_key disk_key;
        btrfs_dir_item_key(eb, item, &disk_key);
@@ -2050,7 +2054,7 @@ BTRFS_SETGET_STACK_FUNCS(stack_header_nritems, struct btrfs_header,
                         nritems, 32);
 BTRFS_SETGET_STACK_FUNCS(stack_header_bytenr, struct btrfs_header, bytenr, 64);
 
-static inline int btrfs_header_flag(struct extent_buffer *eb, u64 flag)
+static inline int btrfs_header_flag(const struct extent_buffer *eb, u64 flag)
 {
        return (btrfs_header_flags(eb) & flag) == flag;
 }
@@ -2069,7 +2073,7 @@ static inline int btrfs_clear_header_flag(struct extent_buffer *eb, u64 flag)
        return (flags & flag) == flag;
 }
 
-static inline int btrfs_header_backref_rev(struct extent_buffer *eb)
+static inline int btrfs_header_backref_rev(const struct extent_buffer *eb)
 {
        u64 flags = btrfs_header_flags(eb);
        return flags >> BTRFS_BACKREF_REV_SHIFT;
@@ -2089,12 +2093,12 @@ static inline unsigned long btrfs_header_fsid(void)
        return offsetof(struct btrfs_header, fsid);
 }
 
-static inline unsigned long btrfs_header_chunk_tree_uuid(struct extent_buffer *eb)
+static inline unsigned long btrfs_header_chunk_tree_uuid(const struct extent_buffer *eb)
 {
        return offsetof(struct btrfs_header, chunk_tree_uuid);
 }
 
-static inline int btrfs_is_leaf(struct extent_buffer *eb)
+static inline int btrfs_is_leaf(const struct extent_buffer *eb)
 {
        return btrfs_header_level(eb) == 0;
 }
@@ -2128,12 +2132,12 @@ BTRFS_SETGET_STACK_FUNCS(root_stransid, struct btrfs_root_item,
 BTRFS_SETGET_STACK_FUNCS(root_rtransid, struct btrfs_root_item,
                         rtransid, 64);
 
-static inline bool btrfs_root_readonly(struct btrfs_root *root)
+static inline bool btrfs_root_readonly(const struct btrfs_root *root)
 {
        return (root->root_item.flags & cpu_to_le64(BTRFS_ROOT_SUBVOL_RDONLY)) != 0;
 }
 
-static inline bool btrfs_root_dead(struct btrfs_root *root)
+static inline bool btrfs_root_dead(const struct btrfs_root *root)
 {
        return (root->root_item.flags & cpu_to_le64(BTRFS_ROOT_SUBVOL_DEAD)) != 0;
 }
@@ -2190,51 +2194,51 @@ BTRFS_SETGET_STACK_FUNCS(backup_num_devices, struct btrfs_root_backup,
 /* struct btrfs_balance_item */
 BTRFS_SETGET_FUNCS(balance_flags, struct btrfs_balance_item, flags, 64);
 
-static inline void btrfs_balance_data(struct extent_buffer *eb,
-                                     struct btrfs_balance_item *bi,
+static inline void btrfs_balance_data(const struct extent_buffer *eb,
+                                     const struct btrfs_balance_item *bi,
                                      struct btrfs_disk_balance_args *ba)
 {
        read_eb_member(eb, bi, struct btrfs_balance_item, data, ba);
 }
 
 static inline void btrfs_set_balance_data(struct extent_buffer *eb,
-                                         struct btrfs_balance_item *bi,
-                                         struct btrfs_disk_balance_args *ba)
+                                 struct btrfs_balance_item *bi,
+                                 const struct btrfs_disk_balance_args *ba)
 {
        write_eb_member(eb, bi, struct btrfs_balance_item, data, ba);
 }
 
-static inline void btrfs_balance_meta(struct extent_buffer *eb,
-                                     struct btrfs_balance_item *bi,
+static inline void btrfs_balance_meta(const struct extent_buffer *eb,
+                                     const struct btrfs_balance_item *bi,
                                      struct btrfs_disk_balance_args *ba)
 {
        read_eb_member(eb, bi, struct btrfs_balance_item, meta, ba);
 }
 
 static inline void btrfs_set_balance_meta(struct extent_buffer *eb,
-                                         struct btrfs_balance_item *bi,
-                                         struct btrfs_disk_balance_args *ba)
+                                 struct btrfs_balance_item *bi,
+                                 const struct btrfs_disk_balance_args *ba)
 {
        write_eb_member(eb, bi, struct btrfs_balance_item, meta, ba);
 }
 
-static inline void btrfs_balance_sys(struct extent_buffer *eb,
-                                    struct btrfs_balance_item *bi,
+static inline void btrfs_balance_sys(const struct extent_buffer *eb,
+                                    const struct btrfs_balance_item *bi,
                                     struct btrfs_disk_balance_args *ba)
 {
        read_eb_member(eb, bi, struct btrfs_balance_item, sys, ba);
 }
 
 static inline void btrfs_set_balance_sys(struct extent_buffer *eb,
-                                        struct btrfs_balance_item *bi,
-                                        struct btrfs_disk_balance_args *ba)
+                                struct btrfs_balance_item *bi,
+                                const struct btrfs_disk_balance_args *ba)
 {
        write_eb_member(eb, bi, struct btrfs_balance_item, sys, ba);
 }
 
 static inline void
 btrfs_disk_balance_args_to_cpu(struct btrfs_balance_args *cpu,
-                              struct btrfs_disk_balance_args *disk)
+                              const struct btrfs_disk_balance_args *disk)
 {
        memset(cpu, 0, sizeof(*cpu));
 
@@ -2254,7 +2258,7 @@ btrfs_disk_balance_args_to_cpu(struct btrfs_balance_args *cpu,
 
 static inline void
 btrfs_cpu_balance_args_to_disk(struct btrfs_disk_balance_args *disk,
-                              struct btrfs_balance_args *cpu)
+                              const struct btrfs_balance_args *cpu)
 {
        memset(disk, 0, sizeof(*disk));
 
@@ -2322,7 +2326,7 @@ BTRFS_SETGET_STACK_FUNCS(super_magic, struct btrfs_super_block, magic, 64);
 BTRFS_SETGET_STACK_FUNCS(super_uuid_tree_generation, struct btrfs_super_block,
                         uuid_tree_generation, 64);
 
-static inline int btrfs_super_csum_size(struct btrfs_super_block *s)
+static inline int btrfs_super_csum_size(const struct btrfs_super_block *s)
 {
        u16 t = btrfs_super_csum_type(s);
        /*
@@ -2337,8 +2341,8 @@ static inline int btrfs_super_csum_size(struct btrfs_super_block *s)
  * this returns the address of the start of the last item,
  * which is the stop of the leaf data stack
  */
-static inline unsigned int leaf_data_end(struct btrfs_fs_info *fs_info,
-                                        struct extent_buffer *leaf)
+static inline unsigned int leaf_data_end(const struct btrfs_fs_info *fs_info,
+                                        const struct extent_buffer *leaf)
 {
        u32 nr = btrfs_header_nritems(leaf);
 
@@ -2363,7 +2367,7 @@ BTRFS_SETGET_STACK_FUNCS(stack_file_extent_compression,
                         struct btrfs_file_extent_item, compression, 8);
 
 static inline unsigned long
-btrfs_file_extent_inline_start(struct btrfs_file_extent_item *e)
+btrfs_file_extent_inline_start(const struct btrfs_file_extent_item *e)
 {
        return (unsigned long)e + BTRFS_FILE_EXTENT_INLINE_DATA_START;
 }
@@ -2397,8 +2401,9 @@ BTRFS_SETGET_FUNCS(file_extent_other_encoding, struct btrfs_file_extent_item,
  * size of any extent headers.  If a file is compressed on disk, this is
  * the compressed size
  */
-static inline u32 btrfs_file_extent_inline_item_len(struct extent_buffer *eb,
-                                                   struct btrfs_item *e)
+static inline u32 btrfs_file_extent_inline_item_len(
+                                               const struct extent_buffer *eb,
+                                               struct btrfs_item *e)
 {
        return btrfs_item_size(eb, e) - BTRFS_FILE_EXTENT_INLINE_DATA_START;
 }
@@ -2406,9 +2411,9 @@ static inline u32 btrfs_file_extent_inline_item_len(struct extent_buffer *eb,
 /* this returns the number of file bytes represented by the inline item.
  * If an item is compressed, this is the uncompressed size
  */
-static inline u32 btrfs_file_extent_inline_len(struct extent_buffer *eb,
-                                              int slot,
-                                              struct btrfs_file_extent_item *fi)
+static inline u32 btrfs_file_extent_inline_len(const struct extent_buffer *eb,
+                                       int slot,
+                                       const struct btrfs_file_extent_item *fi)
 {
        struct btrfs_map_token token;
 
@@ -2430,8 +2435,8 @@ static inline u32 btrfs_file_extent_inline_len(struct extent_buffer *eb,
 
 
 /* btrfs_dev_stats_item */
-static inline u64 btrfs_dev_stats_value(struct extent_buffer *eb,
-                                       struct btrfs_dev_stats_item *ptr,
+static inline u64 btrfs_dev_stats_value(const struct extent_buffer *eb,
+                                       const struct btrfs_dev_stats_item *ptr,
                                        int index)
 {
        u64 val;
@@ -2561,6 +2566,17 @@ static inline gfp_t btrfs_alloc_write_mask(struct address_space *mapping)
 
 /* extent-tree.c */
 
+enum btrfs_inline_ref_type {
+       BTRFS_REF_TYPE_INVALID =         0,
+       BTRFS_REF_TYPE_BLOCK =           1,
+       BTRFS_REF_TYPE_DATA =            2,
+       BTRFS_REF_TYPE_ANY =             3,
+};
+
+int btrfs_get_extent_inline_ref_type(const struct extent_buffer *eb,
+                                    struct btrfs_extent_inline_ref *iref,
+                                    enum btrfs_inline_ref_type is_data);
+
 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,
@@ -2670,8 +2686,7 @@ int btrfs_read_block_groups(struct btrfs_fs_info *info);
 int btrfs_can_relocate(struct btrfs_fs_info *fs_info, u64 bytenr);
 int btrfs_make_block_group(struct btrfs_trans_handle *trans,
                           struct btrfs_fs_info *fs_info, u64 bytes_used,
-                          u64 type, u64 chunk_objectid, u64 chunk_offset,
-                          u64 size);
+                          u64 type, u64 chunk_offset, u64 size);
 struct btrfs_trans_handle *btrfs_start_trans_remove_block_group(
                                struct btrfs_fs_info *fs_info,
                                const u64 chunk_offset);
@@ -2772,8 +2787,8 @@ int btrfs_init_space_info(struct btrfs_fs_info *fs_info);
 int btrfs_delayed_refs_qgroup_accounting(struct btrfs_trans_handle *trans,
                                         struct btrfs_fs_info *fs_info);
 int __get_raid_index(u64 flags);
-int btrfs_start_write_no_snapshoting(struct btrfs_root *root);
-void btrfs_end_write_no_snapshoting(struct btrfs_root *root);
+int btrfs_start_write_no_snapshotting(struct btrfs_root *root);
+void btrfs_end_write_no_snapshotting(struct btrfs_root *root);
 void btrfs_wait_for_snapshot_creation(struct btrfs_root *root);
 void check_system_chunk(struct btrfs_trans_handle *trans,
                        struct btrfs_fs_info *fs_info, const u64 type);
@@ -2973,8 +2988,8 @@ int btrfs_del_root_ref(struct btrfs_trans_handle *trans,
                       struct btrfs_fs_info *fs_info,
                       u64 root_id, u64 ref_id, u64 dirid, u64 *sequence,
                       const char *name, int name_len);
-int btrfs_del_root(struct btrfs_trans_handle *trans, struct btrfs_root *root,
-                  const struct btrfs_key *key);
+int btrfs_del_root(struct btrfs_trans_handle *trans,
+                  struct btrfs_fs_info *fs_info, const struct btrfs_key *key);
 int btrfs_insert_root(struct btrfs_trans_handle *trans, struct btrfs_root *root,
                      const struct btrfs_key *key,
                      struct btrfs_root_item *item);
@@ -3135,21 +3150,6 @@ noinline int can_nocow_extent(struct inode *inode, u64 offset, u64 *len,
                              u64 *orig_start, u64 *orig_block_len,
                              u64 *ram_bytes);
 
-/* RHEL and EL kernels have a patch that renames PG_checked to FsMisc */
-#if defined(ClearPageFsMisc) && !defined(ClearPageChecked)
-#define ClearPageChecked ClearPageFsMisc
-#define SetPageChecked SetPageFsMisc
-#define PageChecked PageFsMisc
-#endif
-
-/* This forces readahead on a given range of bytes in an inode */
-static inline void btrfs_force_ra(struct address_space *mapping,
-                                 struct file_ra_state *ra, struct file *file,
-                                 pgoff_t offset, unsigned long req_size)
-{
-       page_cache_sync_readahead(mapping, ra, file, offset, req_size);
-}
-
 struct inode *btrfs_lookup_dentry(struct inode *dir, struct dentry *dentry);
 int btrfs_set_inode_index(struct btrfs_inode *dir, u64 *index);
 int btrfs_unlink_inode(struct btrfs_trans_handle *trans,
@@ -3229,7 +3229,6 @@ long btrfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
 long btrfs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
 int btrfs_ioctl_get_supported_features(void __user *arg);
 void btrfs_update_iflags(struct inode *inode);
-void btrfs_inherit_iflags(struct inode *inode, struct inode *dir);
 int btrfs_is_empty_uuid(u8 *uuid);
 int btrfs_defrag_file(struct inode *inode, struct file *file,
                      struct btrfs_ioctl_defrag_range_args *range,
index 8ae409b5a61d7186f050780beced1bf72cd572ca..19e4ad2f3f2e4a32050024f34b4e0ebc3c6511b9 100644 (file)
@@ -1727,6 +1727,7 @@ int btrfs_readdir_delayed_dir_index(struct dir_context *ctx,
 
                if (over)
                        return 1;
+               ctx->pos++;
        }
        return 0;
 }
index bee3edeea7a37404de4d428a57e90c6bbcac6bc1..7a93a3e1a847d9271e0227fef998aee978a719db 100644 (file)
@@ -639,11 +639,39 @@ static void btrfs_dev_replace_update_device_in_mapping_tree(
        write_unlock(&em_tree->lock);
 }
 
+/*
+ * Read progress of device replace status according to the state and last
+ * stored position. The value format is the same as for
+ * btrfs_dev_replace::progress_1000
+ */
+static u64 btrfs_dev_replace_progress(struct btrfs_fs_info *fs_info)
+{
+       struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace;
+       u64 ret = 0;
+
+       switch (dev_replace->replace_state) {
+       case BTRFS_IOCTL_DEV_REPLACE_STATE_NEVER_STARTED:
+       case BTRFS_IOCTL_DEV_REPLACE_STATE_CANCELED:
+               ret = 0;
+               break;
+       case BTRFS_IOCTL_DEV_REPLACE_STATE_FINISHED:
+               ret = 1000;
+               break;
+       case BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED:
+       case BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED:
+               ret = div64_u64(dev_replace->cursor_left,
+                               div_u64(btrfs_device_get_total_bytes(
+                                               dev_replace->srcdev), 1000));
+               break;
+       }
+
+       return ret;
+}
+
 void btrfs_dev_replace_status(struct btrfs_fs_info *fs_info,
                              struct btrfs_ioctl_dev_replace_args *args)
 {
        struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace;
-       struct btrfs_device *srcdev;
 
        btrfs_dev_replace_lock(dev_replace, 0);
        /* even if !dev_replace_is_valid, the values are good enough for
@@ -656,21 +684,7 @@ void btrfs_dev_replace_status(struct btrfs_fs_info *fs_info,
                atomic64_read(&dev_replace->num_write_errors);
        args->status.num_uncorrectable_read_errors =
                atomic64_read(&dev_replace->num_uncorrectable_read_errors);
-       switch (dev_replace->replace_state) {
-       case BTRFS_IOCTL_DEV_REPLACE_STATE_NEVER_STARTED:
-       case BTRFS_IOCTL_DEV_REPLACE_STATE_CANCELED:
-               args->status.progress_1000 = 0;
-               break;
-       case BTRFS_IOCTL_DEV_REPLACE_STATE_FINISHED:
-               args->status.progress_1000 = 1000;
-               break;
-       case BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED:
-       case BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED:
-               srcdev = dev_replace->srcdev;
-               args->status.progress_1000 = div64_u64(dev_replace->cursor_left,
-                       div_u64(btrfs_device_get_total_bytes(srcdev), 1000));
-               break;
-       }
+       args->status.progress_1000 = btrfs_dev_replace_progress(fs_info);
        btrfs_dev_replace_unlock(dev_replace, 0);
 }
 
@@ -795,25 +809,19 @@ static int btrfs_dev_replace_kthread(void *data)
 {
        struct btrfs_fs_info *fs_info = data;
        struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace;
-       struct btrfs_ioctl_dev_replace_args *status_args;
        u64 progress;
 
-       status_args = kzalloc(sizeof(*status_args), GFP_KERNEL);
-       if (status_args) {
-               btrfs_dev_replace_status(fs_info, status_args);
-               progress = status_args->status.progress_1000;
-               kfree(status_args);
-               progress = div_u64(progress, 10);
-               btrfs_info_in_rcu(fs_info,
-                       "continuing dev_replace from %s (devid %llu) to %s @%u%%",
-                       dev_replace->srcdev->missing ? "<missing disk>" :
-                       rcu_str_deref(dev_replace->srcdev->name),
-                       dev_replace->srcdev->devid,
-                       dev_replace->tgtdev ?
-                       rcu_str_deref(dev_replace->tgtdev->name) :
-                       "<missing target disk>",
-                       (unsigned int)progress);
-       }
+       progress = btrfs_dev_replace_progress(fs_info);
+       progress = div_u64(progress, 10);
+       btrfs_info_in_rcu(fs_info,
+               "continuing dev_replace from %s (devid %llu) to %s @%u%%",
+               dev_replace->srcdev->missing ? "<missing disk>"
+                       : rcu_str_deref(dev_replace->srcdev->name),
+               dev_replace->srcdev->devid,
+               dev_replace->tgtdev ? rcu_str_deref(dev_replace->tgtdev->name)
+                       : "<missing target disk>",
+               (unsigned int)progress);
+
        btrfs_dev_replace_continue_on_mount(fs_info);
        clear_bit(BTRFS_FS_EXCL_OP, &fs_info->flags);
 
index 4f428a48d51359a78c42940509f801734e1050c6..46329524dd5f46323fb76f47c83c86403c2de6ec 100644 (file)
@@ -529,7 +529,7 @@ static int check_tree_block_fsid(struct btrfs_fs_info *fs_info,
                                 struct extent_buffer *eb)
 {
        struct btrfs_fs_devices *fs_devices = fs_info->fs_devices;
-       u8 fsid[BTRFS_UUID_SIZE];
+       u8 fsid[BTRFS_FSID_SIZE];
        int ret = 1;
 
        read_extent_buffer(eb, fsid, btrfs_header_fsid(), BTRFS_FSID_SIZE);
@@ -1343,7 +1343,7 @@ static void __setup_root(struct btrfs_root *root, struct btrfs_fs_info *fs_info,
        atomic_set(&root->log_batch, 0);
        atomic_set(&root->orphan_inodes, 0);
        refcount_set(&root->refs, 1);
-       atomic_set(&root->will_be_snapshoted, 0);
+       atomic_set(&root->will_be_snapshotted, 0);
        atomic64_set(&root->qgroup_meta_rsv, 0);
        root->log_transid = 0;
        root->log_transid_committed = -1;
@@ -2694,8 +2694,8 @@ int open_ctree(struct super_block *sb,
        btrfs_init_balance(fs_info);
        btrfs_init_async_reclaim_work(&fs_info->async_reclaim_work);
 
-       sb->s_blocksize = 4096;
-       sb->s_blocksize_bits = blksize_bits(4096);
+       sb->s_blocksize = BTRFS_BDEV_BLOCKSIZE;
+       sb->s_blocksize_bits = blksize_bits(BTRFS_BDEV_BLOCKSIZE);
 
        btrfs_init_btree_inode(fs_info);
 
@@ -3035,15 +3035,10 @@ retry_root_backup:
                btrfs_err(fs_info, "failed to read block groups: %d", ret);
                goto fail_sysfs;
        }
-       fs_info->num_tolerated_disk_barrier_failures =
-               btrfs_calc_num_tolerated_disk_barrier_failures(fs_info);
-       if (fs_info->fs_devices->missing_devices >
-            fs_info->num_tolerated_disk_barrier_failures &&
-           !(sb->s_flags & MS_RDONLY)) {
+
+       if (!(sb->s_flags & MS_RDONLY) && !btrfs_check_rw_degradable(fs_info)) {
                btrfs_warn(fs_info,
-"missing devices (%llu) exceeds the limit (%d), writeable mount is not allowed",
-                       fs_info->fs_devices->missing_devices,
-                       fs_info->num_tolerated_disk_barrier_failures);
+               "writeable mount is not allowed due to too many missing devices");
                goto fail_sysfs;
        }
 
@@ -3058,11 +3053,9 @@ retry_root_backup:
        if (IS_ERR(fs_info->transaction_kthread))
                goto fail_cleaner;
 
-       if (!btrfs_test_opt(fs_info, SSD) &&
-           !btrfs_test_opt(fs_info, NOSSD) &&
+       if (!btrfs_test_opt(fs_info, NOSSD) &&
            !fs_info->fs_devices->rotating) {
-               btrfs_info(fs_info, "detected SSD devices, enabling SSD mode");
-               btrfs_set_opt(fs_info->mount_opt, SSD);
+               btrfs_set_and_info(fs_info, SSD, "enabling ssd optimizations");
        }
 
        /*
@@ -3321,7 +3314,7 @@ int btrfs_read_dev_one_super(struct block_device *bdev, int copy_num,
        if (bytenr + BTRFS_SUPER_INFO_SIZE >= i_size_read(bdev->bd_inode))
                return -EINVAL;
 
-       bh = __bread(bdev, bytenr / 4096, BTRFS_SUPER_INFO_SIZE);
+       bh = __bread(bdev, bytenr / BTRFS_BDEV_BLOCKSIZE, BTRFS_SUPER_INFO_SIZE);
        /*
         * If we fail to read from the underlying devices, as of now
         * the best option we have is to mark it EIO.
@@ -3378,19 +3371,17 @@ struct buffer_head *btrfs_read_dev_super(struct block_device *bdev)
 }
 
 /*
- * this should be called twice, once with wait == 0 and
- * once with wait == 1.  When wait == 0 is done, all the buffer heads
- * we write are pinned.
+ * Write superblock @sb to the @device. Do not wait for completion, all the
+ * buffer heads we write are pinned.
  *
- * They are released when wait == 1 is done.
- * max_mirrors must be the same for both runs, and it indicates how
- * many supers on this one device should be written.
+ * Write @max_mirrors copies of the superblock, where 0 means default that fit
+ * the expected device size at commit time. Note that max_mirrors must be
+ * same for write and wait phases.
  *
- * max_mirrors == 0 means to write them all.
+ * Return number of errors when buffer head is not found or submission fails.
  */
 static int write_dev_supers(struct btrfs_device *device,
-                           struct btrfs_super_block *sb,
-                           int wait, int max_mirrors)
+                           struct btrfs_super_block *sb, int max_mirrors)
 {
        struct buffer_head *bh;
        int i;
@@ -3408,57 +3399,33 @@ static int write_dev_supers(struct btrfs_device *device,
                    device->commit_total_bytes)
                        break;
 
-               if (wait) {
-                       bh = __find_get_block(device->bdev, bytenr / 4096,
-                                             BTRFS_SUPER_INFO_SIZE);
-                       if (!bh) {
-                               errors++;
-                               continue;
-                       }
-                       wait_on_buffer(bh);
-                       if (!buffer_uptodate(bh))
-                               errors++;
+               btrfs_set_super_bytenr(sb, bytenr);
 
-                       /* drop our reference */
-                       brelse(bh);
+               crc = ~(u32)0;
+               crc = btrfs_csum_data((const char *)sb + BTRFS_CSUM_SIZE, crc,
+                                     BTRFS_SUPER_INFO_SIZE - BTRFS_CSUM_SIZE);
+               btrfs_csum_final(crc, sb->csum);
 
-                       /* drop the reference from the wait == 0 run */
-                       brelse(bh);
+               /* One reference for us, and we leave it for the caller */
+               bh = __getblk(device->bdev, bytenr / BTRFS_BDEV_BLOCKSIZE,
+                             BTRFS_SUPER_INFO_SIZE);
+               if (!bh) {
+                       btrfs_err(device->fs_info,
+                           "couldn't get super buffer head for bytenr %llu",
+                           bytenr);
+                       errors++;
                        continue;
-               } else {
-                       btrfs_set_super_bytenr(sb, bytenr);
-
-                       crc = ~(u32)0;
-                       crc = btrfs_csum_data((const char *)sb +
-                                             BTRFS_CSUM_SIZE, crc,
-                                             BTRFS_SUPER_INFO_SIZE -
-                                             BTRFS_CSUM_SIZE);
-                       btrfs_csum_final(crc, sb->csum);
-
-                       /*
-                        * one reference for us, and we leave it for the
-                        * caller
-                        */
-                       bh = __getblk(device->bdev, bytenr / 4096,
-                                     BTRFS_SUPER_INFO_SIZE);
-                       if (!bh) {
-                               btrfs_err(device->fs_info,
-                                   "couldn't get super buffer head for bytenr %llu",
-                                   bytenr);
-                               errors++;
-                               continue;
-                       }
+               }
 
-                       memcpy(bh->b_data, sb, BTRFS_SUPER_INFO_SIZE);
+               memcpy(bh->b_data, sb, BTRFS_SUPER_INFO_SIZE);
 
-                       /* one reference for submit_bh */
-                       get_bh(bh);
+               /* one reference for submit_bh */
+               get_bh(bh);
 
-                       set_buffer_uptodate(bh);
-                       lock_buffer(bh);
-                       bh->b_end_io = btrfs_end_buffer_write_sync;
-                       bh->b_private = device;
-               }
+               set_buffer_uptodate(bh);
+               lock_buffer(bh);
+               bh->b_end_io = btrfs_end_buffer_write_sync;
+               bh->b_private = device;
 
                /*
                 * we fua the first super.  The others we allow
@@ -3466,9 +3433,10 @@ static int write_dev_supers(struct btrfs_device *device,
                 */
                if (i == 0) {
                        ret = btrfsic_submit_bh(REQ_OP_WRITE,
-                                               REQ_SYNC | REQ_FUA, bh);
+                               REQ_SYNC | REQ_FUA | REQ_META | REQ_PRIO, bh);
                } else {
-                       ret = btrfsic_submit_bh(REQ_OP_WRITE, REQ_SYNC, bh);
+                       ret = btrfsic_submit_bh(REQ_OP_WRITE,
+                               REQ_SYNC | REQ_META | REQ_PRIO, bh);
                }
                if (ret)
                        errors++;
@@ -3476,6 +3444,50 @@ static int write_dev_supers(struct btrfs_device *device,
        return errors < i ? 0 : -1;
 }
 
+/*
+ * Wait for write completion of superblocks done by write_dev_supers,
+ * @max_mirrors same for write and wait phases.
+ *
+ * Return number of errors when buffer head is not found or not marked up to
+ * date.
+ */
+static int wait_dev_supers(struct btrfs_device *device, int max_mirrors)
+{
+       struct buffer_head *bh;
+       int i;
+       int errors = 0;
+       u64 bytenr;
+
+       if (max_mirrors == 0)
+               max_mirrors = BTRFS_SUPER_MIRROR_MAX;
+
+       for (i = 0; i < max_mirrors; i++) {
+               bytenr = btrfs_sb_offset(i);
+               if (bytenr + BTRFS_SUPER_INFO_SIZE >=
+                   device->commit_total_bytes)
+                       break;
+
+               bh = __find_get_block(device->bdev,
+                                     bytenr / BTRFS_BDEV_BLOCKSIZE,
+                                     BTRFS_SUPER_INFO_SIZE);
+               if (!bh) {
+                       errors++;
+                       continue;
+               }
+               wait_on_buffer(bh);
+               if (!buffer_uptodate(bh))
+                       errors++;
+
+               /* drop our reference */
+               brelse(bh);
+
+               /* drop the reference from the writing run */
+               brelse(bh);
+       }
+
+       return errors < i ? 0 : -1;
+}
+
 /*
  * endio for the write_dev_flush, this will wake anyone waiting
  * for the barrier when it is done
@@ -3504,7 +3516,7 @@ static void write_dev_flush(struct btrfs_device *device)
        init_completion(&device->flush_wait);
        bio->bi_private = &device->flush_wait;
 
-       submit_bio(bio);
+       btrfsic_submit_bio(bio);
        device->flush_bio_sent = 1;
 }
 
@@ -3524,20 +3536,10 @@ static blk_status_t wait_dev_flush(struct btrfs_device *device)
        return bio->bi_status;
 }
 
-static int check_barrier_error(struct btrfs_fs_devices *fsdevs)
+static int check_barrier_error(struct btrfs_fs_info *fs_info)
 {
-       int dev_flush_error = 0;
-       struct btrfs_device *dev;
-
-       list_for_each_entry_rcu(dev, &fsdevs->devices, dev_list) {
-               if (!dev->bdev || dev->last_flush_error)
-                       dev_flush_error++;
-       }
-
-       if (dev_flush_error >
-           fsdevs->fs_info->num_tolerated_disk_barrier_failures)
+       if (!btrfs_check_rw_degradable(fs_info))
                return -EIO;
-
        return 0;
 }
 
@@ -3592,7 +3594,7 @@ static int barrier_all_devices(struct btrfs_fs_info *info)
                 * to arrive at the volume status. So error checking
                 * is being pushed to a separate loop.
                 */
-               return check_barrier_error(info->fs_devices);
+               return check_barrier_error(info);
        }
        return 0;
 }
@@ -3626,60 +3628,6 @@ int btrfs_get_num_tolerated_disk_barrier_failures(u64 flags)
        return min_tolerated;
 }
 
-int btrfs_calc_num_tolerated_disk_barrier_failures(
-       struct btrfs_fs_info *fs_info)
-{
-       struct btrfs_ioctl_space_info space;
-       struct btrfs_space_info *sinfo;
-       u64 types[] = {BTRFS_BLOCK_GROUP_DATA,
-                      BTRFS_BLOCK_GROUP_SYSTEM,
-                      BTRFS_BLOCK_GROUP_METADATA,
-                      BTRFS_BLOCK_GROUP_DATA | BTRFS_BLOCK_GROUP_METADATA};
-       int i;
-       int c;
-       int num_tolerated_disk_barrier_failures =
-               (int)fs_info->fs_devices->num_devices;
-
-       for (i = 0; i < ARRAY_SIZE(types); i++) {
-               struct btrfs_space_info *tmp;
-
-               sinfo = NULL;
-               rcu_read_lock();
-               list_for_each_entry_rcu(tmp, &fs_info->space_info, list) {
-                       if (tmp->flags == types[i]) {
-                               sinfo = tmp;
-                               break;
-                       }
-               }
-               rcu_read_unlock();
-
-               if (!sinfo)
-                       continue;
-
-               down_read(&sinfo->groups_sem);
-               for (c = 0; c < BTRFS_NR_RAID_TYPES; c++) {
-                       u64 flags;
-
-                       if (list_empty(&sinfo->block_groups[c]))
-                               continue;
-
-                       btrfs_get_block_group_info(&sinfo->block_groups[c],
-                                                  &space);
-                       if (space.total_bytes == 0 || space.used_bytes == 0)
-                               continue;
-                       flags = space.flags;
-
-                       num_tolerated_disk_barrier_failures = min(
-                               num_tolerated_disk_barrier_failures,
-                               btrfs_get_num_tolerated_disk_barrier_failures(
-                                       flags));
-               }
-               up_read(&sinfo->groups_sem);
-       }
-
-       return num_tolerated_disk_barrier_failures;
-}
-
 int write_all_supers(struct btrfs_fs_info *fs_info, int max_mirrors)
 {
        struct list_head *head;
@@ -3732,12 +3680,12 @@ int write_all_supers(struct btrfs_fs_info *fs_info, int max_mirrors)
                btrfs_set_stack_device_io_width(dev_item, dev->io_width);
                btrfs_set_stack_device_sector_size(dev_item, dev->sector_size);
                memcpy(dev_item->uuid, dev->uuid, BTRFS_UUID_SIZE);
-               memcpy(dev_item->fsid, dev->fs_devices->fsid, BTRFS_UUID_SIZE);
+               memcpy(dev_item->fsid, dev->fs_devices->fsid, BTRFS_FSID_SIZE);
 
                flags = btrfs_super_flags(sb);
                btrfs_set_super_flags(sb, flags | BTRFS_HEADER_FLAG_WRITTEN);
 
-               ret = write_dev_supers(dev, sb, 0, max_mirrors);
+               ret = write_dev_supers(dev, sb, max_mirrors);
                if (ret)
                        total_errors++;
        }
@@ -3760,7 +3708,7 @@ int write_all_supers(struct btrfs_fs_info *fs_info, int max_mirrors)
                if (!dev->in_fs_metadata || !dev->writeable)
                        continue;
 
-               ret = write_dev_supers(dev, sb, 1, max_mirrors);
+               ret = wait_dev_supers(dev, max_mirrors);
                if (ret)
                        total_errors++;
        }
@@ -3995,7 +3943,6 @@ void close_ctree(struct btrfs_fs_info *fs_info)
        __btrfs_free_block_rsv(root->orphan_block_rsv);
        root->orphan_block_rsv = NULL;
 
-       mutex_lock(&fs_info->chunk_mutex);
        while (!list_empty(&fs_info->pinned_chunks)) {
                struct extent_map *em;
 
@@ -4004,7 +3951,6 @@ void close_ctree(struct btrfs_fs_info *fs_info)
                list_del_init(&em->list);
                free_extent_map(em);
        }
-       mutex_unlock(&fs_info->chunk_mutex);
 }
 
 int btrfs_buffer_uptodate(struct extent_buffer *buf, u64 parent_transid,
@@ -4053,7 +3999,7 @@ void btrfs_mark_buffer_dirty(struct extent_buffer *buf)
                                         fs_info->dirty_metadata_batch);
 #ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY
        if (btrfs_header_level(buf) == 0 && check_leaf(root, buf)) {
-               btrfs_print_leaf(fs_info, buf);
+               btrfs_print_leaf(buf);
                ASSERT(0);
        }
 #endif
@@ -4173,7 +4119,7 @@ static int btrfs_check_super_valid(struct btrfs_fs_info *fs_info)
                ret = -EINVAL;
        }
 
-       if (memcmp(fs_info->fsid, sb->dev_item.fsid, BTRFS_UUID_SIZE) != 0) {
+       if (memcmp(fs_info->fsid, sb->dev_item.fsid, BTRFS_FSID_SIZE) != 0) {
                btrfs_err(fs_info,
                           "dev_item UUID does not match fsid: %pU != %pU",
                           fs_info->fsid, sb->dev_item.fsid);
index 0a634d3ffc16d1069fbfeab1e02dc42c6bf481d2..7f7c35d6347a39107ee0d43e4160b7ca7efabdc8 100644 (file)
 #define BTRFS_SUPER_MIRROR_MAX  3
 #define BTRFS_SUPER_MIRROR_SHIFT 12
 
+/*
+ * Fixed blocksize for all devices, applies to specific ways of reading
+ * metadata like superblock. Must meet the set_blocksize requirements.
+ *
+ * Do not change.
+ */
+#define BTRFS_BDEV_BLOCKSIZE   (4096)
+
 enum btrfs_wq_endio_type {
        BTRFS_WQ_ENDIO_DATA = 0,
        BTRFS_WQ_ENDIO_METADATA = 1,
@@ -142,8 +150,6 @@ struct btrfs_root *btrfs_create_tree(struct btrfs_trans_handle *trans,
 int btree_lock_page_hook(struct page *page, void *data,
                                void (*flush_fn)(void *));
 int btrfs_get_num_tolerated_disk_barrier_failures(u64 flags);
-int btrfs_calc_num_tolerated_disk_barrier_failures(
-       struct btrfs_fs_info *fs_info);
 int __init btrfs_end_io_wq_init(void);
 void btrfs_end_io_wq_exit(void);
 
index e3b0b4196d3df173fd52d62076396f21029f073d..e2d7e86b51d1b24059dda46fda085174ac993a3f 100644 (file)
@@ -1148,6 +1148,64 @@ static int convert_extent_item_v0(struct btrfs_trans_handle *trans,
 }
 #endif
 
+/*
+ * is_data == BTRFS_REF_TYPE_BLOCK, tree block type is required,
+ * is_data == BTRFS_REF_TYPE_DATA, data type is requried,
+ * is_data == BTRFS_REF_TYPE_ANY, either type is OK.
+ */
+int btrfs_get_extent_inline_ref_type(const struct extent_buffer *eb,
+                                    struct btrfs_extent_inline_ref *iref,
+                                    enum btrfs_inline_ref_type is_data)
+{
+       int type = btrfs_extent_inline_ref_type(eb, iref);
+       u64 offset = btrfs_extent_inline_ref_offset(eb, iref);
+
+       if (type == BTRFS_TREE_BLOCK_REF_KEY ||
+           type == BTRFS_SHARED_BLOCK_REF_KEY ||
+           type == BTRFS_SHARED_DATA_REF_KEY ||
+           type == BTRFS_EXTENT_DATA_REF_KEY) {
+               if (is_data == BTRFS_REF_TYPE_BLOCK) {
+                       if (type == BTRFS_TREE_BLOCK_REF_KEY)
+                               return type;
+                       if (type == BTRFS_SHARED_BLOCK_REF_KEY) {
+                               ASSERT(eb->fs_info);
+                               /*
+                                * Every shared one has parent tree
+                                * block, which must be aligned to
+                                * nodesize.
+                                */
+                               if (offset &&
+                                   IS_ALIGNED(offset, eb->fs_info->nodesize))
+                                       return type;
+                       }
+               } else if (is_data == BTRFS_REF_TYPE_DATA) {
+                       if (type == BTRFS_EXTENT_DATA_REF_KEY)
+                               return type;
+                       if (type == BTRFS_SHARED_DATA_REF_KEY) {
+                               ASSERT(eb->fs_info);
+                               /*
+                                * Every shared one has parent tree
+                                * block, which must be aligned to
+                                * nodesize.
+                                */
+                               if (offset &&
+                                   IS_ALIGNED(offset, eb->fs_info->nodesize))
+                                       return type;
+                       }
+               } else {
+                       ASSERT(is_data == BTRFS_REF_TYPE_ANY);
+                       return type;
+               }
+       }
+
+       btrfs_print_leaf((struct extent_buffer *)eb);
+       btrfs_err(eb->fs_info, "eb %llu invalid extent inline ref type %d",
+                 eb->start, type);
+       WARN_ON(1);
+
+       return BTRFS_REF_TYPE_INVALID;
+}
+
 static u64 hash_extent_data_ref(u64 root_objectid, u64 owner, u64 offset)
 {
        u32 high_crc = ~(u32)0;
@@ -1417,12 +1475,18 @@ static noinline u32 extent_data_ref_count(struct btrfs_path *path,
        struct btrfs_extent_data_ref *ref1;
        struct btrfs_shared_data_ref *ref2;
        u32 num_refs = 0;
+       int type;
 
        leaf = path->nodes[0];
        btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
        if (iref) {
-               if (btrfs_extent_inline_ref_type(leaf, iref) ==
-                   BTRFS_EXTENT_DATA_REF_KEY) {
+               /*
+                * If type is invalid, we should have bailed out earlier than
+                * this call.
+                */
+               type = btrfs_get_extent_inline_ref_type(leaf, iref, BTRFS_REF_TYPE_DATA);
+               ASSERT(type != BTRFS_REF_TYPE_INVALID);
+               if (type == BTRFS_EXTENT_DATA_REF_KEY) {
                        ref1 = (struct btrfs_extent_data_ref *)(&iref->offset);
                        num_refs = btrfs_extent_data_ref_count(leaf, ref1);
                } else {
@@ -1583,6 +1647,7 @@ int lookup_inline_extent_backref(struct btrfs_trans_handle *trans,
        int ret;
        int err = 0;
        bool skinny_metadata = btrfs_fs_incompat(fs_info, SKINNY_METADATA);
+       int needed;
 
        key.objectid = bytenr;
        key.type = BTRFS_EXTENT_ITEM_KEY;
@@ -1674,6 +1739,11 @@ again:
                BUG_ON(ptr > end);
        }
 
+       if (owner >= BTRFS_FIRST_FREE_OBJECTID)
+               needed = BTRFS_REF_TYPE_DATA;
+       else
+               needed = BTRFS_REF_TYPE_BLOCK;
+
        err = -ENOENT;
        while (1) {
                if (ptr >= end) {
@@ -1681,7 +1751,12 @@ again:
                        break;
                }
                iref = (struct btrfs_extent_inline_ref *)ptr;
-               type = btrfs_extent_inline_ref_type(leaf, iref);
+               type = btrfs_get_extent_inline_ref_type(leaf, iref, needed);
+               if (type == BTRFS_REF_TYPE_INVALID) {
+                       err = -EINVAL;
+                       goto out;
+               }
+
                if (want < type)
                        break;
                if (want > type) {
@@ -1873,7 +1948,12 @@ void update_inline_extent_backref(struct btrfs_fs_info *fs_info,
        if (extent_op)
                __run_delayed_extent_op(extent_op, leaf, ei);
 
-       type = btrfs_extent_inline_ref_type(leaf, iref);
+       /*
+        * If type is invalid, we should have bailed out after
+        * lookup_inline_extent_backref().
+        */
+       type = btrfs_get_extent_inline_ref_type(leaf, iref, BTRFS_REF_TYPE_ANY);
+       ASSERT(type != BTRFS_REF_TYPE_INVALID);
 
        if (type == BTRFS_EXTENT_DATA_REF_KEY) {
                dref = (struct btrfs_extent_data_ref *)(&iref->offset);
@@ -3158,6 +3238,7 @@ static noinline int check_committed_ref(struct btrfs_root *root,
        struct btrfs_extent_item *ei;
        struct btrfs_key key;
        u32 item_size;
+       int type;
        int ret;
 
        key.objectid = bytenr;
@@ -3199,8 +3280,9 @@ static noinline int check_committed_ref(struct btrfs_root *root,
                goto out;
 
        iref = (struct btrfs_extent_inline_ref *)(ei + 1);
-       if (btrfs_extent_inline_ref_type(leaf, iref) !=
-           BTRFS_EXTENT_DATA_REF_KEY)
+
+       type = btrfs_get_extent_inline_ref_type(leaf, iref, BTRFS_REF_TYPE_DATA);
+       if (type != BTRFS_EXTENT_DATA_REF_KEY)
                goto out;
 
        ref = (struct btrfs_extent_data_ref *)(&iref->offset);
@@ -4199,9 +4281,9 @@ static u64 btrfs_space_info_used(struct btrfs_space_info *s_info,
 
 int btrfs_alloc_data_chunk_ondemand(struct btrfs_inode *inode, u64 bytes)
 {
-       struct btrfs_space_info *data_sinfo;
        struct btrfs_root *root = inode->root;
        struct btrfs_fs_info *fs_info = root->fs_info;
+       struct btrfs_space_info *data_sinfo = fs_info->data_sinfo;
        u64 used;
        int ret = 0;
        int need_commit = 2;
@@ -4215,10 +4297,6 @@ int btrfs_alloc_data_chunk_ondemand(struct btrfs_inode *inode, u64 bytes)
                ASSERT(current->journal_info);
        }
 
-       data_sinfo = fs_info->data_sinfo;
-       if (!data_sinfo)
-               goto alloc;
-
 again:
        /* make sure we have enough space to handle the data first */
        spin_lock(&data_sinfo->lock);
@@ -4236,7 +4314,7 @@ again:
 
                        data_sinfo->force_alloc = CHUNK_ALLOC_FORCE;
                        spin_unlock(&data_sinfo->lock);
-alloc:
+
                        alloc_target = btrfs_data_alloc_profile(fs_info);
                        /*
                         * It is ugly that we don't call nolock join
@@ -4264,9 +4342,6 @@ alloc:
                                }
                        }
 
-                       if (!data_sinfo)
-                               data_sinfo = fs_info->data_sinfo;
-
                        goto again;
                }
 
@@ -4425,8 +4500,7 @@ static int should_alloc_chunk(struct btrfs_fs_info *fs_info,
                              struct btrfs_space_info *sinfo, int force)
 {
        struct btrfs_block_rsv *global_rsv = &fs_info->global_block_rsv;
-       u64 num_bytes = sinfo->total_bytes - sinfo->bytes_readonly;
-       u64 num_allocated = sinfo->bytes_used + sinfo->bytes_reserved;
+       u64 bytes_used = btrfs_space_info_used(sinfo, false);
        u64 thresh;
 
        if (force == CHUNK_ALLOC_FORCE)
@@ -4438,7 +4512,7 @@ static int should_alloc_chunk(struct btrfs_fs_info *fs_info,
         * global_rsv, it doesn't change except when the transaction commits.
         */
        if (sinfo->flags & BTRFS_BLOCK_GROUP_METADATA)
-               num_allocated += calc_global_rsv_need_space(global_rsv);
+               bytes_used += calc_global_rsv_need_space(global_rsv);
 
        /*
         * in limited mode, we want to have some free space up to
@@ -4448,11 +4522,11 @@ static int should_alloc_chunk(struct btrfs_fs_info *fs_info,
                thresh = btrfs_super_total_bytes(fs_info->super_copy);
                thresh = max_t(u64, SZ_64M, div_factor_fine(thresh, 1));
 
-               if (num_bytes - num_allocated < thresh)
+               if (sinfo->total_bytes - bytes_used < thresh)
                        return 1;
        }
 
-       if (num_allocated + SZ_2M < div_factor(num_bytes, 8))
+       if (bytes_used + SZ_2M < div_factor(sinfo->total_bytes, 8))
                return 0;
        return 1;
 }
@@ -4904,9 +4978,14 @@ struct reserve_ticket {
        wait_queue_head_t wait;
 };
 
-static int flush_space(struct btrfs_fs_info *fs_info,
+/*
+ * Try to flush some data based on policy set by @state. This is only advisory
+ * and may fail for various reasons. The caller is supposed to examine the
+ * state of @space_info to detect the outcome.
+ */
+static void flush_space(struct btrfs_fs_info *fs_info,
                       struct btrfs_space_info *space_info, u64 num_bytes,
-                      u64 orig_bytes, int state)
+                      int state)
 {
        struct btrfs_root *root = fs_info->extent_root;
        struct btrfs_trans_handle *trans;
@@ -4931,7 +5010,7 @@ static int flush_space(struct btrfs_fs_info *fs_info,
                break;
        case FLUSH_DELALLOC:
        case FLUSH_DELALLOC_WAIT:
-               shrink_delalloc(fs_info, num_bytes * 2, orig_bytes,
+               shrink_delalloc(fs_info, num_bytes * 2, num_bytes,
                                state == FLUSH_DELALLOC_WAIT);
                break;
        case ALLOC_CHUNK:
@@ -4949,16 +5028,16 @@ static int flush_space(struct btrfs_fs_info *fs_info,
                break;
        case COMMIT_TRANS:
                ret = may_commit_transaction(fs_info, space_info,
-                                            orig_bytes, 0);
+                                            num_bytes, 0);
                break;
        default:
                ret = -ENOSPC;
                break;
        }
 
-       trace_btrfs_flush_space(fs_info, space_info->flags, num_bytes,
-                               orig_bytes, state, ret);
-       return ret;
+       trace_btrfs_flush_space(fs_info, space_info->flags, num_bytes, state,
+                               ret);
+       return;
 }
 
 static inline u64
@@ -5060,11 +5139,7 @@ static void btrfs_async_reclaim_metadata_space(struct work_struct *work)
 
        flush_state = FLUSH_DELAYED_ITEMS_NR;
        do {
-               struct reserve_ticket *ticket;
-               int ret;
-
-               ret = flush_space(fs_info, space_info, to_reclaim, to_reclaim,
-                                 flush_state);
+               flush_space(fs_info, space_info, to_reclaim, flush_state);
                spin_lock(&space_info->lock);
                if (list_empty(&space_info->tickets)) {
                        space_info->flush = 0;
@@ -5074,8 +5149,6 @@ static void btrfs_async_reclaim_metadata_space(struct work_struct *work)
                to_reclaim = btrfs_calc_reclaim_metadata_size(fs_info,
                                                              space_info,
                                                              false);
-               ticket = list_first_entry(&space_info->tickets,
-                                         struct reserve_ticket, list);
                if (last_tickets_id == space_info->tickets_id) {
                        flush_state++;
                } else {
@@ -5120,8 +5193,7 @@ static void priority_reclaim_metadata_space(struct btrfs_fs_info *fs_info,
        spin_unlock(&space_info->lock);
 
        do {
-               flush_space(fs_info, space_info, to_reclaim, to_reclaim,
-                           flush_state);
+               flush_space(fs_info, space_info, to_reclaim, flush_state);
                flush_state++;
                spin_lock(&space_info->lock);
                if (ticket->bytes == 0) {
@@ -6664,19 +6736,20 @@ fetch_cluster_info(struct btrfs_fs_info *fs_info,
                   struct btrfs_space_info *space_info, u64 *empty_cluster)
 {
        struct btrfs_free_cluster *ret = NULL;
-       bool ssd = btrfs_test_opt(fs_info, SSD);
 
        *empty_cluster = 0;
        if (btrfs_mixed_space_info(space_info))
                return ret;
 
-       if (ssd)
-               *empty_cluster = SZ_2M;
        if (space_info->flags & BTRFS_BLOCK_GROUP_METADATA) {
                ret = &fs_info->meta_alloc_cluster;
-               if (!ssd)
+               if (btrfs_test_opt(fs_info, SSD))
+                       *empty_cluster = SZ_2M;
+               else
                        *empty_cluster = SZ_64K;
-       } else if ((space_info->flags & BTRFS_BLOCK_GROUP_DATA) && ssd) {
+       } else if ((space_info->flags & BTRFS_BLOCK_GROUP_DATA) &&
+                  btrfs_test_opt(fs_info, SSD_SPREAD)) {
+               *empty_cluster = SZ_2M;
                ret = &fs_info->data_alloc_cluster;
        }
 
@@ -6755,7 +6828,7 @@ static int unpin_extent_range(struct btrfs_fs_info *fs_info,
                if (!readonly && return_free_space &&
                    global_rsv->space_info == space_info) {
                        u64 to_add = len;
-                       WARN_ON(!return_free_space);
+
                        spin_lock(&global_rsv->lock);
                        if (!global_rsv->full) {
                                to_add = min(len, global_rsv->size -
@@ -6841,7 +6914,7 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans,
                if (ret) {
                        const char *errstr = btrfs_decode_error(ret);
                        btrfs_warn(fs_info,
-                                  "Discard failed while removing blockgroup: errno=%d %s\n",
+                          "discard failed while removing blockgroup: errno=%d %s",
                                   ret, errstr);
                }
        }
@@ -6969,7 +7042,7 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
                                          "umm, got %d back from search, was looking for %llu",
                                          ret, bytenr);
                                if (ret > 0)
-                                       btrfs_print_leaf(info, path->nodes[0]);
+                                       btrfs_print_leaf(path->nodes[0]);
                        }
                        if (ret < 0) {
                                btrfs_abort_transaction(trans, ret);
@@ -6978,7 +7051,7 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
                        extent_slot = path->slots[0];
                }
        } else if (WARN_ON(ret == -ENOENT)) {
-               btrfs_print_leaf(info, path->nodes[0]);
+               btrfs_print_leaf(path->nodes[0]);
                btrfs_err(info,
                        "unable to find ref byte nr %llu parent %llu root %llu  owner %llu offset %llu",
                        bytenr, parent, root_objectid, owner_objectid,
@@ -7015,7 +7088,7 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
                        btrfs_err(info,
                                  "umm, got %d back from search, was looking for %llu",
                                ret, bytenr);
-                       btrfs_print_leaf(info, path->nodes[0]);
+                       btrfs_print_leaf(path->nodes[0]);
                }
                if (ret < 0) {
                        btrfs_abort_transaction(trans, ret);
@@ -9193,7 +9266,7 @@ int btrfs_drop_snapshot(struct btrfs_root *root,
        if (err)
                goto out_end_trans;
 
-       ret = btrfs_del_root(trans, tree_root, &root->root_key);
+       ret = btrfs_del_root(trans, fs_info, &root->root_key);
        if (ret) {
                btrfs_abort_transaction(trans, ret);
                goto out_end_trans;
@@ -9952,11 +10025,8 @@ btrfs_create_block_group_cache(struct btrfs_fs_info *fs_info,
        cache->key.offset = size;
        cache->key.type = BTRFS_BLOCK_GROUP_ITEM_KEY;
 
-       cache->sectorsize = fs_info->sectorsize;
        cache->fs_info = fs_info;
-       cache->full_stripe_len = btrfs_full_stripe_len(fs_info,
-                                                      &fs_info->mapping_tree,
-                                                      start);
+       cache->full_stripe_len = btrfs_full_stripe_len(fs_info, start);
        set_free_space_tree_thresholds(cache);
 
        atomic_set(&cache->count, 1);
@@ -10192,8 +10262,7 @@ next:
 
 int btrfs_make_block_group(struct btrfs_trans_handle *trans,
                           struct btrfs_fs_info *fs_info, u64 bytes_used,
-                          u64 type, u64 chunk_objectid, u64 chunk_offset,
-                          u64 size)
+                          u64 type, u64 chunk_offset, u64 size)
 {
        struct btrfs_block_group_cache *cache;
        int ret;
@@ -10205,7 +10274,8 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans,
                return -ENOMEM;
 
        btrfs_set_block_group_used(&cache->item, bytes_used);
-       btrfs_set_block_group_chunk_objectid(&cache->item, chunk_objectid);
+       btrfs_set_block_group_chunk_objectid(&cache->item,
+                                            BTRFS_FIRST_CHUNK_TREE_OBJECTID);
        btrfs_set_block_group_flags(&cache->item, type);
 
        cache->flags = type;
@@ -11001,14 +11071,14 @@ int btrfs_trim_fs(struct btrfs_fs_info *fs_info, struct fstrim_range *range)
 }
 
 /*
- * btrfs_{start,end}_write_no_snapshoting() are similar to
+ * btrfs_{start,end}_write_no_snapshotting() are similar to
  * mnt_{want,drop}_write(), they are used to prevent some tasks from writing
  * data into the page cache through nocow before the subvolume is snapshoted,
  * but flush the data into disk after the snapshot creation, or to prevent
- * operations while snapshoting is ongoing and that cause the snapshot to be
+ * operations while snapshotting is ongoing and that cause the snapshot to be
  * inconsistent (writes followed by expanding truncates for example).
  */
-void btrfs_end_write_no_snapshoting(struct btrfs_root *root)
+void btrfs_end_write_no_snapshotting(struct btrfs_root *root)
 {
        percpu_counter_dec(&root->subv_writers->counter);
        /*
@@ -11019,9 +11089,9 @@ void btrfs_end_write_no_snapshoting(struct btrfs_root *root)
                wake_up(&root->subv_writers->wait);
 }
 
-int btrfs_start_write_no_snapshoting(struct btrfs_root *root)
+int btrfs_start_write_no_snapshotting(struct btrfs_root *root)
 {
-       if (atomic_read(&root->will_be_snapshoted))
+       if (atomic_read(&root->will_be_snapshotted))
                return 0;
 
        percpu_counter_inc(&root->subv_writers->counter);
@@ -11029,14 +11099,14 @@ int btrfs_start_write_no_snapshoting(struct btrfs_root *root)
         * Make sure counter is updated before we check for snapshot creation.
         */
        smp_mb();
-       if (atomic_read(&root->will_be_snapshoted)) {
-               btrfs_end_write_no_snapshoting(root);
+       if (atomic_read(&root->will_be_snapshotted)) {
+               btrfs_end_write_no_snapshotting(root);
                return 0;
        }
        return 1;
 }
 
-static int wait_snapshoting_atomic_t(atomic_t *a)
+static int wait_snapshotting_atomic_t(atomic_t *a)
 {
        schedule();
        return 0;
@@ -11047,11 +11117,11 @@ void btrfs_wait_for_snapshot_creation(struct btrfs_root *root)
        while (true) {
                int ret;
 
-               ret = btrfs_start_write_no_snapshoting(root);
+               ret = btrfs_start_write_no_snapshotting(root);
                if (ret)
                        break;
-               wait_on_atomic_t(&root->will_be_snapshoted,
-                                wait_snapshoting_atomic_t,
+               wait_on_atomic_t(&root->will_be_snapshotted,
+                                wait_snapshotting_atomic_t,
                                 TASK_UNINTERRUPTIBLE);
        }
 }
index 42b12a85ab49d929e29742fcb97be67d0f2d45cc..0f077c5db58ec8b985a23fcf9a441ff0ecb39400 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;
@@ -1998,7 +1997,7 @@ int repair_io_failure(struct btrfs_fs_info *fs_info, u64 ino, u64 start,
         * read repair operation.
         */
        btrfs_bio_counter_inc_blocked(fs_info);
-       if (btrfs_is_parity_mirror(fs_info, logical, length, mirror_num)) {
+       if (btrfs_is_parity_mirror(fs_info, logical, length)) {
                /*
                 * Note that we don't use BTRFS_MAP_WRITE because it's supposed
                 * to update all raid stripes, but here we just want to correct
@@ -2757,7 +2756,10 @@ static int merge_bio(struct extent_io_tree *tree, struct page *page,
 
 }
 
-static int submit_extent_page(int op, int op_flags, struct extent_io_tree *tree,
+/*
+ * @opf:       bio REQ_OP_* and REQ_* flags as one value
+ */
+static int submit_extent_page(unsigned int opf, struct extent_io_tree *tree,
                              struct writeback_control *wbc,
                              struct page *page, sector_t sector,
                              size_t size, unsigned long offset,
@@ -2804,7 +2806,7 @@ static int submit_extent_page(int op, int op_flags, struct extent_io_tree *tree,
        bio->bi_end_io = end_io_func;
        bio->bi_private = tree;
        bio->bi_write_hint = page->mapping->host->i_write_hint;
-       bio_set_op_attrs(bio, op, op_flags);
+       bio->bi_opf = opf;
        if (wbc) {
                wbc_init_bio(wbc, bio);
                wbc_account_io(wbc, page, page_size);
@@ -2878,7 +2880,7 @@ static int __do_readpage(struct extent_io_tree *tree,
                         get_extent_t *get_extent,
                         struct extent_map **em_cached,
                         struct bio **bio, int mirror_num,
-                        unsigned long *bio_flags, int read_flags,
+                        unsigned long *bio_flags, unsigned int read_flags,
                         u64 *prev_em_start)
 {
        struct inode *inode = page->mapping->host;
@@ -3059,7 +3061,7 @@ static int __do_readpage(struct extent_io_tree *tree,
                        continue;
                }
 
-               ret = submit_extent_page(REQ_OP_READ, read_flags, tree, NULL,
+               ret = submit_extent_page(REQ_OP_READ | read_flags, tree, NULL,
                                         page, sector, disk_io_size, pg_offset,
                                         bdev, bio,
                                         end_bio_extent_readpage, mirror_num,
@@ -3164,7 +3166,8 @@ static int __extent_read_full_page(struct extent_io_tree *tree,
                                   struct page *page,
                                   get_extent_t *get_extent,
                                   struct bio **bio, int mirror_num,
-                                  unsigned long *bio_flags, int read_flags)
+                                  unsigned long *bio_flags,
+                                  unsigned int read_flags)
 {
        struct inode *inode = page->mapping->host;
        struct btrfs_ordered_extent *ordered;
@@ -3311,7 +3314,7 @@ static noinline_for_stack int __extent_writepage_io(struct inode *inode,
                                 struct extent_page_data *epd,
                                 loff_t i_size,
                                 unsigned long nr_written,
-                                int write_flags, int *nr_ret)
+                                unsigned int write_flags, int *nr_ret)
 {
        struct extent_io_tree *tree = epd->tree;
        u64 start = page_offset(page);
@@ -3427,7 +3430,7 @@ static noinline_for_stack int __extent_writepage_io(struct inode *inode,
                               page->index, cur, end);
                }
 
-               ret = submit_extent_page(REQ_OP_WRITE, write_flags, tree, wbc,
+               ret = submit_extent_page(REQ_OP_WRITE | write_flags, tree, wbc,
                                         page, sector, iosize, pg_offset,
                                         bdev, &epd->bio,
                                         end_bio_extent_writepage,
@@ -3465,7 +3468,7 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc,
        size_t pg_offset = 0;
        loff_t i_size = i_size_read(inode);
        unsigned long end_index = i_size >> PAGE_SHIFT;
-       int write_flags = 0;
+       unsigned int write_flags = 0;
        unsigned long nr_written = 0;
 
        if (wbc->sync_mode == WB_SYNC_ALL)
@@ -3715,7 +3718,7 @@ static noinline_for_stack int write_one_eb(struct extent_buffer *eb,
        unsigned long i, num_pages;
        unsigned long bio_flags = 0;
        unsigned long start, end;
-       int write_flags = (epd->sync_io ? REQ_SYNC : 0) | REQ_META;
+       unsigned int write_flags = (epd->sync_io ? REQ_SYNC : 0) | REQ_META;
        int ret = 0;
 
        clear_bit(EXTENT_BUFFER_WRITE_ERR, &eb->bflags);
@@ -3745,7 +3748,7 @@ static noinline_for_stack int write_one_eb(struct extent_buffer *eb,
 
                clear_page_dirty_for_io(p);
                set_page_writeback(p);
-               ret = submit_extent_page(REQ_OP_WRITE, write_flags, tree, wbc,
+               ret = submit_extent_page(REQ_OP_WRITE | write_flags, tree, wbc,
                                         p, offset >> 9, PAGE_SIZE, 0, bdev,
                                         &epd->bio,
                                         end_bio_extent_buffer_writepage,
@@ -4606,24 +4609,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 +4621,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)
@@ -5405,9 +5393,8 @@ unlock_exit:
        return ret;
 }
 
-void read_extent_buffer(struct extent_buffer *eb, void *dstv,
-                       unsigned long start,
-                       unsigned long len)
+void read_extent_buffer(const struct extent_buffer *eb, void *dstv,
+                       unsigned long start, unsigned long len)
 {
        size_t cur;
        size_t offset;
@@ -5417,8 +5404,12 @@ void read_extent_buffer(struct extent_buffer *eb, void *dstv,
        size_t start_offset = eb->start & ((u64)PAGE_SIZE - 1);
        unsigned long i = (start_offset + start) >> PAGE_SHIFT;
 
-       WARN_ON(start > eb->len);
-       WARN_ON(start + len > eb->start + eb->len);
+       if (start + len > eb->len) {
+               WARN(1, KERN_ERR "btrfs bad mapping eb start %llu len %lu, wanted %lu %lu\n",
+                    eb->start, eb->len, start, len);
+               memset(dst, 0, len);
+               return;
+       }
 
        offset = (start_offset + start) & (PAGE_SIZE - 1);
 
@@ -5436,9 +5427,9 @@ void read_extent_buffer(struct extent_buffer *eb, void *dstv,
        }
 }
 
-int read_extent_buffer_to_user(struct extent_buffer *eb, void __user *dstv,
-                       unsigned long start,
-                       unsigned long len)
+int read_extent_buffer_to_user(const struct extent_buffer *eb,
+                              void __user *dstv,
+                              unsigned long start, unsigned long len)
 {
        size_t cur;
        size_t offset;
@@ -5478,10 +5469,10 @@ int read_extent_buffer_to_user(struct extent_buffer *eb, void __user *dstv,
  * return 1 if the item spans two pages.
  * return -EINVAL otherwise.
  */
-int map_private_extent_buffer(struct extent_buffer *eb, unsigned long start,
-                              unsigned long min_len, char **map,
-                              unsigned long *map_start,
-                              unsigned long *map_len)
+int map_private_extent_buffer(const struct extent_buffer *eb,
+                             unsigned long start, unsigned long min_len,
+                             char **map, unsigned long *map_start,
+                             unsigned long *map_len)
 {
        size_t offset = start & (PAGE_SIZE - 1);
        char *kaddr;
@@ -5491,6 +5482,12 @@ int map_private_extent_buffer(struct extent_buffer *eb, unsigned long start,
        unsigned long end_i = (start_offset + start + min_len - 1) >>
                PAGE_SHIFT;
 
+       if (start + min_len > eb->len) {
+               WARN(1, KERN_ERR "btrfs bad mapping eb start %llu len %lu, wanted %lu %lu\n",
+                      eb->start, eb->len, start, min_len);
+               return -EINVAL;
+       }
+
        if (i != end_i)
                return 1;
 
@@ -5502,12 +5499,6 @@ int map_private_extent_buffer(struct extent_buffer *eb, unsigned long start,
                *map_start = ((u64)i << PAGE_SHIFT) - start_offset;
        }
 
-       if (start + min_len > eb->len) {
-               WARN(1, KERN_ERR "btrfs bad mapping eb start %llu len %lu, wanted %lu %lu\n",
-                      eb->start, eb->len, start, min_len);
-               return -EINVAL;
-       }
-
        p = eb->pages[i];
        kaddr = page_address(p);
        *map = kaddr + offset;
@@ -5515,9 +5506,8 @@ int map_private_extent_buffer(struct extent_buffer *eb, unsigned long start,
        return 0;
 }
 
-int memcmp_extent_buffer(struct extent_buffer *eb, const void *ptrv,
-                         unsigned long start,
-                         unsigned long len)
+int memcmp_extent_buffer(const struct extent_buffer *eb, const void *ptrv,
+                        unsigned long start, unsigned long len)
 {
        size_t cur;
        size_t offset;
index 4f030912f3efe784cfec3117a4459c07d77518c8..faffa28ba707f3733e841aff16b02da259730249 100644 (file)
@@ -449,14 +449,13 @@ static inline void extent_buffer_get(struct extent_buffer *eb)
        atomic_inc(&eb->refs);
 }
 
-int memcmp_extent_buffer(struct extent_buffer *eb, const void *ptrv,
-                         unsigned long start,
-                         unsigned long len);
-void read_extent_buffer(struct extent_buffer *eb, void *dst,
+int memcmp_extent_buffer(const struct extent_buffer *eb, const void *ptrv,
+                        unsigned long start, unsigned long len);
+void read_extent_buffer(const struct extent_buffer *eb, void *dst,
                        unsigned long start,
                        unsigned long len);
-int read_extent_buffer_to_user(struct extent_buffer *eb, void __user *dst,
-                              unsigned long start,
+int read_extent_buffer_to_user(const struct extent_buffer *eb,
+                              void __user *dst, unsigned long start,
                               unsigned long len);
 void write_extent_buffer_fsid(struct extent_buffer *eb, const void *src);
 void write_extent_buffer_chunk_tree_uuid(struct extent_buffer *eb,
@@ -486,10 +485,10 @@ void set_extent_buffer_uptodate(struct extent_buffer *eb);
 void clear_extent_buffer_uptodate(struct extent_buffer *eb);
 int extent_buffer_uptodate(struct extent_buffer *eb);
 int extent_buffer_under_io(struct extent_buffer *eb);
-int map_private_extent_buffer(struct extent_buffer *eb, unsigned long offset,
-                     unsigned long min_len, char **map,
-                     unsigned long *map_start,
-                     unsigned long *map_len);
+int map_private_extent_buffer(const struct extent_buffer *eb,
+                             unsigned long offset, unsigned long min_len,
+                             char **map, unsigned long *map_start,
+                             unsigned long *map_len);
 void extent_range_clear_dirty_for_io(struct inode *inode, u64 start, u64 end);
 void extent_range_redirty_for_io(struct inode *inode, u64 start, u64 end);
 void extent_clear_unlock_delalloc(struct inode *inode, u64 start, u64 end,
index 9e75d8a39aacf7dbcfdd961dd41ddd71e924a3a3..74fd7756cff3c963820753fbb78b76a093c5a5fd 100644 (file)
@@ -1536,7 +1536,7 @@ static noinline int check_can_nocow(struct btrfs_inode *inode, loff_t pos,
        u64 num_bytes;
        int ret;
 
-       ret = btrfs_start_write_no_snapshoting(root);
+       ret = btrfs_start_write_no_snapshotting(root);
        if (!ret)
                return -ENOSPC;
 
@@ -1561,7 +1561,7 @@ static noinline int check_can_nocow(struct btrfs_inode *inode, loff_t pos,
                        NULL, NULL, NULL);
        if (ret <= 0) {
                ret = 0;
-               btrfs_end_write_no_snapshoting(root);
+               btrfs_end_write_no_snapshotting(root);
        } else {
                *write_bytes = min_t(size_t, *write_bytes ,
                                     num_bytes - pos + lockstart);
@@ -1664,7 +1664,7 @@ static noinline ssize_t __btrfs_buffered_write(struct file *file,
                                                data_reserved, pos,
                                                write_bytes);
                        else
-                               btrfs_end_write_no_snapshoting(root);
+                               btrfs_end_write_no_snapshotting(root);
                        break;
                }
 
@@ -1767,7 +1767,7 @@ again:
 
                release_bytes = 0;
                if (only_release_metadata)
-                       btrfs_end_write_no_snapshoting(root);
+                       btrfs_end_write_no_snapshotting(root);
 
                if (only_release_metadata && copied > 0) {
                        lockstart = round_down(pos,
@@ -1797,7 +1797,7 @@ again:
 
        if (release_bytes) {
                if (only_release_metadata) {
-                       btrfs_end_write_no_snapshoting(root);
+                       btrfs_end_write_no_snapshotting(root);
                        btrfs_delalloc_release_metadata(BTRFS_I(inode),
                                        release_bytes);
                } else {
@@ -1990,8 +1990,15 @@ out:
 
 int btrfs_release_file(struct inode *inode, struct file *filp)
 {
-       if (filp->private_data)
+       struct btrfs_file_private *private = filp->private_data;
+
+       if (private && private->trans)
                btrfs_ioctl_trans_end(filp);
+       if (private && private->filldir_buf)
+               kfree(private->filldir_buf);
+       kfree(private);
+       filp->private_data = NULL;
+
        /*
         * ordered_data_close is set by settattr when we are about to truncate
         * a file from a non-zero size to a zero size.  This tries to
index c5e6180cdb8c9250e3a525e311a42795c4831c32..cdc9f4015ec36c08688a81bb1ba2bf657a9845ef 100644 (file)
@@ -709,7 +709,7 @@ static int __load_free_space_cache(struct btrfs_root *root, struct inode *inode,
 
        if (!BTRFS_I(inode)->generation) {
                btrfs_info(fs_info,
-                          "The free space cache file (%llu) is invalid. skip it\n",
+                          "the free space cache file (%llu) is invalid, skip it",
                           offset);
                return 0;
        }
index a5e34de06c2fe593e7578d59a27614f73a57ea1a..684f12247db7e376350789b6161190c6412431b7 100644 (file)
@@ -1257,7 +1257,7 @@ int btrfs_clear_free_space_tree(struct btrfs_fs_info *fs_info)
        if (ret)
                goto abort;
 
-       ret = btrfs_del_root(trans, tree_root, &free_space_root->root_key);
+       ret = btrfs_del_root(trans, fs_info, &free_space_root->root_key);
        if (ret)
                goto abort;
 
index 54ffced3bce8c037f045441155e86f03842e5da7..ba3787df43c3076520aff16bce5929a0293ac964 100644 (file)
@@ -44,7 +44,7 @@ int remove_from_free_space_tree(struct btrfs_trans_handle *trans,
                                struct btrfs_fs_info *fs_info,
                                u64 start, u64 size);
 
-/* Exposed for testing. */
+#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
 struct btrfs_free_space_info *
 search_free_space_info(struct btrfs_trans_handle *trans,
                       struct btrfs_fs_info *fs_info,
@@ -68,5 +68,6 @@ int convert_free_space_to_extents(struct btrfs_trans_handle *trans,
                                  struct btrfs_path *path);
 int free_space_test_bit(struct btrfs_block_group_cache *block_group,
                        struct btrfs_path *path, u64 offset);
+#endif
 
 #endif
index 24bcd5cd9cf2fc680cc7ed32fb58cd254bb055b5..17ad018da0a253d8c593c77cea554ca7f234fcba 100644 (file)
@@ -392,20 +392,23 @@ static noinline int add_async_extent(struct async_cow *cow,
        return 0;
 }
 
-static inline int inode_need_compress(struct inode *inode)
+static inline int inode_need_compress(struct inode *inode, u64 start, u64 end)
 {
        struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
 
        /* force compress */
        if (btrfs_test_opt(fs_info, FORCE_COMPRESS))
                return 1;
+       /* defrag ioctl */
+       if (BTRFS_I(inode)->defrag_compress)
+               return 1;
        /* bad compression ratios */
        if (BTRFS_I(inode)->flags & BTRFS_INODE_NOCOMPRESS)
                return 0;
        if (btrfs_test_opt(fs_info, COMPRESS) ||
            BTRFS_I(inode)->flags & BTRFS_INODE_COMPRESS ||
-           BTRFS_I(inode)->force_compress)
-               return 1;
+           BTRFS_I(inode)->prop_compress)
+               return btrfs_compress_heuristic(inode, start, end);
        return 0;
 }
 
@@ -503,7 +506,7 @@ again:
         * inode has not been flagged as nocompress.  This flag can
         * change at any time if we discover bad compression ratios.
         */
-       if (inode_need_compress(inode)) {
+       if (inode_need_compress(inode, start, end)) {
                WARN_ON(pages);
                pages = kcalloc(nr_pages, sizeof(struct page *), GFP_NOFS);
                if (!pages) {
@@ -511,8 +514,10 @@ again:
                        goto cont;
                }
 
-               if (BTRFS_I(inode)->force_compress)
-                       compress_type = BTRFS_I(inode)->force_compress;
+               if (BTRFS_I(inode)->defrag_compress)
+                       compress_type = BTRFS_I(inode)->defrag_compress;
+               else if (BTRFS_I(inode)->prop_compress)
+                       compress_type = BTRFS_I(inode)->prop_compress;
 
                /*
                 * we need to call clear_page_dirty_for_io on each
@@ -645,7 +650,7 @@ cont:
 
                /* flag the file so we don't compress in the future */
                if (!btrfs_test_opt(fs_info, FORCE_COMPRESS) &&
-                   !(BTRFS_I(inode)->force_compress)) {
+                   !(BTRFS_I(inode)->prop_compress)) {
                        BTRFS_I(inode)->flags |= BTRFS_INODE_NOCOMPRESS;
                }
        }
@@ -1381,7 +1386,7 @@ next_slot:
                         * we fall into common COW way.
                         */
                        if (!nolock) {
-                               err = btrfs_start_write_no_snapshoting(root);
+                               err = btrfs_start_write_no_snapshotting(root);
                                if (!err)
                                        goto out_check;
                        }
@@ -1393,12 +1398,12 @@ next_slot:
                        if (csum_exist_in_range(fs_info, disk_bytenr,
                                                num_bytes)) {
                                if (!nolock)
-                                       btrfs_end_write_no_snapshoting(root);
+                                       btrfs_end_write_no_snapshotting(root);
                                goto out_check;
                        }
                        if (!btrfs_inc_nocow_writers(fs_info, disk_bytenr)) {
                                if (!nolock)
-                                       btrfs_end_write_no_snapshoting(root);
+                                       btrfs_end_write_no_snapshotting(root);
                                goto out_check;
                        }
                        nocow = 1;
@@ -1415,7 +1420,7 @@ out_check:
                if (extent_end <= start) {
                        path->slots[0]++;
                        if (!nolock && nocow)
-                               btrfs_end_write_no_snapshoting(root);
+                               btrfs_end_write_no_snapshotting(root);
                        if (nocow)
                                btrfs_dec_nocow_writers(fs_info, disk_bytenr);
                        goto next_slot;
@@ -1438,7 +1443,7 @@ out_check:
                                             NULL);
                        if (ret) {
                                if (!nolock && nocow)
-                                       btrfs_end_write_no_snapshoting(root);
+                                       btrfs_end_write_no_snapshotting(root);
                                if (nocow)
                                        btrfs_dec_nocow_writers(fs_info,
                                                                disk_bytenr);
@@ -1459,7 +1464,7 @@ out_check:
                                          BTRFS_ORDERED_PREALLOC);
                        if (IS_ERR(em)) {
                                if (!nolock && nocow)
-                                       btrfs_end_write_no_snapshoting(root);
+                                       btrfs_end_write_no_snapshotting(root);
                                if (nocow)
                                        btrfs_dec_nocow_writers(fs_info,
                                                                disk_bytenr);
@@ -1499,7 +1504,7 @@ out_check:
                                             PAGE_UNLOCK | PAGE_SET_PRIVATE2);
 
                if (!nolock && nocow)
-                       btrfs_end_write_no_snapshoting(root);
+                       btrfs_end_write_no_snapshotting(root);
                cur_offset = extent_end;
 
                /*
@@ -1576,7 +1581,7 @@ static int run_delalloc_range(void *private_data, struct page *locked_page,
        } else if (BTRFS_I(inode)->flags & BTRFS_INODE_PREALLOC && !force_cow) {
                ret = run_delalloc_nocow(inode, locked_page, start, end,
                                         page_started, 0, nr_written);
-       } else if (!inode_need_compress(inode)) {
+       } else if (!inode_need_compress(inode, start, end)) {
                ret = cow_file_range(inode, locked_page, start, end, end,
                                      page_started, nr_written, 1, NULL);
        } else {
@@ -1796,10 +1801,11 @@ static void btrfs_clear_bit_hook(void *private_data,
        u64 len = state->end + 1 - state->start;
        u32 num_extents = count_max_extents(len);
 
-       spin_lock(&inode->lock);
-       if ((state->state & EXTENT_DEFRAG) && (*bits & EXTENT_DEFRAG))
+       if ((state->state & EXTENT_DEFRAG) && (*bits & EXTENT_DEFRAG)) {
+               spin_lock(&inode->lock);
                inode->defrag_bytes -= len;
-       spin_unlock(&inode->lock);
+               spin_unlock(&inode->lock);
+       }
 
        /*
         * set_bit and clear bit hooks normally require _irqsave/restore
@@ -3159,8 +3165,6 @@ zeroit:
        memset(kaddr + pgoff, 1, len);
        flush_dcache_page(page);
        kunmap_atomic(kaddr);
-       if (csum_expected == 0)
-               return 0;
        return -EIO;
 }
 
@@ -5055,7 +5059,7 @@ static int btrfs_setsize(struct inode *inode, struct iattr *attr)
 
        if (newsize > oldsize) {
                /*
-                * Don't do an expanding truncate while snapshoting is ongoing.
+                * Don't do an expanding truncate while snapshotting is ongoing.
                 * This is to ensure the snapshot captures a fully consistent
                 * state of this file - if the snapshot captures this expanding
                 * truncation, it must capture all writes that happened before
@@ -5064,13 +5068,13 @@ static int btrfs_setsize(struct inode *inode, struct iattr *attr)
                btrfs_wait_for_snapshot_creation(root);
                ret = btrfs_cont_expand(inode, oldsize, newsize);
                if (ret) {
-                       btrfs_end_write_no_snapshoting(root);
+                       btrfs_end_write_no_snapshotting(root);
                        return ret;
                }
 
                trans = btrfs_start_transaction(root, 1);
                if (IS_ERR(trans)) {
-                       btrfs_end_write_no_snapshoting(root);
+                       btrfs_end_write_no_snapshotting(root);
                        return PTR_ERR(trans);
                }
 
@@ -5078,7 +5082,7 @@ static int btrfs_setsize(struct inode *inode, struct iattr *attr)
                btrfs_ordered_update_i_size(inode, i_size_read(inode), NULL);
                pagecache_isize_extended(inode, oldsize, newsize);
                ret = btrfs_update_inode(trans, root, inode);
-               btrfs_end_write_no_snapshoting(root);
+               btrfs_end_write_no_snapshotting(root);
                btrfs_end_transaction(trans);
        } else {
 
@@ -5873,25 +5877,74 @@ unsigned char btrfs_filetype_table[] = {
        DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR, DT_BLK, DT_FIFO, DT_SOCK, DT_LNK
 };
 
+/*
+ * All this infrastructure exists because dir_emit can fault, and we are holding
+ * the tree lock when doing readdir.  For now just allocate a buffer and copy
+ * our information into that, and then dir_emit from the buffer.  This is
+ * similar to what NFS does, only we don't keep the buffer around in pagecache
+ * because I'm afraid I'll mess that up.  Long term we need to make filldir do
+ * copy_to_user_inatomic so we don't have to worry about page faulting under the
+ * tree lock.
+ */
+static int btrfs_opendir(struct inode *inode, struct file *file)
+{
+       struct btrfs_file_private *private;
+
+       private = kzalloc(sizeof(struct btrfs_file_private), GFP_KERNEL);
+       if (!private)
+               return -ENOMEM;
+       private->filldir_buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
+       if (!private->filldir_buf) {
+               kfree(private);
+               return -ENOMEM;
+       }
+       file->private_data = private;
+       return 0;
+}
+
+struct dir_entry {
+       u64 ino;
+       u64 offset;
+       unsigned type;
+       int name_len;
+};
+
+static int btrfs_filldir(void *addr, int entries, struct dir_context *ctx)
+{
+       while (entries--) {
+               struct dir_entry *entry = addr;
+               char *name = (char *)(entry + 1);
+
+               ctx->pos = entry->offset;
+               if (!dir_emit(ctx, name, entry->name_len, entry->ino,
+                             entry->type))
+                       return 1;
+               addr += sizeof(struct dir_entry) + entry->name_len;
+               ctx->pos++;
+       }
+       return 0;
+}
+
 static int btrfs_real_readdir(struct file *file, struct dir_context *ctx)
 {
        struct inode *inode = file_inode(file);
        struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
        struct btrfs_root *root = BTRFS_I(inode)->root;
+       struct btrfs_file_private *private = file->private_data;
        struct btrfs_dir_item *di;
        struct btrfs_key key;
        struct btrfs_key found_key;
        struct btrfs_path *path;
+       void *addr;
        struct list_head ins_list;
        struct list_head del_list;
        int ret;
        struct extent_buffer *leaf;
        int slot;
-       unsigned char d_type;
-       int over = 0;
-       char tmp_name[32];
        char *name_ptr;
        int name_len;
+       int entries = 0;
+       int total_len = 0;
        bool put = false;
        struct btrfs_key location;
 
@@ -5902,12 +5955,14 @@ static int btrfs_real_readdir(struct file *file, struct dir_context *ctx)
        if (!path)
                return -ENOMEM;
 
+       addr = private->filldir_buf;
        path->reada = READA_FORWARD;
 
        INIT_LIST_HEAD(&ins_list);
        INIT_LIST_HEAD(&del_list);
        put = btrfs_readdir_get_delayed_items(inode, &ins_list, &del_list);
 
+again:
        key.type = BTRFS_DIR_INDEX_KEY;
        key.offset = ctx->pos;
        key.objectid = btrfs_ino(BTRFS_I(inode));
@@ -5917,6 +5972,8 @@ static int btrfs_real_readdir(struct file *file, struct dir_context *ctx)
                goto err;
 
        while (1) {
+               struct dir_entry *entry;
+
                leaf = path->nodes[0];
                slot = path->slots[0];
                if (slot >= btrfs_header_nritems(leaf)) {
@@ -5938,41 +5995,43 @@ static int btrfs_real_readdir(struct file *file, struct dir_context *ctx)
                        goto next;
                if (btrfs_should_delete_dir_index(&del_list, found_key.offset))
                        goto next;
-
-               ctx->pos = found_key.offset;
-
                di = btrfs_item_ptr(leaf, slot, struct btrfs_dir_item);
                if (verify_dir_item(fs_info, leaf, slot, di))
                        goto next;
 
                name_len = btrfs_dir_name_len(leaf, di);
-               if (name_len <= sizeof(tmp_name)) {
-                       name_ptr = tmp_name;
-               } else {
-                       name_ptr = kmalloc(name_len, GFP_KERNEL);
-                       if (!name_ptr) {
-                               ret = -ENOMEM;
-                               goto err;
-                       }
+               if ((total_len + sizeof(struct dir_entry) + name_len) >=
+                   PAGE_SIZE) {
+                       btrfs_release_path(path);
+                       ret = btrfs_filldir(private->filldir_buf, entries, ctx);
+                       if (ret)
+                               goto nopos;
+                       addr = private->filldir_buf;
+                       entries = 0;
+                       total_len = 0;
+                       goto again;
                }
+
+               entry = addr;
+               entry->name_len = name_len;
+               name_ptr = (char *)(entry + 1);
                read_extent_buffer(leaf, name_ptr, (unsigned long)(di + 1),
                                   name_len);
-
-               d_type = btrfs_filetype_table[btrfs_dir_type(leaf, di)];
+               entry->type = btrfs_filetype_table[btrfs_dir_type(leaf, di)];
                btrfs_dir_item_key_to_cpu(leaf, di, &location);
-
-               over = !dir_emit(ctx, name_ptr, name_len, location.objectid,
-                                d_type);
-
-               if (name_ptr != tmp_name)
-                       kfree(name_ptr);
-
-               if (over)
-                       goto nopos;
-               ctx->pos++;
+               entry->ino = location.objectid;
+               entry->offset = found_key.offset;
+               entries++;
+               addr += sizeof(struct dir_entry) + name_len;
+               total_len += sizeof(struct dir_entry) + name_len;
 next:
                path->slots[0]++;
        }
+       btrfs_release_path(path);
+
+       ret = btrfs_filldir(private->filldir_buf, entries, ctx);
+       if (ret)
+               goto nopos;
 
        ret = btrfs_readdir_delayed_dir_index(ctx, &ins_list);
        if (ret)
@@ -6185,6 +6244,37 @@ static int btrfs_insert_inode_locked(struct inode *inode)
                   btrfs_find_actor, &args);
 }
 
+/*
+ * Inherit flags from the parent inode.
+ *
+ * Currently only the compression flags and the cow flags are inherited.
+ */
+static void btrfs_inherit_iflags(struct inode *inode, struct inode *dir)
+{
+       unsigned int flags;
+
+       if (!dir)
+               return;
+
+       flags = BTRFS_I(dir)->flags;
+
+       if (flags & BTRFS_INODE_NOCOMPRESS) {
+               BTRFS_I(inode)->flags &= ~BTRFS_INODE_COMPRESS;
+               BTRFS_I(inode)->flags |= BTRFS_INODE_NOCOMPRESS;
+       } else if (flags & BTRFS_INODE_COMPRESS) {
+               BTRFS_I(inode)->flags &= ~BTRFS_INODE_NOCOMPRESS;
+               BTRFS_I(inode)->flags |= BTRFS_INODE_COMPRESS;
+       }
+
+       if (flags & BTRFS_INODE_NODATACOW) {
+               BTRFS_I(inode)->flags |= BTRFS_INODE_NODATACOW;
+               if (S_ISREG(inode->i_mode))
+                       BTRFS_I(inode)->flags |= BTRFS_INODE_NODATASUM;
+       }
+
+       btrfs_update_iflags(inode);
+}
+
 static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
                                     struct btrfs_root *root,
                                     struct inode *dir,
@@ -7991,7 +8081,7 @@ static blk_status_t dio_read_error(struct inode *inode, struct bio *failed_bio,
        struct extent_io_tree *failure_tree = &BTRFS_I(inode)->io_failure_tree;
        struct bio *bio;
        int isector;
-       int read_mode = 0;
+       unsigned int read_mode = 0;
        int segs;
        int ret;
        blk_status_t status;
@@ -8021,7 +8111,7 @@ static blk_status_t dio_read_error(struct inode *inode, struct bio *failed_bio,
        bio_set_op_attrs(bio, REQ_OP_READ, read_mode);
 
        btrfs_debug(BTRFS_I(inode)->root->fs_info,
-                   "Repair DIO Read Error: submitting new dio read[%#x] to this_mirror=%d, in_validation=%d\n",
+                   "repair DIO read error: submitting new dio read[%#x] to this_mirror=%d, in_validation=%d",
                    read_mode, failrec->this_mirror, failrec->in_validation);
 
        status = submit_dio_repair_bio(inode, bio, failrec->this_mirror);
@@ -8106,7 +8196,7 @@ next_block_or_try_again:
                        goto next;
                }
 
-               wait_for_completion(&done.done);
+               wait_for_completion_io(&done.done);
 
                if (!done.uptodate) {
                        /* We might have another mirror, so try again */
@@ -8221,7 +8311,7 @@ try_again:
                        goto next;
                }
 
-               wait_for_completion(&done.done);
+               wait_for_completion_io(&done.done);
 
                if (!done.uptodate) {
                        /* We might have another mirror, so try again */
@@ -8428,7 +8518,7 @@ static inline blk_status_t btrfs_lookup_and_bind_dio_csum(struct inode *inode,
 
 static inline blk_status_t
 __btrfs_submit_dio_bio(struct bio *bio, struct inode *inode, u64 file_offset,
-                      int skip_sum, int async_submit)
+                      int async_submit)
 {
        struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
        struct btrfs_dio_private *dip = bio->bi_private;
@@ -8446,7 +8536,7 @@ __btrfs_submit_dio_bio(struct bio *bio, struct inode *inode, u64 file_offset,
                        goto err;
        }
 
-       if (skip_sum)
+       if (BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM)
                goto map;
 
        if (write && async_submit) {
@@ -8476,8 +8566,7 @@ err:
        return ret;
 }
 
-static int btrfs_submit_direct_hook(struct btrfs_dio_private *dip,
-                                   int skip_sum)
+static int btrfs_submit_direct_hook(struct btrfs_dio_private *dip)
 {
        struct inode *inode = dip->inode;
        struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
@@ -8541,7 +8630,7 @@ static int btrfs_submit_direct_hook(struct btrfs_dio_private *dip,
                 */
                atomic_inc(&dip->pending_bios);
 
-               status = __btrfs_submit_dio_bio(bio, inode, file_offset, skip_sum,
+               status = __btrfs_submit_dio_bio(bio, inode, file_offset,
                                                async_submit);
                if (status) {
                        bio_put(bio);
@@ -8561,8 +8650,7 @@ static int btrfs_submit_direct_hook(struct btrfs_dio_private *dip,
        } while (submit_len > 0);
 
 submit:
-       status = __btrfs_submit_dio_bio(bio, inode, file_offset, skip_sum,
-                                       async_submit);
+       status = __btrfs_submit_dio_bio(bio, inode, file_offset, async_submit);
        if (!status)
                return 0;
 
@@ -8587,12 +8675,9 @@ static void btrfs_submit_direct(struct bio *dio_bio, struct inode *inode,
        struct btrfs_dio_private *dip = NULL;
        struct bio *bio = NULL;
        struct btrfs_io_bio *io_bio;
-       int skip_sum;
        bool write = (bio_op(dio_bio) == REQ_OP_WRITE);
        int ret = 0;
 
-       skip_sum = BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM;
-
        bio = btrfs_bio_clone(dio_bio);
 
        dip = kzalloc(sizeof(*dip), GFP_NOFS);
@@ -8635,7 +8720,7 @@ static void btrfs_submit_direct(struct bio *dio_bio, struct inode *inode,
                        dio_data->unsubmitted_oe_range_end;
        }
 
-       ret = btrfs_submit_direct_hook(dip, skip_sum);
+       ret = btrfs_submit_direct_hook(dip);
        if (!ret)
                return;
 
@@ -8735,7 +8820,6 @@ static ssize_t btrfs_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
                return 0;
 
        inode_dio_begin(inode);
-       smp_mb__after_atomic();
 
        /*
         * The generic stuff only does filemap_write_and_wait_range, which
@@ -9408,7 +9492,8 @@ struct inode *btrfs_alloc_inode(struct super_block *sb)
        ei->reserved_extents = 0;
 
        ei->runtime_flags = 0;
-       ei->force_compress = BTRFS_COMPRESS_NONE;
+       ei->prop_compress = BTRFS_COMPRESS_NONE;
+       ei->defrag_compress = BTRFS_COMPRESS_NONE;
 
        ei->delayed_node = NULL;
 
@@ -10748,6 +10833,7 @@ static const struct file_operations btrfs_dir_file_operations = {
        .llseek         = generic_file_llseek,
        .read           = generic_read_dir,
        .iterate_shared = btrfs_real_readdir,
+       .open           = btrfs_opendir,
        .unlocked_ioctl = btrfs_ioctl,
 #ifdef CONFIG_COMPAT
        .compat_ioctl   = btrfs_compat_ioctl,
index fa1b78cf25f68083de3db86ead690a41563316ce..ae8fbf9d3de2ad0028ba2b1f5af81d4f3028f4ea 100644 (file)
@@ -156,37 +156,6 @@ void btrfs_update_iflags(struct inode *inode)
                      new_fl);
 }
 
-/*
- * Inherit flags from the parent inode.
- *
- * Currently only the compression flags and the cow flags are inherited.
- */
-void btrfs_inherit_iflags(struct inode *inode, struct inode *dir)
-{
-       unsigned int flags;
-
-       if (!dir)
-               return;
-
-       flags = BTRFS_I(dir)->flags;
-
-       if (flags & BTRFS_INODE_NOCOMPRESS) {
-               BTRFS_I(inode)->flags &= ~BTRFS_INODE_COMPRESS;
-               BTRFS_I(inode)->flags |= BTRFS_INODE_NOCOMPRESS;
-       } else if (flags & BTRFS_INODE_COMPRESS) {
-               BTRFS_I(inode)->flags &= ~BTRFS_INODE_NOCOMPRESS;
-               BTRFS_I(inode)->flags |= BTRFS_INODE_COMPRESS;
-       }
-
-       if (flags & BTRFS_INODE_NODATACOW) {
-               BTRFS_I(inode)->flags |= BTRFS_INODE_NODATACOW;
-               if (S_ISREG(inode->i_mode))
-                       BTRFS_I(inode)->flags |= BTRFS_INODE_NODATASUM;
-       }
-
-       btrfs_update_iflags(inode);
-}
-
 static int btrfs_ioctl_getflags(struct file *file, void __user *arg)
 {
        struct btrfs_inode *ip = BTRFS_I(file_inode(file));
@@ -638,7 +607,7 @@ fail_free:
        return ret;
 }
 
-static void btrfs_wait_for_no_snapshoting_writes(struct btrfs_root *root)
+static void btrfs_wait_for_no_snapshotting_writes(struct btrfs_root *root)
 {
        s64 writers;
        DEFINE_WAIT(wait);
@@ -681,9 +650,9 @@ static int create_snapshot(struct btrfs_root *root, struct inode *dir,
                goto free_pending;
        }
 
-       atomic_inc(&root->will_be_snapshoted);
+       atomic_inc(&root->will_be_snapshotted);
        smp_mb__after_atomic();
-       btrfs_wait_for_no_snapshoting_writes(root);
+       btrfs_wait_for_no_snapshotting_writes(root);
 
        ret = btrfs_start_delalloc_inodes(root, 0);
        if (ret)
@@ -754,8 +723,8 @@ static int create_snapshot(struct btrfs_root *root, struct inode *dir,
 fail:
        btrfs_subvolume_release_metadata(fs_info, &pending_snapshot->block_rsv);
 dec_and_free:
-       if (atomic_dec_and_test(&root->will_be_snapshoted))
-               wake_up_atomic_t(&root->will_be_snapshoted);
+       if (atomic_dec_and_test(&root->will_be_snapshotted))
+               wake_up_atomic_t(&root->will_be_snapshotted);
 free_pending:
        kfree(pending_snapshot->root_item);
        btrfs_free_path(pending_snapshot->path);
@@ -1286,6 +1255,7 @@ int btrfs_defrag_file(struct inode *inode, struct file *file,
        unsigned long cluster = max_cluster;
        u64 new_align = ~((u64)SZ_128K - 1);
        struct page **pages = NULL;
+       bool do_compress = range->flags & BTRFS_DEFRAG_RANGE_COMPRESS;
 
        if (isize == 0)
                return 0;
@@ -1293,7 +1263,7 @@ int btrfs_defrag_file(struct inode *inode, struct file *file,
        if (range->start >= isize)
                return -EINVAL;
 
-       if (range->flags & BTRFS_DEFRAG_RANGE_COMPRESS) {
+       if (do_compress) {
                if (range->compress_type > BTRFS_COMPRESS_TYPES)
                        return -EINVAL;
                if (range->compress_type)
@@ -1304,20 +1274,19 @@ int btrfs_defrag_file(struct inode *inode, struct file *file,
                extent_thresh = SZ_256K;
 
        /*
-        * if we were not given a file, allocate a readahead
-        * context
+        * If we were not given a file, allocate a readahead context. As
+        * readahead is just an optimization, defrag will work without it so
+        * we don't error out.
         */
        if (!file) {
-               ra = kzalloc(sizeof(*ra), GFP_NOFS);
-               if (!ra)
-                       return -ENOMEM;
-               file_ra_state_init(ra, inode->i_mapping);
+               ra = kzalloc(sizeof(*ra), GFP_KERNEL);
+               if (ra)
+                       file_ra_state_init(ra, inode->i_mapping);
        } else {
                ra = &file->f_ra;
        }
 
-       pages = kmalloc_array(max_cluster, sizeof(struct page *),
-                       GFP_NOFS);
+       pages = kmalloc_array(max_cluster, sizeof(struct page *), GFP_KERNEL);
        if (!pages) {
                ret = -ENOMEM;
                goto out_ra;
@@ -1373,8 +1342,7 @@ int btrfs_defrag_file(struct inode *inode, struct file *file,
 
                if (!should_defrag_range(inode, (u64)i << PAGE_SHIFT,
                                         extent_thresh, &last_len, &skip,
-                                        &defrag_end, range->flags &
-                                        BTRFS_DEFRAG_RANGE_COMPRESS)) {
+                                        &defrag_end, do_compress)){
                        unsigned long next;
                        /*
                         * the should_defrag function tells us how much to skip
@@ -1395,14 +1363,15 @@ int btrfs_defrag_file(struct inode *inode, struct file *file,
 
                if (i + cluster > ra_index) {
                        ra_index = max(i, ra_index);
-                       btrfs_force_ra(inode->i_mapping, ra, file, ra_index,
-                                      cluster);
+                       if (ra)
+                               page_cache_sync_readahead(inode->i_mapping, ra,
+                                               file, ra_index, cluster);
                        ra_index += cluster;
                }
 
                inode_lock(inode);
-               if (range->flags & BTRFS_DEFRAG_RANGE_COMPRESS)
-                       BTRFS_I(inode)->force_compress = compress_type;
+               if (do_compress)
+                       BTRFS_I(inode)->defrag_compress = compress_type;
                ret = cluster_pages_for_defrag(inode, pages, i, cluster);
                if (ret < 0) {
                        inode_unlock(inode);
@@ -1449,7 +1418,7 @@ int btrfs_defrag_file(struct inode *inode, struct file *file,
                        filemap_flush(inode->i_mapping);
        }
 
-       if ((range->flags & BTRFS_DEFRAG_RANGE_COMPRESS)) {
+       if (do_compress) {
                /* the filemap_flush will queue IO into the worker threads, but
                 * we have to make sure the IO is actually started and that
                 * ordered extents get created before we return
@@ -1471,9 +1440,9 @@ int btrfs_defrag_file(struct inode *inode, struct file *file,
        ret = defrag_count;
 
 out_ra:
-       if (range->flags & BTRFS_DEFRAG_RANGE_COMPRESS) {
+       if (do_compress) {
                inode_lock(inode);
-               BTRFS_I(inode)->force_compress = BTRFS_COMPRESS_NONE;
+               BTRFS_I(inode)->defrag_compress = BTRFS_COMPRESS_NONE;
                inode_unlock(inode);
        }
        if (!file)
@@ -1600,8 +1569,7 @@ static noinline int btrfs_ioctl_resize(struct file *file,
                goto out_free;
        }
 
-       new_size = div_u64(new_size, fs_info->sectorsize);
-       new_size *= fs_info->sectorsize;
+       new_size = round_down(new_size, fs_info->sectorsize);
 
        btrfs_info_in_rcu(fs_info, "new size for %s is %llu",
                          rcu_str_deref(device->name), new_size);
@@ -2201,9 +2169,6 @@ static noinline int btrfs_ioctl_tree_search_v2(struct file *file,
 
        buf_size = args.buf_size;
 
-       if (buf_size < sizeof(struct btrfs_ioctl_search_header))
-               return -EOVERFLOW;
-
        /* limit result size to 16MB */
        if (buf_size > buf_limit)
                buf_size = buf_limit;
@@ -3998,15 +3963,35 @@ static long btrfs_ioctl_trans_start(struct file *file)
        struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
        struct btrfs_root *root = BTRFS_I(inode)->root;
        struct btrfs_trans_handle *trans;
+       struct btrfs_file_private *private;
        int ret;
+       static bool warned = false;
 
        ret = -EPERM;
        if (!capable(CAP_SYS_ADMIN))
                goto out;
 
+       if (!warned) {
+               btrfs_warn(fs_info,
+                       "Userspace transaction mechanism is considered "
+                       "deprecated and slated to be removed in 4.17. "
+                       "If you have a valid use case please "
+                       "speak up on the mailing list");
+               WARN_ON(1);
+               warned = true;
+       }
+
        ret = -EINPROGRESS;
-       if (file->private_data)
+       private = file->private_data;
+       if (private && private->trans)
                goto out;
+       if (!private) {
+               private = kzalloc(sizeof(struct btrfs_file_private),
+                                 GFP_KERNEL);
+               if (!private)
+                       return -ENOMEM;
+               file->private_data = private;
+       }
 
        ret = -EROFS;
        if (btrfs_root_readonly(root))
@@ -4023,7 +4008,7 @@ static long btrfs_ioctl_trans_start(struct file *file)
        if (IS_ERR(trans))
                goto out_drop;
 
-       file->private_data = trans;
+       private->trans = trans;
        return 0;
 
 out_drop:
@@ -4278,14 +4263,13 @@ long btrfs_ioctl_trans_end(struct file *file)
 {
        struct inode *inode = file_inode(file);
        struct btrfs_root *root = BTRFS_I(inode)->root;
-       struct btrfs_trans_handle *trans;
+       struct btrfs_file_private *private = file->private_data;
 
-       trans = file->private_data;
-       if (!trans)
+       if (!private || !private->trans)
                return -EINVAL;
-       file->private_data = NULL;
 
-       btrfs_end_transaction(trans);
+       btrfs_end_transaction(private->trans);
+       private->trans = NULL;
 
        atomic_dec(&root->fs_info->open_ioctl_trans);
 
index fcae61e175f38899e3424c13120f06f510efa90b..569205e651c7dd46c98a8fe3d0798140322d4ec3 100644 (file)
@@ -44,7 +44,7 @@ static void print_dev_item(struct extent_buffer *eb,
 static void print_extent_data_ref(struct extent_buffer *eb,
                                  struct btrfs_extent_data_ref *ref)
 {
-       pr_info("\t\textent data backref root %llu objectid %llu offset %llu count %u\n",
+       pr_cont("extent data backref root %llu objectid %llu offset %llu count %u\n",
               btrfs_extent_data_ref_root(eb, ref),
               btrfs_extent_data_ref_objectid(eb, ref),
               btrfs_extent_data_ref_offset(eb, ref),
@@ -63,6 +63,7 @@ static void print_extent_item(struct extent_buffer *eb, int slot, int type)
        u32 item_size = btrfs_item_size_nr(eb, slot);
        u64 flags;
        u64 offset;
+       int ref_index = 0;
 
        if (item_size < sizeof(*ei)) {
 #ifdef BTRFS_COMPAT_EXTENT_TREE_V0
@@ -104,12 +105,20 @@ static void print_extent_item(struct extent_buffer *eb, int slot, int type)
                iref = (struct btrfs_extent_inline_ref *)ptr;
                type = btrfs_extent_inline_ref_type(eb, iref);
                offset = btrfs_extent_inline_ref_offset(eb, iref);
+               pr_info("\t\tref#%d: ", ref_index++);
                switch (type) {
                case BTRFS_TREE_BLOCK_REF_KEY:
-                       pr_info("\t\ttree block backref root %llu\n", offset);
+                       pr_cont("tree block backref root %llu\n", offset);
                        break;
                case BTRFS_SHARED_BLOCK_REF_KEY:
-                       pr_info("\t\tshared block backref parent %llu\n", offset);
+                       pr_cont("shared block backref parent %llu\n", offset);
+                       /*
+                        * offset is supposed to be a tree block which
+                        * must be aligned to nodesize.
+                        */
+                       if (!IS_ALIGNED(offset, eb->fs_info->nodesize))
+                               pr_info("\t\t\t(parent %llu is NOT ALIGNED to nodesize %llu)\n",
+                                       offset, (unsigned long long)eb->fs_info->nodesize);
                        break;
                case BTRFS_EXTENT_DATA_REF_KEY:
                        dref = (struct btrfs_extent_data_ref *)(&iref->offset);
@@ -117,11 +126,20 @@ static void print_extent_item(struct extent_buffer *eb, int slot, int type)
                        break;
                case BTRFS_SHARED_DATA_REF_KEY:
                        sref = (struct btrfs_shared_data_ref *)(iref + 1);
-                       pr_info("\t\tshared data backref parent %llu count %u\n",
+                       pr_cont("shared data backref parent %llu count %u\n",
                               offset, btrfs_shared_data_ref_count(eb, sref));
+                       /*
+                        * offset is supposed to be a tree block which
+                        * must be aligned to nodesize.
+                        */
+                       if (!IS_ALIGNED(offset, eb->fs_info->nodesize))
+                               pr_info("\t\t\t(parent %llu is NOT ALIGNED to nodesize %llu)\n",
+                                    offset, (unsigned long long)eb->fs_info->nodesize);
                        break;
                default:
-                       BUG();
+                       pr_cont("(extent %llu has INVALID ref type %d)\n",
+                                 eb->start, type);
+                       return;
                }
                ptr += btrfs_extent_inline_ref_size(type);
        }
@@ -161,8 +179,9 @@ static void print_uuid_item(struct extent_buffer *l, unsigned long offset,
        }
 }
 
-void btrfs_print_leaf(struct btrfs_fs_info *fs_info, struct extent_buffer *l)
+void btrfs_print_leaf(struct extent_buffer *l)
 {
+       struct btrfs_fs_info *fs_info;
        int i;
        u32 type, nr;
        struct btrfs_item *item;
@@ -180,6 +199,7 @@ void btrfs_print_leaf(struct btrfs_fs_info *fs_info, struct extent_buffer *l)
        if (!l)
                return;
 
+       fs_info = l->fs_info;
        nr = btrfs_header_nritems(l);
 
        btrfs_info(fs_info, "leaf %llu total ptrs %d free space %d",
@@ -318,18 +338,20 @@ void btrfs_print_leaf(struct btrfs_fs_info *fs_info, struct extent_buffer *l)
        }
 }
 
-void btrfs_print_tree(struct btrfs_fs_info *fs_info, struct extent_buffer *c)
+void btrfs_print_tree(struct extent_buffer *c)
 {
+       struct btrfs_fs_info *fs_info;
        int i; u32 nr;
        struct btrfs_key key;
        int level;
 
        if (!c)
                return;
+       fs_info = c->fs_info;
        nr = btrfs_header_nritems(c);
        level = btrfs_header_level(c);
        if (level == 0) {
-               btrfs_print_leaf(fs_info, c);
+               btrfs_print_leaf(c);
                return;
        }
        btrfs_info(fs_info,
@@ -359,7 +381,7 @@ void btrfs_print_tree(struct btrfs_fs_info *fs_info, struct extent_buffer *c)
                if (btrfs_header_level(next) !=
                       level - 1)
                        BUG();
-               btrfs_print_tree(fs_info, next);
+               btrfs_print_tree(next);
                free_extent_buffer(next);
        }
 }
index 4f2e0ea0e95aaaab8ee9e117397d9b1def371995..3afd508ed8c51895e187e8804dce9f238111b150 100644 (file)
@@ -18,6 +18,6 @@
 
 #ifndef __PRINT_TREE_
 #define __PRINT_TREE_
-void btrfs_print_leaf(struct btrfs_fs_info *fs_info, struct extent_buffer *l);
-void btrfs_print_tree(struct btrfs_fs_info *fs_info, struct extent_buffer *c);
+void btrfs_print_leaf(struct extent_buffer *l);
+void btrfs_print_tree(struct extent_buffer *c);
 #endif
index 4b23ae5d0e5c0330260ae96d2574b9422c16978d..09c0266f248d07737436b655cea98f6e93e15f37 100644 (file)
@@ -403,28 +403,28 @@ static int prop_compression_apply(struct inode *inode,
        if (len == 0) {
                BTRFS_I(inode)->flags |= BTRFS_INODE_NOCOMPRESS;
                BTRFS_I(inode)->flags &= ~BTRFS_INODE_COMPRESS;
-               BTRFS_I(inode)->force_compress = BTRFS_COMPRESS_NONE;
+               BTRFS_I(inode)->prop_compress = BTRFS_COMPRESS_NONE;
 
                return 0;
        }
 
-       if (!strncmp("lzo", value, len))
+       if (!strncmp("lzo", value, 3))
                type = BTRFS_COMPRESS_LZO;
-       else if (!strncmp("zlib", value, len))
+       else if (!strncmp("zlib", value, 4))
                type = BTRFS_COMPRESS_ZLIB;
        else
                return -EINVAL;
 
        BTRFS_I(inode)->flags &= ~BTRFS_INODE_NOCOMPRESS;
        BTRFS_I(inode)->flags |= BTRFS_INODE_COMPRESS;
-       BTRFS_I(inode)->force_compress = type;
+       BTRFS_I(inode)->prop_compress = type;
 
        return 0;
 }
 
 static const char *prop_compression_extract(struct inode *inode)
 {
-       switch (BTRFS_I(inode)->force_compress) {
+       switch (BTRFS_I(inode)->prop_compress) {
        case BTRFS_COMPRESS_ZLIB:
                return "zlib";
        case BTRFS_COMPRESS_LZO:
index 4ce351efe2813e101c74658873a25cff434633d6..5c8b61c86e61f9ed5445f5022a3b20f1134068bf 100644 (file)
@@ -946,7 +946,6 @@ out:
 int btrfs_quota_disable(struct btrfs_trans_handle *trans,
                        struct btrfs_fs_info *fs_info)
 {
-       struct btrfs_root *tree_root = fs_info->tree_root;
        struct btrfs_root *quota_root;
        int ret = 0;
 
@@ -968,7 +967,7 @@ int btrfs_quota_disable(struct btrfs_trans_handle *trans,
        if (ret)
                goto out;
 
-       ret = btrfs_del_root(trans, tree_root, &quota_root->root_key);
+       ret = btrfs_del_root(trans, fs_info, &quota_root->root_key);
        if (ret)
                goto out;
 
@@ -1603,7 +1602,7 @@ int btrfs_qgroup_trace_subtree(struct btrfs_trans_handle *trans,
        struct extent_buffer *eb = root_eb;
        struct btrfs_path *path = NULL;
 
-       BUG_ON(root_level < 0 || root_level > BTRFS_MAX_LEVEL);
+       BUG_ON(root_level < 0 || root_level >= BTRFS_MAX_LEVEL);
        BUG_ON(root_eb == NULL);
 
        if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags))
@@ -2646,7 +2645,7 @@ out:
        if (IS_ERR(trans)) {
                err = PTR_ERR(trans);
                btrfs_err(fs_info,
-                         "fail to start transaction for status update: %d\n",
+                         "fail to start transaction for status update: %d",
                          err);
                goto done;
        }
index 65661d1aae4e65c7314c98ad27d9139708e71103..3a49a3c2fca4549a8e6fd19cf4ec9de119aa0a5d 100644 (file)
@@ -32,6 +32,7 @@
 #include "free-space-cache.h"
 #include "inode-map.h"
 #include "qgroup.h"
+#include "print-tree.h"
 
 /*
  * backref_node, mapping_node and tree_block start with this
@@ -799,9 +800,17 @@ again:
                if (ptr < end) {
                        /* update key for inline back ref */
                        struct btrfs_extent_inline_ref *iref;
+                       int type;
                        iref = (struct btrfs_extent_inline_ref *)ptr;
-                       key.type = btrfs_extent_inline_ref_type(eb, iref);
+                       type = btrfs_get_extent_inline_ref_type(eb, iref,
+                                                       BTRFS_REF_TYPE_BLOCK);
+                       if (type == BTRFS_REF_TYPE_INVALID) {
+                               err = -EINVAL;
+                               goto out;
+                       }
+                       key.type = type;
                        key.offset = btrfs_extent_inline_ref_offset(eb, iref);
+
                        WARN_ON(key.type != BTRFS_TREE_BLOCK_REF_KEY &&
                                key.type != BTRFS_SHARED_BLOCK_REF_KEY);
                }
@@ -1308,8 +1317,6 @@ static int __must_check __add_reloc_root(struct btrfs_root *root)
                btrfs_panic(fs_info, -EEXIST,
                            "Duplicate root found for start=%llu while inserting into relocation tree",
                            node->bytenr);
-               kfree(node);
-               return -EEXIST;
        }
 
        list_add_tail(&root->root_list, &rc->reloc_roots);
@@ -3477,7 +3484,16 @@ again:
                        goto again;
                }
        }
-       BUG_ON(ret);
+       if (ret) {
+               ASSERT(ret == 1);
+               btrfs_print_leaf(path->nodes[0]);
+               btrfs_err(fs_info,
+            "tree block extent item (%llu) is not found in extent tree",
+                    bytenr);
+               WARN_ON(1);
+               ret = -EINVAL;
+               goto out;
+       }
 
        ret = add_tree_block(rc, &key, path, blocks);
 out:
@@ -3755,7 +3771,8 @@ int add_data_references(struct reloc_control *rc,
 
        while (ptr < end) {
                iref = (struct btrfs_extent_inline_ref *)ptr;
-               key.type = btrfs_extent_inline_ref_type(eb, iref);
+               key.type = btrfs_get_extent_inline_ref_type(eb, iref,
+                                                       BTRFS_REF_TYPE_DATA);
                if (key.type == BTRFS_SHARED_DATA_REF_KEY) {
                        key.offset = btrfs_extent_inline_ref_offset(eb, iref);
                        ret = __add_tree_block(rc, key.offset, blocksize,
@@ -3765,7 +3782,10 @@ int add_data_references(struct reloc_control *rc,
                        ret = find_data_references(rc, extent_key,
                                                   eb, dref, blocks);
                } else {
-                       BUG();
+                       ret = -EINVAL;
+                       btrfs_err(rc->extent_root->fs_info,
+                    "extent %llu slot %d has an invalid inline ref type",
+                            eb->start, path->slots[0]);
                }
                if (ret) {
                        err = ret;
index 460db0cb2d0734db78c52a934620953b5677de23..9fb9896610e0c43fb5c7b827ba7590c139c736ea 100644 (file)
@@ -151,7 +151,7 @@ int btrfs_update_root(struct btrfs_trans_handle *trans, struct btrfs_root
        }
 
        if (ret != 0) {
-               btrfs_print_leaf(fs_info, path->nodes[0]);
+               btrfs_print_leaf(path->nodes[0]);
                btrfs_crit(fs_info, "unable to update root key %llu %u %llu",
                           key->objectid, key->type, key->offset);
                BUG_ON(1);
@@ -335,10 +335,11 @@ int btrfs_find_orphan_roots(struct btrfs_fs_info *fs_info)
        return err;
 }
 
-/* drop the root item for 'key' from 'root' */
-int btrfs_del_root(struct btrfs_trans_handle *trans, struct btrfs_root *root,
-                  const struct btrfs_key *key)
+/* drop the root item for 'key' from the tree root */
+int btrfs_del_root(struct btrfs_trans_handle *trans,
+                  struct btrfs_fs_info *fs_info, const struct btrfs_key *key)
 {
+       struct btrfs_root *root = fs_info->tree_root;
        struct btrfs_path *path;
        int ret;
 
index b0b71e8e4c36d23b50133f4c10073bfcccefcc41..e3f6c49e5c4d8aad323b77f72ed6e12da26bee72 100644 (file)
@@ -182,8 +182,8 @@ struct scrub_ctx {
        struct scrub_bio        *wr_curr_bio;
        struct mutex            wr_lock;
        int                     pages_per_wr_bio; /* <= SCRUB_PAGES_PER_WR_BIO */
-       atomic_t                flush_all_writes;
        struct btrfs_device     *wr_tgtdev;
+       bool                    flush_all_writes;
 
        /*
         * statistics
@@ -717,7 +717,7 @@ struct scrub_ctx *scrub_setup_ctx(struct btrfs_device *dev, int is_dev_replace)
                WARN_ON(!fs_info->dev_replace.tgtdev);
                sctx->pages_per_wr_bio = SCRUB_PAGES_PER_WR_BIO;
                sctx->wr_tgtdev = fs_info->dev_replace.tgtdev;
-               atomic_set(&sctx->flush_all_writes, 0);
+               sctx->flush_all_writes = false;
        }
 
        return sctx;
@@ -1704,7 +1704,7 @@ static int scrub_submit_raid56_bio_wait(struct btrfs_fs_info *fs_info,
        if (ret)
                return ret;
 
-       wait_for_completion(&done.event);
+       wait_for_completion_io(&done.event);
        if (done.status)
                return -EIO;
 
@@ -1769,7 +1769,7 @@ static inline int scrub_check_fsid(u8 fsid[],
        struct btrfs_fs_devices *fs_devices = spage->dev->fs_devices;
        int ret;
 
-       ret = memcmp(fsid, fs_devices->fsid, BTRFS_UUID_SIZE);
+       ret = memcmp(fsid, fs_devices->fsid, BTRFS_FSID_SIZE);
        return !ret;
 }
 
@@ -2402,8 +2402,7 @@ static void scrub_missing_raid56_worker(struct btrfs_work *work)
 
        scrub_block_put(sblock);
 
-       if (sctx->is_dev_replace &&
-           atomic_read(&sctx->flush_all_writes)) {
+       if (sctx->is_dev_replace && sctx->flush_all_writes) {
                mutex_lock(&sctx->wr_lock);
                scrub_wr_submit(sctx);
                mutex_unlock(&sctx->wr_lock);
@@ -2607,8 +2606,7 @@ static void scrub_bio_end_io_worker(struct btrfs_work *work)
        sctx->first_free = sbio->index;
        spin_unlock(&sctx->list_lock);
 
-       if (sctx->is_dev_replace &&
-           atomic_read(&sctx->flush_all_writes)) {
+       if (sctx->is_dev_replace && sctx->flush_all_writes) {
                mutex_lock(&sctx->wr_lock);
                scrub_wr_submit(sctx);
                mutex_unlock(&sctx->wr_lock);
@@ -2622,7 +2620,8 @@ static inline void __scrub_mark_bitmap(struct scrub_parity *sparity,
                                       u64 start, u64 len)
 {
        u64 offset;
-       int nsectors;
+       u64 nsectors64;
+       u32 nsectors;
        int sectorsize = sparity->sctx->fs_info->sectorsize;
 
        if (len >= sparity->stripe_len) {
@@ -2633,7 +2632,10 @@ static inline void __scrub_mark_bitmap(struct scrub_parity *sparity,
        start -= sparity->logic_start;
        start = div64_u64_rem(start, sparity->stripe_len, &offset);
        offset = div_u64(offset, sectorsize);
-       nsectors = (int)len / sectorsize;
+       nsectors64 = div_u64(len, sectorsize);
+
+       ASSERT(nsectors64 < UINT_MAX);
+       nsectors = (u32)nsectors64;
 
        if (offset + nsectors <= sparity->nsectors) {
                bitmap_set(bitmap, offset, nsectors);
@@ -2706,7 +2708,9 @@ static int scrub_find_csum(struct scrub_ctx *sctx, u64 logical, u8 *csum)
        if (!sum)
                return 0;
 
-       index = ((u32)(logical - sum->bytenr)) / sctx->fs_info->sectorsize;
+       index = div_u64(logical - sum->bytenr, sctx->fs_info->sectorsize);
+       ASSERT(index < UINT_MAX);
+
        num_sectors = sum->len / sctx->fs_info->sectorsize;
        memcpy(csum, sum->sums + index, sctx->csum_size);
        if (index == num_sectors - 1) {
@@ -3440,14 +3444,14 @@ static noinline_for_stack int scrub_stripe(struct scrub_ctx *sctx,
                 */
                if (atomic_read(&fs_info->scrub_pause_req)) {
                        /* push queued extents */
-                       atomic_set(&sctx->flush_all_writes, 1);
+                       sctx->flush_all_writes = true;
                        scrub_submit(sctx);
                        mutex_lock(&sctx->wr_lock);
                        scrub_wr_submit(sctx);
                        mutex_unlock(&sctx->wr_lock);
                        wait_event(sctx->list_wait,
                                   atomic_read(&sctx->bios_in_flight) == 0);
-                       atomic_set(&sctx->flush_all_writes, 0);
+                       sctx->flush_all_writes = false;
                        scrub_blocked_if_needed(fs_info);
                }
 
@@ -3869,8 +3873,7 @@ int scrub_enumerate_chunks(struct scrub_ctx *sctx,
                        ro_set = 0;
                } else {
                        btrfs_warn(fs_info,
-                                  "failed setting block group ro, ret=%d\n",
-                                  ret);
+                                  "failed setting block group ro: %d", ret);
                        btrfs_put_block_group(cache);
                        break;
                }
@@ -3893,7 +3896,7 @@ int scrub_enumerate_chunks(struct scrub_ctx *sctx,
                 * write requests are really completed when bios_in_flight
                 * changes to 0.
                 */
-               atomic_set(&sctx->flush_all_writes, 1);
+               sctx->flush_all_writes = true;
                scrub_submit(sctx);
                mutex_lock(&sctx->wr_lock);
                scrub_wr_submit(sctx);
@@ -3911,7 +3914,7 @@ int scrub_enumerate_chunks(struct scrub_ctx *sctx,
                 */
                wait_event(sctx->list_wait,
                           atomic_read(&sctx->workers_pending) == 0);
-               atomic_set(&sctx->flush_all_writes, 0);
+               sctx->flush_all_writes = false;
 
                scrub_pause_off(fs_info);
 
@@ -4012,14 +4015,8 @@ static noinline_for_stack int scrub_workers_get(struct btrfs_fs_info *fs_info,
        int max_active = fs_info->thread_pool_size;
 
        if (fs_info->scrub_workers_refcnt == 0) {
-               if (is_dev_replace)
-                       fs_info->scrub_workers =
-                               btrfs_alloc_workqueue(fs_info, "scrub", flags,
-                                                     1, 4);
-               else
-                       fs_info->scrub_workers =
-                               btrfs_alloc_workqueue(fs_info, "scrub", flags,
-                                                     max_active, 4);
+               fs_info->scrub_workers = btrfs_alloc_workqueue(fs_info, "scrub",
+                               flags, is_dev_replace ? 1 : max_active, 4);
                if (!fs_info->scrub_workers)
                        goto fail_scrub_workers;
 
index b082210df9c8b44d822dcb20ae07fb56a76fdde3..8f1d3d6e7087a94d0a88e89d62238f143dc32e75 100644 (file)
@@ -4733,7 +4733,7 @@ static ssize_t fill_read_buf(struct send_ctx *sctx, u64 offset, u32 len)
        /* initial readahead */
        memset(&sctx->ra, 0, sizeof(struct file_ra_state));
        file_ra_state_init(&sctx->ra, inode->i_mapping);
-       btrfs_force_ra(inode->i_mapping, &sctx->ra, NULL, index,
+       page_cache_sync_readahead(inode->i_mapping, &sctx->ra, NULL, index,
                       last_index - index + 1);
 
        while (index <= last_index) {
@@ -4992,6 +4992,25 @@ static int clone_range(struct send_ctx *sctx,
        struct btrfs_key key;
        int ret;
 
+       /*
+        * Prevent cloning from a zero offset with a length matching the sector
+        * size because in some scenarios this will make the receiver fail.
+        *
+        * For example, if in the source filesystem the extent at offset 0
+        * has a length of sectorsize and it was written using direct IO, then
+        * it can never be an inline extent (even if compression is enabled).
+        * Then this extent can be cloned in the original filesystem to a non
+        * zero file offset, but it may not be possible to clone in the
+        * destination filesystem because it can be inlined due to compression
+        * on the destination filesystem (as the receiver's write operations are
+        * always done using buffered IO). The same happens when the original
+        * filesystem does not have compression enabled but the destination
+        * filesystem has.
+        */
+       if (clone_root->offset == 0 &&
+           len == sctx->send_root->fs_info->sectorsize)
+               return send_extent_data(sctx, offset, len);
+
        path = alloc_path_for_send();
        if (!path)
                return -ENOMEM;
index 875c757e73e2a8eacae1d9817bd83d56d32b21cf..5e2b92d8361735fb27d2b17ff132439821b4fb34 100644 (file)
@@ -50,8 +50,8 @@ static inline void put_unaligned_le8(u8 val, void *p)
  */
 
 #define DEFINE_BTRFS_SETGET_BITS(bits)                                 \
-u##bits btrfs_get_token_##bits(struct extent_buffer *eb, void *ptr,    \
-                              unsigned long off,                       \
+u##bits btrfs_get_token_##bits(const struct extent_buffer *eb,         \
+                              const void *ptr, unsigned long off,      \
                               struct btrfs_map_token *token)           \
 {                                                                      \
        unsigned long part_offset = (unsigned long)ptr;                 \
@@ -90,7 +90,8 @@ u##bits btrfs_get_token_##bits(struct extent_buffer *eb, void *ptr,   \
        return res;                                                     \
 }                                                                      \
 void btrfs_set_token_##bits(struct extent_buffer *eb,                  \
-                           void *ptr, unsigned long off, u##bits val,  \
+                           const void *ptr, unsigned long off,         \
+                           u##bits val,                                \
                            struct btrfs_map_token *token)              \
 {                                                                      \
        unsigned long part_offset = (unsigned long)ptr;                 \
@@ -133,7 +134,7 @@ DEFINE_BTRFS_SETGET_BITS(16)
 DEFINE_BTRFS_SETGET_BITS(32)
 DEFINE_BTRFS_SETGET_BITS(64)
 
-void btrfs_node_key(struct extent_buffer *eb,
+void btrfs_node_key(const struct extent_buffer *eb,
                    struct btrfs_disk_key *disk_key, int nr)
 {
        unsigned long ptr = btrfs_node_key_ptr_offset(nr);
index 12540b6104b5d9269baf4b35de420eca930b15af..0b7a1d8cd08bb767e3fd7fca1a5b30f5c44c4f1b 100644 (file)
@@ -61,6 +61,7 @@
 #include "tests/btrfs-tests.h"
 
 #include "qgroup.h"
+#include "backref.h"
 #define CREATE_TRACE_POINTS
 #include <trace/events/btrfs.h>
 
@@ -425,7 +426,7 @@ int btrfs_parse_options(struct btrfs_fs_info *info, char *options,
         * strsep changes the string, duplicate it because parse_options
         * gets called twice
         */
-       options = kstrdup(options, GFP_NOFS);
+       options = kstrdup(options, GFP_KERNEL);
        if (!options)
                return -ENOMEM;
 
@@ -498,14 +499,14 @@ int btrfs_parse_options(struct btrfs_fs_info *info, char *options,
                                btrfs_test_opt(info, FORCE_COMPRESS);
                        if (token == Opt_compress ||
                            token == Opt_compress_force ||
-                           strcmp(args[0].from, "zlib") == 0) {
+                           strncmp(args[0].from, "zlib", 4) == 0) {
                                compress_type = "zlib";
                                info->compress_type = BTRFS_COMPRESS_ZLIB;
                                btrfs_set_opt(info->mount_opt, COMPRESS);
                                btrfs_clear_opt(info->mount_opt, NODATACOW);
                                btrfs_clear_opt(info->mount_opt, NODATASUM);
                                no_compress = 0;
-                       } else if (strcmp(args[0].from, "lzo") == 0) {
+                       } else if (strncmp(args[0].from, "lzo", 3) == 0) {
                                compress_type = "lzo";
                                info->compress_type = BTRFS_COMPRESS_LZO;
                                btrfs_set_opt(info->mount_opt, COMPRESS);
@@ -548,20 +549,22 @@ int btrfs_parse_options(struct btrfs_fs_info *info, char *options,
                        break;
                case Opt_ssd:
                        btrfs_set_and_info(info, SSD,
-                                          "use ssd allocation scheme");
+                                          "enabling ssd optimizations");
                        btrfs_clear_opt(info->mount_opt, NOSSD);
                        break;
                case Opt_ssd_spread:
+                       btrfs_set_and_info(info, SSD,
+                                          "enabling ssd optimizations");
                        btrfs_set_and_info(info, SSD_SPREAD,
-                                          "use spread ssd allocation scheme");
-                       btrfs_set_opt(info->mount_opt, SSD);
+                                          "using spread ssd allocation scheme");
                        btrfs_clear_opt(info->mount_opt, NOSSD);
                        break;
                case Opt_nossd:
-                       btrfs_set_and_info(info, NOSSD,
-                                            "not using ssd allocation scheme");
-                       btrfs_clear_opt(info->mount_opt, SSD);
-                       btrfs_clear_opt(info->mount_opt, SSD_SPREAD);
+                       btrfs_set_opt(info->mount_opt, NOSSD);
+                       btrfs_clear_and_info(info, SSD,
+                                            "not using ssd optimizations");
+                       btrfs_clear_and_info(info, SSD_SPREAD,
+                                            "not using spread ssd allocation scheme");
                        break;
                case Opt_barrier:
                        btrfs_clear_and_info(info, NOBARRIER,
@@ -949,7 +952,7 @@ static char *get_subvol_name_from_objectid(struct btrfs_fs_info *fs_info,
        }
        path->leave_spinning = 1;
 
-       name = kmalloc(PATH_MAX, GFP_NOFS);
+       name = kmalloc(PATH_MAX, GFP_KERNEL);
        if (!name) {
                ret = -ENOMEM;
                goto err;
@@ -1335,10 +1338,11 @@ static char *setup_root_args(char *args)
        char *buf, *dst, *sep;
 
        if (!args)
-               return kstrdup("subvolid=0", GFP_NOFS);
+               return kstrdup("subvolid=0", GFP_KERNEL);
 
        /* The worst case is that we add ",subvolid=0" to the end. */
-       buf = dst = kmalloc(strlen(args) + strlen(",subvolid=0") + 1, GFP_NOFS);
+       buf = dst = kmalloc(strlen(args) + strlen(",subvolid=0") + 1,
+                       GFP_KERNEL);
        if (!buf)
                return NULL;
 
@@ -1567,7 +1571,7 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags,
         * it for searching for existing supers, so this lets us do that and
         * then open_ctree will properly initialize everything later.
         */
-       fs_info = kzalloc(sizeof(struct btrfs_fs_info), GFP_NOFS);
+       fs_info = kzalloc(sizeof(struct btrfs_fs_info), GFP_KERNEL);
        if (!fs_info) {
                error = -ENOMEM;
                goto error_sec_opts;
@@ -1575,8 +1579,8 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags,
 
        fs_info->fs_devices = fs_devices;
 
-       fs_info->super_copy = kzalloc(BTRFS_SUPER_INFO_SIZE, GFP_NOFS);
-       fs_info->super_for_commit = kzalloc(BTRFS_SUPER_INFO_SIZE, GFP_NOFS);
+       fs_info->super_copy = kzalloc(BTRFS_SUPER_INFO_SIZE, GFP_KERNEL);
+       fs_info->super_for_commit = kzalloc(BTRFS_SUPER_INFO_SIZE, GFP_KERNEL);
        security_init_mnt_opts(&fs_info->security_opts);
        if (!fs_info->super_copy || !fs_info->super_for_commit) {
                error = -ENOMEM;
@@ -1780,8 +1784,7 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data)
                        goto restore;
                }
 
-               if (fs_info->fs_devices->missing_devices >
-                    fs_info->num_tolerated_disk_barrier_failures) {
+               if (!btrfs_check_rw_degradable(fs_info)) {
                        btrfs_warn(fs_info,
                                "too many missing devices, writeable remount is not allowed");
                        ret = -EACCES;
@@ -1814,6 +1817,8 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data)
                        goto restore;
                }
 
+               btrfs_qgroup_rescan_resume(fs_info);
+
                if (!fs_info->uuid_root) {
                        btrfs_info(fs_info, "creating UUID tree");
                        ret = btrfs_create_uuid_tree(fs_info);
index b18ab8f327a53dd10b09bee6169f34ecff5eb809..d3f25376a0f86d255fa2db7999ff8da612422da9 100644 (file)
@@ -211,7 +211,6 @@ btrfs_alloc_dummy_block_group(struct btrfs_fs_info *fs_info,
        cache->key.objectid = 0;
        cache->key.offset = length;
        cache->key.type = BTRFS_BLOCK_GROUP_ITEM_KEY;
-       cache->sectorsize = fs_info->sectorsize;
        cache->full_stripe_len = fs_info->sectorsize;
        cache->fs_info = fs_info;
 
index b29954c016738ad05c40ebefb2ba34f4cb8d75ca..1458bb0ea124a3784403adf6196e9bd146098b0d 100644 (file)
@@ -81,7 +81,7 @@ static int __check_free_space_extents(struct btrfs_trans_handle *trans,
                                        i++;
                                }
                                prev_bit = bit;
-                               offset += cache->sectorsize;
+                               offset += fs_info->sectorsize;
                        }
                }
                if (prev_bit == 1) {
index 3a11ae63676ea8a299828c18fc772e74e57a07e5..ad7f4bab640be36d9f43b8b2f3371a7bd871738f 100644 (file)
@@ -1143,8 +1143,6 @@ again:
                                goto again;
                        }
                        kfree(victim_name);
-                       if (ret)
-                               return ret;
 next:
                        cur_offset += victim_name_len + sizeof(*extref);
                }
@@ -3690,7 +3688,7 @@ static noinline int copy_items(struct btrfs_trans_handle *trans,
 
                src_offset = btrfs_item_ptr_offset(src, start_slot + i);
 
-               if ((i == (nr - 1)))
+               if (i == nr - 1)
                        last_key = ins_keys[i];
 
                if (ins_keys[i].type == BTRFS_INODE_ITEM_KEY) {
@@ -4450,7 +4448,10 @@ static int btrfs_log_trailing_hole(struct btrfs_trans_handle *trans,
                        len = btrfs_file_extent_inline_len(leaf,
                                                           path->slots[0],
                                                           extent);
-                       ASSERT(len == i_size);
+                       ASSERT(len == i_size ||
+                              (len == fs_info->sectorsize &&
+                               btrfs_file_extent_compression(leaf, extent) !=
+                               BTRFS_COMPRESS_NONE));
                        return 0;
                }
 
index 002aa318da67bb560979430ae6eee0f6ad263417..c188256a367c99ebdcff970ce13147e4365a2cbd 100644 (file)
@@ -152,7 +152,15 @@ struct list_head *btrfs_get_fs_uuids(void)
        return &fs_uuids;
 }
 
-static struct btrfs_fs_devices *__alloc_fs_devices(void)
+/*
+ * alloc_fs_devices - allocate struct btrfs_fs_devices
+ * @fsid:      if not NULL, copy the uuid to fs_devices::fsid
+ *
+ * Return a pointer to a new struct btrfs_fs_devices on success, or ERR_PTR().
+ * The returned struct is not linked onto any lists and can be destroyed with
+ * kfree() right away.
+ */
+static struct btrfs_fs_devices *alloc_fs_devices(const u8 *fsid)
 {
        struct btrfs_fs_devices *fs_devs;
 
@@ -166,31 +174,8 @@ static struct btrfs_fs_devices *__alloc_fs_devices(void)
        INIT_LIST_HEAD(&fs_devs->resized_devices);
        INIT_LIST_HEAD(&fs_devs->alloc_list);
        INIT_LIST_HEAD(&fs_devs->list);
-
-       return fs_devs;
-}
-
-/**
- * alloc_fs_devices - allocate struct btrfs_fs_devices
- * @fsid:      a pointer to UUID for this FS.  If NULL a new UUID is
- *             generated.
- *
- * Return: a pointer to a new &struct btrfs_fs_devices on success;
- * ERR_PTR() on error.  Returned struct is not linked onto any lists and
- * can be destroyed with kfree() right away.
- */
-static struct btrfs_fs_devices *alloc_fs_devices(const u8 *fsid)
-{
-       struct btrfs_fs_devices *fs_devs;
-
-       fs_devs = __alloc_fs_devices();
-       if (IS_ERR(fs_devs))
-               return fs_devs;
-
        if (fsid)
                memcpy(fs_devs->fsid, fsid, BTRFS_FSID_SIZE);
-       else
-               generate_random_uuid(fs_devs->fsid);
 
        return fs_devs;
 }
@@ -269,9 +254,17 @@ static struct btrfs_device *__alloc_device(void)
        return dev;
 }
 
-static noinline struct btrfs_device *__find_device(struct list_head *head,
-                                                  u64 devid, u8 *uuid)
+/*
+ * Find a device specified by @devid or @uuid in the list of @fs_devices, or
+ * return NULL.
+ *
+ * If devid and uuid are both specified, the match must be exact, otherwise
+ * only devid is used.
+ */
+static struct btrfs_device *find_device(struct btrfs_fs_devices *fs_devices,
+               u64 devid, const u8 *uuid)
 {
+       struct list_head *head = &fs_devices->devices;
        struct btrfs_device *dev;
 
        list_for_each_entry(dev, head, dev_list) {
@@ -310,7 +303,7 @@ btrfs_get_bdev_and_sb(const char *device_path, fmode_t flags, void *holder,
 
        if (flush)
                filemap_write_and_wait((*bdev)->bd_inode->i_mapping);
-       ret = set_blocksize(*bdev, 4096);
+       ret = set_blocksize(*bdev, BTRFS_BDEV_BLOCKSIZE);
        if (ret) {
                blkdev_put(*bdev, flags);
                goto error;
@@ -636,8 +629,8 @@ static noinline int device_list_add(const char *path,
 
                device = NULL;
        } else {
-               device = __find_device(&fs_devices->devices, devid,
-                                      disk_super->dev_item.uuid);
+               device = find_device(fs_devices, devid,
+                               disk_super->dev_item.uuid);
        }
 
        if (!device) {
@@ -1578,7 +1571,6 @@ out:
 
 static int btrfs_alloc_dev_extent(struct btrfs_trans_handle *trans,
                                  struct btrfs_device *device,
-                                 u64 chunk_tree, u64 chunk_objectid,
                                  u64 chunk_offset, u64 start, u64 num_bytes)
 {
        int ret;
@@ -1606,12 +1598,12 @@ static int btrfs_alloc_dev_extent(struct btrfs_trans_handle *trans,
        leaf = path->nodes[0];
        extent = btrfs_item_ptr(leaf, path->slots[0],
                                struct btrfs_dev_extent);
-       btrfs_set_dev_extent_chunk_tree(leaf, extent, chunk_tree);
-       btrfs_set_dev_extent_chunk_objectid(leaf, extent, chunk_objectid);
+       btrfs_set_dev_extent_chunk_tree(leaf, extent,
+                                       BTRFS_CHUNK_TREE_OBJECTID);
+       btrfs_set_dev_extent_chunk_objectid(leaf, extent,
+                                           BTRFS_FIRST_CHUNK_TREE_OBJECTID);
        btrfs_set_dev_extent_chunk_offset(leaf, extent, chunk_offset);
 
-       write_extent_buffer_chunk_tree_uuid(leaf, fs_info->chunk_tree_uuid);
-
        btrfs_set_dev_extent_length(leaf, extent, num_bytes);
        btrfs_mark_buffer_dirty(leaf);
 out:
@@ -1726,7 +1718,7 @@ static int btrfs_add_device(struct btrfs_trans_handle *trans,
        ptr = btrfs_device_uuid(dev_item);
        write_extent_buffer(leaf, device->uuid, ptr, BTRFS_UUID_SIZE);
        ptr = btrfs_device_fsid(dev_item);
-       write_extent_buffer(leaf, fs_info->fsid, ptr, BTRFS_UUID_SIZE);
+       write_extent_buffer(leaf, fs_info->fsid, ptr, BTRFS_FSID_SIZE);
        btrfs_mark_buffer_dirty(leaf);
 
        ret = 0;
@@ -1872,7 +1864,6 @@ int btrfs_rm_device(struct btrfs_fs_info *fs_info, const char *device_path,
        struct btrfs_fs_devices *cur_devices;
        u64 num_devices;
        int ret = 0;
-       bool clear_super = false;
 
        mutex_lock(&uuid_mutex);
 
@@ -1908,7 +1899,6 @@ int btrfs_rm_device(struct btrfs_fs_info *fs_info, const char *device_path,
                list_del_init(&device->dev_alloc_list);
                device->fs_devices->rw_devices--;
                mutex_unlock(&fs_info->chunk_mutex);
-               clear_super = true;
        }
 
        mutex_unlock(&uuid_mutex);
@@ -1987,9 +1977,6 @@ int btrfs_rm_device(struct btrfs_fs_info *fs_info, const char *device_path,
                free_fs_devices(cur_devices);
        }
 
-       fs_info->num_tolerated_disk_barrier_failures =
-               btrfs_calc_num_tolerated_disk_barrier_failures(fs_info);
-
 out:
        mutex_unlock(&uuid_mutex);
        return ret;
@@ -2202,7 +2189,7 @@ static int btrfs_prepare_sprout(struct btrfs_fs_info *fs_info)
        if (!fs_devices->seeding)
                return -EINVAL;
 
-       seed_devices = __alloc_fs_devices();
+       seed_devices = alloc_fs_devices(NULL);
        if (IS_ERR(seed_devices))
                return PTR_ERR(seed_devices);
 
@@ -2261,7 +2248,7 @@ static int btrfs_finish_sprout(struct btrfs_trans_handle *trans,
        struct btrfs_dev_item *dev_item;
        struct btrfs_device *device;
        struct btrfs_key key;
-       u8 fs_uuid[BTRFS_UUID_SIZE];
+       u8 fs_uuid[BTRFS_FSID_SIZE];
        u8 dev_uuid[BTRFS_UUID_SIZE];
        u64 devid;
        int ret;
@@ -2304,7 +2291,7 @@ next_slot:
                read_extent_buffer(leaf, dev_uuid, btrfs_device_uuid(dev_item),
                                   BTRFS_UUID_SIZE);
                read_extent_buffer(leaf, fs_uuid, btrfs_device_fsid(dev_item),
-                                  BTRFS_UUID_SIZE);
+                                  BTRFS_FSID_SIZE);
                device = btrfs_find_device(fs_info, devid, dev_uuid, fs_uuid);
                BUG_ON(!device); /* Logic error */
 
@@ -2407,7 +2394,7 @@ int btrfs_init_new_device(struct btrfs_fs_info *fs_info, const char *device_path
        device->is_tgtdev_for_dev_replace = 0;
        device->mode = FMODE_EXCL;
        device->dev_stats_valid = 1;
-       set_blocksize(device->bdev, 4096);
+       set_blocksize(device->bdev, BTRFS_BDEV_BLOCKSIZE);
 
        if (seeding_dev) {
                sb->s_flags &= ~MS_RDONLY;
@@ -2487,8 +2474,6 @@ int btrfs_init_new_device(struct btrfs_fs_info *fs_info, const char *device_path
                                   "sysfs: failed to create fsid for sprout");
        }
 
-       fs_info->num_tolerated_disk_barrier_failures =
-               btrfs_calc_num_tolerated_disk_barrier_failures(fs_info);
        ret = btrfs_commit_transaction(trans);
 
        if (seeding_dev) {
@@ -2612,7 +2597,7 @@ int btrfs_init_dev_replace_tgtdev(struct btrfs_fs_info *fs_info,
        device->is_tgtdev_for_dev_replace = 1;
        device->mode = FMODE_EXCL;
        device->dev_stats_valid = 1;
-       set_blocksize(device->bdev, 4096);
+       set_blocksize(device->bdev, BTRFS_BDEV_BLOCKSIZE);
        device->fs_devices = fs_info->fs_devices;
        list_add(&device->dev_list, &fs_info->fs_devices->devices);
        fs_info->fs_devices->num_devices++;
@@ -2728,8 +2713,7 @@ int btrfs_grow_device(struct btrfs_trans_handle *trans,
 }
 
 static int btrfs_free_chunk(struct btrfs_trans_handle *trans,
-                           struct btrfs_fs_info *fs_info, u64 chunk_objectid,
-                           u64 chunk_offset)
+                           struct btrfs_fs_info *fs_info, u64 chunk_offset)
 {
        struct btrfs_root *root = fs_info->chunk_root;
        int ret;
@@ -2740,7 +2724,7 @@ static int btrfs_free_chunk(struct btrfs_trans_handle *trans,
        if (!path)
                return -ENOMEM;
 
-       key.objectid = chunk_objectid;
+       key.objectid = BTRFS_FIRST_CHUNK_TREE_OBJECTID;
        key.offset = chunk_offset;
        key.type = BTRFS_CHUNK_ITEM_KEY;
 
@@ -2763,8 +2747,7 @@ out:
        return ret;
 }
 
-static int btrfs_del_sys_chunk(struct btrfs_fs_info *fs_info,
-                              u64 chunk_objectid, u64 chunk_offset)
+static int btrfs_del_sys_chunk(struct btrfs_fs_info *fs_info, u64 chunk_offset)
 {
        struct btrfs_super_block *super_copy = fs_info->super_copy;
        struct btrfs_disk_key *disk_key;
@@ -2797,7 +2780,7 @@ static int btrfs_del_sys_chunk(struct btrfs_fs_info *fs_info,
                        ret = -EIO;
                        break;
                }
-               if (key.objectid == chunk_objectid &&
+               if (key.objectid == BTRFS_FIRST_CHUNK_TREE_OBJECTID &&
                    key.offset == chunk_offset) {
                        memmove(ptr, ptr + len, array_size - (cur + len));
                        array_size -= len;
@@ -2846,7 +2829,6 @@ int btrfs_remove_chunk(struct btrfs_trans_handle *trans,
        struct extent_map *em;
        struct map_lookup *map;
        u64 dev_extent_len = 0;
-       u64 chunk_objectid = BTRFS_FIRST_CHUNK_TREE_OBJECTID;
        int i, ret = 0;
        struct btrfs_fs_devices *fs_devices = fs_info->fs_devices;
 
@@ -2902,7 +2884,7 @@ int btrfs_remove_chunk(struct btrfs_trans_handle *trans,
        }
        mutex_unlock(&fs_devices->device_list_mutex);
 
-       ret = btrfs_free_chunk(trans, fs_info, chunk_objectid, chunk_offset);
+       ret = btrfs_free_chunk(trans, fs_info, chunk_offset);
        if (ret) {
                btrfs_abort_transaction(trans, ret);
                goto out;
@@ -2911,8 +2893,7 @@ int btrfs_remove_chunk(struct btrfs_trans_handle *trans,
        trace_btrfs_chunk_free(fs_info, map, chunk_offset, em->len);
 
        if (map->type & BTRFS_BLOCK_GROUP_SYSTEM) {
-               ret = btrfs_del_sys_chunk(fs_info, chunk_objectid,
-                                         chunk_offset);
+               ret = btrfs_del_sys_chunk(fs_info, chunk_offset);
                if (ret) {
                        btrfs_abort_transaction(trans, ret);
                        goto out;
@@ -3312,7 +3293,6 @@ static int chunk_devid_filter(struct extent_buffer *leaf,
 /* [pstart, pend) */
 static int chunk_drange_filter(struct extent_buffer *leaf,
                               struct btrfs_chunk *chunk,
-                              u64 chunk_offset,
                               struct btrfs_balance_args *bargs)
 {
        struct btrfs_stripe *stripe;
@@ -3439,7 +3419,7 @@ static int should_balance_chunk(struct btrfs_fs_info *fs_info,
 
        /* drange filter, makes sense only with devid filter */
        if ((bargs->flags & BTRFS_BALANCE_ARGS_DRANGE) &&
-           chunk_drange_filter(leaf, chunk, chunk_offset, bargs)) {
+           chunk_drange_filter(leaf, chunk, bargs)) {
                return 0;
        }
 
@@ -3898,13 +3878,6 @@ int btrfs_balance(struct btrfs_balance_control *bctl,
                           meta_target, data_target);
        }
 
-       if (bctl->sys.flags & BTRFS_BALANCE_ARGS_CONVERT) {
-               fs_info->num_tolerated_disk_barrier_failures = min(
-                       btrfs_calc_num_tolerated_disk_barrier_failures(fs_info),
-                       btrfs_get_num_tolerated_disk_barrier_failures(
-                               bctl->sys.target));
-       }
-
        ret = insert_balance_item(fs_info, bctl);
        if (ret && ret != -EEXIST)
                goto out;
@@ -3927,11 +3900,6 @@ int btrfs_balance(struct btrfs_balance_control *bctl,
        mutex_lock(&fs_info->balance_mutex);
        atomic_dec(&fs_info->balance_running);
 
-       if (bctl->sys.flags & BTRFS_BALANCE_ARGS_CONVERT) {
-               fs_info->num_tolerated_disk_barrier_failures =
-                       btrfs_calc_num_tolerated_disk_barrier_failures(fs_info);
-       }
-
        if (bargs) {
                memset(bargs, 0, sizeof(*bargs));
                update_ioctl_balance_args(fs_info, 0, bargs);
@@ -4127,7 +4095,6 @@ static int btrfs_uuid_scan_kthread(void *data)
        struct btrfs_fs_info *fs_info = data;
        struct btrfs_root *root = fs_info->tree_root;
        struct btrfs_key key;
-       struct btrfs_key max_key;
        struct btrfs_path *path = NULL;
        int ret = 0;
        struct extent_buffer *eb;
@@ -4146,10 +4113,6 @@ static int btrfs_uuid_scan_kthread(void *data)
        key.type = BTRFS_ROOT_ITEM_KEY;
        key.offset = 0;
 
-       max_key.objectid = (u64)-1;
-       max_key.type = BTRFS_ROOT_ITEM_KEY;
-       max_key.offset = (u64)-1;
-
        while (1) {
                ret = btrfs_search_forward(root, &key, path, 0);
                if (ret) {
@@ -4601,12 +4564,6 @@ static int btrfs_cmp_device_info(const void *a, const void *b)
        return 0;
 }
 
-static u32 find_raid56_stripe_len(u32 data_devices, u32 dev_stripe_target)
-{
-       /* TODO allow them to set a preferred stripe size */
-       return SZ_64K;
-}
-
 static void check_raid56_incompat_flag(struct btrfs_fs_info *info, u64 type)
 {
        if (!(type & BTRFS_BLOCK_GROUP_RAID56_MASK))
@@ -4629,7 +4586,7 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
 {
        struct btrfs_fs_info *info = trans->fs_info;
        struct btrfs_fs_devices *fs_devices = info->fs_devices;
-       struct list_head *cur;
+       struct btrfs_device *device;
        struct map_lookup *map = NULL;
        struct extent_map_tree *em_tree;
        struct extent_map *em;
@@ -4649,7 +4606,6 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
        u64 max_chunk_size;
        u64 stripe_size;
        u64 num_bytes;
-       u64 raid_stripe_len = BTRFS_STRIPE_LEN;
        int ndevs;
        int i;
        int j;
@@ -4703,22 +4659,15 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
        if (!devices_info)
                return -ENOMEM;
 
-       cur = fs_devices->alloc_list.next;
-
        /*
         * in the first pass through the devices list, we gather information
         * about the available holes on each device.
         */
        ndevs = 0;
-       while (cur != &fs_devices->alloc_list) {
-               struct btrfs_device *device;
+       list_for_each_entry(device, &fs_devices->alloc_list, dev_alloc_list) {
                u64 max_avail;
                u64 dev_offset;
 
-               device = list_entry(cur, struct btrfs_device, dev_alloc_list);
-
-               cur = cur->next;
-
                if (!device->writeable) {
                        WARN(1, KERN_ERR
                               "BTRFS: read-only device in alloc_list\n");
@@ -4769,15 +4718,15 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
             btrfs_cmp_device_info, NULL);
 
        /* round down to number of usable stripes */
-       ndevs -= ndevs % devs_increment;
+       ndevs = round_down(ndevs, devs_increment);
 
        if (ndevs < devs_increment * sub_stripes || ndevs < devs_min) {
                ret = -ENOSPC;
                goto error;
        }
 
-       if (devs_max && ndevs > devs_max)
-               ndevs = devs_max;
+       ndevs = min(ndevs, devs_max);
+
        /*
         * the primary goal is to maximize the number of stripes, so use as many
         * devices as possible, even if the stripes are not maximum sized.
@@ -4791,16 +4740,11 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
         */
        data_stripes = num_stripes / ncopies;
 
-       if (type & BTRFS_BLOCK_GROUP_RAID5) {
-               raid_stripe_len = find_raid56_stripe_len(ndevs - 1,
-                                                        info->stripesize);
+       if (type & BTRFS_BLOCK_GROUP_RAID5)
                data_stripes = num_stripes - 1;
-       }
-       if (type & BTRFS_BLOCK_GROUP_RAID6) {
-               raid_stripe_len = find_raid56_stripe_len(ndevs - 2,
-                                                        info->stripesize);
+
+       if (type & BTRFS_BLOCK_GROUP_RAID6)
                data_stripes = num_stripes - 2;
-       }
 
        /*
         * Use the number of data stripes to figure out how big this chunk
@@ -4825,8 +4769,7 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
        stripe_size = div_u64(stripe_size, dev_stripes);
 
        /* align to BTRFS_STRIPE_LEN */
-       stripe_size = div64_u64(stripe_size, raid_stripe_len);
-       stripe_size *= raid_stripe_len;
+       stripe_size = round_down(stripe_size, BTRFS_STRIPE_LEN);
 
        map = kmalloc(map_lookup_size(num_stripes), GFP_NOFS);
        if (!map) {
@@ -4843,10 +4786,9 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
                                                   j * stripe_size;
                }
        }
-       map->sector_size = info->sectorsize;
-       map->stripe_len = raid_stripe_len;
-       map->io_align = raid_stripe_len;
-       map->io_width = raid_stripe_len;
+       map->stripe_len = BTRFS_STRIPE_LEN;
+       map->io_align = BTRFS_STRIPE_LEN;
+       map->io_width = BTRFS_STRIPE_LEN;
        map->type = type;
        map->sub_stripes = sub_stripes;
 
@@ -4881,9 +4823,7 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
                goto error;
        }
 
-       ret = btrfs_make_block_group(trans, info, 0, type,
-                                    BTRFS_FIRST_CHUNK_TREE_OBJECTID,
-                                    start, num_bytes);
+       ret = btrfs_make_block_group(trans, info, 0, type, start, num_bytes);
        if (ret)
                goto error_del_extent;
 
@@ -4963,11 +4903,8 @@ int btrfs_finish_chunk_alloc(struct btrfs_trans_handle *trans,
                ret = btrfs_update_device(trans, device);
                if (ret)
                        break;
-               ret = btrfs_alloc_dev_extent(trans, device,
-                                            chunk_root->root_key.objectid,
-                                            BTRFS_FIRST_CHUNK_TREE_OBJECTID,
-                                            chunk_offset, dev_offset,
-                                            stripe_size);
+               ret = btrfs_alloc_dev_extent(trans, device, chunk_offset,
+                                            dev_offset, stripe_size);
                if (ret)
                        break;
        }
@@ -5172,7 +5109,6 @@ int btrfs_num_copies(struct btrfs_fs_info *fs_info, u64 logical, u64 len)
 }
 
 unsigned long btrfs_full_stripe_len(struct btrfs_fs_info *fs_info,
-                                   struct btrfs_mapping_tree *map_tree,
                                    u64 logical)
 {
        struct extent_map *em;
@@ -5180,29 +5116,30 @@ unsigned long btrfs_full_stripe_len(struct btrfs_fs_info *fs_info,
        unsigned long len = fs_info->sectorsize;
 
        em = get_chunk_map(fs_info, logical, len);
-       WARN_ON(IS_ERR(em));
 
-       map = em->map_lookup;
-       if (map->type & BTRFS_BLOCK_GROUP_RAID56_MASK)
-               len = map->stripe_len * nr_data_stripes(map);
-       free_extent_map(em);
+       if (!WARN_ON(IS_ERR(em))) {
+               map = em->map_lookup;
+               if (map->type & BTRFS_BLOCK_GROUP_RAID56_MASK)
+                       len = map->stripe_len * nr_data_stripes(map);
+               free_extent_map(em);
+       }
        return len;
 }
 
-int btrfs_is_parity_mirror(struct btrfs_fs_info *fs_info,
-                          u64 logical, u64 len, int mirror_num)
+int btrfs_is_parity_mirror(struct btrfs_fs_info *fs_info, u64 logical, u64 len)
 {
        struct extent_map *em;
        struct map_lookup *map;
        int ret = 0;
 
        em = get_chunk_map(fs_info, logical, len);
-       WARN_ON(IS_ERR(em));
 
-       map = em->map_lookup;
-       if (map->type & BTRFS_BLOCK_GROUP_RAID56_MASK)
-               ret = 1;
-       free_extent_map(em);
+       if(!WARN_ON(IS_ERR(em))) {
+               map = em->map_lookup;
+               if (map->type & BTRFS_BLOCK_GROUP_RAID56_MASK)
+                       ret = 1;
+               free_extent_map(em);
+       }
        return ret;
 }
 
@@ -6295,9 +6232,8 @@ struct btrfs_device *btrfs_find_device(struct btrfs_fs_info *fs_info, u64 devid,
        cur_devices = fs_info->fs_devices;
        while (cur_devices) {
                if (!fsid ||
-                   !memcmp(cur_devices->fsid, fsid, BTRFS_UUID_SIZE)) {
-                       device = __find_device(&cur_devices->devices,
-                                              devid, uuid);
+                   !memcmp(cur_devices->fsid, fsid, BTRFS_FSID_SIZE)) {
+                       device = find_device(cur_devices, devid, uuid);
                        if (device)
                                return device;
                }
@@ -6450,7 +6386,6 @@ static int read_one_chunk(struct btrfs_fs_info *fs_info, struct btrfs_key *key,
        struct extent_map *em;
        u64 logical;
        u64 length;
-       u64 stripe_len;
        u64 devid;
        u8 uuid[BTRFS_UUID_SIZE];
        int num_stripes;
@@ -6459,7 +6394,6 @@ static int read_one_chunk(struct btrfs_fs_info *fs_info, struct btrfs_key *key,
 
        logical = key->offset;
        length = btrfs_chunk_length(leaf, chunk);
-       stripe_len = btrfs_chunk_stripe_len(leaf, chunk);
        num_stripes = btrfs_chunk_num_stripes(leaf, chunk);
 
        ret = btrfs_check_chunk_valid(fs_info, leaf, chunk, logical);
@@ -6498,7 +6432,6 @@ static int read_one_chunk(struct btrfs_fs_info *fs_info, struct btrfs_key *key,
        map->num_stripes = num_stripes;
        map->io_width = btrfs_chunk_io_width(leaf, chunk);
        map->io_align = btrfs_chunk_io_align(leaf, chunk);
-       map->sector_size = btrfs_chunk_sector_size(leaf, chunk);
        map->stripe_len = btrfs_chunk_stripe_len(leaf, chunk);
        map->type = btrfs_chunk_type(leaf, chunk);
        map->sub_stripes = btrfs_chunk_sub_stripes(leaf, chunk);
@@ -6514,6 +6447,7 @@ static int read_one_chunk(struct btrfs_fs_info *fs_info, struct btrfs_key *key,
                if (!map->stripes[i].dev &&
                    !btrfs_test_opt(fs_info, DEGRADED)) {
                        free_extent_map(em);
+                       btrfs_report_missing_device(fs_info, devid, uuid);
                        return -EIO;
                }
                if (!map->stripes[i].dev) {
@@ -6524,8 +6458,7 @@ static int read_one_chunk(struct btrfs_fs_info *fs_info, struct btrfs_key *key,
                                free_extent_map(em);
                                return -EIO;
                        }
-                       btrfs_warn(fs_info, "devid %llu uuid %pU is missing",
-                                  devid, uuid);
+                       btrfs_report_missing_device(fs_info, devid, uuid);
                }
                map->stripes[i].dev->in_fs_metadata = 1;
        }
@@ -6569,10 +6502,11 @@ static struct btrfs_fs_devices *open_seed_devices(struct btrfs_fs_info *fs_info,
        int ret;
 
        BUG_ON(!mutex_is_locked(&uuid_mutex));
+       ASSERT(fsid);
 
        fs_devices = fs_info->fs_devices->seed;
        while (fs_devices) {
-               if (!memcmp(fs_devices->fsid, fsid, BTRFS_UUID_SIZE))
+               if (!memcmp(fs_devices->fsid, fsid, BTRFS_FSID_SIZE))
                        return fs_devices;
 
                fs_devices = fs_devices->seed;
@@ -6625,16 +6559,16 @@ static int read_one_dev(struct btrfs_fs_info *fs_info,
        struct btrfs_device *device;
        u64 devid;
        int ret;
-       u8 fs_uuid[BTRFS_UUID_SIZE];
+       u8 fs_uuid[BTRFS_FSID_SIZE];
        u8 dev_uuid[BTRFS_UUID_SIZE];
 
        devid = btrfs_device_id(leaf, dev_item);
        read_extent_buffer(leaf, dev_uuid, btrfs_device_uuid(dev_item),
                           BTRFS_UUID_SIZE);
        read_extent_buffer(leaf, fs_uuid, btrfs_device_fsid(dev_item),
-                          BTRFS_UUID_SIZE);
+                          BTRFS_FSID_SIZE);
 
-       if (memcmp(fs_uuid, fs_info->fsid, BTRFS_UUID_SIZE)) {
+       if (memcmp(fs_uuid, fs_info->fsid, BTRFS_FSID_SIZE)) {
                fs_devices = open_seed_devices(fs_info, fs_uuid);
                if (IS_ERR(fs_devices))
                        return PTR_ERR(fs_devices);
@@ -6642,17 +6576,21 @@ static int read_one_dev(struct btrfs_fs_info *fs_info,
 
        device = btrfs_find_device(fs_info, devid, dev_uuid, fs_uuid);
        if (!device) {
-               if (!btrfs_test_opt(fs_info, DEGRADED))
+               if (!btrfs_test_opt(fs_info, DEGRADED)) {
+                       btrfs_report_missing_device(fs_info, devid, dev_uuid);
                        return -EIO;
+               }
 
                device = add_missing_dev(fs_devices, devid, dev_uuid);
                if (!device)
                        return -ENOMEM;
-               btrfs_warn(fs_info, "devid %llu uuid %pU missing",
-                               devid, dev_uuid);
+               btrfs_report_missing_device(fs_info, devid, dev_uuid);
        } else {
-               if (!device->bdev && !btrfs_test_opt(fs_info, DEGRADED))
-                       return -EIO;
+               if (!device->bdev) {
+                       btrfs_report_missing_device(fs_info, devid, dev_uuid);
+                       if (!btrfs_test_opt(fs_info, DEGRADED))
+                               return -EIO;
+               }
 
                if(!device->bdev && !device->missing) {
                        /*
@@ -6818,6 +6756,70 @@ out_short_read:
        return -EIO;
 }
 
+void btrfs_report_missing_device(struct btrfs_fs_info *fs_info, u64 devid,
+                                u8 *uuid)
+{
+       btrfs_warn_rl(fs_info, "devid %llu uuid %pU is missing", devid, uuid);
+}
+
+/*
+ * Check if all chunks in the fs are OK for read-write degraded mount
+ *
+ * Return true if all chunks meet the minimal RW mount requirements.
+ * Return false if any chunk doesn't meet the minimal RW mount requirements.
+ */
+bool btrfs_check_rw_degradable(struct btrfs_fs_info *fs_info)
+{
+       struct btrfs_mapping_tree *map_tree = &fs_info->mapping_tree;
+       struct extent_map *em;
+       u64 next_start = 0;
+       bool ret = true;
+
+       read_lock(&map_tree->map_tree.lock);
+       em = lookup_extent_mapping(&map_tree->map_tree, 0, (u64)-1);
+       read_unlock(&map_tree->map_tree.lock);
+       /* No chunk at all? Return false anyway */
+       if (!em) {
+               ret = false;
+               goto out;
+       }
+       while (em) {
+               struct map_lookup *map;
+               int missing = 0;
+               int max_tolerated;
+               int i;
+
+               map = em->map_lookup;
+               max_tolerated =
+                       btrfs_get_num_tolerated_disk_barrier_failures(
+                                       map->type);
+               for (i = 0; i < map->num_stripes; i++) {
+                       struct btrfs_device *dev = map->stripes[i].dev;
+
+                       if (!dev || !dev->bdev || dev->missing ||
+                           dev->last_flush_error)
+                               missing++;
+               }
+               if (missing > max_tolerated) {
+                       btrfs_warn(fs_info,
+       "chunk %llu missing %d devices, max tolerance is %d for writeable mount",
+                                  em->start, missing, max_tolerated);
+                       free_extent_map(em);
+                       ret = false;
+                       goto out;
+               }
+               next_start = extent_map_end(em);
+               free_extent_map(em);
+
+               read_lock(&map_tree->map_tree.lock);
+               em = lookup_extent_mapping(&map_tree->map_tree, next_start,
+                                          (u64)(-1) - next_start);
+               read_unlock(&map_tree->map_tree.lock);
+       }
+out:
+       return ret;
+}
+
 int btrfs_read_chunk_tree(struct btrfs_fs_info *fs_info)
 {
        struct btrfs_root *root = fs_info->chunk_root;
index 93277fc60930561a7ffb8c40d2e4ae61ce5908a0..6108fdfec67fb4340042030435ac959a77b03997 100644 (file)
@@ -353,7 +353,6 @@ struct map_lookup {
        int io_align;
        int io_width;
        u64 stripe_len;
-       int sector_size;
        int num_stripes;
        int sub_stripes;
        struct btrfs_bio_stripe stripes[];
@@ -481,9 +480,8 @@ void btrfs_init_dev_replace_tgtdev_for_resume(struct btrfs_fs_info *fs_info,
                                              struct btrfs_device *tgtdev);
 void btrfs_scratch_superblocks(struct block_device *bdev, const char *device_path);
 int btrfs_is_parity_mirror(struct btrfs_fs_info *fs_info,
-                          u64 logical, u64 len, int mirror_num);
+                          u64 logical, u64 len);
 unsigned long btrfs_full_stripe_len(struct btrfs_fs_info *fs_info,
-                                   struct btrfs_mapping_tree *map_tree,
                                    u64 logical);
 int btrfs_finish_chunk_alloc(struct btrfs_trans_handle *trans,
                                struct btrfs_fs_info *fs_info,
@@ -543,4 +541,8 @@ struct list_head *btrfs_get_fs_uuids(void);
 void btrfs_set_fs_info_ptr(struct btrfs_fs_info *fs_info);
 void btrfs_reset_fs_info_ptr(struct btrfs_fs_info *fs_info);
 
+bool btrfs_check_rw_degradable(struct btrfs_fs_info *fs_info);
+void btrfs_report_missing_device(struct btrfs_fs_info *fs_info, u64 devid,
+                                u8 *uuid);
+
 #endif
index cd99a3658156bc8229a54a15a56917f19f74502c..dc1d0df91e0b0ee193f6c0b58184fb1272cf1c70 100644 (file)
@@ -26,6 +26,7 @@ struct btrfs_work;
 struct __btrfs_workqueue;
 struct btrfs_qgroup_extent_record;
 struct btrfs_qgroup;
+struct prelim_ref;
 
 #define show_ref_type(type)                                            \
        __print_symbolic(type,                                          \
@@ -73,11 +74,11 @@ struct btrfs_qgroup;
        { BTRFS_BLOCK_GROUP_RAID5,      "RAID5"},       \
        { BTRFS_BLOCK_GROUP_RAID6,      "RAID6"}
 
-#define BTRFS_UUID_SIZE 16
-#define TP_STRUCT__entry_fsid __array(u8, fsid, BTRFS_UUID_SIZE)
+#define BTRFS_FSID_SIZE 16
+#define TP_STRUCT__entry_fsid __array(u8, fsid, BTRFS_FSID_SIZE)
 
 #define TP_fast_assign_fsid(fs_info)                                   \
-       memcpy(__entry->fsid, fs_info->fsid, BTRFS_UUID_SIZE)
+       memcpy(__entry->fsid, fs_info->fsid, BTRFS_FSID_SIZE)
 
 #define TP_STRUCT__entry_btrfs(args...)                                        \
        TP_STRUCT__entry(                                               \
@@ -92,7 +93,7 @@ struct btrfs_qgroup;
 
 TRACE_EVENT(btrfs_transaction_commit,
 
-       TP_PROTO(struct btrfs_root *root),
+       TP_PROTO(const struct btrfs_root *root),
 
        TP_ARGS(root),
 
@@ -113,7 +114,7 @@ TRACE_EVENT(btrfs_transaction_commit,
 
 DECLARE_EVENT_CLASS(btrfs__inode,
 
-       TP_PROTO(struct inode *inode),
+       TP_PROTO(const struct inode *inode),
 
        TP_ARGS(inode),
 
@@ -151,21 +152,21 @@ DECLARE_EVENT_CLASS(btrfs__inode,
 
 DEFINE_EVENT(btrfs__inode, btrfs_inode_new,
 
-       TP_PROTO(struct inode *inode),
+       TP_PROTO(const struct inode *inode),
 
        TP_ARGS(inode)
 );
 
 DEFINE_EVENT(btrfs__inode, btrfs_inode_request,
 
-       TP_PROTO(struct inode *inode),
+       TP_PROTO(const struct inode *inode),
 
        TP_ARGS(inode)
 );
 
 DEFINE_EVENT(btrfs__inode, btrfs_inode_evict,
 
-       TP_PROTO(struct inode *inode),
+       TP_PROTO(const struct inode *inode),
 
        TP_ARGS(inode)
 );
@@ -192,8 +193,8 @@ DEFINE_EVENT(btrfs__inode, btrfs_inode_evict,
 
 TRACE_EVENT_CONDITION(btrfs_get_extent,
 
-       TP_PROTO(struct btrfs_root *root, struct btrfs_inode *inode,
-                struct extent_map *map),
+       TP_PROTO(const struct btrfs_root *root, const struct btrfs_inode *inode,
+                const struct extent_map *map),
 
        TP_ARGS(root, inode, map),
 
@@ -388,7 +389,8 @@ DEFINE_EVENT(
 
 DECLARE_EVENT_CLASS(btrfs__ordered_extent,
 
-       TP_PROTO(struct inode *inode, struct btrfs_ordered_extent *ordered),
+       TP_PROTO(const struct inode *inode,
+                const struct btrfs_ordered_extent *ordered),
 
        TP_ARGS(inode, ordered),
 
@@ -440,36 +442,40 @@ DECLARE_EVENT_CLASS(btrfs__ordered_extent,
 
 DEFINE_EVENT(btrfs__ordered_extent, btrfs_ordered_extent_add,
 
-       TP_PROTO(struct inode *inode, struct btrfs_ordered_extent *ordered),
+       TP_PROTO(const struct inode *inode,
+                const struct btrfs_ordered_extent *ordered),
 
        TP_ARGS(inode, ordered)
 );
 
 DEFINE_EVENT(btrfs__ordered_extent, btrfs_ordered_extent_remove,
 
-       TP_PROTO(struct inode *inode, struct btrfs_ordered_extent *ordered),
+       TP_PROTO(const struct inode *inode,
+                const struct btrfs_ordered_extent *ordered),
 
        TP_ARGS(inode, ordered)
 );
 
 DEFINE_EVENT(btrfs__ordered_extent, btrfs_ordered_extent_start,
 
-       TP_PROTO(struct inode *inode, struct btrfs_ordered_extent *ordered),
+       TP_PROTO(const struct inode *inode,
+                const struct btrfs_ordered_extent *ordered),
 
        TP_ARGS(inode, ordered)
 );
 
 DEFINE_EVENT(btrfs__ordered_extent, btrfs_ordered_extent_put,
 
-       TP_PROTO(struct inode *inode, struct btrfs_ordered_extent *ordered),
+       TP_PROTO(const struct inode *inode,
+                const struct btrfs_ordered_extent *ordered),
 
        TP_ARGS(inode, ordered)
 );
 
 DECLARE_EVENT_CLASS(btrfs__writepage,
 
-       TP_PROTO(struct page *page, struct inode *inode,
-                struct writeback_control *wbc),
+       TP_PROTO(const struct page *page, const struct inode *inode,
+                const struct writeback_control *wbc),
 
        TP_ARGS(page, inode, wbc),
 
@@ -517,15 +523,15 @@ DECLARE_EVENT_CLASS(btrfs__writepage,
 
 DEFINE_EVENT(btrfs__writepage, __extent_writepage,
 
-       TP_PROTO(struct page *page, struct inode *inode,
-                struct writeback_control *wbc),
+       TP_PROTO(const struct page *page, const struct inode *inode,
+                const struct writeback_control *wbc),
 
        TP_ARGS(page, inode, wbc)
 );
 
 TRACE_EVENT(btrfs_writepage_end_io_hook,
 
-       TP_PROTO(struct page *page, u64 start, u64 end, int uptodate),
+       TP_PROTO(const struct page *page, u64 start, u64 end, int uptodate),
 
        TP_ARGS(page, start, end, uptodate),
 
@@ -558,7 +564,7 @@ TRACE_EVENT(btrfs_writepage_end_io_hook,
 
 TRACE_EVENT(btrfs_sync_file,
 
-       TP_PROTO(struct file *file, int datasync),
+       TP_PROTO(const struct file *file, int datasync),
 
        TP_ARGS(file, datasync),
 
@@ -570,8 +576,8 @@ TRACE_EVENT(btrfs_sync_file,
        ),
 
        TP_fast_assign(
-               struct dentry *dentry = file->f_path.dentry;
-               struct inode *inode = d_inode(dentry);
+               const struct dentry *dentry = file->f_path.dentry;
+               const struct inode *inode = d_inode(dentry);
 
                TP_fast_assign_fsid(btrfs_sb(file->f_path.dentry->d_sb));
                __entry->ino            = inode->i_ino;
@@ -589,7 +595,7 @@ TRACE_EVENT(btrfs_sync_file,
 
 TRACE_EVENT(btrfs_sync_fs,
 
-       TP_PROTO(struct btrfs_fs_info *fs_info, int wait),
+       TP_PROTO(const struct btrfs_fs_info *fs_info, int wait),
 
        TP_ARGS(fs_info, wait),
 
@@ -606,13 +612,13 @@ TRACE_EVENT(btrfs_sync_fs,
 
 TRACE_EVENT(btrfs_add_block_group,
 
-       TP_PROTO(struct btrfs_fs_info *fs_info,
-                struct btrfs_block_group_cache *block_group, int create),
+       TP_PROTO(const struct btrfs_fs_info *fs_info,
+                const struct btrfs_block_group_cache *block_group, int create),
 
        TP_ARGS(fs_info, block_group, create),
 
        TP_STRUCT__entry(
-               __array(        u8,     fsid,   BTRFS_UUID_SIZE )
+               __array(        u8,     fsid,   BTRFS_FSID_SIZE )
                __field(        u64,    offset                  )
                __field(        u64,    size                    )
                __field(        u64,    flags                   )
@@ -622,7 +628,7 @@ TRACE_EVENT(btrfs_add_block_group,
        ),
 
        TP_fast_assign(
-               memcpy(__entry->fsid, fs_info->fsid, BTRFS_UUID_SIZE);
+               memcpy(__entry->fsid, fs_info->fsid, BTRFS_FSID_SIZE);
                __entry->offset         = block_group->key.objectid;
                __entry->size           = block_group->key.offset;
                __entry->flags          = block_group->flags;
@@ -654,9 +660,9 @@ TRACE_EVENT(btrfs_add_block_group,
 
 DECLARE_EVENT_CLASS(btrfs_delayed_tree_ref,
 
-       TP_PROTO(struct btrfs_fs_info *fs_info,
-                struct btrfs_delayed_ref_node *ref,
-                struct btrfs_delayed_tree_ref *full_ref,
+       TP_PROTO(const struct btrfs_fs_info *fs_info,
+                const struct btrfs_delayed_ref_node *ref,
+                const struct btrfs_delayed_tree_ref *full_ref,
                 int action),
 
        TP_ARGS(fs_info, ref, full_ref, action),
@@ -697,9 +703,9 @@ DECLARE_EVENT_CLASS(btrfs_delayed_tree_ref,
 
 DEFINE_EVENT(btrfs_delayed_tree_ref,  add_delayed_tree_ref,
 
-       TP_PROTO(struct btrfs_fs_info *fs_info,
-                struct btrfs_delayed_ref_node *ref,
-                struct btrfs_delayed_tree_ref *full_ref,
+       TP_PROTO(const struct btrfs_fs_info *fs_info,
+                const struct btrfs_delayed_ref_node *ref,
+                const struct btrfs_delayed_tree_ref *full_ref,
                 int action),
 
        TP_ARGS(fs_info, ref, full_ref, action)
@@ -707,9 +713,9 @@ DEFINE_EVENT(btrfs_delayed_tree_ref,  add_delayed_tree_ref,
 
 DEFINE_EVENT(btrfs_delayed_tree_ref,  run_delayed_tree_ref,
 
-       TP_PROTO(struct btrfs_fs_info *fs_info,
-                struct btrfs_delayed_ref_node *ref,
-                struct btrfs_delayed_tree_ref *full_ref,
+       TP_PROTO(const struct btrfs_fs_info *fs_info,
+                const struct btrfs_delayed_ref_node *ref,
+                const struct btrfs_delayed_tree_ref *full_ref,
                 int action),
 
        TP_ARGS(fs_info, ref, full_ref, action)
@@ -717,9 +723,9 @@ DEFINE_EVENT(btrfs_delayed_tree_ref,  run_delayed_tree_ref,
 
 DECLARE_EVENT_CLASS(btrfs_delayed_data_ref,
 
-       TP_PROTO(struct btrfs_fs_info *fs_info,
-                struct btrfs_delayed_ref_node *ref,
-                struct btrfs_delayed_data_ref *full_ref,
+       TP_PROTO(const struct btrfs_fs_info *fs_info,
+                const struct btrfs_delayed_ref_node *ref,
+                const struct btrfs_delayed_data_ref *full_ref,
                 int action),
 
        TP_ARGS(fs_info, ref, full_ref, action),
@@ -764,9 +770,9 @@ DECLARE_EVENT_CLASS(btrfs_delayed_data_ref,
 
 DEFINE_EVENT(btrfs_delayed_data_ref,  add_delayed_data_ref,
 
-       TP_PROTO(struct btrfs_fs_info *fs_info,
-                struct btrfs_delayed_ref_node *ref,
-                struct btrfs_delayed_data_ref *full_ref,
+       TP_PROTO(const struct btrfs_fs_info *fs_info,
+                const struct btrfs_delayed_ref_node *ref,
+                const struct btrfs_delayed_data_ref *full_ref,
                 int action),
 
        TP_ARGS(fs_info, ref, full_ref, action)
@@ -774,9 +780,9 @@ DEFINE_EVENT(btrfs_delayed_data_ref,  add_delayed_data_ref,
 
 DEFINE_EVENT(btrfs_delayed_data_ref,  run_delayed_data_ref,
 
-       TP_PROTO(struct btrfs_fs_info *fs_info,
-                struct btrfs_delayed_ref_node *ref,
-                struct btrfs_delayed_data_ref *full_ref,
+       TP_PROTO(const struct btrfs_fs_info *fs_info,
+                const struct btrfs_delayed_ref_node *ref,
+                const struct btrfs_delayed_data_ref *full_ref,
                 int action),
 
        TP_ARGS(fs_info, ref, full_ref, action)
@@ -784,9 +790,9 @@ DEFINE_EVENT(btrfs_delayed_data_ref,  run_delayed_data_ref,
 
 DECLARE_EVENT_CLASS(btrfs_delayed_ref_head,
 
-       TP_PROTO(struct btrfs_fs_info *fs_info,
-                struct btrfs_delayed_ref_node *ref,
-                struct btrfs_delayed_ref_head *head_ref,
+       TP_PROTO(const struct btrfs_fs_info *fs_info,
+                const struct btrfs_delayed_ref_node *ref,
+                const struct btrfs_delayed_ref_head *head_ref,
                 int action),
 
        TP_ARGS(fs_info, ref, head_ref, action),
@@ -814,9 +820,9 @@ DECLARE_EVENT_CLASS(btrfs_delayed_ref_head,
 
 DEFINE_EVENT(btrfs_delayed_ref_head,  add_delayed_ref_head,
 
-       TP_PROTO(struct btrfs_fs_info *fs_info,
-                struct btrfs_delayed_ref_node *ref,
-                struct btrfs_delayed_ref_head *head_ref,
+       TP_PROTO(const struct btrfs_fs_info *fs_info,
+                const struct btrfs_delayed_ref_node *ref,
+                const struct btrfs_delayed_ref_head *head_ref,
                 int action),
 
        TP_ARGS(fs_info, ref, head_ref, action)
@@ -824,9 +830,9 @@ DEFINE_EVENT(btrfs_delayed_ref_head,  add_delayed_ref_head,
 
 DEFINE_EVENT(btrfs_delayed_ref_head,  run_delayed_ref_head,
 
-       TP_PROTO(struct btrfs_fs_info *fs_info,
-                struct btrfs_delayed_ref_node *ref,
-                struct btrfs_delayed_ref_head *head_ref,
+       TP_PROTO(const struct btrfs_fs_info *fs_info,
+                const struct btrfs_delayed_ref_node *ref,
+                const struct btrfs_delayed_ref_head *head_ref,
                 int action),
 
        TP_ARGS(fs_info, ref, head_ref, action)
@@ -846,8 +852,8 @@ DEFINE_EVENT(btrfs_delayed_ref_head,  run_delayed_ref_head,
 
 DECLARE_EVENT_CLASS(btrfs__chunk,
 
-       TP_PROTO(struct btrfs_fs_info *fs_info, struct map_lookup *map,
-                u64 offset, u64 size),
+       TP_PROTO(const struct btrfs_fs_info *fs_info,
+                const struct map_lookup *map, u64 offset, u64 size),
 
        TP_ARGS(fs_info, map, offset, size),
 
@@ -880,24 +886,24 @@ DECLARE_EVENT_CLASS(btrfs__chunk,
 
 DEFINE_EVENT(btrfs__chunk,  btrfs_chunk_alloc,
 
-       TP_PROTO(struct btrfs_fs_info *fs_info, struct map_lookup *map,
-                u64 offset, u64 size),
+       TP_PROTO(const struct btrfs_fs_info *fs_info,
+                const struct map_lookup *map, u64 offset, u64 size),
 
        TP_ARGS(fs_info, map, offset, size)
 );
 
 DEFINE_EVENT(btrfs__chunk,  btrfs_chunk_free,
 
-       TP_PROTO(struct btrfs_fs_info *fs_info, struct map_lookup *map,
-                u64 offset, u64 size),
+       TP_PROTO(const struct btrfs_fs_info *fs_info,
+                const struct map_lookup *map, u64 offset, u64 size),
 
        TP_ARGS(fs_info, map, offset, size)
 );
 
 TRACE_EVENT(btrfs_cow_block,
 
-       TP_PROTO(struct btrfs_root *root, struct extent_buffer *buf,
-                struct extent_buffer *cow),
+       TP_PROTO(const struct btrfs_root *root, const struct extent_buffer *buf,
+                const struct extent_buffer *cow),
 
        TP_ARGS(root, buf, cow),
 
@@ -931,7 +937,7 @@ TRACE_EVENT(btrfs_cow_block,
 
 TRACE_EVENT(btrfs_space_reservation,
 
-       TP_PROTO(struct btrfs_fs_info *fs_info, char *type, u64 val,
+       TP_PROTO(const struct btrfs_fs_info *fs_info, char *type, u64 val,
                 u64 bytes, int reserve),
 
        TP_ARGS(fs_info, type, val, bytes, reserve),
@@ -963,13 +969,13 @@ TRACE_EVENT(btrfs_space_reservation,
 
 TRACE_EVENT(btrfs_trigger_flush,
 
-       TP_PROTO(struct btrfs_fs_info *fs_info, u64 flags, u64 bytes,
+       TP_PROTO(const struct btrfs_fs_info *fs_info, u64 flags, u64 bytes,
                 int flush, char *reason),
 
        TP_ARGS(fs_info, flags, bytes, flush, reason),
 
        TP_STRUCT__entry(
-               __array(        u8,     fsid,   BTRFS_UUID_SIZE )
+               __array(        u8,     fsid,   BTRFS_FSID_SIZE )
                __field(        u64,    flags                   )
                __field(        u64,    bytes                   )
                __field(        int,    flush                   )
@@ -977,7 +983,7 @@ TRACE_EVENT(btrfs_trigger_flush,
        ),
 
        TP_fast_assign(
-               memcpy(__entry->fsid, fs_info->fsid, BTRFS_UUID_SIZE);
+               memcpy(__entry->fsid, fs_info->fsid, BTRFS_FSID_SIZE);
                __entry->flags  = flags;
                __entry->bytes  = bytes;
                __entry->flush  = flush;
@@ -1004,42 +1010,39 @@ TRACE_EVENT(btrfs_trigger_flush,
 
 TRACE_EVENT(btrfs_flush_space,
 
-       TP_PROTO(struct btrfs_fs_info *fs_info, u64 flags, u64 num_bytes,
-                u64 orig_bytes, int state, int ret),
+       TP_PROTO(const struct btrfs_fs_info *fs_info, u64 flags, u64 num_bytes,
+                int state, int ret),
 
-       TP_ARGS(fs_info, flags, num_bytes, orig_bytes, state, ret),
+       TP_ARGS(fs_info, flags, num_bytes, state, ret),
 
        TP_STRUCT__entry(
-               __array(        u8,     fsid,   BTRFS_UUID_SIZE )
+               __array(        u8,     fsid,   BTRFS_FSID_SIZE )
                __field(        u64,    flags                   )
                __field(        u64,    num_bytes               )
-               __field(        u64,    orig_bytes              )
                __field(        int,    state                   )
                __field(        int,    ret                     )
        ),
 
        TP_fast_assign(
-               memcpy(__entry->fsid, fs_info->fsid, BTRFS_UUID_SIZE);
+               memcpy(__entry->fsid, fs_info->fsid, BTRFS_FSID_SIZE);
                __entry->flags          =       flags;
                __entry->num_bytes      =       num_bytes;
-               __entry->orig_bytes     =       orig_bytes;
                __entry->state          =       state;
                __entry->ret            =       ret;
        ),
 
-       TP_printk("%pU: state=%d(%s) flags=%llu(%s) num_bytes=%llu "
-                 "orig_bytes=%llu ret=%d", __entry->fsid, __entry->state,
+       TP_printk("%pU: state=%d(%s) flags=%llu(%s) num_bytes=%llu ret=%d",
+                 __entry->fsid, __entry->state,
                  show_flush_state(__entry->state),
                  (unsigned long long)__entry->flags,
                  __print_flags((unsigned long)__entry->flags, "|",
                                BTRFS_GROUP_FLAGS),
-                 (unsigned long long)__entry->num_bytes,
-                 (unsigned long long)__entry->orig_bytes, __entry->ret)
+                 (unsigned long long)__entry->num_bytes, __entry->ret)
 );
 
 DECLARE_EVENT_CLASS(btrfs__reserved_extent,
 
-       TP_PROTO(struct btrfs_fs_info *fs_info, u64 start, u64 len),
+       TP_PROTO(const struct btrfs_fs_info *fs_info, u64 start, u64 len),
 
        TP_ARGS(fs_info, start, len),
 
@@ -1061,22 +1064,22 @@ DECLARE_EVENT_CLASS(btrfs__reserved_extent,
 
 DEFINE_EVENT(btrfs__reserved_extent,  btrfs_reserved_extent_alloc,
 
-       TP_PROTO(struct btrfs_fs_info *fs_info, u64 start, u64 len),
+       TP_PROTO(const struct btrfs_fs_info *fs_info, u64 start, u64 len),
 
        TP_ARGS(fs_info, start, len)
 );
 
 DEFINE_EVENT(btrfs__reserved_extent,  btrfs_reserved_extent_free,
 
-       TP_PROTO(struct btrfs_fs_info *fs_info, u64 start, u64 len),
+       TP_PROTO(const struct btrfs_fs_info *fs_info, u64 start, u64 len),
 
        TP_ARGS(fs_info, start, len)
 );
 
 TRACE_EVENT(find_free_extent,
 
-       TP_PROTO(struct btrfs_fs_info *fs_info, u64 num_bytes, u64 empty_size,
-                u64 data),
+       TP_PROTO(const struct btrfs_fs_info *fs_info, u64 num_bytes,
+                u64 empty_size, u64 data),
 
        TP_ARGS(fs_info, num_bytes, empty_size, data),
 
@@ -1101,8 +1104,8 @@ TRACE_EVENT(find_free_extent,
 
 DECLARE_EVENT_CLASS(btrfs__reserve_extent,
 
-       TP_PROTO(struct btrfs_fs_info *fs_info,
-                struct btrfs_block_group_cache *block_group, u64 start,
+       TP_PROTO(const struct btrfs_fs_info *fs_info,
+                const struct btrfs_block_group_cache *block_group, u64 start,
                 u64 len),
 
        TP_ARGS(fs_info, block_group, start, len),
@@ -1132,8 +1135,8 @@ DECLARE_EVENT_CLASS(btrfs__reserve_extent,
 
 DEFINE_EVENT(btrfs__reserve_extent, btrfs_reserve_extent,
 
-       TP_PROTO(struct btrfs_fs_info *fs_info,
-                struct btrfs_block_group_cache *block_group, u64 start,
+       TP_PROTO(const struct btrfs_fs_info *fs_info,
+                const struct btrfs_block_group_cache *block_group, u64 start,
                 u64 len),
 
        TP_ARGS(fs_info, block_group, start, len)
@@ -1141,8 +1144,8 @@ DEFINE_EVENT(btrfs__reserve_extent, btrfs_reserve_extent,
 
 DEFINE_EVENT(btrfs__reserve_extent, btrfs_reserve_extent_cluster,
 
-       TP_PROTO(struct btrfs_fs_info *fs_info,
-                struct btrfs_block_group_cache *block_group, u64 start,
+       TP_PROTO(const struct btrfs_fs_info *fs_info,
+                const struct btrfs_block_group_cache *block_group, u64 start,
                 u64 len),
 
        TP_ARGS(fs_info, block_group, start, len)
@@ -1150,7 +1153,7 @@ DEFINE_EVENT(btrfs__reserve_extent, btrfs_reserve_extent_cluster,
 
 TRACE_EVENT(btrfs_find_cluster,
 
-       TP_PROTO(struct btrfs_block_group_cache *block_group, u64 start,
+       TP_PROTO(const struct btrfs_block_group_cache *block_group, u64 start,
                 u64 bytes, u64 empty_size, u64 min_bytes),
 
        TP_ARGS(block_group, start, bytes, empty_size, min_bytes),
@@ -1183,7 +1186,7 @@ TRACE_EVENT(btrfs_find_cluster,
 
 TRACE_EVENT(btrfs_failed_cluster_setup,
 
-       TP_PROTO(struct btrfs_block_group_cache *block_group),
+       TP_PROTO(const struct btrfs_block_group_cache *block_group),
 
        TP_ARGS(block_group),
 
@@ -1200,8 +1203,9 @@ TRACE_EVENT(btrfs_failed_cluster_setup,
 
 TRACE_EVENT(btrfs_setup_cluster,
 
-       TP_PROTO(struct btrfs_block_group_cache *block_group,
-                struct btrfs_free_cluster *cluster, u64 size, int bitmap),
+       TP_PROTO(const struct btrfs_block_group_cache *block_group,
+                const struct btrfs_free_cluster *cluster,
+                u64 size, int bitmap),
 
        TP_ARGS(block_group, cluster, size, bitmap),
 
@@ -1235,12 +1239,13 @@ TRACE_EVENT(btrfs_setup_cluster,
 struct extent_state;
 TRACE_EVENT(alloc_extent_state,
 
-       TP_PROTO(struct extent_state *state, gfp_t mask, unsigned long IP),
+       TP_PROTO(const struct extent_state *state,
+                gfp_t mask, unsigned long IP),
 
        TP_ARGS(state, mask, IP),
 
        TP_STRUCT__entry(
-               __field(struct extent_state *, state)
+               __field(const struct extent_state *, state)
                __field(gfp_t, mask)
                __field(unsigned long, ip)
        ),
@@ -1252,17 +1257,17 @@ TRACE_EVENT(alloc_extent_state,
        ),
 
        TP_printk("state=%p mask=%s caller=%pS", __entry->state,
-                 show_gfp_flags(__entry->mask), (void *)__entry->ip)
+                 show_gfp_flags(__entry->mask), (const void *)__entry->ip)
 );
 
 TRACE_EVENT(free_extent_state,
 
-       TP_PROTO(struct extent_state *state, unsigned long IP),
+       TP_PROTO(const struct extent_state *state, unsigned long IP),
 
        TP_ARGS(state, IP),
 
        TP_STRUCT__entry(
-               __field(struct extent_state *, state)
+               __field(const struct extent_state *, state)
                __field(unsigned long, ip)
        ),
 
@@ -1272,22 +1277,22 @@ TRACE_EVENT(free_extent_state,
        ),
 
        TP_printk("state=%p caller=%pS", __entry->state,
-                 (void *)__entry->ip)
+                 (const void *)__entry->ip)
 );
 
 DECLARE_EVENT_CLASS(btrfs__work,
 
-       TP_PROTO(struct btrfs_work *work),
+       TP_PROTO(const struct btrfs_work *work),
 
        TP_ARGS(work),
 
        TP_STRUCT__entry_btrfs(
-               __field(        void *, work                    )
-               __field(        void *, wq                      )
-               __field(        void *, func                    )
-               __field(        void *, ordered_func            )
-               __field(        void *, ordered_free            )
-               __field(        void *, normal_work             )
+               __field(        const void *,   work                    )
+               __field(        const void *,   wq                      )
+               __field(        const void *,   func                    )
+               __field(        const void *,   ordered_func            )
+               __field(        const void *,   ordered_free            )
+               __field(        const void *,   normal_work             )
        ),
 
        TP_fast_assign_btrfs(btrfs_work_owner(work),
@@ -1312,12 +1317,12 @@ DECLARE_EVENT_CLASS(btrfs__work,
  */
 DECLARE_EVENT_CLASS(btrfs__work__done,
 
-       TP_PROTO(struct btrfs_fs_info *fs_info, void *wtag),
+       TP_PROTO(const struct btrfs_fs_info *fs_info, const void *wtag),
 
        TP_ARGS(fs_info, wtag),
 
        TP_STRUCT__entry_btrfs(
-               __field(        void *, wtag                    )
+               __field(        const void *,   wtag                    )
        ),
 
        TP_fast_assign_btrfs(fs_info,
@@ -1329,40 +1334,41 @@ DECLARE_EVENT_CLASS(btrfs__work__done,
 
 DEFINE_EVENT(btrfs__work, btrfs_work_queued,
 
-       TP_PROTO(struct btrfs_work *work),
+       TP_PROTO(const struct btrfs_work *work),
 
        TP_ARGS(work)
 );
 
 DEFINE_EVENT(btrfs__work, btrfs_work_sched,
 
-       TP_PROTO(struct btrfs_work *work),
+       TP_PROTO(const struct btrfs_work *work),
 
        TP_ARGS(work)
 );
 
 DEFINE_EVENT(btrfs__work__done, btrfs_all_work_done,
 
-       TP_PROTO(struct btrfs_fs_info *fs_info, void *wtag),
+       TP_PROTO(const struct btrfs_fs_info *fs_info, const void *wtag),
 
        TP_ARGS(fs_info, wtag)
 );
 
 DEFINE_EVENT(btrfs__work, btrfs_ordered_sched,
 
-       TP_PROTO(struct btrfs_work *work),
+       TP_PROTO(const struct btrfs_work *work),
 
        TP_ARGS(work)
 );
 
 DECLARE_EVENT_CLASS(btrfs__workqueue,
 
-       TP_PROTO(struct __btrfs_workqueue *wq, const char *name, int high),
+       TP_PROTO(const struct __btrfs_workqueue *wq,
+                const char *name, int high),
 
        TP_ARGS(wq, name, high),
 
        TP_STRUCT__entry_btrfs(
-               __field(        void *, wq                      )
+               __field(        const void *,   wq                      )
                __string(       name,   name                    )
                __field(        int ,   high                    )
        ),
@@ -1381,19 +1387,20 @@ DECLARE_EVENT_CLASS(btrfs__workqueue,
 
 DEFINE_EVENT(btrfs__workqueue, btrfs_workqueue_alloc,
 
-       TP_PROTO(struct __btrfs_workqueue *wq, const char *name, int high),
+       TP_PROTO(const struct __btrfs_workqueue *wq,
+                const char *name, int high),
 
        TP_ARGS(wq, name, high)
 );
 
 DECLARE_EVENT_CLASS(btrfs__workqueue_done,
 
-       TP_PROTO(struct __btrfs_workqueue *wq),
+       TP_PROTO(const struct __btrfs_workqueue *wq),
 
        TP_ARGS(wq),
 
        TP_STRUCT__entry_btrfs(
-               __field(        void *, wq                      )
+               __field(        const void *,   wq              )
        ),
 
        TP_fast_assign_btrfs(btrfs_workqueue_owner(wq),
@@ -1405,7 +1412,7 @@ DECLARE_EVENT_CLASS(btrfs__workqueue_done,
 
 DEFINE_EVENT(btrfs__workqueue_done, btrfs_workqueue_destroy,
 
-       TP_PROTO(struct __btrfs_workqueue *wq),
+       TP_PROTO(const struct __btrfs_workqueue *wq),
 
        TP_ARGS(wq)
 );
@@ -1417,7 +1424,8 @@ DEFINE_EVENT(btrfs__workqueue_done, btrfs_workqueue_destroy,
 
 DECLARE_EVENT_CLASS(btrfs__qgroup_rsv_data,
 
-       TP_PROTO(struct inode *inode, u64 start, u64 len, u64 reserved, int op),
+       TP_PROTO(const struct inode *inode, u64 start, u64 len,
+                u64 reserved, int op),
 
        TP_ARGS(inode, start, len, reserved, op),
 
@@ -1449,21 +1457,24 @@ DECLARE_EVENT_CLASS(btrfs__qgroup_rsv_data,
 
 DEFINE_EVENT(btrfs__qgroup_rsv_data, btrfs_qgroup_reserve_data,
 
-       TP_PROTO(struct inode *inode, u64 start, u64 len, u64 reserved, int op),
+       TP_PROTO(const struct inode *inode, u64 start, u64 len,
+                u64 reserved, int op),
 
        TP_ARGS(inode, start, len, reserved, op)
 );
 
 DEFINE_EVENT(btrfs__qgroup_rsv_data, btrfs_qgroup_release_data,
 
-       TP_PROTO(struct inode *inode, u64 start, u64 len, u64 reserved, int op),
+       TP_PROTO(const struct inode *inode, u64 start, u64 len,
+                u64 reserved, int op),
 
        TP_ARGS(inode, start, len, reserved, op)
 );
 
 DECLARE_EVENT_CLASS(btrfs__qgroup_delayed_ref,
 
-       TP_PROTO(struct btrfs_fs_info *fs_info, u64 ref_root, u64 reserved),
+       TP_PROTO(const struct btrfs_fs_info *fs_info,
+                u64 ref_root, u64 reserved),
 
        TP_ARGS(fs_info, ref_root, reserved),
 
@@ -1483,14 +1494,15 @@ DECLARE_EVENT_CLASS(btrfs__qgroup_delayed_ref,
 
 DEFINE_EVENT(btrfs__qgroup_delayed_ref, btrfs_qgroup_free_delayed_ref,
 
-       TP_PROTO(struct btrfs_fs_info *fs_info, u64 ref_root, u64 reserved),
+       TP_PROTO(const struct btrfs_fs_info *fs_info,
+                u64 ref_root, u64 reserved),
 
        TP_ARGS(fs_info, ref_root, reserved)
 );
 
 DECLARE_EVENT_CLASS(btrfs_qgroup_extent,
-       TP_PROTO(struct btrfs_fs_info *fs_info,
-                struct btrfs_qgroup_extent_record *rec),
+       TP_PROTO(const struct btrfs_fs_info *fs_info,
+                const struct btrfs_qgroup_extent_record *rec),
 
        TP_ARGS(fs_info, rec),
 
@@ -1511,23 +1523,23 @@ DECLARE_EVENT_CLASS(btrfs_qgroup_extent,
 
 DEFINE_EVENT(btrfs_qgroup_extent, btrfs_qgroup_account_extents,
 
-       TP_PROTO(struct btrfs_fs_info *fs_info,
-                struct btrfs_qgroup_extent_record *rec),
+       TP_PROTO(const struct btrfs_fs_info *fs_info,
+                const struct btrfs_qgroup_extent_record *rec),
 
        TP_ARGS(fs_info, rec)
 );
 
 DEFINE_EVENT(btrfs_qgroup_extent, btrfs_qgroup_trace_extent,
 
-       TP_PROTO(struct btrfs_fs_info *fs_info,
-                struct btrfs_qgroup_extent_record *rec),
+       TP_PROTO(const struct btrfs_fs_info *fs_info,
+                const struct btrfs_qgroup_extent_record *rec),
 
        TP_ARGS(fs_info, rec)
 );
 
 TRACE_EVENT(btrfs_qgroup_account_extent,
 
-       TP_PROTO(struct btrfs_fs_info *fs_info, u64 bytenr,
+       TP_PROTO(const struct btrfs_fs_info *fs_info, u64 bytenr,
                 u64 num_bytes, u64 nr_old_roots, u64 nr_new_roots),
 
        TP_ARGS(fs_info, bytenr, num_bytes, nr_old_roots, nr_new_roots),
@@ -1556,7 +1568,7 @@ TRACE_EVENT(btrfs_qgroup_account_extent,
 
 TRACE_EVENT(qgroup_update_counters,
 
-       TP_PROTO(struct btrfs_fs_info *fs_info, u64 qgid,
+       TP_PROTO(const struct btrfs_fs_info *fs_info, u64 qgid,
                 u64 cur_old_count, u64 cur_new_count),
 
        TP_ARGS(fs_info, qgid, cur_old_count, cur_new_count),
@@ -1622,6 +1634,63 @@ TRACE_EVENT(qgroup_meta_reserve,
                show_root_type(__entry->refroot), __entry->diff)
 );
 
+DECLARE_EVENT_CLASS(btrfs__prelim_ref,
+       TP_PROTO(const struct btrfs_fs_info *fs_info,
+                const struct prelim_ref *oldref,
+                const struct prelim_ref *newref, u64 tree_size),
+       TP_ARGS(fs_info, newref, oldref, tree_size),
+
+       TP_STRUCT__entry_btrfs(
+               __field(        u64,  root_id           )
+               __field(        u64,  objectid          )
+               __field(         u8,  type              )
+               __field(        u64,  offset            )
+               __field(        int,  level             )
+               __field(        int,  old_count         )
+               __field(        u64,  parent            )
+               __field(        u64,  bytenr            )
+               __field(        int,  mod_count         )
+               __field(        u64,  tree_size         )
+       ),
+
+       TP_fast_assign_btrfs(fs_info,
+               __entry->root_id        = oldref->root_id;
+               __entry->objectid       = oldref->key_for_search.objectid;
+               __entry->type           = oldref->key_for_search.type;
+               __entry->offset         = oldref->key_for_search.offset;
+               __entry->level          = oldref->level;
+               __entry->old_count      = oldref->count;
+               __entry->parent         = oldref->parent;
+               __entry->bytenr         = oldref->wanted_disk_byte;
+               __entry->mod_count      = newref ? newref->count : 0;
+               __entry->tree_size      = tree_size;
+       ),
+
+       TP_printk_btrfs("root_id=%llu key=[%llu,%u,%llu] level=%d count=[%d+%d=%d] parent=%llu wanted_disk_byte=%llu nodes=%llu",
+                       (unsigned long long)__entry->root_id,
+                       (unsigned long long)__entry->objectid, __entry->type,
+                       (unsigned long long)__entry->offset, __entry->level,
+                       __entry->old_count, __entry->mod_count,
+                       __entry->old_count + __entry->mod_count,
+                       (unsigned long long)__entry->parent,
+                       (unsigned long long)__entry->bytenr,
+                       (unsigned long long)__entry->tree_size)
+);
+
+DEFINE_EVENT(btrfs__prelim_ref, btrfs_prelim_ref_merge,
+       TP_PROTO(const struct btrfs_fs_info *fs_info,
+                const struct prelim_ref *oldref,
+                const struct prelim_ref *newref, u64 tree_size),
+       TP_ARGS(fs_info, oldref, newref, tree_size)
+);
+
+DEFINE_EVENT(btrfs__prelim_ref, btrfs_prelim_ref_insert,
+       TP_PROTO(const struct btrfs_fs_info *fs_info,
+                const struct prelim_ref *oldref,
+                const struct prelim_ref *newref, u64 tree_size),
+       TP_ARGS(fs_info, oldref, newref, tree_size)
+);
+
 #endif /* _TRACE_BTRFS_H */
 
 /* This part must be outside protection */