Btrfs: During deletes and truncate, remove many items at once from the tree
authorChris Mason <chris.mason@oracle.com>
Tue, 29 Jan 2008 20:11:36 +0000 (15:11 -0500)
committerChris Mason <chris.mason@oracle.com>
Thu, 25 Sep 2008 15:04:00 +0000 (11:04 -0400)
Signed-off-by: Chris Mason <chris.mason@oracle.com>
fs/btrfs/ctree.c
fs/btrfs/ctree.h
fs/btrfs/extent_io.c
fs/btrfs/inode.c

index 43d23148a4fe0f86a0df19de17b28a226cf608fe..84ad53e06b3a739c17850a4f449b929876e84f42 100644 (file)
@@ -2514,34 +2514,36 @@ static int del_ptr(struct btrfs_trans_handle *trans, struct btrfs_root *root,
  * delete the item at the leaf level in path.  If that empties
  * the leaf, remove it from the tree
  */
-int btrfs_del_item(struct btrfs_trans_handle *trans, struct btrfs_root *root,
-                  struct btrfs_path *path)
+int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root,
+                   struct btrfs_path *path, int slot, int nr)
 {
-       int slot;
        struct extent_buffer *leaf;
        struct btrfs_item *item;
-       int doff;
-       int dsize;
+       int last_off;
+       int dsize = 0;
        int ret = 0;
        int wret;
+       int i;
        u32 nritems;
 
        leaf = path->nodes[0];
-       slot = path->slots[0];
-       doff = btrfs_item_offset_nr(leaf, slot);
-       dsize = btrfs_item_size_nr(leaf, slot);
+       last_off = btrfs_item_offset_nr(leaf, slot + nr - 1);
+
+       for (i = 0; i < nr; i++)
+               dsize += btrfs_item_size_nr(leaf, slot + i);
+
        nritems = btrfs_header_nritems(leaf);
 
-       if (slot != nritems - 1) {
+       if (slot + nr != nritems) {
                int i;
                int data_end = leaf_data_end(root, leaf);
 
                memmove_extent_buffer(leaf, btrfs_leaf_data(leaf) +
                              data_end + dsize,
                              btrfs_leaf_data(leaf) + data_end,
-                             doff - data_end);
+                             last_off - data_end);
 
-               for (i = slot + 1; i < nritems; i++) {
+               for (i = slot + nr; i < nritems; i++) {
                        u32 ioff;
 
                        item = btrfs_item_nr(leaf, i);
@@ -2562,12 +2564,12 @@ int btrfs_del_item(struct btrfs_trans_handle *trans, struct btrfs_root *root,
                }
 
                memmove_extent_buffer(leaf, btrfs_item_nr_offset(slot),
-                             btrfs_item_nr_offset(slot + 1),
+                             btrfs_item_nr_offset(slot + nr),
                              sizeof(struct btrfs_item) *
-                             (nritems - slot - 1));
+                             (nritems - slot - nr));
        }
-       btrfs_set_header_nritems(leaf, nritems - 1);
-       nritems--;
+       btrfs_set_header_nritems(leaf, nritems - nr);
+       nritems -= nr;
 
        /* delete the leaf if we've emptied it */
        if (nritems == 0) {
@@ -2600,7 +2602,7 @@ int btrfs_del_item(struct btrfs_trans_handle *trans, struct btrfs_root *root,
                }
 
                /* delete the leaf if it is mostly empty */
-               if (used < BTRFS_LEAF_DATA_SIZE(root) / 3) {
+               if (used < BTRFS_LEAF_DATA_SIZE(root) / 4) {
                        /* push_leaf_left fixes the path.
                         * make sure the path still points to our leaf
                         * for possible call to del_ptr below
@@ -2608,13 +2610,13 @@ int btrfs_del_item(struct btrfs_trans_handle *trans, struct btrfs_root *root,
                        slot = path->slots[1];
                        extent_buffer_get(leaf);
 
-                       wret = push_leaf_right(trans, root, path, 1, 1);
+                       wret = push_leaf_left(trans, root, path, 1, 1);
                        if (wret < 0 && wret != -ENOSPC)
                                ret = wret;
 
                        if (path->nodes[0] == leaf &&
                            btrfs_header_nritems(leaf)) {
-                               wret = push_leaf_left(trans, root, path, 1, 1);
+                               wret = push_leaf_right(trans, root, path, 1, 1);
                                if (wret < 0 && wret != -ENOSPC)
                                        ret = wret;
                        }
index 6c65473e0fe3266f563a910eb6b0187bf247ead7..098cf0883150a8437dfcb730f02f8d4db5d19730 100644 (file)
@@ -1038,8 +1038,16 @@ void btrfs_release_path(struct btrfs_root *root, struct btrfs_path *p);
 struct btrfs_path *btrfs_alloc_path(void);
 void btrfs_free_path(struct btrfs_path *p);
 void btrfs_init_path(struct btrfs_path *p);
-int btrfs_del_item(struct btrfs_trans_handle *trans, struct btrfs_root *root,
-                  struct btrfs_path *path);
+int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root,
+                  struct btrfs_path *path, int slot, int nr);
+
+static inline int btrfs_del_item(struct btrfs_trans_handle *trans,
+                                struct btrfs_root *root,
+                                struct btrfs_path *path)
+{
+       return btrfs_del_items(trans, root, path, path->slots[0], 1);
+}
+
 int btrfs_insert_item(struct btrfs_trans_handle *trans, struct btrfs_root
                      *root, struct btrfs_key *key, void *data, u32 data_size);
 int btrfs_insert_empty_item(struct btrfs_trans_handle *trans, struct btrfs_root
index 1f734c34dc24be1ba2a28c721fb2d39095f7529c..8aec72253a174048ab1b5fa5ba9338f893520e31 100644 (file)
@@ -2863,7 +2863,6 @@ int read_extent_buffer_pages(struct extent_io_tree *tree,
        if (ret || !wait) {
                return ret;
        }
-
        for (i = start_i; i < num_pages; i++) {
                page = extent_buffer_page(eb, i);
                wait_on_page_locked(page);
index bac8722e14e1938e0c3640a0718773fde913976b..0a2fe51c41272aad424a162a4909a7bef1d8b92a 100644 (file)
@@ -692,27 +692,6 @@ fail:
        return err;
 }
 
-static int btrfs_free_inode(struct btrfs_trans_handle *trans,
-                           struct btrfs_root *root,
-                           struct inode *inode)
-{
-       struct btrfs_path *path;
-       int ret;
-
-       clear_inode(inode);
-
-       path = btrfs_alloc_path();
-       BUG_ON(!path);
-       ret = btrfs_lookup_inode(trans, root, path,
-                                &BTRFS_I(inode)->location, -1);
-       if (ret > 0)
-               ret = -ENOENT;
-       if (!ret)
-               ret = btrfs_del_item(trans, root, path);
-       btrfs_free_path(path);
-       return ret;
-}
-
 /*
  * this can truncate away extent items, csum items and directory items.
  * It starts at a high offset and removes keys until it can't find
@@ -723,7 +702,8 @@ static int btrfs_free_inode(struct btrfs_trans_handle *trans,
  */
 static int btrfs_truncate_in_trans(struct btrfs_trans_handle *trans,
                                   struct btrfs_root *root,
-                                  struct inode *inode)
+                                  struct inode *inode,
+                                  u32 min_type)
 {
        int ret;
        struct btrfs_path *path;
@@ -739,6 +719,8 @@ static int btrfs_truncate_in_trans(struct btrfs_trans_handle *trans,
        u64 root_owner = 0;
        int found_extent;
        int del_item;
+       int pending_del_nr = 0;
+       int pending_del_slot = 0;
        int extent_type = -1;
 
        btrfs_drop_extent_cache(inode, inode->i_size, (u64)-1);
@@ -751,17 +733,19 @@ static int btrfs_truncate_in_trans(struct btrfs_trans_handle *trans,
        key.offset = (u64)-1;
        key.type = (u8)-1;
 
+       btrfs_init_path(path);
+search_again:
+       ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
+       if (ret < 0) {
+               goto error;
+       }
+       if (ret > 0) {
+               BUG_ON(path->slots[0] == 0);
+               path->slots[0]--;
+       }
+
        while(1) {
-               btrfs_init_path(path);
                fi = NULL;
-               ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
-               if (ret < 0) {
-                       goto error;
-               }
-               if (ret > 0) {
-                       BUG_ON(path->slots[0] == 0);
-                       path->slots[0]--;
-               }
                leaf = path->nodes[0];
                btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
                found_type = btrfs_key_type(&found_key);
@@ -769,10 +753,7 @@ static int btrfs_truncate_in_trans(struct btrfs_trans_handle *trans,
                if (found_key.objectid != inode->i_ino)
                        break;
 
-               if (found_type != BTRFS_CSUM_ITEM_KEY &&
-                   found_type != BTRFS_DIR_ITEM_KEY &&
-                   found_type != BTRFS_DIR_INDEX_KEY &&
-                   found_type != BTRFS_EXTENT_DATA_KEY)
+               if (found_type < min_type)
                        break;
 
                item_end = found_key.offset;
@@ -801,14 +782,17 @@ static int btrfs_truncate_in_trans(struct btrfs_trans_handle *trans,
                                found_type = BTRFS_INODE_ITEM_KEY;
                        } else if (found_type == BTRFS_EXTENT_ITEM_KEY) {
                                found_type = BTRFS_CSUM_ITEM_KEY;
+                       } else if (found_type == BTRFS_EXTENT_DATA_KEY) {
+                               found_type = BTRFS_XATTR_ITEM_KEY;
+                       } else if (found_type == BTRFS_XATTR_ITEM_KEY) {
+                               found_type = BTRFS_INODE_REF_KEY;
                        } else if (found_type) {
                                found_type--;
                        } else {
                                break;
                        }
                        btrfs_set_key_type(&key, found_type);
-                       btrfs_release_path(root, path);
-                       continue;
+                       goto next;
                }
                if (found_key.offset >= inode->i_size)
                        del_item = 1;
@@ -860,13 +844,21 @@ static int btrfs_truncate_in_trans(struct btrfs_trans_handle *trans,
                }
 delete:
                if (del_item) {
-                       ret = btrfs_del_item(trans, root, path);
-                       if (ret)
-                               goto error;
+                       if (!pending_del_nr) {
+                               /* no pending yet, add ourselves */
+                               pending_del_slot = path->slots[0];
+                               pending_del_nr = 1;
+                       } else if (pending_del_nr &&
+                                  path->slots[0] + 1 == pending_del_slot) {
+                               /* hop on the pending chunk */
+                               pending_del_nr++;
+                               pending_del_slot = path->slots[0];
+                       } else {
+                               printk("bad pending slot %d pending_del_nr %d pending_del_slot %d\n", path->slots[0], pending_del_nr, pending_del_slot);
+                       }
                } else {
                        break;
                }
-               btrfs_release_path(root, path);
                if (found_extent) {
                        ret = btrfs_free_extent(trans, root, extent_start,
                                                extent_num_bytes,
@@ -875,9 +867,36 @@ delete:
                                                found_key.offset, 0);
                        BUG_ON(ret);
                }
+next:
+               if (path->slots[0] == 0) {
+                       if (pending_del_nr)
+                               goto del_pending;
+                       btrfs_release_path(root, path);
+                       goto search_again;
+               }
+
+               path->slots[0]--;
+               if (pending_del_nr &&
+                   path->slots[0] + 1 != pending_del_slot) {
+                       struct btrfs_key debug;
+del_pending:
+                       btrfs_item_key_to_cpu(path->nodes[0], &debug,
+                                             pending_del_slot);
+                       ret = btrfs_del_items(trans, root, path,
+                                             pending_del_slot,
+                                             pending_del_nr);
+                       BUG_ON(ret);
+                       pending_del_nr = 0;
+                       btrfs_release_path(root, path);
+                       goto search_again;
+               }
        }
        ret = 0;
 error:
+       if (pending_del_nr) {
+               ret = btrfs_del_items(trans, root, path, pending_del_slot,
+                                     pending_del_nr);
+       }
        btrfs_release_path(root, path);
        btrfs_free_path(path);
        inode->i_sb->s_dirt = 1;
@@ -1067,16 +1086,12 @@ void btrfs_delete_inode(struct inode *inode)
        trans = btrfs_start_transaction(root, 1);
 
        btrfs_set_trans_block_group(trans, inode);
-       ret = btrfs_truncate_in_trans(trans, root, inode);
-       if (ret)
-               goto no_delete_lock;
-       ret = btrfs_delete_xattrs(trans, root, inode);
-       if (ret)
-               goto no_delete_lock;
-       ret = btrfs_free_inode(trans, root, inode);
+       ret = btrfs_truncate_in_trans(trans, root, inode, 0);
        if (ret)
                goto no_delete_lock;
+
        nr = trans->blocks_used;
+       clear_inode(inode);
 
        btrfs_end_transaction(trans, root);
        mutex_unlock(&root->fs_info->fs_mutex);
@@ -2190,7 +2205,8 @@ static void btrfs_truncate(struct inode *inode)
        btrfs_set_trans_block_group(trans, inode);
 
        /* FIXME, add redo link to tree so we don't leak on crash */
-       ret = btrfs_truncate_in_trans(trans, root, inode);
+       ret = btrfs_truncate_in_trans(trans, root, inode,
+                                     BTRFS_EXTENT_DATA_KEY);
        btrfs_update_inode(trans, root, inode);
        nr = trans->blocks_used;