[S_IFLNK >> S_SHIFT]    = BTRFS_FT_SYMLINK,
 };
 
+int btrfs_check_free_space(struct btrfs_root *root, u64 num_required,
+                          int for_del)
+{
+       u64 total = btrfs_super_total_bytes(&root->fs_info->super_copy);
+       u64 used = btrfs_super_bytes_used(&root->fs_info->super_copy);
+       u64 thresh;
+       int ret = 0;
+
+       if (for_del)
+               thresh = (total * 90) / 100;
+       else
+               thresh = (total * 85) / 100;
+
+       spin_lock(&root->fs_info->delalloc_lock);
+       if (used + root->fs_info->delalloc_bytes + num_required > thresh)
+               ret = -ENOSPC;
+       spin_unlock(&root->fs_info->delalloc_lock);
+       return ret;
+}
+
 static int cow_file_range(struct inode *inode, u64 start, u64 end)
 {
        struct btrfs_root *root = BTRFS_I(inode)->root;
        u64 extent_end;
        u64 bytenr;
        u64 cow_end;
+       u64 loops = 0;
        struct btrfs_root *root = BTRFS_I(inode)->root;
        struct extent_buffer *leaf;
        int found_type;
                       btrfs_file_extent_num_bytes(leaf, item);
                err = 0;
 
+               if (loops && start != extent_start)
+                       goto not_found;
+
                if (start < extent_start || start >= extent_end)
                        goto not_found;
 
                return 0;
        }
        btrfs_release_path(root, path);
+       loops++;
        goto again;
 
 not_found:
 static int run_delalloc_range(struct inode *inode, u64 start, u64 end)
 {
        struct btrfs_root *root = BTRFS_I(inode)->root;
+       u64 num_bytes;
        int ret;
 
        mutex_lock(&root->fs_info->fs_mutex);
                ret = run_delalloc_nocow(inode, start, end);
        else
                ret = cow_file_range(inode, start, end);
+
+       spin_lock(&root->fs_info->delalloc_lock);
+       num_bytes = end + 1 - start;
+       if (root->fs_info->delalloc_bytes < num_bytes) {
+               printk("delalloc accounting error total %llu sub %llu\n",
+                      root->fs_info->delalloc_bytes, num_bytes);
+       } else {
+               root->fs_info->delalloc_bytes -= num_bytes;
+       }
+       spin_unlock(&root->fs_info->delalloc_lock);
+
        mutex_unlock(&root->fs_info->fs_mutex);
        return ret;
 }
        struct btrfs_root *root;
        struct btrfs_trans_handle *trans;
        int ret;
-       unsigned long nr;
+       unsigned long nr = 0;
 
        root = BTRFS_I(dir)->root;
        mutex_lock(&root->fs_info->fs_mutex);
+
+       ret = btrfs_check_free_space(root, 1, 1);
+       if (ret)
+               goto fail;
+
        trans = btrfs_start_transaction(root, 1);
 
        btrfs_set_trans_block_group(trans, dir);
        nr = trans->blocks_used;
 
        btrfs_end_transaction(trans, root);
+fail:
        mutex_unlock(&root->fs_info->fs_mutex);
        btrfs_btree_balance_dirty(root, nr);
