+++ /dev/null
-Index: iam-src/fs/ext3/namei.c
-===================================================================
---- iam-src.orig/fs/ext3/namei.c 2006-02-12 16:43:57.000000000 +0300
-+++ iam-src/fs/ext3/namei.c 2006-02-12 23:22:12.000000000 +0300
-@@ -83,22 +83,21 @@ static struct buffer_head *ext3_append(h
- #define dxtrace(command)
- #endif
-
--struct fake_dirent
--{
-+struct fake_dirent {
- __le32 inode;
- __le16 rec_len;
- u8 name_len;
- u8 file_type;
- };
-
--struct dx_countlimit
--{
-+struct dx_countlimit {
- __le16 limit;
- __le16 count;
- };
-
--struct dx_entry
--{
-+struct dx_entry; /* incomplete type */
-+
-+struct dx_entry_compat {
- __le32 hash;
- __le32 block;
- };
-@@ -109,8 +108,7 @@ struct dx_entry
- * hash version mod 4 should never be 0. Sincerely, the paranoia department.
- */
-
--struct dx_root
--{
-+struct dx_root {
- struct fake_dirent dot;
- char dot_name[4];
- struct fake_dirent dotdot;
-@@ -124,13 +122,13 @@ struct dx_root
- u8 unused_flags;
- }
- info;
-- struct dx_entry entries[0];
-+ struct {} entries[0];
- };
-
- struct dx_node
- {
- struct fake_dirent fake;
-- struct dx_entry entries[0];
-+ struct {} entries[0];
- };
-
-
-@@ -147,38 +145,76 @@ struct dx_map_entry
- u32 offs;
- };
-
-+struct dx_path;
-+struct dx_param {
-+ size_t dpo_key_size;
-+ size_t dpo_ptr_size;
-+ size_t dpo_node_gap;
-+ size_t dpo_root_gap;
-+
-+ u32 (*dpo_root_ptr)(struct dx_path *path);
-+ int (*dpo_node_check)(struct dx_path *path,
-+ struct dx_frame *frame, void *cookie);
-+ int (*dpo_node_init)(struct dx_path *path,
-+ struct buffer_head *bh, int root);
-+};
-+
- /*
- * Structure to keep track of a path drilled through htree.
- */
- struct dx_path {
-- struct inode *dp_object;
-- struct dx_frame dp_frames[DX_MAX_TREE_HEIGHT];
-- struct dx_frame *dp_frame;
-+ struct inode *dp_object;
-+ struct dx_param *dp_param;
-+ int dp_indirect;
-+ struct dx_frame dp_frames[DX_MAX_TREE_HEIGHT];
-+ struct dx_frame *dp_frame;
-+ void *dp_key_target;
-+ void *dp_key;
- };
-
-+static u32 htree_root_ptr(struct dx_path *p);
-+static int htree_node_check(struct dx_path *path,
-+ struct dx_frame *frame, void *cookie);
-+static int htree_node_init(struct dx_path *path,
-+ struct buffer_head *bh, int root);
-+
-+static struct dx_param htree_compat_param = {
-+ .dpo_key_size = sizeof ((struct dx_map_entry *)NULL)->hash,
-+ .dpo_ptr_size = sizeof ((struct dx_map_entry *)NULL)->offs,
-+ .dpo_node_gap = offsetof(struct dx_node, entries),
-+ .dpo_root_gap = offsetof(struct dx_root, entries),
-+
-+ .dpo_root_ptr = htree_root_ptr,
-+ .dpo_node_check = htree_node_check,
-+ .dpo_node_init = htree_node_init
-+};
-+
-+
- #ifdef CONFIG_EXT3_INDEX
--static inline unsigned dx_get_block (struct dx_entry *entry);
--static void dx_set_block (struct dx_entry *entry, unsigned value);
--static inline unsigned dx_get_hash (struct dx_entry *entry);
--static void dx_set_hash (struct dx_entry *entry, unsigned value);
--static unsigned dx_get_count (struct dx_entry *entries);
--static unsigned dx_get_limit (struct dx_entry *entries);
--static void dx_set_count (struct dx_entry *entries, unsigned value);
--static void dx_set_limit (struct dx_entry *entries, unsigned value);
--static unsigned dx_root_limit (struct inode *dir, unsigned infosize);
--static unsigned dx_node_limit (struct inode *dir);
--static struct dx_frame *dx_probe(struct dentry *dentry,
-- struct inode *dir,
-- struct dx_hash_info *hinfo,
-- struct dx_path *path,
-- int *err);
-+static inline unsigned dx_get_block(struct dx_path *p, struct dx_entry *entry);
-+static void dx_set_block(struct dx_path *p,
-+ struct dx_entry *entry, unsigned value);
-+static inline void *dx_get_key(struct dx_path *p,
-+ struct dx_entry *entry, void *key);
-+static void dx_set_key(struct dx_path *p, struct dx_entry *entry, void *key);
-+static unsigned dx_get_count(struct dx_entry *entries);
-+static unsigned dx_get_limit(struct dx_entry *entries);
-+static void dx_set_count(struct dx_entry *entries, unsigned value);
-+static void dx_set_limit(struct dx_entry *entries, unsigned value);
-+static unsigned dx_root_limit(struct dx_path *p);
-+static unsigned dx_node_limit(struct dx_path *p);
-+static int dx_probe(struct dentry *dentry,
-+ struct inode *dir,
-+ struct dx_hash_info *hinfo,
-+ struct dx_path *path);
- static int dx_make_map (struct ext3_dir_entry_2 *de, int size,
- struct dx_hash_info *hinfo, struct dx_map_entry map[]);
- static void dx_sort_map(struct dx_map_entry *map, unsigned count);
- 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);
--static void dx_insert_block (struct dx_frame *frame, u32 hash, u32 block);
-+static void dx_insert_block (struct dx_path *path,
-+ struct dx_frame *frame, u32 hash, u32 block);
- static int ext3_htree_next_block(struct inode *dir, __u32 hash,
- struct dx_path *path, __u32 *start_hash);
- static struct buffer_head * ext3_dx_find_entry(struct dentry *dentry,
-@@ -186,29 +222,65 @@ static struct buffer_head * ext3_dx_find
- static int ext3_dx_add_entry(handle_t *handle, struct dentry *dentry,
- struct inode *inode);
-
-+static inline void dx_path_init(struct dx_path *path, struct inode *inode);
-+static inline void dx_path_fini(struct dx_path *path);
-+
-+
- /*
- * Future: use high four bits of block for coalesce-on-delete flags
- * Mask them off for now.
- */
-
--static inline unsigned dx_get_block (struct dx_entry *entry)
-+static inline void *entry_off(struct dx_entry *entry, ptrdiff_t off)
-+{
-+ return (void *)((char *)entry + off);
-+}
-+
-+static inline size_t dx_entry_size(struct dx_path *p)
- {
-- return le32_to_cpu(entry->block) & 0x00ffffff;
-+ return p->dp_param->dpo_key_size + p->dp_param->dpo_ptr_size;
- }
-
--static inline void dx_set_block (struct dx_entry *entry, unsigned value)
-+static inline struct dx_entry *dx_entry_shift(struct dx_path *p,
-+ struct dx_entry *entry, int shift)
- {
-- entry->block = cpu_to_le32(value);
-+ void *e = entry;
-+ return e + shift * dx_entry_size(p);
- }
-
--static inline unsigned dx_get_hash (struct dx_entry *entry)
-+static inline ptrdiff_t dx_entry_diff(struct dx_path *p,
-+ struct dx_entry *e1, struct dx_entry *e2)
- {
-- return le32_to_cpu(entry->hash);
-+ ptrdiff_t diff;
-+
-+ diff = (void *)e1 - (void *)e2;
-+ assert(diff / dx_entry_size(p) * dx_entry_size(p) == diff);
-+ return diff / dx_entry_size(p);
-+}
-+
-+static inline unsigned dx_get_block(struct dx_path *p, struct dx_entry *entry)
-+{
-+ return le32_to_cpu(*(u32 *)entry_off(entry, p->dp_param->dpo_key_size))
-+ & 0x00ffffff;
- }
-
--static inline void dx_set_hash (struct dx_entry *entry, unsigned value)
-+static inline void dx_set_block(struct dx_path *p,
-+ struct dx_entry *entry, unsigned value)
- {
-- entry->hash = cpu_to_le32(value);
-+ *(u32*)entry_off(entry, p->dp_param->dpo_key_size) = cpu_to_le32(value);
-+}
-+
-+static inline void *dx_get_key(struct dx_path *p,
-+ struct dx_entry *entry, void *key)
-+{
-+ memcpy(key, entry, p->dp_param->dpo_key_size);
-+ return key;
-+}
-+
-+static inline void dx_set_key(struct dx_path *p,
-+ struct dx_entry *entry, void *key)
-+{
-+ memcpy(entry, key, p->dp_param->dpo_key_size);
- }
-
- static inline unsigned dx_get_count (struct dx_entry *entries)
-@@ -231,17 +303,123 @@ static inline void dx_set_limit (struct
- ((struct dx_countlimit *) entries)->limit = cpu_to_le16(value);
- }
-
--static inline unsigned dx_root_limit (struct inode *dir, unsigned infosize)
-+static inline unsigned dx_root_limit(struct dx_path *p)
- {
-- unsigned entry_space = dir->i_sb->s_blocksize - EXT3_DIR_REC_LEN(1) -
-- EXT3_DIR_REC_LEN(2) - infosize;
-- return 0? 20: entry_space / sizeof(struct dx_entry);
-+ struct dx_param *param = p->dp_param;
-+ unsigned entry_space = p->dp_object->i_sb->s_blocksize -
-+ param->dpo_root_gap;
-+ return entry_space / (param->dpo_key_size + param->dpo_ptr_size);
-+}
-+
-+static inline unsigned dx_node_limit(struct dx_path *p)
-+{
-+ struct dx_param *param = p->dp_param;
-+ unsigned entry_space = p->dp_object->i_sb->s_blocksize -
-+ param->dpo_node_gap;
-+ return entry_space / (param->dpo_key_size + param->dpo_ptr_size);
-+}
-+
-+static inline int dx_index_is_compat(struct dx_path *path)
-+{
-+ return path->dp_param == &htree_compat_param;
-+}
-+
-+static struct dx_entry *dx_get_entries(struct dx_path *path, void *data,
-+ int root)
-+{
-+ return data +
-+ (root ?
-+ path->dp_param->dpo_root_gap : path->dp_param->dpo_node_gap);
-+}
-+
-+static struct dx_entry *dx_node_get_entries(struct dx_path *path,
-+ struct dx_frame *frame)
-+{
-+ return dx_get_entries(path,
-+ frame->bh->b_data, frame == path->dp_frames);
-+}
-+
-+static u32 htree_root_ptr(struct dx_path *path)
-+{
-+ return 0;
-+}
-+
-+struct htree_cookie {
-+ struct dx_hash_info *hinfo;
-+ struct dentry *dentry;
-+};
-+
-+static int htree_node_check(struct dx_path *path, struct dx_frame *frame,
-+ void *cookie)
-+{
-+ void *data;
-+ struct dx_entry *entries;
-+ struct super_block *sb;
-+
-+ data = frame->bh->b_data;
-+ entries = dx_node_get_entries(path, frame);
-+ sb = path->dp_object->i_sb;
-+ if (frame == path->dp_frames) {
-+ /* root node */
-+ struct dx_root *root;
-+ struct htree_cookie *hc = cookie;
-+
-+ root = data;
-+ if (root->info.hash_version != DX_HASH_TEA &&
-+ root->info.hash_version != DX_HASH_HALF_MD4 &&
-+ root->info.hash_version != DX_HASH_R5 &&
-+ root->info.hash_version != DX_HASH_LEGACY) {
-+ 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->dp_indirect = root->info.indirect_levels;
-+ if (path->dp_indirect > DX_MAX_TREE_HEIGHT - 1) {
-+ ext3_warning(sb, __FUNCTION__,
-+ "Unimplemented inode hash depth: %#06x",
-+ root->info.indirect_levels);
-+ return ERR_BAD_DX_DIR;
-+ }
-+
-+ 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->dp_key_target = &hc->hinfo->hash;
-+ } else {
-+ /* non-root index */
-+ assert(entries == data + path->dp_param->dpo_node_gap);
-+ assert(dx_get_limit(entries) == dx_node_limit(path));
-+ }
-+ frame->entries = frame->at = entries;
-+ return 0;
- }
-
--static inline unsigned dx_node_limit (struct inode *dir)
-+static int htree_node_init(struct dx_path *path,
-+ struct buffer_head *bh, int root)
- {
-- unsigned entry_space = dir->i_sb->s_blocksize - EXT3_DIR_REC_LEN(0);
-- return 0? 22: entry_space / sizeof(struct dx_entry);
-+ struct dx_node *node;
-+
-+ assert(!root);
-+
-+ node = (void *)bh->b_data;
-+ node->fake.rec_len = cpu_to_le16(path->dp_object->i_sb->s_blocksize);
-+ node->fake.inode = 0;
-+ return 0;
- }
-
- /*
-@@ -327,123 +505,101 @@ struct stats dx_show_entries(struct dx_h
- }
- #endif /* DX_DEBUG */
-
--/*
-- * 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 struct dx_frame *
--dx_probe(struct dentry *dentry, struct inode *dir,
-- struct dx_hash_info *hinfo, struct dx_path *path, int *err)
--{
-- unsigned count, indirect;
-- struct dx_entry *at, *entries, *p, *q, *m;
-- struct dx_root *root;
-- struct buffer_head *bh;
-- struct dx_frame *frame = path->dp_frames;
-- u32 hash;
-+static int dx_lookup(struct dx_path *path, void *cookie)
-+{
-+ u32 ptr;
-+ int err;
-+ int i;
-
-- frame->bh = NULL;
-- if (dentry)
-- dir = dentry->d_parent->d_inode;
-- if (!(bh = ext3_bread (NULL,dir, 0, 0, err)))
-- goto fail;
-- root = (struct dx_root *) bh->b_data;
-- if (root->info.hash_version != DX_HASH_TEA &&
-- root->info.hash_version != DX_HASH_HALF_MD4 &&
-- root->info.hash_version != DX_HASH_R5 &&
-- root->info.hash_version != DX_HASH_LEGACY) {
-- ext3_warning(dir->i_sb, __FUNCTION__,
-- "Unrecognised inode hash code %d", root->info.hash_version);
-- brelse(bh);
-- *err = ERR_BAD_DX_DIR;
-- goto fail;
-- }
-- hinfo->hash_version = root->info.hash_version;
-- hinfo->seed = EXT3_SB(dir->i_sb)->s_hash_seed;
-- if (dentry)
-- ext3fs_dirhash(dentry->d_name.name, dentry->d_name.len, hinfo);
-- hash = hinfo->hash;
--
-- if (root->info.unused_flags & 1) {
-- ext3_warning(dir->i_sb, __FUNCTION__,
-- "Unimplemented inode hash flags: %#06x",
-- root->info.unused_flags);
-- brelse(bh);
-- *err = ERR_BAD_DX_DIR;
-- goto fail;
-- }
-+ struct dx_param *param;
-+ struct dx_frame *frame;
-
-- if ((indirect = root->info.indirect_levels) > DX_MAX_TREE_HEIGHT - 1) {
-- ext3_warning(dir->i_sb, __FUNCTION__,
-- "Unimplemented inode hash depth: %#06x",
-- root->info.indirect_levels);
-- brelse(bh);
-- *err = ERR_BAD_DX_DIR;
-- goto fail;
-- }
-+ param = path->dp_param;
-
-- entries = (struct dx_entry *) (((char *)&root->info) +
-- root->info.info_length);
-- assert(dx_get_limit(entries) == dx_root_limit(dir,
-- root->info.info_length));
-- dxtrace (printk("Look up %x", hash));
-- while (1)
-- {
-+ for (frame = path->dp_frames, i = 0,
-+ ptr = param->dpo_root_ptr(path); i <= path->dp_indirect;
-+ ptr = dx_get_block(path, frame->at), ++frame, ++i) {
-+ struct dx_entry *entries;
-+ struct dx_entry *p;
-+ struct dx_entry *q;
-+ struct dx_entry *m;
-+ unsigned count;
-+
-+ frame->bh = ext3_bread(NULL, path->dp_object, ptr, 0, &err);
-+ if (frame->bh == NULL) {
-+ err = -EIO;
-+ break;
-+ }
-+ err = param->dpo_node_check(path, frame, cookie);
-+ if (err != 0)
-+ break;
-+
-+ entries = frame->entries;
- count = dx_get_count(entries);
-- assert (count && count <= dx_get_limit(entries));
-- p = entries + 1;
-- q = entries + count - 1;
-- while (p <= q)
-- {
-- m = p + (q - p)/2;
-+ assert(count && count <= dx_get_limit(entries));
-+ p = dx_entry_shift(path, entries, 1);
-+ q = dx_entry_shift(path, entries, count - 1);
-+ while (p <= q) {
-+ m = dx_entry_shift(path,
-+ p, dx_entry_diff(path, q, p) / 2);
- dxtrace(printk("."));
-- if (dx_get_hash(m) > hash)
-- q = m - 1;
-+ if (memcmp(dx_get_key(path, m, path->dp_key),
-+ path->dp_key_target,
-+ param->dpo_key_size) > 0)
-+ q = dx_entry_shift(path, m, -1);
- else
-- p = m + 1;
-+ p = dx_entry_shift(path, m, +1);
- }
-
-- if (0) // linear search cross check
-- {
-+ frame->at = dx_entry_shift(path, p, -1);
-+ if (1) { // linear search cross check
- unsigned n = count - 1;
-+ struct dx_entry *at;
-+
- at = entries;
-- while (n--)
-- {
-+ while (n--) {
- dxtrace(printk(","));
-- if (dx_get_hash(++at) > hash)
-- {
-- at--;
-+ at = dx_entry_shift(path, at, +1);
-+ if (memcmp(dx_get_key(path, at, path->dp_key),
-+ path->dp_key_target,
-+ param->dpo_key_size) > 0) {
-+ at = dx_entry_shift(path, at, -1);
- break;
- }
- }
-- assert (at == p - 1);
-+ assert(at == frame->at);
- }
--
-- at = p - 1;
-- dxtrace(printk(" %x->%u\n", at == entries? 0: dx_get_hash(at), dx_get_block(at)));
-- frame->bh = bh;
-- frame->entries = entries;
-- frame->at = at;
-- if (!indirect--)
-- return path->dp_frame = frame;
-- if (!(bh = ext3_bread (NULL,dir, dx_get_block(at), 0, err)))
-- goto fail2;
-- at = entries = ((struct dx_node *) bh->b_data)->entries;
-- assert (dx_get_limit(entries) == dx_node_limit (dir));
-- frame++;
-- }
--fail2:
-- while (frame >= path->dp_frames) {
-- brelse(frame->bh);
-- frame--;
- }
--fail:
-- return NULL;
-+ if (err != 0)
-+ dx_path_fini(path);
-+ path->dp_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 dx_path *path)
-+{
-+ int err;
-+ __u32 hash_storage;
-+ struct htree_cookie hc = {
-+ .dentry = dentry,
-+ .hinfo = hinfo
-+ };
-+
-+ assert(dx_index_is_compat(path));
-+ path->dp_key = &hash_storage;
-+ err = dx_lookup(path, &hc);
-+ assert(err != 0 || path->dp_frames[path->dp_indirect].bh != NULL);
-+ return err;
- }
-
- static inline void dx_path_init(struct dx_path *path, struct inode *inode)
-@@ -458,8 +614,10 @@ static inline void dx_path_fini(struct d
- int i;
-
- for (i = 0; i < ARRAY_SIZE(path->dp_frames); i--) {
-- if (path->dp_frames[i].bh != NULL)
-+ if (path->dp_frames[i].bh != NULL) {
- brelse(path->dp_frames[i].bh);
-+ path->dp_frames[i].bh = NULL;
-+ }
- }
- }
-
-@@ -488,6 +646,8 @@ static int ext3_htree_next_block(struct
- int err, num_frames = 0;
- __u32 bhash;
-
-+ assert(dx_index_is_compat(path));
-+
- p = path->dp_frame;
- /*
- * Find the next leaf page by incrementing the frame pointer.
-@@ -497,7 +657,9 @@ static int ext3_htree_next_block(struct
- * nodes need to be read.
- */
- while (1) {
-- if (++(p->at) < p->entries + dx_get_count(p->entries))
-+ p->at = dx_entry_shift(path, p->at, +1);
-+ if (p->at < dx_entry_shift(path, p->entries,
-+ dx_get_count(p->entries)))
- break;
- if (p == path->dp_frames)
- return 0;
-@@ -512,7 +674,7 @@ static int ext3_htree_next_block(struct
- * desired contiuation hash. If it doesn't, return since
- * there's no point to read in the successive index pages.
- */
-- bhash = dx_get_hash(p->at);
-+ dx_get_key(path, p->at, &bhash);
- if (start_hash)
- *start_hash = bhash;
- if ((hash & 1) == 0) {
-@@ -524,12 +686,13 @@ static int ext3_htree_next_block(struct
- * block so no check is necessary
- */
- while (num_frames--) {
-- if (!(bh = ext3_bread(NULL, dir, dx_get_block(p->at), 0, &err)))
-+ if (!(bh = ext3_bread(NULL, dir,
-+ dx_get_block(path, p->at), 0, &err)))
- return err; /* Failure */
- ++p;
- brelse (p->bh);
- p->bh = bh;
-- p->at = p->entries = ((struct dx_node *) bh->b_data)->entries;
-+ p->at = p->entries = dx_node_get_entries(path, p);
- }
- return 1;
- }
-@@ -609,6 +772,7 @@ int ext3_htree_fill_tree(struct file *di
- start_minor_hash));
- dir = dir_file->f_dentry->d_inode;
- dx_path_init(&path, dir);
-+ path.dp_param = &htree_compat_param;
- if (!(EXT3_I(dir)->i_flags & EXT3_INDEX_FL)) {
- hinfo.hash_version = EXT3_SB(dir->i_sb)->s_def_hash_version;
- hinfo.seed = EXT3_SB(dir->i_sb)->s_hash_seed;
-@@ -619,7 +783,8 @@ int ext3_htree_fill_tree(struct file *di
- }
- hinfo.hash = start_hash;
- hinfo.minor_hash = 0;
-- if (!dx_probe(NULL, dir_file->f_dentry->d_inode, &hinfo, &path, &err))
-+ err = dx_probe(NULL, dir_file->f_dentry->d_inode, &hinfo, &path);
-+ if (err != 0)
- return err;
-
- /* Add '.' and '..' from the htree header */
-@@ -634,7 +799,7 @@ int ext3_htree_fill_tree(struct file *di
- }
-
- while (1) {
-- block = dx_get_block(path.dp_frame->at);
-+ block = dx_get_block(&path, path.dp_frame->at);
- ret = htree_dirblock_to_tree(dir_file, dir, block, &hinfo,
- start_hash, start_minor_hash);
- if (ret < 0) {
-@@ -722,17 +887,19 @@ static void dx_sort_map (struct dx_map_e
- } while(more);
- }
-
--static void dx_insert_block(struct dx_frame *frame, u32 hash, u32 block)
-+static void dx_insert_block(struct dx_path *path,
-+ struct dx_frame *frame, u32 hash, u32 block)
- {
- struct dx_entry *entries = frame->entries;
-- struct dx_entry *old = frame->at, *new = old + 1;
-+ struct dx_entry *old = frame->at, *new = dx_entry_shift(path, old, +1);
- int count = dx_get_count(entries);
-
- assert(count < dx_get_limit(entries));
-- assert(old < entries + count);
-- memmove(new + 1, new, (char *)(entries + count) - (char *)(new));
-- dx_set_hash(new, hash);
-- dx_set_block(new, block);
-+ assert(old < dx_entry_shift(path, entries, count));
-+ memmove(dx_entry_shift(path, new, 1), new,
-+ (char *)dx_entry_shift(path, entries, count) - (char *)new);
-+ dx_set_key(path, new, &hash);
-+ dx_set_block(path, new, block);
- dx_set_count(entries, count + 1);
- }
- #endif
-@@ -934,7 +1101,9 @@ static struct buffer_head * ext3_dx_find
- struct dx_hash_info hinfo;
- u32 hash;
- struct dx_path path;
-- struct dx_entry dummy_dot;
-+ struct dx_entry_compat dummy_dot = {
-+ .block = 0
-+ };
- struct ext3_dir_entry_2 *de, *top;
- struct buffer_head *bh;
- unsigned long block;
-@@ -944,19 +1113,21 @@ static struct buffer_head * ext3_dx_find
- struct inode *dir = dentry->d_parent->d_inode;
-
- dx_path_init(&path, dir);
-+ path.dp_param = &htree_compat_param;
-+
- sb = dir->i_sb;
- /* NFS may look up ".." - look at dx_root directory block */
- if (namelen > 2 || name[0] != '.'||(name[1] != '.' && name[1] != '\0')){
-- if (!(dx_probe(dentry, NULL, &hinfo, &path, err)))
-+ *err = dx_probe(dentry, NULL, &hinfo, &path);
-+ if (*err != 0)
- return NULL;
- } else {
-- path.dp_frame->bh = NULL; /* for dx_path_fini() */
-- path.dp_frame->at = &dummy_dot; /* hack for zero entry*/
-- dx_set_block(path.dp_frame->at, 0); /* dx_root block is 0 */
-+ path.dp_frame->bh = NULL; /* for dx_path_fini() */
-+ path.dp_frame->at = (void *)&dummy_dot; /* hack for zero entry*/
- }
- hash = hinfo.hash;
- do {
-- block = dx_get_block(path.dp_frame->at);
-+ block = dx_get_block(&path, path.dp_frame->at);
- if (!(bh = ext3_bread (NULL,dir, block, 0, err)))
- goto errout;
- de = (struct ext3_dir_entry_2 *) bh->b_data;
-@@ -1115,10 +1286,11 @@ static struct ext3_dir_entry_2* dx_pack_
-
- /* 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 inode *dir,
-+static struct ext3_dir_entry_2 *do_split(handle_t *handle, struct dx_path *path,
- struct buffer_head **bh,struct dx_frame *frame,
- struct dx_hash_info *hinfo, int *error)
- {
-+ struct inode *dir = path->dp_object;
- unsigned blocksize = dir->i_sb->s_blocksize;
- unsigned count, continued;
- struct buffer_head *bh2;
-@@ -1180,7 +1352,7 @@ static struct ext3_dir_entry_2 *do_split
- swap(*bh, bh2);
- de = de2;
- }
-- dx_insert_block (frame, hash2 + continued, newblock);
-+ dx_insert_block(path, frame, hash2 + continued, newblock);
- err = ext3_journal_dirty_metadata (handle, bh2);
- if (err)
- goto journal_error;
-@@ -1315,6 +1487,7 @@ static int make_indexed_dir(handle_t *ha
- struct fake_dirent *fde;
-
- dx_path_init(&path, dir);
-+ path.dp_param = &htree_compat_param;
- blocksize = dir->i_sb->s_blocksize;
- dxtrace(printk("Creating index\n"));
- retval = ext3_journal_get_write_access(handle, bh);
-@@ -1350,10 +1523,10 @@ static int make_indexed_dir(handle_t *ha
- root->info.info_length = sizeof(root->info);
- root->info.hash_version = EXT3_SB(dir->i_sb)->s_def_hash_version;
- root->info.hash_version = DX_HASH_R5;
-- entries = root->entries;
-- dx_set_block (entries, 1);
-+ entries = (void *)root->entries;
-+ dx_set_block (&path, entries, 1);
- dx_set_count (entries, 1);
-- dx_set_limit (entries, dx_root_limit(dir, sizeof(root->info)));
-+ dx_set_limit (entries, dx_root_limit(&path));
-
- /* Initialize as for dx_probe */
- hinfo.hash_version = root->info.hash_version;
-@@ -1363,7 +1536,7 @@ static int make_indexed_dir(handle_t *ha
- path.dp_frame->at = entries;
- path.dp_frame->bh = bh;
- bh = bh2;
-- de = do_split(handle,dir, &bh, path.dp_frame, &hinfo, &retval);
-+ de = do_split(handle, &path, &bh, path.dp_frame, &hinfo, &retval);
- dx_path_fini(&path);
- if (!de)
- return retval;
-@@ -1446,8 +1619,8 @@ static int ext3_dx_add_entry(handle_t *h
- struct inode *inode)
- {
- struct dx_path path;
-+ struct dx_param *param;
- struct dx_frame *frame, *safe;
-- struct dx_node *node2;
- struct dx_entry *entries; /* old block contents */
- struct dx_entry *entries2; /* new block contents */
- struct dx_hash_info hinfo;
-@@ -1463,7 +1636,10 @@ static int ext3_dx_add_entry(handle_t *h
- size_t isize;
-
- dx_path_init(&path, dir);
-- if (!dx_probe(dentry, NULL, &hinfo, &path, &err))
-+ param = path.dp_param = &htree_compat_param;
-+
-+ err = dx_probe(dentry, NULL, &hinfo, &path);
-+ if (err != 0)
- return err;
- frame = path.dp_frame;
- entries = frame->entries;
-@@ -1471,7 +1647,8 @@ static int ext3_dx_add_entry(handle_t *h
- /* XXX nikita: global serialization! */
- isize = dir->i_size;
-
-- if (!(bh = ext3_bread(handle,dir, dx_get_block(frame->at), 0, &err)))
-+ if (!(bh = ext3_bread(handle, dir,
-+ dx_get_block(&path, frame->at), 0, &err)))
- goto cleanup;
-
- BUFFER_TRACE(bh, "get_write_access");
-@@ -1519,12 +1696,9 @@ static int ext3_dx_add_entry(handle_t *h
- * transaction... */
- 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])
-+ if (!bh_new[i] ||
-+ param->dpo_node_init(&path, bh_new[i], 0) != 0)
- goto cleanup;
-- node2 = (struct dx_node *)(bh_new[i]->b_data);
-- entries2 = node2->entries;
-- node2->fake.rec_len = cpu_to_le16(sb->s_blocksize);
-- node2->fake.inode = 0;
- BUFFER_TRACE(frame->bh, "get_write_access");
- err = ext3_journal_get_write_access(handle, frame->bh);
- if (err)
-@@ -1545,11 +1719,10 @@ static int ext3_dx_add_entry(handle_t *h
-
- entries = frame->entries;
- count = dx_get_count(entries);
-- idx = frame->at - entries;
-+ idx = dx_entry_diff(&path, frame->at, entries);
-
- bh2 = bh_new[i];
-- node2 = (struct dx_node *)(bh2->b_data);
-- entries2 = node2->entries;
-+ entries2 = dx_get_entries(&path, bh2->b_data, 0);
-
- if (frame == path.dp_frames) {
- /* splitting root node. Tricky point:
-@@ -1571,19 +1744,19 @@ static int ext3_dx_add_entry(handle_t *h
- indirects = root->info.indirect_levels;
- dxtrace(printk("Creating new root %d\n", indirects));
- memcpy((char *) entries2, (char *) entries,
-- count * sizeof(struct dx_entry));
-- dx_set_limit(entries2, dx_node_limit(dir));
-+ count * dx_entry_size(&path));
-+ dx_set_limit(entries2, dx_node_limit(&path));
-
- /* Set up root */
- dx_set_count(entries, 1);
-- dx_set_block(entries + 0, newblock[i]);
-+ dx_set_block(&path, entries, newblock[i]);
- root->info.indirect_levels = indirects + 1;
-
- /* Shift frames in the path */
- memmove(frames + 2, frames + 1,
- (sizeof path.dp_frames) - 2 * sizeof frames[0]);
- /* Add new access path frame */
-- frames[1].at = entries2 + idx;
-+ frames[1].at = dx_entry_shift(&path, entries2, idx);
- frames[1].entries = entries = entries2;
- frames[1].bh = bh2;
- ++ frame;
-@@ -1594,23 +1767,30 @@ static int ext3_dx_add_entry(handle_t *h
- } else {
- /* splitting non-root index node. */
- unsigned count1 = count/2, count2 = count - count1;
-- unsigned hash2 = dx_get_hash(entries + count1);
-+ unsigned hash2;
-+
-+ dx_get_key(&path,
-+ dx_entry_shift(&path, entries, count1),
-+ &hash2);
-+
- dxtrace(printk("Split index %i/%i\n", count1, count2));
-
-- memcpy ((char *) entries2, (char *) (entries + count1),
-- count2 * sizeof(struct dx_entry));
-+ memcpy ((char *) entries2,
-+ (char *) dx_entry_shift(&path, entries, count1),
-+ count2 * dx_entry_size(&path));
- dx_set_count (entries, count1);
- dx_set_count (entries2, count2);
-- dx_set_limit (entries2, dx_node_limit(dir));
-+ dx_set_limit (entries2, dx_node_limit(&path));
-
- /* Which index block gets the new entry? */
- if (idx >= count1) {
-- frame->at = entries2 + idx - count1;
-+ frame->at = dx_entry_shift(&path, entries2,
-+ idx - count1);
- frame->entries = entries = entries2;
- swap(frame->bh, bh2);
- bh_new[i] = bh2;
- }
-- dx_insert_block (frame - 1, hash2, newblock[i]);
-+ dx_insert_block(&path, frame - 1, hash2, newblock[i]);
- dxtrace(dx_show_index ("node", frame->entries));
- dxtrace(dx_show_index ("node",
- ((struct dx_node *) bh2->b_data)->entries));
-@@ -1619,7 +1799,7 @@ static int ext3_dx_add_entry(handle_t *h
- goto journal_error;
- }
- }
-- de = do_split(handle, dir, &bh, --frame, &hinfo, &err);
-+ de = do_split(handle, &path, &bh, --frame, &hinfo, &err);
- if (!de)
- goto cleanup;
- err = add_dirent_to_buf(handle, dentry, inode, de, bh);