#include <linux/kthread.h>
 #include <linux/slab.h>
 #include <linux/ratelimit.h>
+#include <linux/percpu_counter.h>
 #include "compat.h"
 #include "hash.h"
 #include "ctree.h"
        struct btrfs_space_info *found;
        int i;
        int factor;
+       int ret;
 
        if (flags & (BTRFS_BLOCK_GROUP_DUP | BTRFS_BLOCK_GROUP_RAID1 |
                     BTRFS_BLOCK_GROUP_RAID10))
        if (!found)
                return -ENOMEM;
 
+       ret = percpu_counter_init(&found->total_bytes_pinned, 0);
+       if (ret) {
+               kfree(found);
+               return ret;
+       }
+
        for (i = 0; i < BTRFS_NR_RAID_TYPES; i++)
                INIT_LIST_HEAD(&found->block_groups[i]);
        init_rwsem(&found->groups_sem);
                }
 
                /*
-                * If we have less pinned bytes than we want to allocate then
-                * don't bother committing the transaction, it won't help us.
+                * If we don't have enough pinned space to deal with this
+                * allocation don't bother committing the transaction.
                 */
-               if (data_sinfo->bytes_pinned < bytes)
+               if (percpu_counter_compare(&data_sinfo->total_bytes_pinned,
+                                          bytes) < 0)
                        committed = 1;
                spin_unlock(&data_sinfo->lock);
 
                if (!committed &&
                    !atomic_read(&root->fs_info->open_ioctl_trans)) {
                        committed = 1;
+
                        trans = btrfs_join_transaction(root);
                        if (IS_ERR(trans))
                                return PTR_ERR(trans);
 
        /* See if there is enough pinned space to make this reservation */
        spin_lock(&space_info->lock);
-       if (space_info->bytes_pinned >= bytes) {
+       if (percpu_counter_compare(&space_info->total_bytes_pinned,
+                                  bytes) >= 0) {
                spin_unlock(&space_info->lock);
                goto commit;
        }
 
        spin_lock(&space_info->lock);
        spin_lock(&delayed_rsv->lock);
-       if (space_info->bytes_pinned + delayed_rsv->size < bytes) {
+       if (percpu_counter_compare(&space_info->total_bytes_pinned,
+                                  bytes - delayed_rsv->size) >= 0) {
                spin_unlock(&delayed_rsv->lock);
                spin_unlock(&space_info->lock);
                return -ENOSPC;
        struct btrfs_caching_control *next;
        struct btrfs_caching_control *caching_ctl;
        struct btrfs_block_group_cache *cache;
+       struct btrfs_space_info *space_info;
 
        down_write(&fs_info->extent_commit_sem);
 
 
        up_write(&fs_info->extent_commit_sem);
 
+       list_for_each_entry_rcu(space_info, &fs_info->space_info, list)
+               percpu_counter_set(&space_info->total_bytes_pinned, 0);
+
        update_global_block_rsv(fs_info);
 }
 
        return 0;
 }
 
+static void add_pinned_bytes(struct btrfs_fs_info *fs_info, u64 num_bytes,
+                            u64 owner, u64 root_objectid)
+{
+       struct btrfs_space_info *space_info;
+       u64 flags;
+
+       if (owner < BTRFS_FIRST_FREE_OBJECTID) {
+               if (root_objectid == BTRFS_CHUNK_TREE_OBJECTID)
+                       flags = BTRFS_BLOCK_GROUP_SYSTEM;
+               else
+                       flags = BTRFS_BLOCK_GROUP_METADATA;
+       } else {
+               flags = BTRFS_BLOCK_GROUP_DATA;
+       }
+
+       space_info = __find_space_info(fs_info, flags);
+       BUG_ON(!space_info); /* Logic bug */
+       percpu_counter_add(&space_info->total_bytes_pinned, num_bytes);
+}
+
+
 static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
                                struct btrfs_root *root,
                                u64 bytenr, u64 num_bytes, u64 parent,
                                goto out;
                        }
                }
+               add_pinned_bytes(root->fs_info, -num_bytes, owner_objectid,
+                                root_objectid);
        } else {
                if (found_extent) {
                        BUG_ON(is_data && refs_to_drop !=
                           u64 parent, int last_ref)
 {
        struct btrfs_block_group_cache *cache = NULL;
+       int pin = 1;
        int ret;
 
        if (root->root_key.objectid != BTRFS_TREE_LOG_OBJECTID) {
 
                btrfs_add_free_space(cache, buf->start, buf->len);
                btrfs_update_reserved_bytes(cache, buf->len, RESERVE_FREE);
+               pin = 0;
        }
 out:
+       if (pin)
+               add_pinned_bytes(root->fs_info, buf->len,
+                                btrfs_header_level(buf),
+                                root->root_key.objectid);
+
        /*
         * Deleting the buffer, clear the corrupt flag since it doesn't matter
         * anymore.
        int ret;
        struct btrfs_fs_info *fs_info = root->fs_info;
 
+       add_pinned_bytes(root->fs_info, num_bytes, owner, root_objectid);
+
        /*
         * tree log blocks never actually go into the extent allocation
         * tree, just update pinning info and exit early.
                                dump_space_info(space_info, 0, 0);
                        }
                }
+               percpu_counter_destroy(&space_info->total_bytes_pinned);
                list_del(&space_info->list);
                kfree(space_info);
        }