From 07eb5008f353147feee5b66c3f091cf74ef993a7 Mon Sep 17 00:00:00 2001 From: Chris Mason Date: Thu, 19 Apr 2007 15:41:24 -0400 Subject: [PATCH] bring back the inode number directory index --- ctree.c | 53 +++++++++++++++++++++++++++++++++++++++++++++- ctree.h | 30 ++------------------------ dir-item.c | 60 +++++++++++++++++++++++++++++++++++++--------------- print-tree.c | 34 ++++++++++++++++++----------- 4 files changed, 119 insertions(+), 58 deletions(-) diff --git a/ctree.c b/ctree.c index 01baa0bf..a1e6f556 100644 --- 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 308008af..a258b18a 100644 --- 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, diff --git a/dir-item.c b/dir-item.c index 1a8daad2..a72894e5 100644 --- a/dir-item.c +++ b/dir-item.c @@ -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); + + /* FIXME, use some real flag for selecting the extra index */ + if (root == root->fs_info->tree_root) goto out; - dir_item = btrfs_item_ptr(&path.nodes[0]->leaf, path.slots[0], - struct btrfs_dir_item); + 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); diff --git a/print-tree.c b/print-tree.c index d56860bb..17724b2b 100644 --- a/print-tree.c +++ b/print-tree.c @@ -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);