Btrfs: use the commit_root for reading free_space_inode crcs
[pandora-kernel.git] / fs / btrfs / file-item.c
index 4f19a3e..08bcfa9 100644 (file)
@@ -48,7 +48,8 @@ int btrfs_insert_file_extent(struct btrfs_trans_handle *trans,
        struct extent_buffer *leaf;
 
        path = btrfs_alloc_path();
-       BUG_ON(!path);
+       if (!path)
+               return -ENOMEM;
        file_key.objectid = objectid;
        file_key.offset = pos;
        btrfs_set_key_type(&file_key, BTRFS_EXTENT_DATA_KEY);
@@ -169,11 +170,22 @@ static int __btrfs_lookup_bio_sums(struct btrfs_root *root,
        struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
 
        path = btrfs_alloc_path();
+       if (!path)
+               return -ENOMEM;
        if (bio->bi_size > PAGE_CACHE_SIZE * 8)
                path->reada = 2;
 
        WARN_ON(bio->bi_vcnt <= 0);
 
+       /*
+        * the free space stuff is only read when it hasn't been
+        * updated in the current transaction.  So, we can safely
+        * read from the commit root and sidestep a nasty deadlock
+        * between reading the free space cache and updating the csum tree.
+        */
+       if (btrfs_is_free_space_inode(root, inode))
+               path->search_commit_root = 1;
+
        disk_bytenr = (u64)bio->bi_sector << 9;
        if (dio)
                offset = logical_offset;
@@ -190,7 +202,7 @@ static int __btrfs_lookup_bio_sums(struct btrfs_root *root,
                        u32 item_size;
 
                        if (item)
-                               btrfs_release_path(root, path);
+                               btrfs_release_path(path);
                        item = btrfs_lookup_csum(NULL, root->fs_info->csum_root,
                                                 path, disk_bytenr, 0);
                        if (IS_ERR(item)) {
@@ -205,12 +217,13 @@ static int __btrfs_lookup_bio_sums(struct btrfs_root *root,
                                                EXTENT_NODATASUM, GFP_NOFS);
                                } else {
                                        printk(KERN_INFO "btrfs no csum found "
-                                              "for inode %lu start %llu\n",
-                                              inode->i_ino,
+                                              "for inode %llu start %llu\n",
+                                              (unsigned long long)
+                                              btrfs_ino(inode),
                                               (unsigned long long)offset);
                                }
                                item = NULL;
-                               btrfs_release_path(root, path);
+                               btrfs_release_path(path);
                                goto found;
                        }
                        btrfs_item_key_to_cpu(path->nodes[0], &found_key,
@@ -263,7 +276,7 @@ int btrfs_lookup_bio_sums_dio(struct btrfs_root *root, struct inode *inode,
 }
 
 int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end,
-                            struct list_head *list)
+                            struct list_head *list, int search_commit)
 {
        struct btrfs_key key;
        struct btrfs_path *path;
@@ -280,6 +293,12 @@ int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end,
        path = btrfs_alloc_path();
        BUG_ON(!path);
 
+       if (search_commit) {
+               path->skip_locking = 1;
+               path->reada = 2;
+               path->search_commit_root = 1;
+       }
+
        key.objectid = BTRFS_EXTENT_CSUM_OBJECTID;
        key.offset = start;
        key.type = BTRFS_EXTENT_CSUM_KEY;
@@ -492,7 +511,6 @@ static noinline int truncate_one_csum(struct btrfs_trans_handle *trans,
                u32 new_size = (bytenr - key->offset) >> blocksize_bits;
                new_size *= csum_size;
                ret = btrfs_truncate_item(trans, root, path, new_size, 1);
-               BUG_ON(ret);
        } else if (key->offset >= bytenr && csum_end > end_byte &&
                   end_byte > key->offset) {
                /*
@@ -505,7 +523,6 @@ static noinline int truncate_one_csum(struct btrfs_trans_handle *trans,
                new_size *= csum_size;
 
                ret = btrfs_truncate_item(trans, root, path, new_size, 0);
-               BUG_ON(ret);
 
                key->offset = end_byte;
                ret = btrfs_set_item_key_safe(trans, root, path, key);
@@ -548,10 +565,10 @@ int btrfs_del_csums(struct btrfs_trans_handle *trans,
                ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
                if (ret > 0) {
                        if (path->slots[0] == 0)
-                               goto out;
+                               break;
                        path->slots[0]--;
                } else if (ret < 0) {
-                       goto out;
+                       break;
                }
 
                leaf = path->nodes[0];
@@ -576,7 +593,8 @@ int btrfs_del_csums(struct btrfs_trans_handle *trans,
                /* delete the entire item, it is inside our range */
                if (key.offset >= bytenr && csum_end <= end_byte) {
                        ret = btrfs_del_item(trans, root, path);
-                       BUG_ON(ret);
+                       if (ret)
+                               goto out;
                        if (key.offset == bytenr)
                                break;
                } else if (key.offset < bytenr && csum_end > end_byte) {
@@ -628,11 +646,12 @@ int btrfs_del_csums(struct btrfs_trans_handle *trans,
                        if (key.offset < bytenr)
                                break;
                }
-               btrfs_release_path(root, path);
+               btrfs_release_path(path);
        }
+       ret = 0;
 out:
        btrfs_free_path(path);
-       return 0;
+       return ret;
 }
 
 int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans,
@@ -654,10 +673,6 @@ int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans,
        struct btrfs_sector_sum *sector_sum;
        u32 nritems;
        u32 ins_size;
-       char *eb_map;
-       char *eb_token;
-       unsigned long map_len;
-       unsigned long map_start;
        u16 csum_size =
                btrfs_super_csum_size(&root->fs_info->super_copy);
 
@@ -719,7 +734,7 @@ again:
         * at this point, we know the tree has an item, but it isn't big
         * enough yet to put our csum in.  Grow it
         */
-       btrfs_release_path(root, path);
+       btrfs_release_path(path);
        ret = btrfs_search_slot(trans, root, &file_key, path,
                                csum_size, 1);
        if (ret < 0)
@@ -758,12 +773,11 @@ again:
                        goto insert;
 
                ret = btrfs_extend_item(trans, root, path, diff);
-               BUG_ON(ret);
                goto csum;
        }
 
 insert:
-       btrfs_release_path(root, path);
+       btrfs_release_path(path);
        csum_offset = 0;
        if (found_next) {
                u64 tmp = total_bytes + root->sectorsize;
@@ -805,30 +819,9 @@ found:
        item_end = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_csum_item);
        item_end = (struct btrfs_csum_item *)((unsigned char *)item_end +
                                      btrfs_item_size_nr(leaf, path->slots[0]));
-       eb_token = NULL;
 next_sector:
 
-       if (!eb_token ||
-          (unsigned long)item + csum_size >= map_start + map_len) {
-               int err;
-
-               if (eb_token)
-                       unmap_extent_buffer(leaf, eb_token, KM_USER1);
-               eb_token = NULL;
-               err = map_private_extent_buffer(leaf, (unsigned long)item,
-                                               csum_size,
-                                               &eb_token, &eb_map,
-                                               &map_start, &map_len, KM_USER1);
-               if (err)
-                       eb_token = NULL;
-       }
-       if (eb_token) {
-               memcpy(eb_token + ((unsigned long)item & (PAGE_CACHE_SIZE - 1)),
-                      &sector_sum->sum, csum_size);
-       } else {
-               write_extent_buffer(leaf, &sector_sum->sum,
-                                   (unsigned long)item, csum_size);
-       }
+       write_extent_buffer(leaf, &sector_sum->sum, (unsigned long)item, csum_size);
 
        total_bytes += root->sectorsize;
        sector_sum++;
@@ -841,13 +834,10 @@ next_sector:
                        goto next_sector;
                }
        }
-       if (eb_token) {
-               unmap_extent_buffer(leaf, eb_token, KM_USER1);
-               eb_token = NULL;
-       }
+
        btrfs_mark_buffer_dirty(path->nodes[0]);
        if (total_bytes < sums->len) {
-               btrfs_release_path(root, path);
+               btrfs_release_path(path);
                cond_resched();
                goto again;
        }