From: nikita Date: Thu, 22 Jun 2006 21:57:22 +0000 (+0000) Subject: iam: add iam_htree format X-Git-Tag: v1_8_0_110~486^2~1567 X-Git-Url: https://git.whamcloud.com/gitweb?a=commitdiff_plain;h=2a76a7ee54ee3bce95e5616dda2a0b1109d81370;p=fs%2Flustre-release.git iam: add iam_htree format --- diff --git a/lustre/kernel_patches/patches/ext3-iam-separate.patch b/lustre/kernel_patches/patches/ext3-iam-separate.patch index 27db24d..7169ecf 100644 --- a/lustre/kernel_patches/patches/ext3-iam-separate.patch +++ b/lustre/kernel_patches/patches/ext3-iam-separate.patch @@ -1,7 +1,7 @@ Index: iam/fs/ext3/Makefile =================================================================== --- iam.orig/fs/ext3/Makefile 2006-05-31 20:24:32.000000000 +0400 -+++ iam/fs/ext3/Makefile 2006-06-21 22:25:45.000000000 +0400 ++++ iam/fs/ext3/Makefile 2006-06-23 01:50:19.000000000 +0400 @@ -6,7 +6,7 @@ obj-$(CONFIG_EXT3_FS) += ext3.o ext3-y := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o iopen.o \ @@ -14,8 +14,8 @@ Index: iam/fs/ext3/Makefile Index: iam/fs/ext3/iam.c =================================================================== --- iam.orig/fs/ext3/iam.c 2004-04-06 17:27:52.000000000 +0400 -+++ iam/fs/ext3/iam.c 2006-06-21 01:19:28.000000000 +0400 -@@ -0,0 +1,1244 @@ ++++ iam/fs/ext3/iam.c 2006-06-23 00:42:45.000000000 +0400 +@@ -0,0 +1,1242 @@ +/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- + * vim:expandtab:shiftwidth=8:tabstop=8: + * @@ -235,12 +235,8 @@ Index: iam/fs/ext3/iam.c + path->ipc_descr.ipd_key_scratch[i] = + (struct iam_key *)&path->ipc_scratch[i]; + -+ iam_container_init(&path->ipc_container, &htree_compat_param, inode); -+ /* -+ * XXX hack allowing finalization of iam_path_compat with -+ * iam_path_fini(). -+ */ -+ iput(inode); ++ iam_container_init(&path->ipc_container, ++ &iam_htree_compat_param, inode); + iam_path_init(&path->ipc_path, &path->ipc_container, &path->ipc_descr); +} + @@ -278,6 +274,17 @@ Index: iam/fs/ext3/iam.c +} +EXPORT_SYMBOL(iam_ipd_free); + ++int iam_node_read(struct iam_container *c, iam_ptr_t ptr, ++ handle_t *h, struct buffer_head **bh) ++{ ++ int result = 0; ++ ++ *bh = ext3_bread(h, c->ic_object, (int)ptr, 0, &result); ++ if (*bh == NULL) ++ result = -EIO; ++ return result; ++} ++ +/* + * Leaf helpers. + */ @@ -820,15 +827,6 @@ Index: iam/fs/ext3/iam.c + iam_leaf_ops(folio)->rec_set(folio, r); +} + -+static void iam_it_keycpy(struct iam_iterator *it, const struct iam_key *k) -+{ -+ struct iam_leaf *folio; -+ -+ folio = &it->ii_path.ip_leaf; -+ iam_leaf_ops(folio)->key_set(folio, k); -+} -+ -+ +/* + * Replace contents of record under iterator. + * @@ -1263,8 +1261,8 @@ Index: iam/fs/ext3/iam.c Index: iam/fs/ext3/iam_htree.c =================================================================== --- iam.orig/fs/ext3/iam_htree.c 2004-04-06 17:27:52.000000000 +0400 -+++ iam/fs/ext3/iam_htree.c 2006-06-21 00:09:07.000000000 +0400 -@@ -0,0 +1,582 @@ ++++ iam/fs/ext3/iam_htree.c 2006-06-22 16:56:26.000000000 +0400 +@@ -0,0 +1,579 @@ +/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- + * vim:expandtab:shiftwidth=8:tabstop=8: + * @@ -1293,8 +1291,6 @@ Index: iam/fs/ext3/iam_htree.c + * license text for more details. + */ + -+#if 0 -+ +#include +#include +/* ext3_error(), EXT3_DIR_ROUND() */ @@ -1323,353 +1319,306 @@ Index: iam/fs/ext3/iam_htree.c + return container_of(path->ip_data, struct iam_path_compat, ipc_descr); +} + -+static inline size_t recsize(const struct iam_leaf *folio, size_t namelen) ++static inline struct htree_dirent *getent(const struct iam_leaf *folio) +{ -+ return -+ namelen + -+ offsetof(struct htree_dirent, hd_name) + -+ getipc(folio) -+ -+#define EXT3_DIR_REC_LEN(name_len) (((name_len) + 8 + EXT3_DIR_ROUND) & \ -+ ~EXT3_DIR_ROUND) ++ return (void *)folio->il_at; +} + -+/* -+ * Leaf operations. -+ */ -+ -+static inline struct iam_key *iam_leaf_key_at(struct iam_lentry *entry) ++static __u32 gethash(const struct iam_leaf *folio, ++ const struct htree_dirent *ent) +{ -+ return (struct iam_key *)entry; ++ int result; ++ struct dx_hash_info *hinfo; ++ ++ hinfo = getipc(folio)->ipc_hinfo; ++ assert(hinfo != NULL); ++ result = ext3fs_dirhash(ent->hd_name, ent->hd_namelen, hinfo); ++ assert(result == 0); ++ return hinfo->hash; +} + -+static struct iam_leaf_head *iam_get_head(const struct iam_leaf *l) ++static inline size_t recsize(size_t namelen) +{ -+ return (struct iam_leaf_head *)l->il_bh->b_data; ++ return EXT3_DIR_REC_LEN(namelen); +} + -+static struct iam_lentry *iam_entries(const struct buffer_head *bh) ++static struct htree_dirent *gettop(const struct iam_leaf *folio) +{ -+ return (void *)bh->b_data + sizeof(struct iam_leaf_head); ++ return ++ (void *)folio->il_bh->b_data + ++ iam_leaf_container(folio)->ic_object->i_sb->s_blocksize - ++ recsize(0); +} + -+static struct iam_lentry *iam_get_lentries(const struct iam_leaf *l) ++static inline int ent_is_live(const struct htree_dirent *ent) +{ -+ return iam_entries(l->il_bh); ++ return ent->hd_ino != 0; +} + -+static int leaf_count_limit(const struct iam_leaf *leaf) ++static struct htree_dirent *entnext(const struct htree_dirent *ent) +{ -+ int free_space; ++ return (void *)ent + le16_to_cpu(ent->hd_reclen); ++} + -+ free_space = iam_leaf_container(leaf)->ic_object->i_sb->s_blocksize; -+ free_space -= sizeof(struct iam_leaf_head); -+ return free_space / iam_htree_entry_size(leaf); ++static struct htree_dirent *skipdead(struct htree_dirent *ent) ++{ ++ if (!ent_is_live(ent)) ++ ent = entnext(ent); ++ /* ++ * There can be no more than one dead entry in a row. ++ */ ++ return ent; +} + -+static int lentry_count_get(const struct iam_leaf *leaf) ++static struct htree_dirent *getstart(const struct iam_leaf *folio) +{ -+ return le16_to_cpu(iam_get_head(leaf)->ill_count); ++ return (void *)folio->il_bh->b_data; +} + -+static void lentry_count_set(struct iam_leaf *leaf, unsigned count) ++static int getfreespace(const struct htree_dirent *ent) +{ -+ assert(0 <= count && count <= leaf_count_limit(leaf)); -+ iam_get_head(leaf)->ill_count = cpu_to_le16(count); ++ int free; ++ ++ free = le16_to_cpu(ent->hd_reclen); ++ if (ent_is_live(ent)) ++ free -= recsize(ent->hd_namelen); ++ assert(free >= 0); ++ return free; +} + -+static struct iam_lentry *iam_htree_get_end(const struct iam_leaf *l); ++static int entcmp(const struct iam_leaf *folio, ++ const struct htree_dirent *e0, const struct htree_dirent *e1) ++{ ++ __u32 hash0; ++ __u32 hash1; ++ ++ assert(ent_is_live(e0)); ++ assert(ent_is_live(e1)); ++ ++ hash0 = gethash(folio, e0); ++ hash1 = gethash(folio, e1); ++ if (hash0 < hash1) ++ return -1; ++ else if (hash0 > hash1) ++ return +1; ++ else if (e0 < e1) ++ return -1; ++ else if (e0 > e1) ++ return +1; ++ else ++ return 0; ++} + +static int iam_leaf_at_rec(const struct iam_leaf *folio) +{ -+ return -+ iam_get_lentries(folio) <= folio->il_at && -+ folio->il_at < iam_htree_get_end(folio); ++ struct htree_dirent *ent; ++ ++ ent = getent(folio); ++ return getstart(folio) <= ent && ++ ent < gettop(folio) && ent_is_live(ent); +} + -+/*This func is for flat key, for those keys, -+ *which are not stored explicitly -+ *it would be decrypt in the key buffer ++/* ++ * Leaf operations. + */ ++ +struct iam_key *iam_htree_key(const struct iam_leaf *l, struct iam_key *key) +{ -+ void *ie = l->il_at; ++ __u32 *hash; + assert(iam_leaf_at_rec(l)); -+ return (struct iam_key*)ie; -+} + -+static void iam_htree_start(struct iam_leaf *l) -+{ -+ l->il_at = iam_get_lentries(l); ++ hash = (void *)key; ++ *hash = gethash(l, getent(l)); ++ return key; +} + -+static inline ptrdiff_t iam_htree_diff(const struct iam_leaf *l, -+ const struct iam_lentry *e1, -+ const struct iam_lentry *e2) ++static void iam_htree_start(struct iam_leaf *l) +{ -+ ptrdiff_t diff; -+ int esize; -+ -+ esize = iam_htree_entry_size(l); -+ diff = (void *)e1 - (void *)e2; -+ assert(diff / esize * esize == diff); -+ return diff / esize; ++ l->il_at = (void *)skipdead(getstart(l)); +} + +static int iam_htree_init(struct iam_leaf *l) +{ -+ int result; -+ struct iam_leaf_head *ill; -+ int count; -+ + assert(l->il_bh != NULL); + -+ ill = iam_get_head(l); -+ count = le16_to_cpu(ill->ill_count); -+ if (ill->ill_magic == le16_to_cpu(IAM_LEAF_HEADER_MAGIC) && -+ 0 <= count && count <= leaf_count_limit(l)) { -+ l->il_at = l->il_entries = iam_get_lentries(l); -+ result = 0; -+ } else { -+ struct inode *obj; -+ -+ obj = iam_leaf_container(l)->ic_object; -+ ext3_error(obj->i_sb, __FUNCTION__, -+ "Wrong magic in node %llu (#%lu): %#x != %#x or " -+ "wrong count: %i (%i)", -+ (unsigned long long)l->il_bh->b_blocknr, obj->i_ino, -+ ill->ill_magic, le16_to_cpu(IAM_LEAF_HEADER_MAGIC), -+ count, leaf_count_limit(l)); -+ result = -EIO; -+ BREAKPOINT; -+ } -+ return result; ++ l->il_at = l->il_entries = (void *)getstart(l); ++ return 0; +} + +static void iam_htree_fini(struct iam_leaf *l) +{ + l->il_entries = l->il_at = NULL; -+ return; -+} -+ -+static struct iam_lentry *iam_htree_get_end(const struct iam_leaf *l) -+{ -+ int count = lentry_count_get(l); -+ struct iam_lentry *ile = iam_htree_shift(l, l->il_entries, count); -+ -+ return ile; +} + +struct iam_rec *iam_htree_rec(const struct iam_leaf *l) +{ -+ void *e = l->il_at; + assert(iam_leaf_at_rec(l)); -+ return e + iam_leaf_descr(l)->id_key_size; ++ return (void *)getent(l); +} + +static void iam_htree_next(struct iam_leaf *l) +{ ++ struct htree_dirent *scan; ++ struct htree_dirent *found; ++ + assert(iam_leaf_at_rec(l)); -+ l->il_at = iam_htree_shift(l, l->il_at, 1); ++ found = NULL; ++ for (scan = getstart(l); scan < gettop(l); scan = entnext(scan)) { ++ if (scan != getent(l) && ent_is_live(scan) && ++ entcmp(l, getent(l), scan) > 0 && ++ (found == NULL || entcmp(l, scan, found) < 0)) ++ found = scan; ++ } ++ l->il_at = (void *)(found ? : gettop(l)); +} + ++static int iam_htree_at_end(const struct iam_leaf *folio) ++{ ++ return getent(folio) >= gettop(folio); ++} ++ ++ +static int iam_htree_lookup(struct iam_leaf *l, const struct iam_key *k) +{ -+ struct iam_lentry *p, *q, *m, *t; + struct iam_container *c; -+ int count; ++ struct htree_dirent *scan; ++ struct htree_dirent *found; ++ __u32 hash; + int result; + -+ count = lentry_count_get(l); -+ if (count == 0) -+ return IAM_LOOKUP_EMPTY; -+ -+ result = IAM_LOOKUP_OK; + c = iam_leaf_container(l); -+ -+ p = l->il_entries; -+ q = iam_htree_shift(l, p, count - 1); -+ if (iam_keycmp(c, k, iam_leaf_key_at(p)) < 0) { ++ hash = *(__u32 *)k; ++ found = NULL; ++ for (scan = getstart(l); scan < gettop(l); scan = entnext(scan)) { ++ __u32 scanhash; ++ ++ if (ent_is_live(scan)) { ++ scanhash = gethash(l, scan); ++ if (hash == scanhash) { ++ found = scan; ++ break; ++ } else if (scanhash < hash) ++ found = scan; ++ } ++ } ++ if (found == NULL) { + /* -+ * @k is less than the least key in the leaf ++ * @k is less than all hashes in the leaf. + */ -+ l->il_at = p; ++ iam_htree_start(l); + result = IAM_LOOKUP_BEFORE; -+ } else if (iam_keycmp(c, iam_leaf_key_at(q), k) <= 0) { -+ l->il_at = q; + } else { -+ /* -+ * EWD1293 -+ */ -+ while (iam_htree_shift(l, p, 1) != q) { -+ m = iam_htree_shift(l, p, iam_htree_diff(l, q, p) / 2); -+ assert(p < m && m < q); -+ (iam_keycmp(c, iam_leaf_key_at(m), k) <= 0 ? p : q) = m; -+ } -+ assert(iam_keycmp(c, iam_leaf_key_at(p), k) <= 0 && -+ iam_keycmp(c, k, iam_leaf_key_at(q)) < 0); -+ /* -+ * skip over records with duplicate keys. -+ */ -+ while (p > l->il_entries) { -+ t = iam_htree_shift(l, p, -1); -+ if (iam_keycmp(c, iam_leaf_key_at(t), k) == 0) -+ p = t; -+ else -+ break; -+ } -+ l->il_at = p; ++ l->il_at = (void *)found; ++ result = IAM_LOOKUP_OK; ++ assert(iam_leaf_at_rec(l)); + } -+ assert(iam_leaf_at_rec(l)); -+ + return result; +} + +static void iam_htree_key_set(struct iam_leaf *l, const struct iam_key *k) +{ + assert(iam_leaf_at_rec(l)); -+ iam_keycpy(iam_leaf_container(l), iam_leaf_key_at(l->il_at), k); ++ assert(0); +} + +static void iam_htree_rec_set(struct iam_leaf *l, const struct iam_rec *r) +{ -+ assert(iam_leaf_at_rec(l)); -+ iam_reccpy(iam_leaf_path(l), iam_htree_rec(l), r); ++ memcpy(l->il_at, r, recsize(((struct htree_dirent *)r)->hd_namelen)); +} + +static void iam_htree_rec_add(struct iam_leaf *leaf, -+ const struct iam_key *k, const struct iam_rec *r) ++ const struct iam_key *k, const struct iam_rec *r) +{ -+ struct iam_lentry *end; -+ struct iam_lentry *cur; -+ struct iam_lentry *start; -+ ptrdiff_t diff; -+ int count; ++ struct htree_dirent *scan; ++ struct htree_dirent *new; ++ struct inode *dir; ++ const char *name; ++ int namelen; + + assert(iam_leaf_can_add(leaf, k, r)); + -+ count = lentry_count_get(leaf); -+ /* -+ * This branch handles two exceptional cases: -+ * -+ * - leaf positioned beyond last record, and -+ * -+ * - empty leaf. -+ */ -+ if (!iam_leaf_at_end(leaf)) { -+ end = iam_htree_get_end(leaf); -+ cur = leaf->il_at; -+ if (iam_keycmp(iam_leaf_container(leaf), -+ k, iam_leaf_key_at(cur)) >= 0) -+ iam_htree_next(leaf); -+ else -+ /* -+ * Another exceptional case: insertion with the key -+ * less than least key in the leaf. -+ */ -+ assert(cur == leaf->il_entries); ++ new = (void *)r; ++ assert(*(__u32 *)k == gethash(leaf, new)); + -+ start = leaf->il_at; -+ diff = (void *)end - (void *)start; -+ assert(diff >= 0); -+ memmove(iam_htree_shift(leaf, start, 1), start, diff); -+ } -+ lentry_count_set(leaf, count + 1); -+ iam_htree_key_set(leaf, k); -+ iam_htree_rec_set(leaf, r); -+ assert(iam_leaf_at_rec(leaf)); ++ dir = iam_leaf_container(leaf)->ic_object; ++ name = new->hd_name; ++ namelen = new->hd_namelen; ++ ++ scan = (void *)find_insertion_point(dir, leaf->il_bh, ++ name, namelen); ++ assert(!IS_ERR(scan)); ++ scan = (void *)split_entry(dir, (void *)scan, le32_to_cpu(new->hd_ino), ++ new->hd_type, name, namelen); ++ leaf->il_at = (void *)scan; +} + +static void iam_htree_rec_del(struct iam_leaf *leaf) +{ -+ struct iam_lentry *next, *end; -+ int count; -+ ptrdiff_t diff; ++ struct htree_dirent *scan; ++ struct htree_dirent *prev; + + assert(iam_leaf_at_rec(leaf)); + -+ count = lentry_count_get(leaf); -+ end = iam_htree_get_end(leaf); -+ next = iam_htree_shift(leaf, leaf->il_at, 1); -+ diff = (void *)end - (void *)next; -+ memmove(leaf->il_at, next, diff); ++ for (prev = NULL, scan = getstart(leaf); scan < getent(leaf); ++ prev = scan, scan = entnext(scan)) ++ ; + -+ lentry_count_set(leaf, count - 1); ++ assert(scan == getent(leaf)); ++ if (prev != NULL) { ++ prev->hd_reclen = cpu_to_le16(le16_to_cpu(prev->hd_reclen) + ++ le16_to_cpu(scan->hd_reclen)); ++ } else { ++ assert(scan == getstart(leaf)); ++ scan->hd_ino = 0; ++ } ++ iam_leaf_container(leaf)->ic_object->i_version ++; +} + -+static int iam_htree_can_add(const struct iam_leaf *l, -+ const struct iam_key *k, const struct iam_rec *r) ++static int iam_htree_can_add(const struct iam_leaf *leaf, ++ const struct iam_key *k, const struct iam_rec *r) +{ -+ return lentry_count_get(l) < leaf_count_limit(l); -+} ++ struct htree_dirent *scan; ++ int size; + -+static int iam_htree_at_end(const struct iam_leaf *folio) -+{ -+ return folio->il_at == iam_htree_get_end(folio); ++ size = recsize(((struct htree_dirent *)r)->hd_namelen); ++ for (scan = getstart(leaf); scan < gettop(leaf); scan = entnext(scan)) { ++ if (getfreespace(scan) >= size) ++ return 1; ++ } ++ return 0; +} + +static void iam_htree_init_new(struct iam_container *c, struct buffer_head *bh) +{ -+ struct iam_leaf_head *hdr; -+ -+ hdr = (struct iam_leaf_head*)bh->b_data; -+ hdr->ill_magic = cpu_to_le16(IAM_LEAF_HEADER_MAGIC); -+ hdr->ill_count = cpu_to_le16(0); ++ /* ++ * Do nothing, all work is done by iam_htree_split(). ++ */ +} + +static void iam_htree_split(struct iam_leaf *l, struct buffer_head **bh, + iam_ptr_t new_blknr) +{ -+ struct iam_path *path; -+ struct iam_leaf_head *hdr; -+ const struct iam_key *pivot; -+ struct buffer_head *new_leaf; -+ -+ unsigned count; -+ unsigned split; -+ -+ void *start; -+ void *finis; -+ -+ new_leaf = *bh; -+ path = iam_leaf_path(l); -+ -+ hdr = (void *)new_leaf->b_data; -+ -+ count = lentry_count_get(l); -+ split = count / 2; -+ -+ start = iam_htree_shift(l, iam_get_lentries(l), split); -+ finis = iam_htree_shift(l, iam_get_lentries(l), count); -+ -+ pivot = iam_leaf_key_at(start); ++ __u32 delim_hash; ++ __u32 old_hash; ++ struct buffer_head *newbh = *bh; ++ struct iam_path *path; + -+ memmove(iam_entries(new_leaf), start, finis - start); -+ hdr->ill_count = count - split; -+ lentry_count_set(l, split); ++ old_hash = gethash(l, getent(l)); ++ move_entries(iam_leaf_container(l)->ic_object, ++ getipc(l)->ipc_hinfo, &l->il_bh, bh, &delim_hash); + /* + * Insert pointer to the new node (together with the least key in + * the node) into index node. + */ -+ iam_insert_key(path, path->ip_frame, pivot, new_blknr); -+ if ((void *)l->il_at >= start) { ++ path = iam_leaf_path(l); ++ iam_insert_key(path, path->ip_frame, (void *)&delim_hash, new_blknr); ++ if (l->il_bh == newbh) { + /* + * insertion point moves into new leaf. + */ -+ int shift; -+ int result; -+ -+ shift = iam_htree_diff(l, l->il_at, start); -+ *bh = l->il_bh; -+ l->il_bh = new_leaf; -+ result = iam_htree_init(l); -+ /* -+ * init cannot fail, as node was just initialized. -+ */ -+ assert(result == 0); -+ l->il_at = iam_htree_shift(l, iam_get_lentries(l), shift); ++ assert(delim_hash >= old_hash); ++ iam_htree_lookup(l, (void *)&old_hash); + } -+ +} + +static struct iam_leaf_operations iam_htree_leaf_ops = { @@ -1694,107 +1643,149 @@ Index: iam/fs/ext3/iam_htree.c + * Index operations. + */ + -+enum { -+ /* This is duplicated in lustre/utils/create_iam.c */ -+ /* -+ * Then shalt thou see the dew-BEDABBLED wretch -+ * Turn, and return, indenting with the way; -+ * Each envious brier his weary legs doth scratch, -+ * Each shadow makes him stop, each murmur stay: -+ * For misery is trodden on by many, -+ * And being low never relieved by any. -+ */ -+ IAM_HTREE_ROOT_MAGIC = 0xbedabb1edULL // d01efull -+}; -+ -+/* This is duplicated in lustre/utils/create_iam.c */ -+struct iam_htree_root { -+ __le64 ilr_magic; -+ __le16 ilr_keysize; -+ __le16 ilr_recsize; -+ __le16 ilr_ptrsize; -+ __le16 ilr_indirect_levels; -+}; -+ +static __u32 iam_htree_root_ptr(struct iam_container *c) +{ -+ return 0; ++ return 0; +} + -+static int iam_htree_node_init(struct iam_container *c, struct buffer_head *bh, -+ int root) ++static int iam_htree_node_check(struct iam_path *path, struct iam_frame *frame) +{ -+ return 0; ++ /* XXX no checks yet */ ++ return 0; +} + -+static void iam_htree_root_inc(struct iam_container *c, struct iam_frame *frame) ++static int is_htree(struct super_block *sb, ++ const struct dx_root *root, int silent) +{ -+ struct iam_htree_root *root; -+ root = (void *)frame->bh->b_data; -+ assert(le64_to_cpu(root->ilr_magic) == IAM_HTREE_ROOT_MAGIC); -+ root->ilr_indirect_levels ++; ++ if (root->info.hash_version > DX_HASH_MAX) { ++ if (!silent) ++ ext3_warning(sb, __FUNCTION__, ++ "Unrecognised inode hash code %d", ++ root->info.hash_version); ++ return ERR_BAD_DX_DIR; ++ } ++ ++ if (root->info.unused_flags & 1) { ++ if (!silent) ++ ext3_warning(sb, __FUNCTION__, ++ "Unimplemented inode hash flags: %#06x", ++ root->info.unused_flags); ++ return ERR_BAD_DX_DIR; ++ } ++ ++ if (root->info.indirect_levels > DX_MAX_TREE_HEIGHT - 1) { ++ if (!silent) ++ ext3_warning(sb, __FUNCTION__, ++ "Unimplemented inode hash depth: %#06x", ++ root->info.indirect_levels); ++ return ERR_BAD_DX_DIR; ++ } ++ return 0; +} + -+static int iam_htree_node_check(struct iam_path *path, struct iam_frame *frame) ++static int iam_htree_node_load(struct iam_path *path, struct iam_frame *frame) +{ -+ unsigned count; -+ unsigned limit; -+ unsigned limit_correct; -+ struct iam_entry *entries; ++ void *data; ++ struct iam_entry *entries; ++ struct super_block *sb; + -+ entries = dx_node_get_entries(path, frame); ++ data = frame->bh->b_data; ++ entries = dx_node_get_entries(path, frame); ++ sb = iam_path_obj(path)->i_sb; ++ if (frame == path->ip_frames) { ++ /* root node */ ++ struct dx_root *root; ++ struct iam_path_compat *ipc; ++ int check; + -+ if (frame == path->ip_frames) { -+ struct iam_htree_root *root; ++ root = data; ++ assert(path->ip_data != NULL); ++ ipc = container_of(path->ip_data, struct iam_path_compat, ++ ipc_descr); + -+ root = (void *)frame->bh->b_data; -+ if (le64_to_cpu(root->ilr_magic) != IAM_HTREE_ROOT_MAGIC) { -+ BREAKPOINT; -+ return -EIO; -+ } -+ limit_correct = dx_root_limit(path); -+ } else -+ limit_correct = dx_node_limit(path); -+ count = dx_get_count(entries); -+ limit = dx_get_limit(entries); -+ if (count > limit) { -+ BREAKPOINT; -+ return -EIO; -+ } -+ if (limit != limit_correct) { -+ BREAKPOINT; -+ return -EIO; -+ } -+ return 0; ++ check = is_htree(sb, root, 0); ++ if (check != 0) ++ return check; ++ path->ip_indirect = root->info.indirect_levels; ++ ++ assert((char *)entries == (((char *)&root->info) + ++ root->info.info_length)); ++ assert(dx_get_limit(entries) == dx_root_limit(path)); ++ ++ ipc->ipc_hinfo->hash_version = root->info.hash_version; ++ ipc->ipc_hinfo->seed = EXT3_SB(sb)->s_hash_seed; ++ if (ipc->ipc_dentry) ++ ext3fs_dirhash(ipc->ipc_dentry->d_name.name, ++ ipc->ipc_dentry->d_name.len, ++ ipc->ipc_hinfo); ++ path->ip_key_target = ++ (const struct iam_key *)&ipc->ipc_hinfo->hash; ++ } else { ++ /* non-root index */ ++ assert(entries == data + iam_path_descr(path)->id_node_gap); ++ assert(dx_get_limit(entries) == dx_node_limit(path)); ++ } ++ frame->entries = frame->at = entries; ++ return 0; +} + -+static int iam_htree_node_load(struct iam_path *path, struct iam_frame *frame) ++static int iam_htree_node_init(struct iam_container *c, ++ struct buffer_head *bh, int root) ++{ ++ struct dx_node *node; ++ ++ assert(!root); ++ ++ node = (void *)bh->b_data; ++ node->fake.rec_len = cpu_to_le16(c->ic_object->i_sb->s_blocksize); ++ node->fake.inode = 0; ++ return 0; ++} ++ ++static struct iam_entry *iam_htree_root_inc(struct iam_container *c, ++ struct iam_path *path, ++ struct iam_frame *frame) +{ ++ struct dx_root *root; + struct iam_entry *entries; -+ void *data; -+ entries = dx_node_get_entries(path, frame); + -+ data = frame->bh->b_data; ++ entries = frame->entries; + -+ if (frame == path->ip_frames) { -+ struct iam_htree_root *root; ++ dx_set_count(entries, 1); ++ root = (struct dx_root *) frame->bh->b_data; ++ root->info.indirect_levels++; + -+ root = data; -+ path->ip_indirect = le16_to_cpu(root->ilr_indirect_levels); -+ } -+ frame->entries = frame->at = entries; -+ return 0; ++ return entries; +} + -+static int iam_htree_node_create(struct iam_container *c) ++static int iam_htree_keycmp(const struct iam_container *c, ++ const struct iam_key *k1, const struct iam_key *k2) +{ -+ return 0; ++ __u32 p1 = le32_to_cpu(*(__u32 *)k1); ++ __u32 p2 = le32_to_cpu(*(__u32 *)k2); ++ ++ return p1 > p2 ? +1 : (p1 < p2 ? -1 : 0); +} + -+static int iam_htree_keycmp(const struct iam_container *c, -+ const struct iam_key *k1, const struct iam_key *k2) ++static struct iam_path_descr *iam_htree_ipd_alloc(const struct iam_container *c) +{ -+ return memcmp(k1, k2, c->ic_descr->id_key_size); ++ struct iam_path_compat *ipc; ++ ++ ipc = kmalloc(sizeof *ipc, GFP_KERNEL); ++ if (ipc != NULL) { ++ iam_path_compat_init(ipc, c->ic_object); ++ return &ipc->ipc_descr; ++ } else ++ return NULL; ++} ++ ++static void iam_htree_ipd_free(const struct iam_container *c, ++ struct iam_path_descr *ipd) ++{ ++ struct iam_path_compat *ipc; ++ ++ ipc = container_of(ipd, struct iam_path_compat, ipc_descr); ++ kfree(ipc); +} + +static struct iam_operations iam_htree_ops = { @@ -1803,35 +1794,41 @@ Index: iam/fs/ext3/iam_htree.c + .id_node_init = iam_htree_node_init, + .id_node_check = iam_htree_node_check, + .id_node_load = iam_htree_node_load, -+ .id_create = iam_htree_node_create, + .id_keycmp = iam_htree_keycmp, + .id_root_inc = iam_htree_root_inc, -+ .id_name = "lfix" ++ .id_ipd_alloc = iam_htree_ipd_alloc, ++ .id_ipd_free = iam_htree_ipd_free, ++ .id_name = "htree" ++}; ++ ++/* ++ * Parameters describing iam compatibility mode in which existing ext3 htrees ++ * can be manipulated. ++ */ ++struct iam_descr iam_htree_compat_param = { ++ .id_key_size = sizeof ((struct dx_map_entry *)NULL)->hash, ++ .id_ptr_size = sizeof ((struct dx_map_entry *)NULL)->offs, ++ .id_node_gap = offsetof(struct dx_node, entries), ++ .id_root_gap = offsetof(struct dx_root, entries), ++ .id_ops = &iam_htree_ops, ++ .id_leaf_ops = &iam_htree_leaf_ops +}; ++EXPORT_SYMBOL(iam_htree_compat_param); + +static int iam_htree_guess(struct iam_container *c) +{ + int result; + struct buffer_head *bh; -+ const struct iam_htree_root *root; ++ const struct dx_root *root; + + assert(c->ic_object != NULL); + + result = iam_node_read(c, iam_htree_root_ptr(c), NULL, &bh); + if (result == 0) { + root = (void *)bh->b_data; -+ if (le64_to_cpu(root->ilr_magic) == IAM_HTREE_ROOT_MAGIC) { -+ struct iam_descr *descr; -+ -+ descr = c->ic_descr; -+ descr->id_key_size = le16_to_cpu(root->ilr_keysize); -+ descr->id_rec_size = le16_to_cpu(root->ilr_recsize); -+ descr->id_ptr_size = le16_to_cpu(root->ilr_ptrsize); -+ descr->id_root_gap = sizeof(struct iam_htree_root); -+ descr->id_node_gap = 0; -+ descr->id_ops = &iam_htree_ops; -+ descr->id_leaf_ops = &iam_htree_leaf_ops; -+ } else ++ if (is_htree(c->ic_object->i_sb, root, 1)) ++ c->ic_descr = &iam_htree_compat_param; ++ else + result = -EBADF; + } + return result; @@ -1845,13 +1842,11 @@ Index: iam/fs/ext3/iam_htree.c +{ + iam_format_register(&iam_htree_format); +} -+ -+#endif Index: iam/fs/ext3/iam_lfix.c =================================================================== --- iam.orig/fs/ext3/iam_lfix.c 2004-04-06 17:27:52.000000000 +0400 -+++ iam/fs/ext3/iam_lfix.c 2006-06-20 23:39:51.000000000 +0400 -@@ -0,0 +1,626 @@ ++++ iam/fs/ext3/iam_lfix.c 2006-06-22 15:30:33.000000000 +0400 +@@ -0,0 +1,629 @@ +/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- + * vim:expandtab:shiftwidth=8:tabstop=8: + * @@ -2028,7 +2023,6 @@ Index: iam/fs/ext3/iam_lfix.c +static void iam_lfix_fini(struct iam_leaf *l) +{ + l->il_entries = l->il_at = NULL; -+ return; +} + +static struct iam_lentry *iam_lfix_get_end(const struct iam_leaf *l) @@ -2306,12 +2300,22 @@ Index: iam/fs/ext3/iam_lfix.c + return 0; +} + -+static void iam_lfix_root_inc(struct iam_container *c, struct iam_frame *frame) ++static struct iam_entry *iam_lfix_root_inc(struct iam_container *c, ++ struct iam_path *path, ++ struct iam_frame *frame) +{ + struct iam_lfix_root *root; ++ struct iam_entry *entries; ++ ++ entries = frame->entries; ++ ++ dx_set_count(entries, 2); ++ assert(dx_get_limit(entries) == dx_root_limit(path)); ++ + root = (void *)frame->bh->b_data; + assert(le64_to_cpu(root->ilr_magic) == IAM_LFIX_ROOT_MAGIC); + root->ilr_indirect_levels ++; ++ return iam_entry_shift(path, entries, 1); +} + +static int iam_lfix_node_check(struct iam_path *path, struct iam_frame *frame) @@ -2365,11 +2369,6 @@ Index: iam/fs/ext3/iam_lfix.c + return 0; +} + -+static int iam_lfix_node_create(struct iam_container *c) -+{ -+ return 0; -+} -+ +static int iam_lfix_keycmp(const struct iam_container *c, + const struct iam_key *k1, const struct iam_key *k2) +{ @@ -2393,7 +2392,6 @@ Index: iam/fs/ext3/iam_lfix.c + .id_node_init = iam_lfix_node_init, + .id_node_check = iam_lfix_node_check, + .id_node_load = iam_lfix_node_load, -+ .id_create = iam_lfix_node_create, + .id_keycmp = iam_lfix_keycmp, + .id_root_inc = iam_lfix_root_inc, + .id_ipd_alloc = iam_lfix_ipd_alloc, @@ -2481,7 +2479,7 @@ Index: iam/fs/ext3/iam_lfix.c Index: iam/fs/ext3/namei.c =================================================================== --- iam.orig/fs/ext3/namei.c 2006-05-31 20:24:32.000000000 +0400 -+++ iam/fs/ext3/namei.c 2006-06-21 22:25:40.000000000 +0400 ++++ iam/fs/ext3/namei.c 2006-06-22 16:57:21.000000000 +0400 @@ -24,81 +24,6 @@ * Theodore Ts'o, 2002 */ @@ -2609,21 +2607,58 @@ Index: iam/fs/ext3/namei.c #ifndef swap #define swap(x, y) do { typeof(x) z = x; x = y; y = z; } while (0) -@@ -162,10 +88,6 @@ struct fake_dirent { - u8 file_type; - }; +@@ -155,293 +81,10 @@ static struct buffer_head *ext3_append(h + #define dxtrace(command) + #endif +-struct fake_dirent { +- __le32 inode; +- __le16 rec_len; +- u8 name_len; +- u8 file_type; +-}; +- -struct dx_countlimit { - __le16 limit; - __le16 count; -}; - - /* - * dx_root_info is laid out so that if it should somehow get overlaid by a -@@ -203,245 +125,10 @@ struct dx_map_entry - }; - - +- +-/* +- * dx_root_info is laid out so that if it should somehow get overlaid by a +- * dirent the two low bits of the hash version will be zero. Therefore, the +- * hash version mod 4 should never be 0. Sincerely, the paranoia department. +- */ +- +-struct dx_root { +- struct fake_dirent dot; +- char dot_name[4]; +- struct fake_dirent dotdot; +- char dotdot_name[4]; +- struct dx_root_info +- { +- __le32 reserved_zero; +- u8 hash_version; +- u8 info_length; /* 8 */ +- u8 indirect_levels; +- u8 unused_flags; +- } +- info; +- struct {} entries[0]; +-}; +- +-struct dx_node +-{ +- struct fake_dirent fake; +- struct {} entries[0]; +-}; +- +-struct dx_map_entry +-{ +- u32 hash; +- u32 offs; +-}; +- +- -static u32 htree_root_ptr(struct iam_container *c); -static int htree_node_check(struct iam_path *path, struct iam_frame *frame); -static int htree_node_init(struct iam_container *c, @@ -2866,7 +2901,7 @@ Index: iam/fs/ext3/namei.c static unsigned dx_get_limit(struct iam_entry *entries); static void dx_set_count(struct iam_entry *entries, unsigned value); static void dx_set_limit(struct iam_entry *entries, unsigned value); -@@ -457,81 +144,29 @@ static void dx_sort_map(struct dx_map_en +@@ -457,264 +100,51 @@ static void dx_sort_map(struct dx_map_en static struct ext3_dir_entry_2 *dx_move_dirents (char *from, char *to, struct dx_map_entry *offsets, int count); static struct ext3_dir_entry_2* dx_pack_dirents (char *base, int size); @@ -2904,21 +2939,18 @@ Index: iam/fs/ext3/namei.c - return p->ip_container->ic_object; -} - - static inline size_t iam_entry_size(struct iam_path *p) - { +-static inline size_t iam_entry_size(struct iam_path *p) +-{ - return path_descr(p)->id_key_size + path_descr(p)->id_ptr_size; -+ return iam_path_descr(p)->id_key_size + iam_path_descr(p)->id_ptr_size; - } - - static inline struct iam_entry *iam_entry_shift(struct iam_path *p, +-} +- +-static inline struct iam_entry *iam_entry_shift(struct iam_path *p, - struct iam_entry *entry, int shift) -+ struct iam_entry *entry, -+ int shift) - { - void *e = entry; - return e + shift * iam_entry_size(p); - } - +-{ +- void *e = entry; +- return e + shift * iam_entry_size(p); +-} +- -static inline ptrdiff_t iam_entry_diff(struct iam_path *p, - struct iam_entry *e1, struct iam_entry *e2) -{ @@ -2945,105 +2977,67 @@ Index: iam/fs/ext3/namei.c -static inline struct iam_key *dx_get_key(struct iam_path *p, - struct iam_entry *entry, - struct iam_key *key) -+static inline struct iam_key *iam_get_key(struct iam_path *p, -+ struct iam_entry *entry, -+ struct iam_key *key) - { +-{ - memcpy(key, entry, path_descr(p)->id_key_size); - return key; -+ return memcpy(key, entry, iam_path_descr(p)->id_key_size); - } - - static inline struct iam_key *iam_key_at(struct iam_path *p, -@@ -540,85 +175,118 @@ static inline struct iam_key *iam_key_at - return (struct iam_key *)entry; - } - +-} +- +-static inline struct iam_key *iam_key_at(struct iam_path *p, +- struct iam_entry *entry) +-{ +- return (struct iam_key *)entry; +-} +- -static inline void dx_set_key(struct iam_path *p, - struct iam_entry *entry, struct iam_key *key) -+static inline ptrdiff_t iam_entry_diff(struct iam_path *p, -+ struct iam_entry *e1, -+ struct iam_entry *e2) - { +-{ - memcpy(entry, key, path_descr(p)->id_key_size); -} -+ ptrdiff_t diff; - +- -static inline unsigned dx_get_count (struct iam_entry *entries) -{ - return le16_to_cpu(((struct dx_countlimit *) entries)->count); -+ diff = (void *)e1 - (void *)e2; -+ assert(diff / iam_entry_size(p) * iam_entry_size(p) == diff); -+ return diff / iam_entry_size(p); - } - +-} +- -static inline unsigned dx_get_limit (struct iam_entry *entries) -+static inline void dx_set_limit(struct iam_entry *entries, unsigned value) - { +-{ - return le16_to_cpu(((struct dx_countlimit *) entries)->limit); -+ ((struct dx_countlimit *) entries)->limit = cpu_to_le16(value); - } - +-} +- -static inline void dx_set_count (struct iam_entry *entries, unsigned value) -{ - ((struct dx_countlimit *) entries)->count = cpu_to_le16(value); -} -+/* -+ * Two iam_descr's are provided: -+ * -+ * - htree_compat_param that supports legacy ext3-htree indices; -+ * - fixed_rec_param that supports containers with records of fixed size. -+ * -+ */ - +- -static inline void dx_set_limit (struct iam_entry *entries, unsigned value) --{ -- ((struct dx_countlimit *) entries)->limit = cpu_to_le16(value); -+static u32 htree_root_ptr(struct iam_container *c); -+static int htree_node_check(struct iam_path *path, struct iam_frame *frame); -+static int htree_node_load(struct iam_path *path, struct iam_frame *frame); -+static int htree_node_init(struct iam_container *c, struct buffer_head *bh, int root); -+static int htree_keycmp(const struct iam_container *c, -+ const struct iam_key *k1, const struct iam_key *k2); -+ -+static struct iam_path_descr *htree_ipd_alloc(const struct iam_container *c) -+{ -+ struct iam_path_compat *ipc; -+ -+ ipc = kmalloc(sizeof *ipc, GFP_KERNEL); -+ if (ipc != NULL) { -+ iam_path_compat_init(ipc, c->ic_object); -+ return &ipc->ipc_descr; -+ } else -+ return NULL; ++static inline void dx_set_limit(struct iam_entry *entries, unsigned value) + { + ((struct dx_countlimit *) entries)->limit = cpu_to_le16(value); } -static inline unsigned dx_root_limit(struct iam_path *p) -+static void htree_ipd_free(const struct iam_container *c, -+ struct iam_path_descr *ipd) - { +-{ - struct iam_descr *param = path_descr(p); - unsigned entry_space = path_obj(p)->i_sb->s_blocksize - - param->id_root_gap; - return entry_space / (param->id_key_size + param->id_ptr_size); -} -+ struct iam_path_compat *ipc; - +- -static inline unsigned dx_node_limit(struct iam_path *p) --{ ++int dx_index_is_compat(struct iam_path *path) + { - struct iam_descr *param = path_descr(p); - unsigned entry_space = path_obj(p)->i_sb->s_blocksize - - param->id_node_gap; - return entry_space / (param->id_key_size + param->id_ptr_size); -+ ipc = container_of(ipd, struct iam_path_compat, ipc_descr); -+ kfree(ipc); ++ return iam_path_descr(path) == &iam_htree_compat_param; } -static inline int dx_index_is_compat(struct iam_path *path) -{ - return path_descr(path) == &htree_compat_param; -} - +- -static struct iam_entry *dx_get_entries(struct iam_path *path, void *data, - int root) -{ @@ -3051,43 +3045,15 @@ Index: iam/fs/ext3/namei.c - (root ? - path_descr(path)->id_root_gap : path_descr(path)->id_node_gap); -} -+static struct iam_operations htree_operation = { -+ .id_root_ptr = htree_root_ptr, -+ .id_node_check = htree_node_check, -+ .id_node_load = htree_node_load, -+ .id_node_init = htree_node_init, -+ .id_node_read = iam_node_read, -+ .id_keycmp = htree_keycmp, -+ .id_ipd_alloc = htree_ipd_alloc, -+ .id_ipd_free = htree_ipd_free, -+ .id_name = "htree" -+}; -+ -+/* -+ * Parameters describing iam compatibility mode in which existing ext3 htrees -+ * can be manipulated. -+ */ -+struct iam_descr htree_compat_param = { -+ .id_key_size = sizeof ((struct dx_map_entry *)NULL)->hash, -+ .id_ptr_size = sizeof ((struct dx_map_entry *)NULL)->offs, -+ .id_node_gap = offsetof(struct dx_node, entries), -+ .id_root_gap = offsetof(struct dx_root, entries), -+ .id_ops = &htree_operation, -+// .id_leaf_ops = &htree_leaf_operation -+}; -+EXPORT_SYMBOL(htree_compat_param); - +- -static struct iam_entry *dx_node_get_entries(struct iam_path *path, - struct iam_frame *frame) -+int dx_index_is_compat(struct iam_path *path) - { +-{ - return dx_get_entries(path, - frame->bh->b_data, frame == path->ip_frames); -+ return iam_path_descr(path) == &htree_compat_param; - } +-} -static int dx_node_check(struct iam_path *p, struct iam_frame *f) -+ +int dx_node_check(struct iam_path *p, struct iam_frame *f) { struct iam_entry *e; @@ -3111,207 +3077,219 @@ Index: iam/fs/ext3/namei.c - keycmp(c, p->ip_key_scratch[0], p->ip_key_scratch[1]) > 0) + iam_keycmp(c, iam_path_key(p, 0), iam_path_key(p, 1)) > 0) { + BREAKPOINT; -+ return 0; -+ } -+ blk = dx_get_block(p, e); -+ if (inode->i_size < (blk + 1) * inode->i_sb->s_blocksize) { -+ BREAKPOINT; return 0; -+ } - } - return 1; - } -@@ -630,19 +298,29 @@ static u32 htree_root_ptr(struct iam_con - - static int htree_node_check(struct iam_path *path, struct iam_frame *frame) - { -+ /* XXX no checks yet */ -+ return 0; -+} -+ -+static int htree_node_load(struct iam_path *path, struct iam_frame *frame) -+{ - void *data; - struct iam_entry *entries; - struct super_block *sb; - - data = frame->bh->b_data; - entries = dx_node_get_entries(path, frame); +- } +- return 1; +-} +- +-static u32 htree_root_ptr(struct iam_container *c) +-{ +- return 0; +-} +- +-static int htree_node_check(struct iam_path *path, struct iam_frame *frame) +-{ +- void *data; +- struct iam_entry *entries; +- struct super_block *sb; +- +- data = frame->bh->b_data; +- entries = dx_node_get_entries(path, frame); - sb = path_obj(path)->i_sb; -+ sb = iam_path_obj(path)->i_sb; - if (frame == path->ip_frames) { - /* root node */ - struct dx_root *root; +- if (frame == path->ip_frames) { +- /* root node */ +- struct dx_root *root; - struct htree_cookie *hc = path->ip_descr_data; -+ struct iam_path_compat *ipc; - - root = data; -+ assert(path->ip_data != NULL); -+ ipc = container_of(path->ip_data, struct iam_path_compat, -+ ipc_descr); -+ - if (root->info.hash_version > DX_HASH_MAX) { - ext3_warning(sb, __FUNCTION__, - "Unrecognised inode hash code %d", -@@ -669,15 +347,17 @@ static int htree_node_check(struct iam_p - root->info.info_length)); - assert(dx_get_limit(entries) == dx_root_limit(path)); - +- +- root = data; +- if (root->info.hash_version > DX_HASH_MAX) { +- ext3_warning(sb, __FUNCTION__, +- "Unrecognised inode hash code %d", +- root->info.hash_version); +- return ERR_BAD_DX_DIR; + } +- +- if (root->info.unused_flags & 1) { +- ext3_warning(sb, __FUNCTION__, +- "Unimplemented inode hash flags: %#06x", +- root->info.unused_flags); +- return ERR_BAD_DX_DIR; +- } +- +- path->ip_indirect = root->info.indirect_levels; +- if (path->ip_indirect > DX_MAX_TREE_HEIGHT - 1) { +- ext3_warning(sb, __FUNCTION__, +- "Unimplemented inode hash depth: %#06x", +- root->info.indirect_levels); +- return ERR_BAD_DX_DIR; ++ blk = dx_get_block(p, e); ++ if (inode->i_size < (blk + 1) * inode->i_sb->s_blocksize) { ++ BREAKPOINT; ++ return 0; + } +- +- assert((char *)entries == (((char *)&root->info) + +- root->info.info_length)); +- assert(dx_get_limit(entries) == dx_root_limit(path)); +- - hc->hinfo->hash_version = root->info.hash_version; - hc->hinfo->seed = EXT3_SB(sb)->s_hash_seed; - if (hc->dentry) - ext3fs_dirhash(hc->dentry->d_name.name, - hc->dentry->d_name.len, hc->hinfo); - path->ip_key_target = (struct iam_key *)&hc->hinfo->hash; -+ ipc->ipc_hinfo->hash_version = root->info.hash_version; -+ ipc->ipc_hinfo->seed = EXT3_SB(sb)->s_hash_seed; -+ if (ipc->ipc_dentry) -+ ext3fs_dirhash(ipc->ipc_dentry->d_name.name, -+ ipc->ipc_dentry->d_name.len, -+ ipc->ipc_hinfo); -+ path->ip_key_target = -+ (const struct iam_key *)&ipc->ipc_hinfo->hash; - } else { - /* non-root index */ +- } else { +- /* non-root index */ - assert(entries == data + path_descr(path)->id_node_gap); -+ assert(entries == data + iam_path_descr(path)->id_node_gap); - assert(dx_get_limit(entries) == dx_node_limit(path)); +- assert(dx_get_limit(entries) == dx_node_limit(path)); } - frame->entries = frame->at = entries; -@@ -697,8 +377,8 @@ static int htree_node_init(struct iam_co - return 0; - } - +- frame->entries = frame->at = entries; +- return 0; +-} +- +-static int htree_node_init(struct iam_container *c, +- struct buffer_head *bh, int root) +-{ +- struct dx_node *node; +- +- assert(!root); +- +- node = (void *)bh->b_data; +- node->fake.rec_len = cpu_to_le16(c->ic_object->i_sb->s_blocksize); +- node->fake.inode = 0; +- return 0; +-} +- -static int htree_node_read(struct iam_container *c, iam_ptr_t ptr, - handle_t *handle, struct buffer_head **bh) -+int iam_node_read(struct iam_container *c, iam_ptr_t ptr, -+ handle_t *handle, struct buffer_head **bh) - { - int result = 0; - -@@ -708,8 +388,8 @@ static int htree_node_read(struct iam_co - return result; - } - +-{ +- int result = 0; +- +- *bh = ext3_bread(handle, c->ic_object, (int)ptr, 0, &result); +- if (*bh == NULL) +- result = -EIO; +- return result; +-} +- -static int htree_keycmp(struct iam_container *c, - struct iam_key *k1, struct iam_key *k2) -+static int htree_keycmp(const struct iam_container *c, -+ const struct iam_key *k1, const struct iam_key *k2) - { - __u32 p1 = le32_to_cpu(*(__u32 *)k1); - __u32 p2 = le32_to_cpu(*(__u32 *)k2); -@@ -800,7 +480,7 @@ struct stats dx_show_entries(struct dx_h +-{ +- __u32 p1 = le32_to_cpu(*(__u32 *)k1); +- __u32 p2 = le32_to_cpu(*(__u32 *)k2); +- +- return p1 > p2 ? +1 : (p1 < p2 ? -1 : 0); ++ return 1; + } + + /* +@@ -800,598 +230,132 @@ struct stats dx_show_entries(struct dx_h } #endif /* DX_DEBUG */ -static int dx_lookup(struct iam_path *path) -+int dx_lookup(struct iam_path *path) - { - u32 ptr; - int err = 0; -@@ -810,11 +490,11 @@ static int dx_lookup(struct iam_path *pa - struct iam_frame *frame; - struct iam_container *c; - +-{ +- u32 ptr; +- int err = 0; +- int i; +- +- struct iam_descr *param; +- struct iam_frame *frame; +- struct iam_container *c; +- - param = path_descr(path); -+ param = iam_path_descr(path); - c = path->ip_container; - - for (frame = path->ip_frames, i = 0, +- c = path->ip_container; +- +- for (frame = path->ip_frames, i = 0, - ptr = param->id_root_ptr(path->ip_container); -+ ptr = param->id_ops->id_root_ptr(c); - i <= path->ip_indirect; - ptr = dx_get_block(path, frame->at), ++frame, ++i) { - struct iam_entry *entries; -@@ -823,10 +503,16 @@ static int dx_lookup(struct iam_path *pa - struct iam_entry *m; - unsigned count; - +- i <= path->ip_indirect; +- ptr = dx_get_block(path, frame->at), ++frame, ++i) { +- struct iam_entry *entries; +- struct iam_entry *p; +- struct iam_entry *q; +- struct iam_entry *m; +- unsigned count; +- - err = param->id_node_read(c, (iam_ptr_t)ptr, NULL, &frame->bh); -+ err = param->id_ops->id_node_read(c, (iam_ptr_t)ptr, NULL, -+ &frame->bh); - if (err != 0) - break; +- if (err != 0) +- break; - err = param->id_node_check(path, frame); -+ -+ err = param->id_ops->id_node_check(path, frame); -+ if (err != 0) -+ break; -+ -+ err = param->id_ops->id_node_load(path, frame); - if (err != 0) - break; - -@@ -837,12 +523,28 @@ static int dx_lookup(struct iam_path *pa - assert(count && count <= dx_get_limit(entries)); - p = iam_entry_shift(path, entries, 1); - q = iam_entry_shift(path, entries, count - 1); -+ /* -+ * Sanity check: target key is larger or equal to the leftmost -+ * key in the node. -+ */ -+ if (!dx_index_is_compat(path) && -+ iam_keycmp(c, iam_key_at(path, p), -+ path->ip_key_target) > 0) { -+ struct inode *obj; -+ -+ obj = c->ic_object; -+ ext3_error(obj->i_sb, __FUNCTION__, -+ "corrupted search tree #%lu", obj->i_ino); -+ err = -EIO; -+ break; -+ -+ } - while (p <= q) { - m = iam_entry_shift(path, - p, iam_entry_diff(path, q, p) / 2); - dxtrace(printk(".")); +- if (err != 0) +- break; +- +- assert(dx_node_check(path, frame)); +- +- entries = frame->entries; +- count = dx_get_count(entries); +- assert(count && count <= dx_get_limit(entries)); +- p = iam_entry_shift(path, entries, 1); +- q = iam_entry_shift(path, entries, count - 1); +- while (p <= q) { +- m = iam_entry_shift(path, +- p, iam_entry_diff(path, q, p) / 2); +- dxtrace(printk(".")); - if (keycmp(c, iam_key_at(path, m), - path->ip_key_target) > 0) -+ if (iam_keycmp(c, iam_key_at(path, m), -+ path->ip_key_target) > 0) - q = iam_entry_shift(path, m, -1); - else - p = iam_entry_shift(path, m, +1); -@@ -857,12 +559,12 @@ static int dx_lookup(struct iam_path *pa - while (n--) { - dxtrace(printk(",")); - at = iam_entry_shift(path, at, +1); +- q = iam_entry_shift(path, m, -1); +- else +- p = iam_entry_shift(path, m, +1); +- } +- +- frame->at = iam_entry_shift(path, p, -1); +- if (1) { // linear search cross check +- unsigned n = count - 1; +- struct iam_entry *at; +- +- at = entries; +- while (n--) { +- dxtrace(printk(",")); +- at = iam_entry_shift(path, at, +1); - if (keycmp(c, iam_key_at(path, at), - path->ip_key_target) > 0) { -+ if (iam_keycmp(c, iam_key_at(path, at), -+ path->ip_key_target) > 0) { - if (at != iam_entry_shift(path, frame->at, 1)) { - BREAKPOINT; - printk(KERN_EMERG "%i\n", +- if (at != iam_entry_shift(path, frame->at, 1)) { +- BREAKPOINT; +- printk(KERN_EMERG "%i\n", - keycmp(c, iam_key_at(path, at), -+ iam_keycmp(c, iam_key_at(path, at), - path->ip_key_target)); - } - at = iam_entry_shift(path, at, -1); -@@ -891,508 +593,20 @@ static int dx_probe(struct dentry *dentr - struct dx_hash_info *hinfo, struct iam_path *path) - { - int err; +- path->ip_key_target)); +- } +- at = iam_entry_shift(path, at, -1); +- break; +- } +- } +- assert(at == frame->at); +- } +- } +- if (err != 0) +- iam_path_fini(path); +- path->ip_frame = --frame; +- return err; +-} +- +-/* +- * Probe for a directory leaf block to search. +- * +- * dx_probe can return ERR_BAD_DX_DIR, which means there was a format +- * error in the directory index, and the caller should fall back to +- * searching the directory normally. The callers of dx_probe **MUST** +- * check for this error code, and make sure it never gets reflected +- * back to userspace. +- */ +-static int dx_probe(struct dentry *dentry, struct inode *dir, +- struct dx_hash_info *hinfo, struct iam_path *path) +-{ +- int err; - struct htree_cookie hc = { - .dentry = dentry, - .hinfo = hinfo - }; -+ struct iam_path_compat *ipc; -+ -+ assert(path->ip_data != NULL); -+ ipc = container_of(path->ip_data, struct iam_path_compat, ipc_descr); -+ ipc->ipc_dentry = dentry; -+ ipc->ipc_hinfo = hinfo; - - assert(dx_index_is_compat(path)); +- +- assert(dx_index_is_compat(path)); - path->ip_descr_data = &hc; - err = dx_lookup(path); - assert(err != 0 || path->ip_frames[path->ip_indirect].bh != NULL); - return err; - } - - /* +- err = dx_lookup(path); +- assert(err != 0 || path->ip_frames[path->ip_indirect].bh != NULL); +- return err; +-} +- +-/* - * Initialize container @c, acquires additional reference on @inode. - */ -int iam_container_init(struct iam_container *c, @@ -3644,7 +3622,12 @@ Index: iam/fs/ext3/namei.c - .hinfo = &hinfo - }; - int err, i; -- ++int dx_lookup(struct iam_path *path) ++{ ++ u32 ptr; ++ int err = 0; ++ int i; + - iam_path_init(path, c, &hc); - for (i = 0; i < ARRAY_SIZE(path->ip_key_scratch); ++i) - path->ip_key_scratch[i] = @@ -3652,16 +3635,34 @@ Index: iam/fs/ext3/namei.c - err = dx_lookup(path); - if (err) - goto errout; -- ++ struct iam_descr *param; ++ struct iam_frame *frame; ++ struct iam_container *c; + - err = iam_leaf_insert(handle, path, k, r); -- ++ param = iam_path_descr(path); ++ c = path->ip_container; + - if (err != -ENOSPC) - goto errout; -- ++ for (frame = path->ip_frames, i = 0, ++ ptr = param->id_ops->id_root_ptr(c); ++ i <= path->ip_indirect; ++ ptr = dx_get_block(path, frame->at), ++frame, ++i) { ++ struct iam_entry *entries; ++ struct iam_entry *p; ++ struct iam_entry *q; ++ struct iam_entry *m; ++ unsigned count; + - err = split_index_node(handle, path); - if (err) - goto errout; -- ++ err = param->id_ops->id_node_read(c, (iam_ptr_t)ptr, NULL, ++ &frame->bh); ++ if (err != 0) ++ break; + - err = split_leaf_node(handle, path); - if (err) - goto errout; @@ -3671,7 +3672,10 @@ Index: iam/fs/ext3/namei.c - iam_path_fini(path); - return(err); -} -- ++ err = param->id_ops->id_node_check(path, frame); ++ if (err != 0) ++ break; + -EXPORT_SYMBOL(iam_insert); -static int iam_leaf_delete(handle_t *handle, struct iam_path *path, - struct iam_key *k) @@ -3679,7 +3683,10 @@ Index: iam/fs/ext3/namei.c - struct iam_leaf leaf; - struct iam_leaf_entry *p, *q; - int err, count; -- ++ err = param->id_ops->id_node_load(path, frame); ++ if (err != 0) ++ break; + - err = iam_leaf_init(path, &leaf); - if (err) - goto errout; @@ -3687,7 +3694,8 @@ Index: iam/fs/ext3/namei.c - err = iam_leaf_lookup(path, &leaf, k); - if (err) - goto errout; -- ++ assert(dx_node_check(path, frame)); + - count = dx_get_count((struct iam_entry*)leaf.entries); - /*delete the k to leaf entries*/ - p = iam_leaf_entry_shift(path, leaf.at, 1); @@ -3697,23 +3705,87 @@ Index: iam/fs/ext3/namei.c - p = iam_leaf_entry_shift(path, p, 1); - } - dx_set_count((struct iam_entry*)leaf.entries, count - 1); -- ++ entries = frame->entries; ++ count = dx_get_count(entries); ++ assert(count && count <= dx_get_limit(entries)); ++ p = iam_entry_shift(path, entries, 1); ++ q = iam_entry_shift(path, entries, count - 1); ++ /* ++ * Sanity check: target key is larger or equal to the leftmost ++ * key in the node. ++ */ ++ if (!dx_index_is_compat(path) && ++ iam_keycmp(c, iam_key_at(path, p), ++ path->ip_key_target) > 0) { ++ struct inode *obj; ++ ++ obj = c->ic_object; ++ ext3_error(obj->i_sb, __FUNCTION__, ++ "corrupted search tree #%lu", obj->i_ino); ++ err = -EIO; ++ break; ++ ++ } ++ while (p <= q) { ++ m = iam_entry_shift(path, ++ p, iam_entry_diff(path, q, p) / 2); ++ dxtrace(printk(".")); ++ if (iam_keycmp(c, iam_key_at(path, m), ++ path->ip_key_target) > 0) ++ q = iam_entry_shift(path, m, -1); ++ else ++ p = iam_entry_shift(path, m, +1); ++ } + - err = ext3_journal_dirty_metadata(handle, leaf.bh); - if (err) - ext3_std_error(path_obj(path)->i_sb, err); -errout: - iam_leaf_fini(&leaf); -- return err; --} -- --/* ++ frame->at = iam_entry_shift(path, p, -1); ++ if (1) { // linear search cross check ++ unsigned n = count - 1; ++ struct iam_entry *at; ++ ++ at = entries; ++ while (n--) { ++ dxtrace(printk(",")); ++ at = iam_entry_shift(path, at, +1); ++ if (iam_keycmp(c, iam_key_at(path, at), ++ path->ip_key_target) > 0) { ++ if (at != iam_entry_shift(path, frame->at, 1)) { ++ BREAKPOINT; ++ printk(KERN_EMERG "%i\n", ++ iam_keycmp(c, iam_key_at(path, at), ++ path->ip_key_target)); ++ } ++ at = iam_entry_shift(path, at, -1); ++ break; ++ } ++ } ++ assert(at == frame->at); ++ } ++ } ++ if (err != 0) ++ iam_path_fini(path); ++ path->ip_frame = --frame; + return err; + } + + /* - * Delete existing record with key @k. - * - * Return values: 0: success, -ENOENT: not-found, -ve: other error. -- * ++ * Probe for a directory leaf block to search. + * - * postcondition: ergo(result == 0 || result == -ENOENT, - * !iam_lookup(c, k, *)); -- */ ++ * dx_probe can return ERR_BAD_DX_DIR, which means there was a format ++ * error in the directory index, and the caller should fall back to ++ * searching the directory normally. The callers of dx_probe **MUST** ++ * check for this error code, and make sure it never gets reflected ++ * back to userspace. + */ -int iam_delete(handle_t *h, struct iam_container *c, struct iam_key *k) -{ - struct dx_hash_info hinfo; @@ -3742,10 +3814,13 @@ Index: iam/fs/ext3/namei.c - -static int iam_leaf_update(handle_t *handle, struct iam_path *path, - struct iam_key *k, struct iam_rec *r) --{ ++static int dx_probe(struct dentry *dentry, struct inode *dir, ++ struct dx_hash_info *hinfo, struct iam_path *path) + { - struct iam_leaf leaf; -- int err; -- + int err; ++ struct iam_path_compat *ipc; + - err = iam_leaf_init(path, &leaf); - if (err) - goto errout; @@ -3756,7 +3831,11 @@ Index: iam/fs/ext3/namei.c - - memcpy(iam_leaf_entry_at(path, leaf.at), r, path_descr(path)->id_rec_size); - memcpy(iam_leaf_key_at(path, leaf.at), k, path_descr(path)->id_key_size); -- ++ assert(path->ip_data != NULL); ++ ipc = container_of(path->ip_data, struct iam_path_compat, ipc_descr); ++ ipc->ipc_dentry = dentry; ++ ipc->ipc_hinfo = hinfo; + - err = ext3_journal_dirty_metadata(handle, leaf.bh); - if (err) - ext3_std_error(path_obj(path)->i_sb, err); @@ -3788,23 +3867,24 @@ Index: iam/fs/ext3/namei.c - for (i = 0; i < ARRAY_SIZE(path->ip_key_scratch); ++i) - path->ip_key_scratch[i] = - (struct iam_key *)&cpath.ipc_scrach[i]; -- err = dx_lookup(path); ++ assert(dx_index_is_compat(path)); + err = dx_lookup(path); - if (err) - goto errout; - - err = iam_leaf_update(h, path, k, r); -errout: - iam_path_fini(path); -- return err; --} -- ++ assert(err != 0 || path->ip_frames[path->ip_indirect].bh != NULL); + return err; + } + -EXPORT_SYMBOL(iam_update); - --/* + /* * This function increments the frame pointer to search the next leaf * block, and reads in the necessary intervening nodes if the search - * should be necessary. Whether or not the search is necessary is -@@ -1409,16 +623,15 @@ EXPORT_SYMBOL(iam_update); +@@ -1409,16 +373,15 @@ EXPORT_SYMBOL(iam_update); * If start_hash is non-null, it will be filled in with the starting * hash of the next page. */ @@ -3824,7 +3904,7 @@ Index: iam/fs/ext3/namei.c p = path->ip_frame; /* * Find the next leaf page by incrementing the frame pointer. -@@ -1438,28 +651,34 @@ static int ext3_htree_next_block(struct +@@ -1438,28 +401,34 @@ static int ext3_htree_next_block(struct --p; } @@ -3875,7 +3955,7 @@ Index: iam/fs/ext3/namei.c if (err != 0) return err; /* Failure */ ++p; -@@ -1471,6 +690,16 @@ static int ext3_htree_next_block(struct +@@ -1471,6 +440,16 @@ static int ext3_htree_next_block(struct return 1; } @@ -3892,7 +3972,7 @@ Index: iam/fs/ext3/namei.c /* * p is at least 6 bytes before the end of page -@@ -1662,21 +891,30 @@ static void dx_sort_map (struct dx_map_e +@@ -1662,21 +641,30 @@ static void dx_sort_map (struct dx_map_e } while(more); } @@ -3929,7 +4009,7 @@ Index: iam/fs/ext3/namei.c #endif -@@ -1897,14 +1135,15 @@ static struct buffer_head * ext3_dx_find +@@ -1897,14 +885,15 @@ static struct buffer_head * ext3_dx_find if (*err != 0) return NULL; } else { @@ -3948,16 +4028,258 @@ Index: iam/fs/ext3/namei.c if (*err != 0) goto errout; de = (struct ext3_dir_entry_2 *) bh->b_data; -@@ -2067,7 +1306,7 @@ static struct ext3_dir_entry_2 *do_split +@@ -2061,22 +1050,69 @@ static struct ext3_dir_entry_2* dx_pack_ + return prev; + } + ++struct ext3_dir_entry_2 *move_entries(struct inode *dir, ++ struct dx_hash_info *hinfo, ++ struct buffer_head **bh1, ++ struct buffer_head **bh2, ++ __u32 *delim_hash) ++{ ++ char *data1; ++ char *data2; ++ unsigned blocksize = dir->i_sb->s_blocksize; ++ unsigned count; ++ unsigned continued; ++ unsigned split; ++ u32 hash2; ++ ++ struct dx_map_entry *map; ++ struct ext3_dir_entry_2 *de1; ++ struct ext3_dir_entry_2 *de2; ++ ++ data1 = (*bh1)->b_data; ++ data2 = (*bh2)->b_data; ++ ++ /* create map in the end of data2 block */ ++ map = (struct dx_map_entry *) (data2 + blocksize); ++ count = dx_make_map((struct ext3_dir_entry_2 *) data1, ++ blocksize, hinfo, map); ++ map -= count; ++ split = count/2; // need to adjust to actual middle ++ dx_sort_map(map, count); ++ hash2 = map[split].hash; ++ continued = hash2 == map[split - 1].hash; ++ dxtrace(printk("Split block %i at %x, %i/%i\n", ++ dx_get_block(frame->at), hash2, split, count - split)); ++ ++ /* Fancy dance to stay within two buffers */ ++ de2 = dx_move_dirents(data1, data2, map + split, count - split); ++ de1 = dx_pack_dirents(data1, blocksize); ++ de1->rec_len = cpu_to_le16(data1 + blocksize - (char *) de1); ++ de2->rec_len = cpu_to_le16(data2 + blocksize - (char *) de2); ++ dxtrace(dx_show_leaf(hinfo, ++ (struct ext3_dir_entry_2 *) data1, blocksize, 1)); ++ dxtrace(dx_show_leaf(hinfo, ++ (struct ext3_dir_entry_2 *) data2, blocksize, 1)); ++ ++ /* Which block gets the new entry? */ ++ if (hinfo->hash >= hash2) { ++ swap(*bh1, *bh2); ++ de1 = de2; ++ } ++ *delim_hash = hash2 + continued; ++ return de1; ++} ++ + /* Allocate new node, and split leaf node @bh into it, inserting new pointer + * into parent node identified by @frame */ + static struct ext3_dir_entry_2 *do_split(handle_t *handle, struct iam_path *path, struct buffer_head **bh,struct iam_frame *frame, struct dx_hash_info *hinfo, int *error) { - struct inode *dir = path_obj(path); +- unsigned blocksize = dir->i_sb->s_blocksize; +- unsigned count, continued; + struct inode *dir = iam_path_obj(path); - unsigned blocksize = dir->i_sb->s_blocksize; - unsigned count, continued; struct buffer_head *bh2; -@@ -2392,18 +1631,25 @@ static int ext3_add_entry (handle_t *han + u32 newblock; + u32 hash2; +- struct dx_map_entry *map; +- char *data1 = (*bh)->b_data, *data2; +- unsigned split; +- struct ext3_dir_entry_2 *de = NULL, *de2; ++ struct ext3_dir_entry_2 *de = NULL; + int err; + + bh2 = ext3_append (handle, dir, &newblock, error); +@@ -2101,35 +1137,9 @@ static struct ext3_dir_entry_2 *do_split + if (err) + goto journal_error; + +- data2 = bh2->b_data; +- +- /* create map in the end of data2 block */ +- map = (struct dx_map_entry *) (data2 + blocksize); +- count = dx_make_map ((struct ext3_dir_entry_2 *) data1, +- blocksize, hinfo, map); +- map -= count; +- split = count/2; // need to adjust to actual middle +- dx_sort_map (map, count); +- hash2 = map[split].hash; +- continued = hash2 == map[split - 1].hash; +- dxtrace(printk("Split block %i at %x, %i/%i\n", +- dx_get_block(frame->at), hash2, split, count-split)); +- +- /* Fancy dance to stay within two buffers */ +- de2 = dx_move_dirents(data1, data2, map + split, count - split); +- de = dx_pack_dirents(data1,blocksize); +- de->rec_len = cpu_to_le16(data1 + blocksize - (char *) de); +- de2->rec_len = cpu_to_le16(data2 + blocksize - (char *) de2); +- dxtrace(dx_show_leaf (hinfo, (struct ext3_dir_entry_2 *) data1, blocksize, 1)); +- dxtrace(dx_show_leaf (hinfo, (struct ext3_dir_entry_2 *) data2, blocksize, 1)); ++ de = move_entries(dir, hinfo, bh, &bh2, &hash2); + +- /* Which block gets the new entry? */ +- if (hinfo->hash >= hash2) +- { +- swap(*bh, bh2); +- de = de2; +- } +- dx_insert_block(path, frame, hash2 + continued, newblock); ++ dx_insert_block(path, frame, hash2, newblock); + err = ext3_journal_dirty_metadata (handle, bh2); + if (err) + goto journal_error; +@@ -2143,6 +1153,67 @@ errout: + } + #endif + ++struct ext3_dir_entry_2 *find_insertion_point(struct inode *dir, ++ struct buffer_head *bh, ++ const char *name, int namelen) ++{ ++ struct ext3_dir_entry_2 *de; ++ char *top; ++ unsigned long offset; ++ int nlen; ++ int rlen; ++ int reclen; ++ ++ reclen = EXT3_DIR_REC_LEN(namelen); ++ de = (struct ext3_dir_entry_2 *)bh->b_data; ++ top = bh->b_data + dir->i_sb->s_blocksize - reclen; ++ offset = 0; ++ while ((char *) de <= top) { ++ if (!ext3_check_dir_entry("ext3_add_entry", ++ dir, de, bh, offset)) { ++ brelse(bh); ++ return ERR_PTR(-EIO); ++ } ++ if (ext3_match(namelen, name, de)) { ++ brelse(bh); ++ return ERR_PTR(-EEXIST); ++ } ++ nlen = EXT3_DIR_REC_LEN(de->name_len); ++ rlen = le16_to_cpu(de->rec_len); ++ if ((de->inode? rlen - nlen: rlen) >= reclen) ++ return de; ++ de = (struct ext3_dir_entry_2 *)((char *)de + rlen); ++ offset += rlen; ++ } ++ return ERR_PTR(-ENOSPC); ++} ++ ++struct ext3_dir_entry_2 *split_entry(struct inode *dir, ++ struct ext3_dir_entry_2 *de, ++ unsigned long ino, mode_t mode, ++ const char *name, int namelen) ++{ ++ int nlen; ++ int rlen; ++ ++ nlen = EXT3_DIR_REC_LEN(de->name_len); ++ rlen = le16_to_cpu(de->rec_len); ++ if (de->inode) { ++ struct ext3_dir_entry_2 *de1; ++ ++ de1 = (struct ext3_dir_entry_2 *)((char *)de + nlen); ++ de1->rec_len = cpu_to_le16(rlen - nlen); ++ de->rec_len = cpu_to_le16(nlen); ++ de = de1; ++ } ++ de->file_type = EXT3_FT_UNKNOWN; ++ de->inode = cpu_to_le32(ino); ++ if (ino != 0) ++ ext3_set_de_type(dir->i_sb, de, mode); ++ de->name_len = namelen; ++ memcpy(de->name, name, namelen); ++ return de; ++} + + /* + * Add a new entry into a directory (leaf) block. If de is non-NULL, +@@ -2162,34 +1233,16 @@ static int add_dirent_to_buf(handle_t *h + struct inode *dir = dentry->d_parent->d_inode; + const char *name = dentry->d_name.name; + int namelen = dentry->d_name.len; +- unsigned long offset = 0; +- unsigned short reclen; +- int nlen, rlen, err; +- char *top; ++ int err; + +- reclen = EXT3_DIR_REC_LEN(namelen); + if (!de) { +- de = (struct ext3_dir_entry_2 *)bh->b_data; +- top = bh->b_data + dir->i_sb->s_blocksize - reclen; +- while ((char *) de <= top) { +- if (!ext3_check_dir_entry("ext3_add_entry", dir, de, +- bh, offset)) { +- brelse (bh); +- return -EIO; +- } +- if (ext3_match (namelen, name, de)) { +- brelse (bh); +- return -EEXIST; +- } +- nlen = EXT3_DIR_REC_LEN(de->name_len); +- rlen = le16_to_cpu(de->rec_len); +- if ((de->inode? rlen - nlen: rlen) >= reclen) +- break; +- de = (struct ext3_dir_entry_2 *)((char *)de + rlen); +- offset += rlen; ++ de = find_insertion_point(dir, bh, name, namelen); ++ if (IS_ERR(de)) { ++ err = PTR_ERR(de); ++ if (err != -ENOSPC) ++ brelse(bh); ++ return err; + } +- if ((char *) de > top) +- return -ENOSPC; + } + BUFFER_TRACE(bh, "get_write_access"); + err = ext3_journal_get_write_access(handle, bh); +@@ -2200,22 +1253,9 @@ static int add_dirent_to_buf(handle_t *h + } + + /* By now the buffer is marked for journaling */ +- nlen = EXT3_DIR_REC_LEN(de->name_len); +- rlen = le16_to_cpu(de->rec_len); +- if (de->inode) { +- struct ext3_dir_entry_2 *de1 = (struct ext3_dir_entry_2 *)((char *)de + nlen); +- de1->rec_len = cpu_to_le16(rlen - nlen); +- de->rec_len = cpu_to_le16(nlen); +- de = de1; +- } +- de->file_type = EXT3_FT_UNKNOWN; +- if (inode) { +- de->inode = cpu_to_le32(inode->i_ino); +- ext3_set_de_type(dir->i_sb, de, inode->i_mode); +- } else +- de->inode = 0; +- de->name_len = namelen; +- memcpy (de->name, name, namelen); ++ ++ split_entry(dir, de, inode ? inode->i_ino : 0, ++ inode ? inode->i_mode : 0, name, namelen); + /* + * XXX shouldn't update any times until successful + * completion of syscall, but too many callers depend +@@ -2392,18 +1432,25 @@ static int ext3_add_entry (handle_t *han } #ifdef CONFIG_EXT3_INDEX @@ -3986,7 +4308,7 @@ Index: iam/fs/ext3/namei.c frame = path->ip_frame; entries = frame->entries; -@@ -2442,7 +1688,8 @@ static int split_index_node(handle_t *ha +@@ -2442,7 +1489,8 @@ static int split_index_node(handle_t *ha for (frame = safe + 1, i = 0; i < nr_splet; ++i, ++frame) { bh_new[i] = ext3_append (handle, dir, &newblock[i], &err); if (!bh_new[i] || @@ -3996,7 +4318,7 @@ Index: iam/fs/ext3/namei.c goto cleanup; BUFFER_TRACE(frame->bh, "get_write_access"); err = ext3_journal_get_write_access(handle, frame->bh); -@@ -2461,6 +1708,7 @@ static int split_index_node(handle_t *ha +@@ -2461,6 +1509,7 @@ static int split_index_node(handle_t *ha unsigned count; int idx; struct buffer_head *bh2; @@ -4004,7 +4326,7 @@ Index: iam/fs/ext3/namei.c entries = frame->entries; count = dx_get_count(entries); -@@ -2469,6 +1717,7 @@ static int split_index_node(handle_t *ha +@@ -2469,6 +1518,7 @@ static int split_index_node(handle_t *ha bh2 = bh_new[i]; entries2 = dx_get_entries(path, bh2->b_data, 0); @@ -4012,46 +4334,36 @@ Index: iam/fs/ext3/namei.c if (frame == path->ip_frames) { /* splitting root node. Tricky point: * -@@ -2484,6 +1733,8 @@ static int split_index_node(handle_t *ha - u8 indirects; +@@ -2480,22 +1530,20 @@ static int split_index_node(handle_t *ha + * capacity of the root node is smaller than that of + * non-root one. + */ +- struct dx_root *root; +- u8 indirects; struct iam_frame *frames; - -+ assert(i == 0); ++ struct iam_entry *next; + ++ assert(i == 0); + frames = path->ip_frames; - root = (struct dx_root *) frames->bh->b_data; - indirects = root->info.indirect_levels; -@@ -2493,9 +1744,26 @@ static int split_index_node(handle_t *ha +- root = (struct dx_root *) frames->bh->b_data; +- indirects = root->info.indirect_levels; +- dxtrace(printk("Creating new root %d\n", indirects)); + memcpy((char *) entries2, (char *) entries, + count * iam_entry_size(path)); dx_set_limit(entries2, dx_node_limit(path)); /* Set up root */ - dx_set_count(entries, 1); - dx_set_block(path, entries, newblock[i]); - root->info.indirect_levels = indirects + 1; -+ if (dx_index_is_compat(path)) { -+ dx_set_count(entries, 1); -+ dx_set_block(path, entries, newblock[0]); -+ root->info.indirect_levels = indirects + 1; -+ } else { -+ /* -+ * We need this branch here, because htree -+ * shares space between countlimit and first -+ * (hash, block) pair. -+ */ -+ struct iam_entry *next; -+ -+ dx_set_count(entries, 2); -+ assert(dx_get_limit(entries) == -+ dx_root_limit(path)); -+ next = iam_entry_shift(path, entries, 1); -+ dx_set_block(path, next, newblock[0]); -+ descr->id_ops->id_root_inc(path->ip_container, -+ frame); -+ } ++ next = descr->id_ops->id_root_inc(path->ip_container, ++ path, frame); ++ dx_set_block(path, next, newblock[0]); /* Shift frames in the path */ memmove(frames + 2, frames + 1, -@@ -2505,20 +1773,21 @@ static int split_index_node(handle_t *ha +@@ -2505,20 +1553,21 @@ static int split_index_node(handle_t *ha frames[1].entries = entries = entries2; frames[1].bh = bh2; assert(dx_node_check(path, frame)); @@ -4079,7 +4391,7 @@ Index: iam/fs/ext3/namei.c dxtrace(printk("Split index %i/%i\n", count1, count2)); -@@ -2537,16 +1806,30 @@ static int split_index_node(handle_t *ha +@@ -2537,16 +1586,30 @@ static int split_index_node(handle_t *ha swap(frame->bh, bh2); bh_new[i] = bh2; } @@ -4112,7 +4424,7 @@ Index: iam/fs/ext3/namei.c } goto cleanup; journal_error: -@@ -2578,7 +1861,7 @@ static int ext3_dx_add_entry(handle_t *h +@@ -2578,7 +1641,7 @@ static int ext3_dx_add_entry(handle_t *h size_t isize; iam_path_compat_init(&cpath, dir); @@ -4121,7 +4433,7 @@ Index: iam/fs/ext3/namei.c err = dx_probe(dentry, NULL, &hinfo, path); if (err != 0) -@@ -2588,8 +1871,9 @@ static int ext3_dx_add_entry(handle_t *h +@@ -2588,8 +1651,9 @@ static int ext3_dx_add_entry(handle_t *h /* XXX nikita: global serialization! */ isize = dir->i_size; @@ -4133,7 +4445,7 @@ Index: iam/fs/ext3/namei.c if (err != 0) goto cleanup; -@@ -2609,7 +1893,7 @@ static int ext3_dx_add_entry(handle_t *h +@@ -2609,7 +1673,7 @@ static int ext3_dx_add_entry(handle_t *h goto cleanup; /*copy split inode too*/ @@ -4142,7 +4454,7 @@ Index: iam/fs/ext3/namei.c if (!de) goto cleanup; -@@ -2724,12 +2008,12 @@ static struct inode * ext3_new_inode_wan +@@ -2724,12 +1788,12 @@ static struct inode * ext3_new_inode_wan * is so far negative - it has no inode. * * If the create succeeds, we fill in the inode information @@ -4160,7 +4472,7 @@ Index: iam/fs/ext3/namei.c Index: iam/include/linux/lustre_iam.h =================================================================== --- iam.orig/include/linux/lustre_iam.h 2006-05-31 20:24:32.000000000 +0400 -+++ iam/include/linux/lustre_iam.h 2006-06-21 22:25:45.000000000 +0400 ++++ iam/include/linux/lustre_iam.h 2006-06-23 01:50:19.000000000 +0400 @@ -1,9 +1,68 @@ +/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- + * vim:expandtab:shiftwidth=8:tabstop=8: diff --git a/lustre/kernel_patches/patches/ext3-iam-uapi.patch b/lustre/kernel_patches/patches/ext3-iam-uapi.patch index db8ba91..f97e59f 100644 --- a/lustre/kernel_patches/patches/ext3-iam-uapi.patch +++ b/lustre/kernel_patches/patches/ext3-iam-uapi.patch @@ -1,7 +1,7 @@ Index: iam/fs/ext3/Makefile =================================================================== ---- iam.orig/fs/ext3/Makefile 2006-06-21 22:25:45.000000000 +0400 -+++ iam/fs/ext3/Makefile 2006-06-21 22:25:46.000000000 +0400 +--- iam.orig/fs/ext3/Makefile 2006-06-23 01:50:19.000000000 +0400 ++++ iam/fs/ext3/Makefile 2006-06-23 01:50:19.000000000 +0400 @@ -6,7 +6,7 @@ obj-$(CONFIG_EXT3_FS) += ext3.o ext3-y := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o iopen.o \ @@ -13,8 +13,8 @@ Index: iam/fs/ext3/Makefile ext3-$(CONFIG_EXT3_FS_POSIX_ACL) += acl.o Index: iam/fs/ext3/file.c =================================================================== ---- iam.orig/fs/ext3/file.c 2006-06-21 22:25:45.000000000 +0400 -+++ iam/fs/ext3/file.c 2006-06-21 22:25:46.000000000 +0400 +--- iam.orig/fs/ext3/file.c 2006-06-23 01:50:19.000000000 +0400 ++++ iam/fs/ext3/file.c 2006-06-23 01:50:19.000000000 +0400 @@ -23,6 +23,7 @@ #include #include @@ -50,7 +50,7 @@ Index: iam/fs/ext3/file.c Index: iam/fs/ext3/iam-uapi.c =================================================================== --- iam.orig/fs/ext3/iam-uapi.c 2004-04-06 17:27:52.000000000 +0400 -+++ iam/fs/ext3/iam-uapi.c 2006-06-21 22:25:46.000000000 +0400 ++++ iam/fs/ext3/iam-uapi.c 2006-06-23 01:50:19.000000000 +0400 @@ -0,0 +1,348 @@ +/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- + * vim:expandtab:shiftwidth=8:tabstop=8: @@ -402,8 +402,8 @@ Index: iam/fs/ext3/iam-uapi.c +} Index: iam/fs/ext3/ioctl.c =================================================================== ---- iam.orig/fs/ext3/ioctl.c 2006-06-21 22:25:45.000000000 +0400 -+++ iam/fs/ext3/ioctl.c 2006-06-21 22:25:46.000000000 +0400 +--- iam.orig/fs/ext3/ioctl.c 2006-06-23 01:50:19.000000000 +0400 ++++ iam/fs/ext3/ioctl.c 2006-06-23 01:50:19.000000000 +0400 @@ -250,6 +250,6 @@ flags_err: @@ -414,8 +414,8 @@ Index: iam/fs/ext3/ioctl.c } Index: iam/include/linux/lustre_iam.h =================================================================== ---- iam.orig/include/linux/lustre_iam.h 2006-06-21 22:25:45.000000000 +0400 -+++ iam/include/linux/lustre_iam.h 2006-06-21 22:25:46.000000000 +0400 +--- iam.orig/include/linux/lustre_iam.h 2006-06-23 01:50:19.000000000 +0400 ++++ iam/include/linux/lustre_iam.h 2006-06-23 01:50:19.000000000 +0400 @@ -30,9 +30,6 @@ #ifndef __LINUX_LUSTRE_IAM_H__ #define __LINUX_LUSTRE_IAM_H__ @@ -500,18 +500,20 @@ Index: iam/include/linux/lustre_iam.h * Initialize new node (stored in @bh) that is going to be added into * tree. */ -@@ -152,15 +178,29 @@ struct iam_operations { - * Create new container. - * - * Newly created container has a root node and a single leaf. Leaf +@@ -149,18 +175,27 @@ struct iam_operations { + int (*id_keycmp)(const struct iam_container *c, + const struct iam_key *k1, const struct iam_key *k2); + /* +- * Create new container. +- * +- * Newly created container has a root node and a single leaf. Leaf - * contains single record with the smallest possible key. -+ * contains single record with the least possible key. - */ - int (*id_create)(struct iam_container *c); -+ /* + * Modify root node when tree height increases. -+ */ -+ void (*id_root_inc)(struct iam_container *c, struct iam_frame *frame); + */ +- int (*id_create)(struct iam_container *c); ++ struct iam_entry *(*id_root_inc)(struct iam_container *c, ++ struct iam_path *path, ++ struct iam_frame *frame); + + struct iam_path_descr *(*id_ipd_alloc)(const struct iam_container *c); + void (*id_ipd_free)(const struct iam_container *c, @@ -531,7 +533,7 @@ Index: iam/include/linux/lustre_iam.h struct iam_leaf_operations { /* * leaf operations. -@@ -226,7 +266,8 @@ struct iam_leaf_operations { +@@ -226,7 +261,8 @@ struct iam_leaf_operations { * split leaf node, moving some entries into @bh (the latter currently * is assumed to be empty). */ @@ -541,7 +543,7 @@ Index: iam/include/linux/lustre_iam.h }; struct iam_path *iam_leaf_path(const struct iam_leaf *leaf); -@@ -264,6 +305,9 @@ struct iam_descr { +@@ -264,6 +300,9 @@ struct iam_descr { struct iam_leaf_operations *id_leaf_ops; }; @@ -551,7 +553,7 @@ Index: iam/include/linux/lustre_iam.h struct iam_container { /* * Underlying flat file. IO against this object is issued to -@@ -347,7 +391,9 @@ enum iam_it_state { +@@ -347,7 +386,9 @@ enum iam_it_state { /* initial state */ IAM_IT_DETACHED, /* iterator is above particular record in the container */ @@ -562,7 +564,7 @@ Index: iam/include/linux/lustre_iam.h }; /* -@@ -355,7 +401,7 @@ enum iam_it_state { +@@ -355,7 +396,7 @@ enum iam_it_state { */ enum iam_it_flags { /* @@ -571,7 +573,7 @@ Index: iam/include/linux/lustre_iam.h */ IAM_IT_MOVE = (1 << 0), /* -@@ -372,15 +418,26 @@ enum iam_it_flags { +@@ -372,15 +413,26 @@ enum iam_it_flags { * doesn't point to any particular record in this container. * * After successful call to iam_it_get() and until corresponding call to @@ -601,7 +603,7 @@ Index: iam/include/linux/lustre_iam.h * */ struct iam_iterator { -@@ -390,7 +447,8 @@ struct iam_iterator { +@@ -390,7 +442,8 @@ struct iam_iterator { __u32 ii_flags; enum iam_it_state ii_state; /* @@ -611,7 +613,7 @@ Index: iam/include/linux/lustre_iam.h */ struct iam_path ii_path; }; -@@ -420,27 +478,37 @@ int iam_it_init(struct iam_iterator *it +@@ -420,27 +473,37 @@ int iam_it_init(struct iam_iterator *it void iam_it_fini(struct iam_iterator *it); /* @@ -656,7 +658,7 @@ Index: iam/include/linux/lustre_iam.h * iam_it_rec_get(dst) == iam_it_rec_get(src) && * iam_it_key_get(dst, *1) == iam_it_key_get(src, *2)) */ -@@ -460,15 +528,17 @@ void iam_it_put(struct iam_iterator *it) +@@ -460,15 +523,17 @@ void iam_it_put(struct iam_iterator *it) * +1: end of container reached * -ve: error * @@ -677,7 +679,7 @@ Index: iam/include/linux/lustre_iam.h * postcondition: it_state(it) == IAM_IT_ATTACHED */ struct iam_rec *iam_it_rec_get(const struct iam_iterator *it); -@@ -476,14 +546,15 @@ struct iam_rec *iam_it_rec_get(const str +@@ -476,14 +541,15 @@ struct iam_rec *iam_it_rec_get(const str /* * Replace contents of record under iterator. * @@ -695,7 +697,7 @@ Index: iam/include/linux/lustre_iam.h * * precondition: it_state(it) == IAM_IT_ATTACHED * postcondition: it_state(it) == IAM_IT_ATTACHED -@@ -495,11 +566,17 @@ struct iam_key *iam_it_key_get(const str +@@ -495,11 +561,17 @@ struct iam_key *iam_it_key_get(const str * Insert new record with key @k and contents from @r, shifting records to the * right. * @@ -718,7 +720,7 @@ Index: iam/include/linux/lustre_iam.h * it_keycmp(it, iam_it_key_get(it, *), k) == 0 && * !memcmp(iam_it_rec_get(it), r, ...)) */ -@@ -508,8 +585,10 @@ int iam_it_rec_insert(handle_t *h, struc +@@ -508,8 +580,10 @@ int iam_it_rec_insert(handle_t *h, struc /* * Delete record under iterator. * @@ -731,7 +733,7 @@ Index: iam/include/linux/lustre_iam.h */ int iam_it_rec_delete(handle_t *h, struct iam_iterator *it); -@@ -519,7 +598,7 @@ typedef __u64 iam_pos_t; +@@ -519,7 +593,7 @@ typedef __u64 iam_pos_t; * Convert iterator to cookie. * * precondition: it_state(it) == IAM_IT_ATTACHED && @@ -740,7 +742,7 @@ Index: iam/include/linux/lustre_iam.h * postcondition: it_state(it) == IAM_IT_ATTACHED */ iam_pos_t iam_it_store(const struct iam_iterator *it); -@@ -527,8 +606,9 @@ iam_pos_t iam_it_store(const struct iam_ +@@ -527,8 +601,9 @@ iam_pos_t iam_it_store(const struct iam_ /* * Restore iterator from cookie. * @@ -752,10 +754,47 @@ Index: iam/include/linux/lustre_iam.h * postcondition: ergo(result == 0, it_state(it) == IAM_IT_ATTACHED && * iam_it_store(it) == pos) */ -@@ -583,6 +663,17 @@ static inline void iam_keycpy(const stru +@@ -583,6 +658,54 @@ static inline void iam_keycpy(const stru memcpy(k1, k2, c->ic_descr->id_key_size); } ++static inline size_t iam_entry_size(struct iam_path *p) ++{ ++ return iam_path_descr(p)->id_key_size + iam_path_descr(p)->id_ptr_size; ++} ++ ++static inline struct iam_entry *iam_entry_shift(struct iam_path *p, ++ struct iam_entry *entry, ++ int shift) ++{ ++ void *e = entry; ++ return e + shift * iam_entry_size(p); ++} ++ ++static inline struct iam_key *iam_get_key(struct iam_path *p, ++ struct iam_entry *entry, ++ struct iam_key *key) ++{ ++ return memcpy(key, entry, iam_path_descr(p)->id_key_size); ++} ++ ++static inline struct iam_key *iam_key_at(struct iam_path *p, ++ struct iam_entry *entry) ++{ ++ return (struct iam_key *)entry; ++} ++ ++static inline ptrdiff_t iam_entry_diff(struct iam_path *p, ++ struct iam_entry *e1, ++ struct iam_entry *e2) ++{ ++ ptrdiff_t diff; ++ ++ diff = (void *)e1 - (void *)e2; ++ assert(diff / iam_entry_size(p) * iam_entry_size(p) == diff); ++ return diff / iam_entry_size(p); ++} ++ +/* + * Helper for the frequent case, where key was already placed into @k1 by + * callback. @@ -770,7 +809,62 @@ Index: iam/include/linux/lustre_iam.h static inline int iam_keycmp(const struct iam_container *c, const struct iam_key *k1, const struct iam_key *k2) { -@@ -650,6 +741,15 @@ static inline unsigned dx_node_limit(str +@@ -622,11 +745,54 @@ static inline void dx_set_key(struct iam + iam_keycpy(p->ip_container, iam_entry_off(entry, 0), key); + } + ++struct dx_map_entry ++{ ++ u32 hash; ++ u32 offs; ++}; ++ ++struct fake_dirent { ++ __le32 inode; ++ __le16 rec_len; ++ u8 name_len; ++ u8 file_type; ++}; ++ + struct dx_countlimit { + __le16 limit; + __le16 count; + }; + ++/* ++ * dx_root_info is laid out so that if it should somehow get overlaid by a ++ * dirent the two low bits of the hash version will be zero. Therefore, the ++ * hash version mod 4 should never be 0. Sincerely, the paranoia department. ++ */ ++ ++struct dx_root { ++ struct fake_dirent dot; ++ char dot_name[4]; ++ struct fake_dirent dotdot; ++ char dotdot_name[4]; ++ struct dx_root_info ++ { ++ __le32 reserved_zero; ++ u8 hash_version; ++ u8 info_length; /* 8 */ ++ u8 indirect_levels; ++ u8 unused_flags; ++ } ++ info; ++ struct {} entries[0]; ++}; ++ ++struct dx_node ++{ ++ struct fake_dirent fake; ++ struct {} entries[0]; ++}; ++ ++ + static inline unsigned dx_get_count(struct iam_entry *entries) + { + return le16_to_cpu(((struct dx_countlimit *) entries)->count); +@@ -650,6 +816,15 @@ static inline unsigned dx_node_limit(str return entry_space / (param->id_key_size + param->id_ptr_size); } @@ -786,7 +880,7 @@ Index: iam/include/linux/lustre_iam.h static inline struct iam_entry *dx_get_entries(struct iam_path *path, void *data, int root) { -@@ -674,6 +774,7 @@ static inline struct iam_key *iam_path_k +@@ -674,6 +849,7 @@ static inline struct iam_key *iam_path_k int dx_lookup(struct iam_path *path); void dx_insert_block(struct iam_path *path, struct iam_frame *frame, u32 hash, u32 block); @@ -794,17 +888,29 @@ Index: iam/include/linux/lustre_iam.h int ext3_htree_next_block(struct inode *dir, __u32 hash, struct iam_path *path, __u32 *start_hash); -@@ -682,6 +783,9 @@ struct buffer_head *ext3_append(handle_t +@@ -681,6 +857,21 @@ int ext3_htree_next_block(struct inode * + struct buffer_head *ext3_append(handle_t *handle, struct inode *inode, u32 *block, int *err); int split_index_node(handle_t *handle, struct iam_path *path); - -+extern struct iam_descr htree_compat_param; -+ ++struct ext3_dir_entry_2 *split_entry(struct inode *dir, ++ struct ext3_dir_entry_2 *de, ++ unsigned long ino, mode_t mode, ++ const char *name, int namelen); ++struct ext3_dir_entry_2 *find_insertion_point(struct inode *dir, ++ struct buffer_head *bh, ++ const char *name, int namelen); ++struct ext3_dir_entry_2 *move_entries(struct inode *dir, ++ struct dx_hash_info *hinfo, ++ struct buffer_head **bh1, ++ struct buffer_head **bh2, ++ __u32 *delim_hash); ++ ++extern struct iam_descr iam_htree_compat_param; + + /* * external - */ -@@ -702,6 +806,8 @@ void iam_insert_key(struct iam_path *pat +@@ -702,6 +893,8 @@ void iam_insert_key(struct iam_path *pat int iam_leaf_at_end(const struct iam_leaf *l); void iam_leaf_next(struct iam_leaf *folio); @@ -813,10 +919,13 @@ Index: iam/include/linux/lustre_iam.h struct iam_path *iam_leaf_path(const struct iam_leaf *leaf); struct iam_container *iam_leaf_container(const struct iam_leaf *leaf); -@@ -709,8 +815,23 @@ struct iam_descr *iam_leaf_descr(const s +@@ -709,8 +902,26 @@ struct iam_descr *iam_leaf_descr(const s struct iam_leaf_operations *iam_leaf_ops(const struct iam_leaf *leaf); ++int iam_node_read(struct iam_container *c, iam_ptr_t ptr, ++ handle_t *h, struct buffer_head **bh); ++ +/* + * Container format. + */ @@ -837,7 +946,7 @@ Index: iam/include/linux/lustre_iam.h struct list_head if_linkage; }; -@@ -718,5 +839,48 @@ void iam_format_register(struct iam_form +@@ -718,5 +929,48 @@ void iam_format_register(struct iam_form void iam_lfix_format_init(void);