bring back the inode number directory index
authorChris Mason <chris.mason@oracle.com>
Thu, 19 Apr 2007 19:41:24 +0000 (15:41 -0400)
committerDavid Woodhouse <dwmw2@hera.kernel.org>
Thu, 19 Apr 2007 19:41:24 +0000 (15:41 -0400)
ctree.c
ctree.h
dir-item.c
print-tree.c

diff --git a/ctree.c b/ctree.c
index 01baa0bfe0cb4b73ffb10c4692157e03a34c2048..a1e6f55603eee3885a3b894007b57d30a38fc892 100644 (file)
--- a/ctree.c
+++ b/ctree.c
@@ -1147,7 +1147,6 @@ int btrfs_insert_empty_item(struct btrfs_trans_handle *trans, struct btrfs_root
                BUG();
        ret = btrfs_search_slot(trans, root, cpu_key, path, data_size, 1);
        if (ret == 0) {
-               btrfs_release_path(root, path);
                return -EEXIST;
        }
        if (ret < 0)
@@ -1369,6 +1368,58 @@ int btrfs_del_item(struct btrfs_trans_handle *trans, struct btrfs_root *root,
        return ret;
 }
 
+int btrfs_extend_item(struct btrfs_trans_handle *trans, struct btrfs_root
+                     *root, struct btrfs_path *path, u32 data_size)
+{
+       int ret = 0;
+       int slot;
+       int slot_orig;
+       struct btrfs_leaf *leaf;
+       struct btrfs_buffer *leaf_buf;
+       u32 nritems;
+       unsigned int data_end;
+       unsigned int old_data;
+       unsigned int old_size;
+       int i;
+
+       slot_orig = path->slots[0];
+       leaf_buf = path->nodes[0];
+       leaf = &leaf_buf->leaf;
+
+       nritems = btrfs_header_nritems(&leaf->header);
+       data_end = leaf_data_end(root, leaf);
+
+       if (btrfs_leaf_free_space(root, leaf) < data_size)
+               BUG();
+       slot = path->slots[0];
+       old_data = btrfs_item_end(leaf->items + slot);
+
+       BUG_ON(slot < 0);
+       BUG_ON(slot >= nritems);
+
+       /*
+        * item0..itemN ... dataN.offset..dataN.size .. data0.size
+        */
+       /* first correct the data pointers */
+       for (i = slot; i < nritems; i++) {
+               u32 ioff = btrfs_item_offset(leaf->items + i);
+               btrfs_set_item_offset(leaf->items + i,
+                                     ioff - data_size);
+       }
+       /* shift the data */
+       memmove(btrfs_leaf_data(leaf) + data_end - data_size,
+               btrfs_leaf_data(leaf) + data_end, old_data - data_end);
+       data_end = old_data;
+       old_size = btrfs_item_size(leaf->items + slot);
+       btrfs_set_item_size(leaf->items + slot, old_size + data_size);
+
+       ret = 0;
+       if (btrfs_leaf_free_space(root, leaf) < 0)
+               BUG();
+       check_leaf(root, path, 0);
+       return ret;
+}
+
 /*
  * walk up the tree as far as required to find the next leaf.
  * returns 0 if it found something or 1 if there are no greater leaves.
diff --git a/ctree.h b/ctree.h
index 308008af5765977de85ac0eeafaf2a363905af9f..a258b18a137d237ecb7ebaddd5adae6e8918f350 100644 (file)
--- a/ctree.h
+++ b/ctree.h
@@ -278,9 +278,6 @@ struct btrfs_root {
 #define BTRFS_KEY_TYPE_MASK    (((u32)BTRFS_KEY_TYPE_MAX - 1) << \
                                  BTRFS_KEY_TYPE_SHIFT)
 
-#define BTRFS_KEY_OVERFLOW_MAX 128
-#define BTRFS_KEY_OVERFLOW_MASK ((u32)BTRFS_KEY_OVERFLOW_MAX - 1)
-
 /*
  * inode items have the data typically returned from stat and store other
  * info about object characteristics.  There is one for every file and dir in
@@ -606,31 +603,6 @@ static inline void btrfs_set_key_type(struct btrfs_key *key, u32 val)
        key->flags = (key->flags & ~(BTRFS_KEY_TYPE_MASK)) | val;
 }
 
-static inline u32 btrfs_key_overflow(struct btrfs_key *key)
-{
-       return key->flags & BTRFS_KEY_OVERFLOW_MASK;
-}
-
-static inline void btrfs_set_key_overflow(struct btrfs_key *key, u32 over)
-{
-       BUG_ON(over >= BTRFS_KEY_OVERFLOW_MAX);
-       key->flags = (key->flags & ~BTRFS_KEY_OVERFLOW_MASK) | over;
-}
-
-static inline u32 btrfs_disk_key_overflow(struct btrfs_disk_key *key)
-{
-       return le32_to_cpu(key->flags) & BTRFS_KEY_OVERFLOW_MASK;
-}
-
-static inline void btrfs_set_disk_key_overflow(struct btrfs_disk_key *key,
-                                              u32 over)
-{
-       u32 flags = btrfs_disk_key_flags(key);
-       BUG_ON(over >= BTRFS_KEY_OVERFLOW_MAX);
-       flags = (flags & ~BTRFS_KEY_OVERFLOW_MASK) | over;
-       btrfs_set_disk_key_flags(key, flags);
-}
-
 static inline u64 btrfs_header_blocknr(struct btrfs_header *h)
 {
        return le64_to_cpu(h->blocknr);
@@ -970,6 +942,8 @@ static inline void btrfs_set_device_id(struct btrfs_device_item *d,
        ((type *)(btrfs_leaf_data(leaf) + \
        btrfs_item_offset((leaf)->items + (slot))))
 
+int btrfs_extend_item(struct btrfs_trans_handle *trans, struct btrfs_root
+                     *root, struct btrfs_path *path, u32 data_size);
 struct btrfs_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
                                            struct btrfs_root *root);
 int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
index 1a8daad2308ec277700a746cc03d89ff01ee3720..a72894e527cd041439efe8103c7b581e111b464e 100644 (file)
@@ -7,24 +7,32 @@
 #include "hash.h"
 #include "transaction.h"
 
-int insert_with_overflow(struct btrfs_trans_handle *trans, struct btrfs_root
-                           *root, struct btrfs_path *path, struct btrfs_key
-                           *cpu_key, u32 data_size)
+static struct btrfs_dir_item *insert_with_overflow(struct
+                                                  btrfs_trans_handle *trans,
+                                                  struct btrfs_root *root,
+                                                  struct btrfs_path *path,
+                                                  struct btrfs_key *cpu_key,
+                                                  u32 data_size)
 {
-       int overflow;
        int ret;
+       char *ptr;
+       struct btrfs_item *item;
+       struct btrfs_leaf *leaf;
 
        ret = btrfs_insert_empty_item(trans, root, path, cpu_key, data_size);
-       overflow = btrfs_key_overflow(cpu_key);
-
-       while(ret == -EEXIST && overflow < BTRFS_KEY_OVERFLOW_MAX) {
-               overflow++;
-               btrfs_set_key_overflow(cpu_key, overflow);
-               btrfs_release_path(root, path);
-               ret = btrfs_insert_empty_item(trans, root, path, cpu_key,
-                                             data_size);
+       if (ret == -EEXIST) {
+               ret = btrfs_extend_item(trans, root, path, data_size);
+               BUG_ON(ret > 0);
+               if (ret)
+                       return NULL;
        }
-       return ret;
+       BUG_ON(ret > 0);
+       leaf = &path->nodes[0]->leaf;
+       item = leaf->items + path->slots[0];
+       ptr = btrfs_item_ptr(leaf, path->slots[0], char);
+       BUG_ON(data_size > btrfs_item_size(item));
+       ptr += btrfs_item_size(item) - data_size;
+       return (struct btrfs_dir_item *)ptr;
 }
 
 int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
@@ -50,12 +58,30 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
        BUG_ON(ret);
        btrfs_init_path(&path);
        data_size = sizeof(*dir_item) + name_len;
-       ret = insert_with_overflow(trans, root, &path, &key, data_size);
-       if (ret)
+       dir_item = insert_with_overflow(trans, root, &path, &key, data_size);
+       if (!dir_item) {
+               ret = -1;
                goto out;
+       }
+       btrfs_cpu_key_to_disk(&dir_item->location, location);
+       btrfs_set_dir_type(dir_item, type);
+       btrfs_set_dir_flags(dir_item, 0);
+       btrfs_set_dir_name_len(dir_item, name_len);
+       name_ptr = (char *)(dir_item + 1);
+       memcpy(name_ptr, name, name_len);
 
-       dir_item = btrfs_item_ptr(&path.nodes[0]->leaf, path.slots[0],
-                                 struct btrfs_dir_item);
+       /* FIXME, use some real flag for selecting the extra index */
+       if (root == root->fs_info->tree_root)
+               goto out;
+
+       btrfs_release_path(root, &path);
+       btrfs_set_key_type(&key, BTRFS_DIR_INDEX_KEY);
+       key.offset = location->objectid;
+       dir_item = insert_with_overflow(trans, root, &path, &key, data_size);
+       if (!dir_item) {
+               ret = -1;
+               goto out;
+       }
        btrfs_cpu_key_to_disk(&dir_item->location, location);
        btrfs_set_dir_type(dir_item, type);
        btrfs_set_dir_flags(dir_item, 0);
index d56860bb8337d59e13c578a6aedb9d52ca70f85b..17724b2b08a9c3cd9a87d2c630936662c3088084 100644 (file)
@@ -5,6 +5,26 @@
 #include "ctree.h"
 #include "disk-io.h"
 
+static int print_dir_item(struct btrfs_item *item,
+                         struct btrfs_dir_item *di)
+{
+       u32 total;
+       u32 cur = 0;
+       u32 len;
+       total = btrfs_item_size(item);
+       while(cur < total) {
+               printf("\t\tdir index %Lu flags %u type %u\n",
+                       btrfs_disk_key_objectid(&di->location),
+                       btrfs_dir_flags(di),
+                       btrfs_dir_type(di));
+               printf("\t\tname %.*s\n",
+                      btrfs_dir_name_len(di),(char *)(di + 1));
+               len = sizeof(*di) + btrfs_dir_name_len(di);
+               di = (struct btrfs_dir_item *)((char *)di + len);
+               cur += len;
+       }
+       return 0;
+}
 void btrfs_print_leaf(struct btrfs_root *root, struct btrfs_leaf *l)
 {
        int i;
@@ -49,21 +69,11 @@ void btrfs_print_leaf(struct btrfs_root *root, struct btrfs_leaf *l)
                        break;
                case BTRFS_DIR_ITEM_KEY:
                        di = btrfs_item_ptr(l, i, struct btrfs_dir_item);
-                       printf("\t\tdir oid %Lu flags %u type %u\n",
-                               btrfs_disk_key_objectid(&di->location),
-                               btrfs_dir_flags(di),
-                               btrfs_dir_type(di));
-                       printf("\t\tname %.*s\n",
-                              btrfs_dir_name_len(di),(char *)(di + 1));
+                       print_dir_item(l->items + i, di);
                        break;
                case BTRFS_DIR_INDEX_KEY:
                        di = btrfs_item_ptr(l, i, struct btrfs_dir_item);
-                       printf("\t\tdir index %Lu flags %u type %u\n",
-                               btrfs_disk_key_objectid(&di->location),
-                               btrfs_dir_flags(di),
-                               btrfs_dir_type(di));
-                       printf("\t\tname %.*s\n",
-                              btrfs_dir_name_len(di),(char *)(di + 1));
+                       print_dir_item(l->items + i, di);
                        break;
                case BTRFS_ROOT_ITEM_KEY:
                        ri = btrfs_item_ptr(l, i, struct btrfs_root_item);