-
        return ret;
 }
 
 static int btrfs_rmdir(struct inode *dir, struct dentry *dentry)
 {
        struct inode *inode = dentry->d_inode;
-       int err;
+       int err = 0;
        int ret;
        struct btrfs_root *root = BTRFS_I(dir)->root;
        struct btrfs_trans_handle *trans;
-       unsigned long nr;
+       unsigned long nr = 0;
 
        if (inode->i_size > BTRFS_EMPTY_DIR_SIZE)
                return -ENOTEMPTY;
 
        mutex_lock(&root->fs_info->fs_mutex);
+       ret = btrfs_check_free_space(root, 1, 1);
+       if (ret)
+               goto fail;
+
        trans = btrfs_start_transaction(root, 1);
        btrfs_set_trans_block_group(trans, dir);
 
 
        nr = trans->blocks_used;
        ret = btrfs_end_transaction(trans, root);
+fail:
        mutex_unlock(&root->fs_info->fs_mutex);
        btrfs_btree_balance_dirty(root, nr);
 
                              size_t zero_start)
 {
        char *kaddr;
-       int ret = 0;
        struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree;
+       struct btrfs_root *root = BTRFS_I(inode)->root;
        u64 page_start = (u64)page->index << PAGE_CACHE_SHIFT;
        u64 page_end = page_start + PAGE_CACHE_SIZE - 1;
+       u64 existing_delalloc;
+       u64 delalloc_start;
+       int ret = 0;
 
        WARN_ON(!PageLocked(page));
        set_page_extent_mapped(page);
 
        lock_extent(em_tree, page_start, page_end, GFP_NOFS);
+       delalloc_start = page_start;
+       existing_delalloc = count_range_bits(&BTRFS_I(inode)->extent_tree,
+                                            &delalloc_start, page_end,
+                                            PAGE_CACHE_SIZE, EXTENT_DELALLOC);
        set_extent_delalloc(&BTRFS_I(inode)->extent_tree, page_start,
                            page_end, GFP_NOFS);
+
+       spin_lock(&root->fs_info->delalloc_lock);
+       root->fs_info->delalloc_bytes += PAGE_CACHE_SIZE - existing_delalloc;
+       spin_unlock(&root->fs_info->delalloc_lock);
+
        if (zero_start != PAGE_CACHE_SIZE) {
                kaddr = kmap(page);
                memset(kaddr + zero_start, 0, PAGE_CACHE_SIZE - zero_start);
                if (attr->ia_size <= pos)
                        goto out;
 
+               mutex_lock(&root->fs_info->fs_mutex);
+               err = btrfs_check_free_space(root, 1, 0);
+               mutex_unlock(&root->fs_info->fs_mutex);
+               if (err)
+                       goto fail;
+
                btrfs_truncate_page(inode->i_mapping, inode->i_size);
 
                lock_extent(em_tree, pos, block_end, GFP_NOFS);
        }
 out:
        err = inode_setattr(inode, attr);
-
+fail:
        return err;
 }
 void btrfs_delete_inode(struct inode *inode)
 {
        struct btrfs_trans_handle *trans;
        struct btrfs_root *root = BTRFS_I(dir)->root;
-       struct inode *inode;
+       struct inode *inode = NULL;
        int err;
        int drop_inode = 0;
        u64 objectid;
-       unsigned long nr;
+       unsigned long nr = 0;
 
        if (!new_valid_dev(rdev))
                return -EINVAL;
 
        mutex_lock(&root->fs_info->fs_mutex);
+       err = btrfs_check_free_space(root, 1, 0);
+       if (err)
+               goto fail;
+
        trans = btrfs_start_transaction(root, 1);
        btrfs_set_trans_block_group(trans, dir);
 
 out_unlock:
        nr = trans->blocks_used;
        btrfs_end_transaction(trans, root);
+fail:
        mutex_unlock(&root->fs_info->fs_mutex);
 
        if (drop_inode) {
 {
        struct btrfs_trans_handle *trans;
        struct btrfs_root *root = BTRFS_I(dir)->root;
-       struct inode *inode;
+       struct inode *inode = NULL;
        int err;
        int drop_inode = 0;
-       unsigned long nr;
+       unsigned long nr = 0;
        u64 objectid;
 
        mutex_lock(&root->fs_info->fs_mutex);
+       err = btrfs_check_free_space(root, 1, 0);
+       if (err)
+               goto fail;
        trans = btrfs_start_transaction(root, 1);
        btrfs_set_trans_block_group(trans, dir);
 
 out_unlock:
        nr = trans->blocks_used;
        btrfs_end_transaction(trans, root);
+fail:
        mutex_unlock(&root->fs_info->fs_mutex);
 
        if (drop_inode) {
        struct btrfs_trans_handle *trans;
        struct btrfs_root *root = BTRFS_I(dir)->root;
        struct inode *inode = old_dentry->d_inode;
-       unsigned long nr;
+       unsigned long nr = 0;
        int err;
        int drop_inode = 0;
 
        inc_nlink(inode);
 #endif
        mutex_lock(&root->fs_info->fs_mutex);
+       err = btrfs_check_free_space(root, 1, 0);
+       if (err)
+               goto fail;
        trans = btrfs_start_transaction(root, 1);
 
        btrfs_set_trans_block_group(trans, dir);
 
        nr = trans->blocks_used;
        btrfs_end_transaction(trans, root);
+fail:
        mutex_unlock(&root->fs_info->fs_mutex);
 
        if (drop_inode) {
        unsigned long nr = 1;
 
        mutex_lock(&root->fs_info->fs_mutex);
+       err = btrfs_check_free_space(root, 1, 0);
+       if (err)
+               goto out_unlock;
+
        trans = btrfs_start_transaction(root, 1);
        btrfs_set_trans_block_group(trans, dir);
 
 static int btrfs_prepare_write(struct file *file, struct page *page,
                               unsigned from, unsigned to)
 {
+       struct btrfs_root *root = BTRFS_I(page->mapping->host)->root;
+       int err;
+
+       mutex_lock(&root->fs_info->fs_mutex);
+       err = btrfs_check_free_space(root, PAGE_CACHE_SIZE, 0);
+       mutex_lock(&root->fs_info->fs_mutex);
+       if (err)
+               return -ENOSPC;
+
        return extent_prepare_write(&BTRFS_I(page->mapping->host)->extent_tree,
                                    page->mapping->host, page, from, to,
                                    btrfs_get_extent);
        tree = &BTRFS_I(page->mapping->host)->extent_tree;
        return extent_read_full_page(tree, page, btrfs_get_extent);
 }
+
 static int btrfs_writepage(struct page *page, struct writeback_control *wbc)
 {
        struct extent_map_tree *tree;
 int btrfs_page_mkwrite(struct vm_area_struct *vma, struct page *page)
 {
        struct inode *inode = fdentry(vma->vm_file)->d_inode;
+       struct btrfs_root *root = BTRFS_I(inode)->root;
        unsigned long end;
        loff_t size;
-       int ret = -EINVAL;
+       int ret;
        u64 page_start;
 
+       mutex_lock(&root->fs_info->fs_mutex);
+       ret = btrfs_check_free_space(root, PAGE_CACHE_SIZE, 0);
+       mutex_lock(&root->fs_info->fs_mutex);
+       if (ret)
+               goto out;
+
+       ret = -EINVAL;
+
        down_read(&BTRFS_I(inode)->root->snap_sem);
        lock_page(page);
        wait_on_page_writeback(page);
 out_unlock:
        up_read(&BTRFS_I(inode)->root->snap_sem);
        unlock_page(page);
+out:
        return ret;
 }
 
        unsigned long nr = 1;
 
        mutex_lock(&root->fs_info->fs_mutex);
+       ret = btrfs_check_free_space(root, 1, 0);
+       if (ret)
+               goto fail_commit;
+
        trans = btrfs_start_transaction(root, 1);
        BUG_ON(!trans);
 
        int ret;
        int err;
        u64 objectid;
-       unsigned long nr;
+       unsigned long nr = 0;
 
        if (!root->ref_cows)
                return -EINVAL;
        thaw_bdev(root->fs_info->sb->s_bdev, root->fs_info->sb);
 
        mutex_lock(&root->fs_info->fs_mutex);
+       ret = btrfs_check_free_space(root, 1, 0);
+       if (ret)
+               goto fail_unlock;
+
        trans = btrfs_start_transaction(root, 1);
        BUG_ON(!trans);
 
 
        if (err && !ret)
                ret = err;
-
+fail_unlock:
        mutex_unlock(&root->fs_info->fs_mutex);
        up_write(&root->snap_sem);
        btrfs_btree_balance_dirty(root, nr);
 
 int btrfs_defrag_file(struct file *file) {
        struct inode *inode = fdentry(file)->d_inode;
+       struct btrfs_root *root = BTRFS_I(inode)->root;
        struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree;
        struct page *page;
        unsigned long last_index;
        u64 page_start;
        u64 page_end;
        unsigned long i;
+       int ret;
+
+       mutex_lock(&root->fs_info->fs_mutex);
+       ret = btrfs_check_free_space(root, inode->i_size, 0);
+       mutex_unlock(&root->fs_info->fs_mutex);
+       if (ret)
+               return -ENOSPC;
 
        mutex_lock(&inode->i_mutex);
        last_index = inode->i_size >> PAGE_CACHE_SHIFT;
        }
 
        mutex_lock(&root->fs_info->fs_mutex);
+       ret = btrfs_check_free_space(root, 1, 0);
+       if (ret)
+               goto out_unlock;
+
        trans = btrfs_start_transaction(root, 1);
 
        btrfs_set_trans_block_group(trans, new_dir);
 out_fail:
        btrfs_free_path(path);
        btrfs_end_transaction(trans, root);
+out_unlock:
        mutex_unlock(&root->fs_info->fs_mutex);
        return ret;
 }
        struct btrfs_root *root = BTRFS_I(dir)->root;
        struct btrfs_path *path;
        struct btrfs_key key;
-       struct inode *inode;
+       struct inode *inode = NULL;
        int err;
        int drop_inode = 0;
        u64 objectid;
        unsigned long ptr;
        struct btrfs_file_extent_item *ei;
        struct extent_buffer *leaf;
-       unsigned long nr;
+       unsigned long nr = 0;
 
        name_len = strlen(symname) + 1;
        if (name_len > BTRFS_MAX_INLINE_DATA_SIZE(root))
                return -ENAMETOOLONG;
+
        mutex_lock(&root->fs_info->fs_mutex);
+       err = btrfs_check_free_space(root, 1, 0);
+       if (err)
+               goto out_fail;
+
        trans = btrfs_start_transaction(root, 1);
        btrfs_set_trans_block_group(trans, dir);
 
 out_unlock:
        nr = trans->blocks_used;
        btrfs_end_transaction(trans, root);
+out_fail:
        mutex_unlock(&root->fs_info->fs_mutex);
        if (drop_inode) {
                inode_dec_link_count(inode);