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);