From: nikita Date: Sat, 27 May 2006 17:43:21 +0000 (+0000) Subject: iam update: X-Git-Tag: v1_8_0_110~486^2~1749 X-Git-Url: https://git.whamcloud.com/?a=commitdiff_plain;h=5300361366931b1753c033abea4ff85cb510e5f7;p=fs%2Flustre-release.git iam update: - move lfix operations into separate file: iam_lfix.c - cleanup leaf operation vector. --- diff --git a/ldiskfs/ldiskfs/Makefile.in b/ldiskfs/ldiskfs/Makefile.in index 4a76335..df5199d 100644 --- a/ldiskfs/ldiskfs/Makefile.in +++ b/ldiskfs/ldiskfs/Makefile.in @@ -11,7 +11,7 @@ ext3_headers := $(wildcard @LINUX@/fs/ext3/*.h) linux_headers := $(wildcard @LINUX@/include/linux/ext3*.h) ext3_sources := $(filter-out %.mod.c,$(wildcard @LINUX@/fs/ext3/*.c)) -new_sources := iopen.c iopen.h extents.c mballoc.c iam.c +new_sources := iopen.c iopen.h extents.c mballoc.c iam.c iam_lfix.c new_headers := ext3_extents.h ldiskfs_patched_sources := $(notdir $(ext3_sources) $(ext3_headers)) $(new_sources) $(new_headers) ldiskfs_sources := $(ldiskfs_patched_sources) diff --git a/lustre/fld/fld_iam.c b/lustre/fld/fld_iam.c index 9e87f46..b8a77dc 100644 --- a/lustre/fld/fld_iam.c +++ b/lustre/fld/fld_iam.c @@ -53,7 +53,7 @@ struct iam_descr fld_param = { .id_node_gap = 0, /* no gaps in index nodes */ .id_root_gap = sizeof(struct iam_root), .id_ops = &generic_iam_ops, - .id_leaf_ops = &lfix_leaf_ops + .id_leaf_ops = &iam_lfix_leaf_ops }; /* * number of blocks to reserve for particular operations. Should be function @@ -65,8 +65,8 @@ enum { FLD_TXN_INDEX_DELETE_CREDITS = 10 }; -static int fld_keycmp(struct iam_container *c, struct iam_key *k1, - struct iam_key *k2) +static int fld_keycmp(const struct iam_container *c, const struct iam_key *k1, + const struct iam_key *k2) { __u64 p1 = le64_to_cpu(*(__u32 *)k1); __u64 p2 = le64_to_cpu(*(__u32 *)k2); diff --git a/lustre/include/md_object.h b/lustre/include/md_object.h index 3928fff..50e5786 100644 --- a/lustre/include/md_object.h +++ b/lustre/include/md_object.h @@ -190,7 +190,7 @@ static inline int mo_object_create(const struct lu_context *cx, } static inline int mdo_lookup(const struct lu_context *cx, struct md_object *p, - const char *name, struct lu_fid *f) + const char *name, struct lu_fid *f) { return p->mo_dir_ops->mdo_lookup(cx, p, name, f); } diff --git a/lustre/kernel_patches/patches/ext3-iam-separate.patch b/lustre/kernel_patches/patches/ext3-iam-separate.patch index 2465d5f..e3ab05f 100644 --- a/lustre/kernel_patches/patches/ext3-iam-separate.patch +++ b/lustre/kernel_patches/patches/ext3-iam-separate.patch @@ -1,1388 +1,26 @@ -Index: linux-2.6.9/fs/ext3/namei.c +Index: iam/fs/ext3/Makefile =================================================================== ---- linux-2.6.9.orig/fs/ext3/namei.c 2006-05-26 16:47:50.000000000 +0800 -+++ linux-2.6.9/fs/ext3/namei.c 2006-05-26 16:47:50.000000000 +0800 -@@ -24,81 +24,6 @@ - * Theodore Ts'o, 2002 - */ - --/* -- * iam: big theory statement. -- * -- * iam (Index Access Module) is a module providing abstraction of persistent -- * transactional container on top of generalized ext3 htree. -- * -- * iam supports: -- * -- * - key, pointer, and record size specifiable per container. -- * -- * - trees taller than 2 index levels. -- * -- * - read/write to existing ext3 htree directories as iam containers. -- * -- * iam container is a tree, consisting of leaf nodes containing keys and -- * records stored in this container, and index nodes, containing keys and -- * pointers to leaf or index nodes. -- * -- * iam does not work with keys directly, instead it calls user-supplied key -- * comparison function (->dpo_keycmp()). -- * -- * Pointers are (currently) interpreted as logical offsets (measured in -- * blocksful) within underlying flat file on top of which iam tree lives. -- * -- * On-disk format: -- * -- * iam mostly tries to reuse existing htree formats. -- * -- * Format of index node: -- * -- * +-----+-------+-------+-------+------+-------+------------+ -- * | | count | | | | | | -- * | gap | / | entry | entry | .... | entry | free space | -- * | | limit | | | | | | -- * +-----+-------+-------+-------+------+-------+------------+ -- * -- * gap this part of node is never accessed by iam code. It -- * exists for binary compatibility with ext3 htree (that, -- * in turn, stores fake struct ext2_dirent for ext2 -- * compatibility), and to keep some unspecified per-node -- * data. Gap can be different for root and non-root index -- * nodes. Gap size can be specified for each container -- * (gap of 0 is allowed). -- * -- * count/limit current number of entries in this node, and the maximal -- * number of entries that can fit into node. count/limit -- * has the same size as entry, and is itself counted in -- * count. -- * -- * entry index entry: consists of a key immediately followed by -- * a pointer to a child node. Size of a key and size of a -- * pointer depends on container. Entry has neither -- * alignment nor padding. -- * -- * free space portion of node new entries are added to -- * -- * Entries in index node are sorted by their key value. -- * -- * Format of leaf node: -- * -- * +-----+-------+-------+-------+------+-------+------------+ -- * | | count | | | | | | -- * | gap | / | leaf | leaf | .... | leaf | free space | -- * | | limit | | | | | | -- * +-----+-------+-------+-------+------+-------+------------+ -- -- * leaf For leaf entry: consists of a rec immediately followd by -- * a key. size of a key and size of a rec depends on container. -- * -- * -- * -- * -- * -- */ -- - #include - #include - #include -@@ -112,10 +37,10 @@ - #include - #include - #include -+#include - #include "xattr.h" - #include "iopen.h" - #include "acl.h" --#include - /* - * define how far ahead to read directories while searching them. - */ -@@ -125,9 +50,9 @@ - #define NAMEI_RA_INDEX(c,b) (((c) * NAMEI_RA_BLOCKS) + (b)) - - --static struct buffer_head *ext3_append(handle_t *handle, -- struct inode *inode, -- u32 *block, int *err) -+struct buffer_head *ext3_append(handle_t *handle, -+ struct inode *inode, -+ u32 *block, int *err) - { - struct buffer_head *bh; - -@@ -141,9 +66,6 @@ - return bh; - } - --#ifndef assert --#define assert(test) J_ASSERT(test) --#endif - - #ifndef swap - #define swap(x, y) do { typeof(x) z = x; x = y; y = z; } while (0) -@@ -162,10 +84,6 @@ - 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,242 +121,10 @@ - }; +--- iam.orig/fs/ext3/Makefile 2006-05-27 19:58:43.000000000 +0400 ++++ iam/fs/ext3/Makefile 2006-05-27 20:03:07.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 \ + ioctl.o namei.o super.o symlink.o hash.o resize.o \ +- extents.o mballoc.o ++ extents.o mballoc.o iam.o iam_lfix.o --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, -- struct buffer_head *bh, int root); --static int htree_keycmp(struct iam_container *c, -- struct iam_key *k1, struct iam_key *k2); --static int htree_node_read(struct iam_container *c, iam_ptr_t ptr, -- handle_t *h, struct buffer_head **bh); -- --/* -- * Parameters describing iam compatibility mode in which existing ext3 htrees -- * can be manipulated. -- */ --static 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_root_ptr = htree_root_ptr, -- .id_node_check = htree_node_check, -- .id_node_init = htree_node_init, -- .id_node_read = htree_node_read, -- .id_keycmp = htree_keycmp --}; -- -- --struct iam_key; --struct iam_rec; --struct iam_descr; --struct iam_container; --struct iam_path; -- -- -- --/* -- * iam cursor (iterator) api. -- */ -- --/* -- * Flags controlling iterator functionality. -- */ --enum iam_it_flags { -- /* -- * this iterator will move (iam_it_{prev,next}() will be called on it) -- */ -- IAM_IT_MOVE = (1 << 0), -- /* -- * tree can be updated through this iterator. -- */ -- IAM_IT_WRITE = (1 << 1) --}; -- --/* -- * States of iterator state machine. -- */ --enum iam_it_state { -- /* initial state */ -- IAM_IT_DETACHED, -- /* iterator is above particular record in the container */ -- IAM_IT_ATTACHED --}; -- --struct htree_cookie { -- struct dx_hash_info *hinfo; -- struct dentry *dentry; --}; -- --/* -- * Iterator. -- * -- * Immediately after call to iam_it_init() iterator is in "detached" -- * (IAM_IT_DETACHED) state: it is associated with given parent container, but -- * doesn't point to any particular record in this container. -- * -- * After successful call to iam_it_get() and until corresponding call to -- * iam_it_put() iterator is in "attached" state (IAM_IT_ATTACHED). -- * -- * Attached iterator can move through records in a container (provided -- * IAM_IT_MOVE permission) in a key order, can get record and key values as it -- * passes over them, and can modify container (provided IAM_IT_WRITE -- * permission). -- * -- * Concurrency: iterators are supposed to be local to thread. Interfaces below -- * do no internal serialization. -- * -- */ --struct iam_iterator { -- /* -- * iterator flags, taken from enum iam_it_flags. -- */ -- __u32 ii_flags; -- enum iam_it_state ii_state; -- /* -- * path to the record. Valid in IAM_IT_ATTACHED state. -- */ -- struct iam_path ii_path; --}; -- --static inline struct iam_key *keycpy(struct iam_container *c, -- struct iam_key *k1, struct iam_key *k2) --{ -- return memcpy(k1, k2, c->ic_descr->id_key_size); --} -- --static inline int keycmp(struct iam_container *c, -- struct iam_key *k1, struct iam_key *k2) --{ -- return c->ic_descr->id_keycmp(c, k1, k2); --} -- --static struct iam_container *iam_it_container(struct iam_iterator *it) --{ -- return it->ii_path.ip_container; --} -- --static inline int it_keycmp(struct iam_iterator *it, -- struct iam_key *k1, struct iam_key *k2) --{ -- return keycmp(iam_it_container(it), k1, k2); --} -- --/* -- * Initialize iterator to IAM_IT_DETACHED state. -- * -- * postcondition: it_state(it) == IAM_IT_DETACHED -- */ --int iam_it_init(struct iam_iterator *it, struct iam_container *c, __u32 flags); --/* -- * Finalize iterator and release all resources. -- * -- * precondition: it_state(it) == IAM_IT_DETACHED -- */ --void iam_it_fini(struct iam_iterator *it); -- --/* -- * Attach iterator. After successful completion, @it points to record with the -- * largest key not larger than @k. Semantics of ->id_create() method guarantee -- * that such record will always be found. -- * -- * Return value: 0: positioned on existing record, -- * -ve: error. -- * -- * precondition: it_state(it) == IAM_IT_DETACHED -- * postcondition: ergo(result == 0, -- * (it_state(it) == IAM_IT_ATTACHED && -- * it_keycmp(it, iam_it_key_get(it, *), k) < 0)) -- */ --int iam_it_get(struct iam_iterator *it, struct iam_key *k); -- --/* -- * Duplicates iterator. -- * -- * postcondition: it_state(dst) == it_state(src) && -- * iam_it_container(dst) == iam_it_container(src) && -- * dst->ii_flags = src->ii_flags && -- * ergo(it_state(it) == IAM_IT_ATTACHED, -- * iam_it_rec_get(dst) == iam_it_rec_get(src) && -- * iam_it_key_get(dst, *1) == iam_it_key_get(src, *2)) -- */ --void iam_it_dup(struct iam_iterator *dst, struct iam_iterator *src); -- --/* -- * Detach iterator. Does nothing it detached state. -- * -- * postcondition: it_state(it) == IAM_IT_DETACHED -- */ --void iam_it_put(struct iam_iterator *it); -- --/* -- * Move iterator one record right. -- * -- * Return value: 0: success, -- * +1: end of container reached -- * -ve: error -- * -- * precondition: it_state(it) == IAM_IT_ATTACHED && it->ii_flags&IAM_IT_MOVE -- * postcondition: ergo(result >= 0, it_state(it) == IAM_IT_ATTACHED) -- */ --int iam_it_next(struct iam_iterator *it); -- --/* -- * Return pointer to the record under iterator. -- * -- * precondition: it_state(it) == IAM_IT_ATTACHED -- * postcondition: it_state(it) == IAM_IT_ATTACHED -- */ --const struct iam_rec *iam_it_rec_get(struct iam_iterator *it); -- --/* -- * Replace contents of record under iterator. -- * -- * precondition: it_state(it) == IAM_IT_ATTACHED && it->ii_flags&IAM_IT_WRITE -- * postcondition: it_state(it) == IAM_IT_ATTACHED && -- * ergo(result == 0, !memcmp(iam_it_rec_get(it), r, ...)) -- */ --int iam_it_rec_set(handle_t *h, struct iam_iterator *it, struct iam_rec *r); -- --/* -- * Place key under iterator in @k, return @k -- * -- * precondition: it_state(it) == IAM_IT_ATTACHED -- * postcondition: it_state(it) == IAM_IT_ATTACHED -- */ --const struct iam_key *iam_it_key_get(struct iam_iterator *it, -- struct iam_key *k); -- --/* -- * Insert new record with key @k and contents from @r, shifting records to the -- * right. -- * -- * precondition: it_state(it) == IAM_IT_ATTACHED && -- * it->ii_flags&IAM_IT_WRITE && -- * it_keycmp(it, iam_it_key_get(it, *), k) < 0 -- * postcondition: it_state(it) == IAM_IT_ATTACHED && -- * ergo(result == 0, -- * it_keycmp(it, iam_it_key_get(it, *), k) == 0 && -- * !memcmp(iam_it_rec_get(it), r, ...)) -- */ --int iam_it_rec_insert(handle_t *h, struct iam_iterator *it, -- struct iam_key *k, struct iam_rec *r); --/* -- * Delete record under iterator. -- * -- * precondition: it_state(it) == IAM_IT_ATTACHED && it->ii_flags&IAM_IT_WRITE -- * postcondition: it_state(it) == IAM_IT_ATTACHED -- */ --int iam_it_rec_delete(handle_t *h, struct iam_iterator *it); -- - #ifdef CONFIG_EXT3_INDEX - static inline unsigned dx_get_block(struct iam_path *p, struct iam_entry *entry); - static void dx_set_block(struct iam_path *p, - struct iam_entry *entry, unsigned value); --static inline struct iam_key *dx_get_key(struct iam_path *p, -- struct iam_entry *entry, -- struct iam_key *key); - static void dx_set_key(struct iam_path *p, struct iam_entry *entry, - struct iam_key *key); - static unsigned dx_get_count(struct iam_entry *entries); -@@ -457,80 +143,29 @@ - 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 iam_path *path, -- struct iam_frame *frame, u32 hash, u32 block); --static int ext3_htree_next_block(struct inode *dir, __u32 hash, -- struct iam_path *path, __u32 *start_hash); - static struct buffer_head * ext3_dx_find_entry(struct dentry *dentry, - struct ext3_dir_entry_2 **res_dir, int *err); - static int ext3_dx_add_entry(handle_t *handle, struct dentry *dentry, - struct inode *inode); - --static inline void iam_path_init(struct iam_path *path, -- struct iam_container *c, struct htree_cookie *hc); --static inline void iam_path_fini(struct iam_path *path); -- -- --/* -- * Future: use high four bits of block for coalesce-on-delete flags -- * Mask them off for now. -- */ -- --static inline void *entry_off(struct iam_entry *entry, ptrdiff_t off) --{ -- return (void *)((char *)entry + off); --} -- --static inline struct iam_descr *path_descr(struct iam_path *p) --{ -- return p->ip_container->ic_descr; --} -- --static inline struct inode *path_obj(struct iam_path *p) --{ -- return p->ip_container->ic_object; --} -- - 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, -- struct iam_entry *entry, int shift) -+ struct iam_entry *entry, -+ int shift) - { - 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) --{ -- 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); --} -- --static inline unsigned dx_get_block(struct iam_path *p, struct iam_entry *entry) --{ -- return le32_to_cpu(*(u32 *)entry_off(entry, path_descr(p)->id_key_size)) -- & 0x00ffffff; --} -- --static inline void dx_set_block(struct iam_path *p, -- struct iam_entry *entry, unsigned value) --{ -- *(u32*)entry_off(entry, -- path_descr(p)->id_key_size) = cpu_to_le32(value); --} -- --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); -+ memcpy(key, entry, iam_path_descr(p)->id_key_size); - return key; - } - -@@ -540,68 +175,70 @@ - return (struct iam_key *)entry; - } - --static inline void dx_set_key(struct iam_path *p, -- struct iam_entry *entry, struct iam_key *key) --{ -- memcpy(entry, key, path_descr(p)->id_key_size); --} -- --static inline unsigned dx_get_count (struct iam_entry *entries) --{ -- return le16_to_cpu(((struct dx_countlimit *) entries)->count); --} -- --static inline unsigned dx_get_limit (struct iam_entry *entries) -+static inline ptrdiff_t iam_entry_diff(struct iam_path *p, -+ struct iam_entry *e1, -+ struct iam_entry *e2) - { -- return le16_to_cpu(((struct dx_countlimit *) entries)->limit); --} -+ ptrdiff_t diff; - --static inline void dx_set_count (struct iam_entry *entries, unsigned value) --{ -- ((struct dx_countlimit *) entries)->count = cpu_to_le16(value); -+ diff = (void *)e1 - (void *)e2; -+ assert(diff / iam_entry_size(p) * iam_entry_size(p) == diff); -+ return diff / iam_entry_size(p); - } - --static inline void dx_set_limit (struct iam_entry *entries, unsigned value) -+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) - { -- struct iam_descr *param = path_descr(p); -- unsigned entry_space = path_obj(p)->i_sb->s_blocksize - -+ struct iam_descr *param = iam_path_descr(p); -+ unsigned entry_space = iam_path_obj(p)->i_sb->s_blocksize - - param->id_root_gap; - return entry_space / (param->id_key_size + param->id_ptr_size); - } - --static inline unsigned dx_node_limit(struct iam_path *p) --{ -- 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); --} -+/* -+ * 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 int dx_index_is_compat(struct iam_path *path) --{ -- return path_descr(path) == &htree_compat_param; --} -+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, struct buffer_head *bh, int root); -+static int htree_keycmp(struct iam_container *c, -+ struct iam_key *k1, struct iam_key *k2); - --static struct iam_entry *dx_get_entries(struct iam_path *path, void *data, -- int root) --{ -- return data + -- (root ? -- path_descr(path)->id_root_gap : path_descr(path)->id_node_gap); --} -+struct iam_operations htree_operation = { -+ .id_root_ptr = htree_root_ptr, -+ .id_node_check = htree_node_check, -+ .id_node_init = htree_node_init, -+ .id_node_read = iam_node_read, -+ .id_keycmp = htree_keycmp -+}; -+ -+/* -+ * 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 -+}; - --static struct iam_entry *dx_node_get_entries(struct iam_path *path, -- struct iam_frame *frame) -+static inline 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) - { - struct iam_entry *e; -@@ -614,10 +251,10 @@ - count = dx_get_count(e); - e = iam_entry_shift(p, e, 1); - for (i = 0; i < count - 1; ++i, e = iam_entry_shift(p, e, 1)) { -- keycpy(c, p->ip_key_scratch[0], p->ip_key_scratch[1]); -- dx_get_key(p, e, p->ip_key_scratch[1]); -+ iam_keycpy(c, iam_path_key(p, 0), iam_path_key(p, 1)); -+ iam_get_key(p, e, iam_path_key(p, 1)); - if (i > 0 && -- 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) - return 0; - } - return 1; -@@ -636,13 +273,17 @@ - - 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; -- 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 +310,16 @@ - 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 = (struct iam_key *)&ipc->ipc_hinfo->hash; - } 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)); - } - frame->entries = frame->at = entries; -@@ -697,8 +339,8 @@ - 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; - -@@ -800,7 +442,7 @@ - } - #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 +452,11 @@ - 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, -- ptr = param->id_root_ptr(path->ip_container); -+ ptr = param->id_ops->id_root_ptr(path->ip_container); - i <= path->ip_indirect; - ptr = dx_get_block(path, frame->at), ++frame, ++i) { - struct iam_entry *entries; -@@ -823,10 +465,11 @@ - 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; -- err = param->id_node_check(path, frame); -+ err = param->id_ops->id_node_check(path, frame); - if (err != 0) - break; - -@@ -841,8 +484,8 @@ - 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 +500,12 @@ - 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", -- 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 +534,20 @@ - 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)); -- path->ip_descr_data = &hc; - 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, -- struct iam_descr *descr, struct inode *inode) --{ -- memset(c, 0, sizeof *c); -- c->ic_descr = descr; -- c->ic_object = igrab(inode); -- if (c->ic_object != NULL) -- return 0; -- else -- return -ENOENT; --} -- --/* -- * Finalize container @c, release all resources. -- */ --void iam_container_fini(struct iam_container *c) --{ -- if (c->ic_object != NULL) { -- iput(c->ic_object); -- c->ic_object = NULL; -- } --} -- --static inline void iam_path_init(struct iam_path *path, struct iam_container *c, -- struct htree_cookie *hc) --{ -- memset(path, 0, sizeof *path); -- path->ip_container = c; -- path->ip_frame = path->ip_frames; -- path->ip_descr_data = hc; --} -- --static inline void iam_path_fini(struct iam_path *path) --{ -- int i; -- -- for (i = 0; i < ARRAY_SIZE(path->ip_frames); i++) { -- if (path->ip_frames[i].bh != NULL) { -- brelse(path->ip_frames[i].bh); -- path->ip_frames[i].bh = NULL; -- } -- } --} -- --static void iam_path_compat_init(struct iam_path_compat *path, -- struct inode *inode) --{ -- int 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_path_init(&path->ipc_path, &path->ipc_container, NULL); -- for (i = 0; i < ARRAY_SIZE(path->ipc_path.ip_key_scratch); ++i) -- path->ipc_path.ip_key_scratch[i] = -- (struct iam_key *)&path->ipc_scrach[i]; --} -- --static void iam_path_compat_fini(struct iam_path_compat *path) --{ -- iam_path_fini(&path->ipc_path); -- iam_container_fini(&path->ipc_container); --} -- --static int iam_leaf_init(struct iam_path *path, struct iam_leaf *leaf) --{ -- int block, err; -- struct buffer_head *bh; -- -- block = dx_get_block(path, path->ip_frame->at); -- err = path_descr(path)->id_node_read(path->ip_container, block, -- NULL, &bh); -- if (err) -- return err; -- -- leaf->bh = bh; -- leaf->entries = (struct iam_leaf_entry *)bh->b_data; -- return 0; --} -- --static void iam_leaf_fini(struct iam_leaf *leaf) --{ -- if (leaf->bh) -- brelse(leaf->bh); --} -- --/* -- * Search container @c for record with key @k. If record is found, its data -- * are moved into @r. -- * -- * -- * -- * Return values: +ve: found, 0: not-found, -ve: error -- */ -- --int iam_lookup(struct iam_container *c, struct iam_key *k, struct iam_rec *r) --{ -- struct dx_hash_info hinfo; -- struct iam_path_compat cpath; -- struct iam_path *path = &cpath.ipc_path; -- struct htree_cookie hc = { -- .hinfo = &hinfo -- }; -- int err, i; -- -- iam_path_init(path, c, &hc); -- 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); -- do { -- struct iam_leaf leaf; -- err = iam_leaf_init(path, &leaf); -- if (err) -- goto errout; -- -- for (path_descr(path)->id_leaf.start(c, &leaf); -- !path_descr(path)->id_leaf.at_end(c, &leaf); -- path_descr(path)->id_leaf.next(c, &leaf)) { -- struct iam_key *key; -- -- key = kmalloc(path_descr(path)->id_key_size, GFP_KERNEL); -- path_descr(path)->id_leaf.key(c, &leaf, key); -- if (keycmp(c, k, key) == 0) { -- memcpy(r, path_descr(path)->id_leaf.rec(c, &leaf), -- path_descr(path)->id_rec_size); -- iam_path_fini(path); -- iam_leaf_fini(&leaf); -- return 0; -- } -- } -- -- iam_leaf_fini(&leaf); -- /* Check to see if we should continue to search */ -- err = ext3_htree_next_block(c->ic_object, hinfo.hash, path, NULL); -- if (err < 0) -- goto errout; -- } while (err == 1); --errout: -- iam_path_fini(path); -- return(err); --} --EXPORT_SYMBOL(iam_lookup); -- --static inline size_t iam_leaf_entry_size(struct iam_path *p) --{ -- return path_descr(p)->id_rec_size + path_descr(p)->id_key_size; --} -- --static inline ptrdiff_t iam_leaf_entry_diff(struct iam_path *p, -- struct iam_leaf_entry *e1, struct iam_leaf_entry *e2) --{ -- ptrdiff_t diff; -- -- diff = (void *)e1 - (void *)e2; -- assert(diff / iam_leaf_entry_size(p) * iam_leaf_entry_size(p) == diff); -- return diff / iam_leaf_entry_size(p); --} -- --static inline struct iam_leaf_entry* --iam_leaf_entry_shift(struct iam_path *p, struct iam_leaf_entry *entry, int shift) --{ -- void *e = entry; -- return e + shift * iam_leaf_entry_size(p); --} -- --static inline struct iam_key * --dx_leaf_get_key(struct iam_path *p, struct iam_leaf_entry *e, struct iam_key *key) --{ -- memcpy(key, e, path_descr(p)->id_key_size); -- return key; --} -- --static inline struct iam_key * --iam_leaf_key_at(struct iam_path *p, struct iam_leaf_entry *entry) --{ -- void *e = entry; -- return e + path_descr(p)->id_rec_size; --} --static inline struct iam_leaf_entry * --iam_leaf_entry_at(struct iam_path *p, struct iam_leaf_entry *entry) --{ -- return entry; --} -- --static int iam_leaf_lookup(struct iam_path *path, struct iam_leaf *leaf, -- struct iam_key *k) --{ -- struct iam_leaf_entry *p, *q, *m; -- struct iam_leaf_entry *entries = leaf->entries; -- int count = dx_get_count((struct iam_entry *)entries); -- -- p = iam_leaf_entry_shift(path, entries, 1); -- q = iam_leaf_entry_shift(path, entries, count - 1); -- while (p <= q) { -- m = iam_leaf_entry_shift(path, -- p, iam_leaf_entry_diff(path, q, p) / 2); -- dxtrace(printk(".")); -- if (keycmp(path->ip_container, iam_leaf_key_at(path, m), -- path->ip_key_target) > 0) -- q = iam_leaf_entry_shift(path, m, -1); -- else -- p = iam_leaf_entry_shift(path, m, +1); -- } -- leaf->at = q; -- return 0; --} -- --/*XXX what kind of lock should this entry be locked: WangDi */ --static int iam_leaf_insert(handle_t *handle, struct iam_path *path, -- struct iam_key *k, struct iam_rec *r) --{ -- struct iam_leaf leaf; -- struct iam_leaf_entry *p, *q; -- int err, count; -- -- err = iam_leaf_init(path, &leaf); -- if (err) -- goto errout; -- path_descr(path)->id_leaf.start(path->ip_container, &leaf); -- count = dx_get_count((struct iam_entry *)leaf.entries); -- if (dx_get_count((struct iam_entry *)leaf.entries) >= -- dx_get_limit((struct iam_entry *)leaf.entries)){ -- err = -ENOSPC; -- goto errout; -- } -- -- err = iam_leaf_lookup(path, &leaf, k); -- if (err) -- goto errout; -- -- /*insert the k/r to leaf entries*/ -- p = iam_leaf_entry_shift(path, leaf.at, 1); -- q = iam_leaf_entry_shift(path, leaf.entries, count - 1); -- while (q < p) { -- memcpy(iam_leaf_entry_shift(path, q, 1), q, iam_leaf_entry_size(path)); -- q = iam_leaf_entry_shift(path, q, -1); -- } -- memcpy(iam_leaf_entry_at(path, p), r, path_descr(path)->id_rec_size); -- memcpy(iam_leaf_key_at(path, p), k, path_descr(path)->id_key_size); -- -- dx_set_count((struct iam_entry*)leaf.entries, count + 1); -- err = ext3_journal_dirty_metadata(handle, leaf.bh); -- if (err) -- ext3_std_error(path->ip_container->ic_object->i_sb, err); --errout: -- iam_leaf_fini(&leaf); -- return err; --} -- --static int split_leaf_node(handle_t *handle, struct iam_path *path) --{ -- struct inode *dir = path_obj(path); -- unsigned continued = 0; -- struct buffer_head *bh2; -- u32 newblock, hash_split; -- char *data2; -- struct iam_leaf leaf; -- unsigned split; -- int err; -- -- bh2 = ext3_append (handle, dir, &newblock, &err); -- if (!(bh2)) { -- err = -ENOSPC; -- goto errout; -- } -- err = iam_leaf_init(path, &leaf); -- if (err) -- goto errout; -- -- BUFFER_TRACE(leaf.bh, "get_write_access"); -- err = ext3_journal_get_write_access(handle, leaf.bh); -- if (err) { -- journal_error: -- iam_leaf_fini(&leaf); -- brelse(bh2); -- ext3_std_error(dir->i_sb, err); -- err = -EIO; -- goto errout; -- } -- data2 = bh2->b_data; -- split = dx_get_count((struct iam_entry*)leaf.entries)/2; -- hash_split = *(__u32*)iam_leaf_key_at(path, iam_leaf_entry_shift(path, leaf.entries, split)); -- if (keycmp(path->ip_container, iam_leaf_key_at(path, iam_leaf_entry_shift(path, leaf.entries, split)), -- iam_leaf_key_at(path, iam_leaf_entry_shift(path, leaf.entries, split -1))) == 0) -- continued = 1; -- -- memcpy(iam_leaf_entry_shift(path, (struct iam_leaf_entry *)data2, 1), -- iam_leaf_entry_shift(path, leaf.entries, split), -- split * iam_leaf_entry_size(path)); -- -- /* Which block gets the new entry? */ -- dx_insert_block(path, path->ip_frame, hash_split + continued, newblock); -- err = ext3_journal_dirty_metadata (handle, bh2); -- if (err) -- goto journal_error; -- err = ext3_journal_dirty_metadata (handle, leaf.bh); -- if (err) -- goto journal_error; -- brelse (bh2); -- iam_leaf_fini(&leaf); --errout: -- return err; --} -- --static int split_index_node(handle_t *handle, struct iam_path *path); --/* -- * Insert new record @r with key @k into container @c (within context of -- * transaction @h. -- * -- * Return values: 0: success, -ve: error, including -EEXIST when record with -- * given key is already present. -- * -- * postcondition: ergo(result == 0 || result == -EEXIST, -- * iam_lookup(c, k, r2) > 0 && -- * !memcmp(r, r2, c->ic_descr->id_rec_size)); -- */ --int iam_insert(handle_t *handle, struct iam_container *c, struct iam_key *k, -- struct iam_rec *r) --{ -- struct dx_hash_info hinfo; -- struct iam_path_compat cpath; -- struct iam_path *path = &cpath.ipc_path; -- struct htree_cookie hc = { -- .hinfo = &hinfo -- }; -- int err, i; -- -- iam_path_init(path, c, &hc); -- 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); -- if (err) -- goto errout; -- -- err = iam_leaf_insert(handle, path, k, r); -- -- if (err != -ENOSPC) -- goto errout; -- -- err = split_index_node(handle, path); -- if (err) -- goto errout; -- -- err = split_leaf_node(handle, path); -- if (err) -- goto errout; -- -- err = iam_leaf_insert(handle, path, k, r); --errout: -- iam_path_fini(path); -- return(err); --} -- --EXPORT_SYMBOL(iam_insert); --static int iam_leaf_delete(handle_t *handle, struct iam_path *path, -- struct iam_key *k) --{ -- struct iam_leaf leaf; -- struct iam_leaf_entry *p, *q; -- int err, count; -- -- err = iam_leaf_init(path, &leaf); -- if (err) -- goto errout; -- -- err = iam_leaf_lookup(path, &leaf, k); -- if (err) -- goto errout; -- -- count = dx_get_count((struct iam_entry*)leaf.entries); -- /*delete the k to leaf entries*/ -- p = iam_leaf_entry_shift(path, leaf.at, 1); -- q = iam_leaf_entry_shift(path, leaf.entries, count - 1); -- while (p < q) { -- memcpy(p, iam_leaf_entry_shift(path, p, 1), iam_leaf_entry_size(path)); -- p = iam_leaf_entry_shift(path, p, 1); -- } -- dx_set_count((struct iam_entry*)leaf.entries, count - 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; --} -- --/* -- * Delete existing record with key @k. -- * -- * Return values: 0: success, -ENOENT: not-found, -ve: other error. -- * -- * postcondition: ergo(result == 0 || result == -ENOENT, -- * !iam_lookup(c, k, *)); -- */ --int iam_delete(handle_t *h, struct iam_container *c, struct iam_key *k) --{ -- struct dx_hash_info hinfo; -- struct iam_path_compat cpath; -- struct iam_path *path = &cpath.ipc_path; -- struct htree_cookie hc = { -- .hinfo = &hinfo -- }; -- int err, i; -- -- iam_path_init(path, c, &hc); -- 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); -- if (err) -- goto errout; -- -- err = iam_leaf_delete(h, path, k); --errout: -- iam_path_fini(path); -- return err; --} -- --EXPORT_SYMBOL(iam_delete); -- --static int iam_leaf_update(handle_t *handle, struct iam_path *path, -- struct iam_key *k, struct iam_rec *r) --{ -- struct iam_leaf leaf; -- int err; -- -- err = iam_leaf_init(path, &leaf); -- if (err) -- goto errout; -- -- err = iam_leaf_lookup(path, &leaf, k); -- if (err) -- goto errout; -- -- 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); -- -- 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; --} --/* -- * Replace existing record with key @k, or insert new one. New record data are -- * in @r. -- * -- * Return values: 0: success, -ve: error. -- * -- * postcondition: ergo(result == 0, iam_lookup(c, k, r2) > 0 && -- * !memcmp(r, r2, c->ic_descr->id_rec_size)); -- */ --int iam_update(handle_t *h, struct iam_container *c, -- struct iam_key *k, struct iam_rec *r) --{ -- struct dx_hash_info hinfo; -- struct iam_path_compat cpath; -- struct iam_path *path = &cpath.ipc_path; -- struct htree_cookie hc = { -- .hinfo = &hinfo -- }; -- int err, i; -- -- iam_path_init(path, c, &hc); -- 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); -- if (err) -- goto errout; -- -- err = iam_leaf_update(h, path, k, r); --errout: -- iam_path_fini(path); -- 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,8 +564,8 @@ - * If start_hash is non-null, it will be filled in with the starting - * hash of the next page. - */ --static int ext3_htree_next_block(struct inode *dir, __u32 hash, -- struct iam_path *path, __u32 *start_hash) -+int ext3_htree_next_block(struct inode *dir, __u32 hash, -+ struct iam_path *path, __u32 *start_hash) - { - struct iam_frame *p; - struct buffer_head *bh; -@@ -1445,7 +600,7 @@ - * desired contiuation hash. If it doesn't, return since - * there's no point to read in the successive index pages. - */ -- dx_get_key(path, p->at, (struct iam_key *)&bhash); -+ iam_get_key(path, p->at, (struct iam_key *)&bhash); - if (start_hash) - *start_hash = bhash; - if ((hash & 1) == 0) { -@@ -1457,9 +612,10 @@ - * block so no check is necessary - */ - while (num_frames--) { -- err = path_descr(path)->id_node_read(path->ip_container, -- (iam_ptr_t)dx_get_block(path, p->at), -- NULL, &bh); -+ err = iam_path_descr(path)->id_ops-> -+ id_node_read(path->ip_container, -+ (iam_ptr_t)dx_get_block(path, p->at), -+ NULL, &bh); - if (err != 0) - return err; /* Failure */ - ++p; -@@ -1662,8 +818,8 @@ - } while(more); - } - --static void dx_insert_block(struct iam_path *path, -- struct iam_frame *frame, u32 hash, u32 block) -+void dx_insert_block(struct iam_path *path, struct iam_frame *frame, -+ u32 hash, u32 block) - { - struct iam_entry *entries = frame->entries; - struct iam_entry *old = frame->at, *new = iam_entry_shift(path, old, +1); -@@ -1897,14 +1053,15 @@ - if (*err != 0) - return NULL; - } else { -- path->ip_frame->bh = NULL; /* for iam_path_fini() */ -+ path->ip_frame->bh = NULL; /* for iam_path_fini() */ - path->ip_frame->at = (void *)&dummy_dot;/* hack for zero entry*/ - } - hash = hinfo.hash; - do { - block = dx_get_block(path, path->ip_frame->at); -- *err = path_descr(path)->id_node_read(path->ip_container, (iam_ptr_t)block, -- NULL, &bh); -+ *err = iam_path_descr(path)->id_ops->id_node_read(path->ip_container, -+ (iam_ptr_t)block, -+ NULL, &bh); - if (*err != 0) - goto errout; - de = (struct ext3_dir_entry_2 *) bh->b_data; -@@ -2067,7 +1224,7 @@ - struct buffer_head **bh,struct iam_frame *frame, - struct dx_hash_info *hinfo, int *error) - { -- struct inode *dir = path_obj(path); -+ struct inode *dir = iam_path_obj(path); - unsigned blocksize = dir->i_sb->s_blocksize; - unsigned count, continued; - struct buffer_head *bh2; -@@ -2392,15 +1549,15 @@ - } - - #ifdef CONFIG_EXT3_INDEX --static int split_index_node(handle_t *handle, struct iam_path *path) --{ -+int split_index_node(handle_t *handle, struct iam_path *path) -+{ - - struct iam_entry *entries; /* old block contents */ - struct iam_entry *entries2; /* new block contents */ - struct iam_frame *frame, *safe; - struct buffer_head *bh_new[DX_MAX_TREE_HEIGHT] = {0}; - u32 newblock[DX_MAX_TREE_HEIGHT] = {0}; -- struct inode *dir = path_obj(path); -+ struct inode *dir = iam_path_obj(path); - int nr_splet; - int i, err; - -@@ -2442,7 +1599,8 @@ - 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] || -- path_descr(path)->id_node_init(path->ip_container, bh_new[i], 0) != 0) -+ iam_path_descr(path)->id_ops->id_node_init(path->ip_container, -+ bh_new[i], 0) != 0) - goto cleanup; - BUFFER_TRACE(frame->bh, "get_write_access"); - err = ext3_journal_get_write_access(handle, frame->bh); -@@ -2516,9 +1674,9 @@ - unsigned count1 = count/2, count2 = count - count1; - unsigned hash2; - -- dx_get_key(path, -- iam_entry_shift(path, entries, count1), -- (struct iam_key *)&hash2); -+ iam_get_key(path, -+ iam_entry_shift(path, entries, count1), -+ (struct iam_key *)&hash2); - - dxtrace(printk("Split index %i/%i\n", count1, count2)); - -@@ -2578,7 +1736,7 @@ - size_t isize; - - iam_path_compat_init(&cpath, dir); -- param = path_descr(path); -+ param = iam_path_descr(path); - - err = dx_probe(dentry, NULL, &hinfo, path); - if (err != 0) -@@ -2588,8 +1746,9 @@ - /* XXX nikita: global serialization! */ - isize = dir->i_size; - -- err = param->id_node_read(path->ip_container, (iam_ptr_t)dx_get_block(path, frame->at), -- handle, &bh); -+ err = param->id_ops->id_node_read(path->ip_container, -+ (iam_ptr_t)dx_get_block(path, frame->at), -+ handle, &bh); - if (err != 0) - goto cleanup; - -@@ -2724,12 +1883,12 @@ - * is so far negative - it has no inode. - * - * If the create succeeds, we fill in the inode information -- * with d_instantiate(). -+ * with d_instantiate(). - */ - static int ext3_create (struct inode * dir, struct dentry * dentry, int mode, - struct nameidata *nd) - { -- handle_t *handle; -+ handle_t *handle; - struct inode * inode; - int err, retries = 0; - -Index: linux-2.6.9/fs/ext3/iam.c + ext3-$(CONFIG_EXT3_FS_XATTR) += xattr.o xattr_user.o xattr_trusted.o + ext3-$(CONFIG_EXT3_FS_POSIX_ACL) += acl.o +Index: iam/fs/ext3/iam.c =================================================================== ---- linux-2.6.9.orig/fs/ext3/iam.c 2006-05-26 18:25:26.573741592 +0800 -+++ linux-2.6.9/fs/ext3/iam.c 2006-05-26 17:08:48.000000000 +0800 -@@ -0,0 +1,1205 @@ +--- iam.orig/fs/ext3/iam.c 2004-04-06 17:27:52.000000000 +0400 ++++ iam/fs/ext3/iam.c 2006-05-27 21:32:20.000000000 +0400 +@@ -0,0 +1,957 @@ +/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- + * vim:expandtab:shiftwidth=8:tabstop=8: + * + * iam.c -+ * Top-level entry points into osd module ++ * Top-level entry points into iam module + * + * Copyright (c) 2006 Cluster File Systems, Inc. + * Author: Wang Di @@ -1492,1114 +130,2557 @@ Index: linux-2.6.9/fs/ext3/iam.c +#include "iopen.h" +#include "acl.h" + -+static int iam_leaf_at_end(struct iam_container *c, struct iam_leaf *l); -+static void iam_leaf_next(struct iam_container *c, struct iam_leaf *folio); + -+static inline int iam_lfix_entry_size(struct iam_container *c) ++static __u32 iam_root_ptr(struct iam_container *c) +{ -+ return iam_container_descr(c)->id_key_size + -+ iam_container_descr(c)->id_rec_size; ++ return 0; +} + -+static inline struct iam_lentry * -+iam_lentry_shift(struct iam_container *c, struct iam_lentry *entry, int shift) ++static int iam_node_init(struct iam_container *c, struct buffer_head *bh, ++ int root) +{ -+ void *e = entry; -+ return e + shift * iam_lfix_entry_size(c); ++ return 0; +} + -+static inline struct iam_key * -+iam_leaf_key_at(struct iam_container *c, struct iam_lentry *entry) ++static int iam_node_check(struct iam_path *path, struct iam_frame *frame) +{ -+ void *e = entry; -+ return e; ++ struct iam_entry *entries; ++ void *data; ++ entries = dx_node_get_entries(path, frame); ++ ++ data = frame->bh->b_data; ++ ++ if (frame == path->ip_frames) { ++ struct iam_root *root; ++ ++ root = data; ++ path->ip_indirect = root->info.indirect_levels; ++ } ++ frame->entries = frame->at = entries; ++ return 0; +} + -+static struct iam_lentry * -+iam_get_lentries(struct iam_container *c, void *data) ++static int iam_node_create(struct iam_container *c) +{ -+ return data + iam_container_descr(c)->id_node_gap; ++ return 0; +} + -+static int lentry_count_get (struct iam_leaf *leaf) ++struct iam_operations generic_iam_ops = { ++ .id_root_ptr = iam_root_ptr, ++ .id_node_read = iam_node_read, ++ .id_node_init = iam_node_init, ++ .id_node_check = iam_node_check, ++ .id_create = iam_node_create, ++}; ++EXPORT_SYMBOL(generic_iam_ops); ++ ++static inline void iam_reccpy(struct iam_path *p, struct iam_rec *rec_dst, ++ struct iam_rec *rec_src) +{ -+ struct iam_lentry *lentry = leaf->il_entries; -+ return le16_to_cpu(((struct iam_leaf_head *)lentry)->ill_count); ++ memcpy(rec_dst, rec_src, iam_path_descr(p)->id_rec_size); +} + -+static void lentry_count_set (struct iam_leaf *leaf, unsigned count) ++/* ++ * Initialize container @c, acquires additional reference on @inode. ++ */ ++int iam_container_init(struct iam_container *c, ++ struct iam_descr *descr, struct inode *inode) +{ -+ struct iam_lentry *lentry = leaf->il_entries; -+ ((struct iam_leaf_head *)lentry)->ill_count = cpu_to_le16(count); ++ memset(c, 0, sizeof *c); ++ c->ic_descr = descr; ++ c->ic_object = igrab(inode); ++ if (c->ic_object != NULL) ++ return 0; ++ else ++ return -ENOENT; +} ++EXPORT_SYMBOL(iam_container_init); + +/* -+ * Helper function returning scratch key. ++ * Finalize container @c, release all resources. + */ -+static struct iam_key *it_scratch_key(struct iam_iterator *it, int n) ++void iam_container_fini(struct iam_container *c) +{ -+ return iam_path_key(&it->ii_path, n); ++ if (c->ic_object != NULL) { ++ iput(c->ic_object); ++ c->ic_object = NULL; ++ } +} ++EXPORT_SYMBOL(iam_container_fini); + -+static struct iam_container *iam_it_container(struct iam_iterator *it) ++void iam_path_init(struct iam_path *path, struct iam_container *c, ++ struct iam_path_descr *pd) +{ -+ return it->ii_path.ip_container; ++ memset(path, 0, sizeof *path); ++ path->ip_container = c; ++ path->ip_frame = path->ip_frames; ++ path->ip_data = pd; +} + -+static inline int it_keycmp(struct iam_iterator *it, -+ struct iam_key *k1, struct iam_key *k2) ++static void iam_leaf_fini(struct iam_leaf *leaf); ++ ++void iam_path_fini(struct iam_path *path) +{ -+ return iam_keycmp(iam_it_container(it), k1, k2); ++ int i; ++ ++ iam_leaf_fini(&path->ip_leaf); ++ for (i = 0; i < ARRAY_SIZE(path->ip_frames); i++) { ++ if (path->ip_frames[i].bh != NULL) { ++ brelse(path->ip_frames[i].bh); ++ path->ip_frames[i].bh = NULL; ++ } ++ } +} + -+/*This func is for flat key, for those keys, -+ *which are not stored explicitly -+ *it would be decrypt in the key buffer -+ */ -+struct iam_key* -+iam_generic_leaf_flat_key(struct iam_container *c, struct iam_leaf *l, -+ struct iam_key *key) ++extern struct iam_descr htree_compat_param; ++ ++void iam_path_compat_init(struct iam_path_compat *path, struct inode *inode) +{ -+ void *ie = l->il_at; -+ return (struct iam_key*)ie; ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(path->ipc_scratch); ++i) ++ 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_path_init(&path->ipc_path, &path->ipc_container, &path->ipc_descr); +} + -+static void -+iam_generic_leaf_start(struct iam_container *c, struct iam_leaf *l) ++void iam_path_compat_fini(struct iam_path_compat *path) +{ -+ l->il_at = iam_get_lentries(c, l->il_bh->b_data); ++ iam_path_fini(&path->ipc_path); ++ iam_container_fini(&path->ipc_container); +} + -+static inline ptrdiff_t iam_lfix_diff(struct iam_path *p, struct iam_lentry *e1, -+ struct iam_lentry *e2) -+{ -+ ptrdiff_t diff; ++/* ++ * Leaf helpers. ++ */ + -+ diff = (void *)e1 - (void *)e2; -+ assert(diff / iam_lfix_entry_size(p->ip_container) * -+ iam_lfix_entry_size(p->ip_container) == diff); -+ return diff / iam_lfix_entry_size(p->ip_container); ++struct iam_path *iam_leaf_path(const struct iam_leaf *leaf) ++{ ++ return leaf->il_path; +} + -+int iam_lfix_init(struct iam_container *c, struct iam_leaf *l) ++struct iam_container *iam_leaf_container(const struct iam_leaf *leaf) +{ -+ struct iam_leaf_head *ill; ++ return iam_leaf_path(leaf)->ip_container; ++} + -+ assert(l->il_bh != NULL); ++struct iam_descr *iam_leaf_descr(const struct iam_leaf *leaf) ++{ ++ return iam_leaf_container(leaf)->ic_descr; ++} + -+ ill = (struct iam_leaf_head*)l->il_bh->b_data; -+ assert(ill->ill_magic == IAM_LEAF_HEADER_MAGIC); -+ -+ l->il_at = l->il_entries = iam_get_lentries(c, l->il_bh->b_data); -+ return 0; ++struct iam_leaf_operations *iam_leaf_ops(const struct iam_leaf *leaf) ++{ ++ return iam_leaf_descr(leaf)->id_leaf_ops; +} + -+void iam_lfix_fini(struct iam_container *c, struct iam_leaf *l) ++/* ++ * Return pointer to current leaf record. Pointer is valid while corresponding ++ * leaf node is locked and pinned. ++ */ ++struct iam_rec *iam_leaf_rec(struct iam_leaf *leaf) +{ -+ l->il_entries = l->il_at = NULL; -+ return; ++ return iam_leaf_ops(leaf)->rec(leaf); +} + -+static struct iam_lentry * -+iam_lfix_get_end(struct iam_container *c, struct iam_leaf *l) ++/* ++ * Return pointer to the current leaf key. This function may return either ++ * pointer to the key stored in node, or copy key into @key buffer supplied by ++ * caller and return pointer to this buffer. The latter approach is used when ++ * keys in nodes are not stored in plain form (e.g., htree doesn't store keys ++ * at all). ++ * ++ * Caller should assume that returned pointer is only valid while leaf node is ++ * pinned and locked. ++ */ ++struct iam_key *iam_leaf_key(struct iam_leaf *leaf, struct iam_key *key) +{ -+ int count = lentry_count_get(l); -+ struct iam_lentry *ile = iam_lentry_shift(c, l->il_entries, count); -+ -+ return ile; ++ return iam_leaf_ops(leaf)->key(leaf, key); +} + -+struct iam_rec* -+iam_lfix_rec(struct iam_container *c, struct iam_leaf *l) ++static int iam_leaf_load(struct iam_path *path) +{ -+ void *e = l->il_at; -+ return e + iam_container_descr(c)->id_key_size; ++ int block; ++ int err; ++ struct iam_container *c; ++ struct buffer_head *bh; ++ struct iam_leaf *leaf; ++ struct iam_descr *descr; ++ ++ c = path->ip_container; ++ leaf = &path->ip_leaf; ++ descr = iam_path_descr(path); ++ block = dx_get_block(path, path->ip_frame->at); ++ err = descr->id_ops->id_node_read(c, block, NULL, &bh); ++ if (err == 0) { ++ leaf->il_bh = bh; ++ leaf->il_path = path; ++ err = iam_leaf_ops(leaf)->init(leaf); ++ } ++ return err; +} + -+static void -+iam_lfix_next(struct iam_container *c, struct iam_leaf *l) ++static void iam_leaf_fini(struct iam_leaf *leaf) +{ -+ assert(!iam_leaf_at_end(c, l)); -+ l->il_at = iam_lentry_shift(c, l->il_at, 1); ++ iam_leaf_ops(leaf)->fini(leaf); ++ if (leaf->il_bh) { ++ brelse(leaf->il_bh); ++ leaf->il_bh = NULL; ++ } +} + -+static int -+iam_lfix_lookup(struct iam_container *c, struct iam_path *path, -+ struct iam_leaf *l, struct iam_key *k) ++static void iam_leaf_start(struct iam_leaf *folio) +{ -+ struct iam_lentry *p, *q, *m; -+ int count; ++ iam_leaf_ops(folio)->start(folio); ++} + -+ count = lentry_count_get(l); ++void iam_leaf_next(struct iam_leaf *folio) ++{ ++ iam_leaf_ops(folio)->next(folio); ++} + -+ p = iam_lentry_shift(c, l->il_entries, 1); -+ q = iam_lentry_shift(c, l->il_entries, count - 1); ++static void iam_rec_add(struct iam_leaf *leaf, struct iam_key *key, ++ struct iam_rec *rec) ++{ ++ iam_leaf_ops(leaf)->rec_add(leaf, key, rec); ++} + -+ while (p <= q) { -+ m = iam_lentry_shift(c, p, iam_lfix_diff(path, q, p) / 2); -+ if (iam_keycmp(c, iam_leaf_key_at(c, m), k) > 0) -+ q = iam_lentry_shift(c, m, -1); -+ else -+ p = iam_lentry_shift(c, m, +1); -+ } -+ l->il_at = iam_lentry_shift(c, p, -1); -+ iam_keycpy(c, iam_path_key(path, 0), iam_leaf_key_at(c, q)); -+ -+ if (l->il_at == l->il_entries || -+ iam_keycmp(c, iam_leaf_key_at(c, q), k) != 0) -+ return -ENOENT; -+ -+ return 0; ++static void iam_rec_del(struct iam_leaf *leaf) ++{ ++ iam_leaf_ops(leaf)->rec_del(leaf); +} + -+static void iam_lfix_rec_add (struct iam_path *path, -+ struct iam_key *k, struct iam_rec *r) ++int iam_leaf_at_end(const struct iam_leaf *leaf) +{ -+ struct iam_lentry *end, *next, *cur, *nnext; -+ ptrdiff_t diff; -+ int count; ++ return iam_leaf_ops(leaf)->at_end(leaf); ++} + -+ count = lentry_count_get(&path->ip_leaf); -+ end = iam_lfix_get_end(path->ip_container, &path->ip_leaf); -+ cur = path->ip_leaf.il_at; -+ if (cur != end) { -+ next = iam_lentry_shift(path->ip_container, cur, 1); -+ if (next != end) { -+ nnext = iam_lentry_shift(path->ip_container, next, 1); -+ diff = (void *)end - (void *)next; -+ memmove(nnext, next, diff); -+ } -+ iam_lfix_next(path->ip_container, &path->ip_leaf); -+ } -+ lentry_count_set(&path->ip_leaf, count + 1); ++int iam_leaf_split(handle_t *handle, struct iam_leaf *l) ++{ ++ return iam_leaf_ops(l)->split(handle, l); +} + -+static void iam_lfix_rec_del(struct iam_path *path) ++static int iam_leaf_can_add(struct iam_leaf *l, ++ struct iam_key *k, struct iam_rec *r) +{ -+ struct iam_lentry *next, *end; -+ int count; -+ ptrdiff_t diff; ++ return iam_leaf_ops(l)->can_add(l, k, r); ++} + -+ count = lentry_count_get(&path->ip_leaf); -+ end = iam_lfix_get_end(path->ip_container, &path->ip_leaf); -+ next = iam_lentry_shift(path->ip_container, path->ip_leaf.il_at, 1); -+ diff = (void *)end - (void *)next; -+ memmove(path->ip_leaf.il_at, next, diff); ++/***********************************************************************/ ++/* iterator interface */ ++/***********************************************************************/ + -+ lentry_count_set(&path->ip_leaf, count - 1); ++static enum iam_it_state it_state(const struct iam_iterator *it) ++{ ++ return it->ii_state; +} + -+static int iam_lfix_can_add (struct iam_container *c, struct iam_leaf *l, -+ struct iam_key *k, struct iam_rec *r) ++/* ++ * Helper function returning scratch key. ++ */ ++static struct iam_key *it_scratch_key(struct iam_iterator *it, int n) +{ -+ struct iam_lentry *end; -+ int block_size = c->ic_object->i_sb->s_blocksize; -+ unsigned long left, entry_size; ++ return iam_path_key(&it->ii_path, n); ++} ++ ++static struct iam_container *iam_it_container(const struct iam_iterator *it) ++{ ++ return it->ii_path.ip_container; ++} + -+ end = iam_lfix_get_end(c, l); ++static inline int it_keycmp(const struct iam_iterator *it, ++ const struct iam_key *k1, const struct iam_key *k2) ++{ ++ return iam_keycmp(iam_it_container(it), k1, k2); ++} + -+ left = block_size - iam_container_descr(c)->id_node_gap; -+ -+ left -= (unsigned long)((void*)end - (void*)l->il_entries); ++/* ++ * Helper wrapper around iam_it_get(): returns 0 (success) only when record ++ * with exactly the same key as asked is found. ++ */ ++static int iam_it_get_exact(struct iam_iterator *it, struct iam_key *k) ++{ ++ int result; + -+ entry_size = iam_lfix_entry_size(c); -+ -+ if (left >= entry_size) -+ return 1; -+ -+ return 0; ++ result = iam_it_get(it, k); ++ if (result == 0 && ++ (it_keycmp(it, k, iam_it_key_get(it, it_scratch_key(it, 0))) != 0)) ++ /* ++ * Return -ENOENT if cursor is located above record with a key ++ * different from one specified. ++ * ++ * XXX returning -ENOENT only works if iam_it_get never ++ * returns -ENOENT as a legitimate error. ++ */ ++ result = -ENOENT; ++ return result; +} + -+static int iam_lfix_at_end(struct iam_container *c, struct iam_leaf *folio) ++void iam_container_write_lock(struct iam_container *ic) +{ -+ struct iam_lentry *ile = iam_lfix_get_end(c, folio); -+ -+ return (folio->il_at == ile); ++ down(&ic->ic_object->i_sem); +} + -+struct iam_leaf_operations lfix_leaf_ops = { -+ .init = iam_lfix_init, -+ .fini = iam_lfix_fini, -+ .start = iam_generic_leaf_start, -+ .next = iam_lfix_next, -+ .key = iam_generic_leaf_flat_key, -+ .rec = iam_lfix_rec, -+ .lookup = iam_lfix_lookup, -+ .at_end = iam_lfix_at_end, -+ .rec_add = iam_lfix_rec_add, -+ .rec_del = iam_lfix_rec_del, -+ .can_add = iam_lfix_can_add -+}; -+EXPORT_SYMBOL(lfix_leaf_ops); -+ -+static __u32 iam_root_ptr(struct iam_container *c) ++void iam_container_write_unlock(struct iam_container *ic) +{ -+ return 0; ++ up(&ic->ic_object->i_sem); +} + -+static int iam_node_init(struct iam_container *c, struct buffer_head *bh, -+ int root) ++void iam_container_read_lock(struct iam_container *ic) +{ -+ return 0; ++ down(&ic->ic_object->i_sem); +} + -+static int iam_node_check(struct iam_path *path, struct iam_frame *frame) ++void iam_container_read_unlock(struct iam_container *ic) +{ -+ struct iam_entry *entries; -+ void *data; -+ entries = dx_node_get_entries(path, frame); -+ -+ data = frame->bh->b_data; -+ -+ if (frame == path->ip_frames) { -+ struct iam_root *root; -+ -+ root = data; -+ path->ip_indirect = root->info.indirect_levels; -+ } -+ frame->entries = frame->at = entries; -+ return 0; ++ up(&ic->ic_object->i_sem); +} + -+static int iam_node_create(struct iam_container *c) ++static void iam_it_lock(struct iam_iterator *it) +{ -+ return 0; ++ if (it->ii_flags&IAM_IT_WRITE) ++ iam_container_write_lock(iam_it_container(it)); ++ else ++ iam_container_read_lock(iam_it_container(it)); +} + -+struct iam_operations generic_iam_ops = { -+ .id_root_ptr = iam_root_ptr, -+ .id_node_read = iam_node_read, -+ .id_node_init = iam_node_init, -+ .id_node_check = iam_node_check, -+ .id_create = iam_node_create, -+}; -+EXPORT_SYMBOL(generic_iam_ops); -+ -+static inline void iam_reccpy(struct iam_path *p, struct iam_rec *rec_dst, -+ struct iam_rec *rec_src) ++static void iam_it_unlock(struct iam_iterator *it) +{ -+ memcpy(rec_dst, rec_src, iam_path_descr(p)->id_rec_size); ++ if (it->ii_flags&IAM_IT_WRITE) ++ iam_container_write_unlock(iam_it_container(it)); ++ else ++ iam_container_read_unlock(iam_it_container(it)); +} + +/* -+ * Return pointer to current leaf record. Pointer is valid while corresponding -+ * leaf node is locked and pinned. ++ * Initialize iterator to IAM_IT_DETACHED state. ++ * ++ * postcondition: it_state(it) == IAM_IT_DETACHED + */ -+struct iam_rec *iam_leaf_rec(struct iam_container *c, struct iam_leaf *leaf) ++int iam_it_init(struct iam_iterator *it, struct iam_container *c, __u32 flags, ++ struct iam_path_descr *pd) +{ -+ return c->ic_descr->id_leaf_ops->rec(c, leaf); ++ memset(it, 0, sizeof *it); ++ it->ii_flags = flags; ++ it->ii_state = IAM_IT_DETACHED; ++ iam_path_init(&it->ii_path, c, pd); ++ return 0; +} + +/* -+ * Return pointer to the current leaf key. This function may return either -+ * pointer to the key stored in node, or copy key into @key buffer supplied by -+ * caller and return pointer to this buffer. The latter approach is used when -+ * keys in nodes are not stored in plain form (e.g., htree doesn't store keys -+ * at all). ++ * Finalize iterator and release all resources. + * -+ * Caller should assume that returned pointer is only valid while leaf node is -+ * pinned and locked. ++ * precondition: it_state(it) == IAM_IT_DETACHED + */ -+struct iam_key *iam_leaf_key(struct iam_container *c, struct iam_leaf *leaf, -+ struct iam_key *key) ++void iam_it_fini(struct iam_iterator *it) +{ -+ return c->ic_descr->id_leaf_ops->key(c, leaf, key); ++ assert(it_state(it) == IAM_IT_DETACHED); ++ iam_path_fini(&it->ii_path); +} + -+/* -+ * Initialize container @c, acquires additional reference on @inode. -+ */ -+int iam_container_init(struct iam_container *c, -+ struct iam_descr *descr, struct inode *inode) ++int iam_path_lookup(struct iam_path *path) +{ -+ memset(c, 0, sizeof *c); -+ c->ic_descr = descr; -+ c->ic_object = igrab(inode); -+ if (c->ic_object != NULL) -+ return 0; -+ else -+ return -ENOENT; ++ struct iam_container *c; ++ struct iam_descr *descr; ++ struct iam_leaf *leaf; ++ int result; ++ ++ c = path->ip_container; ++ leaf = &path->ip_leaf; ++ descr = iam_path_descr(path); ++ result = dx_lookup(path); ++ if (result == 0) { ++ result = iam_leaf_load(path); ++ if (result == 0) ++ result = iam_leaf_ops(leaf)->lookup(leaf, ++ path->ip_key_target); ++ } ++ return result; +} -+EXPORT_SYMBOL(iam_container_init); + +/* -+ * Finalize container @c, release all resources. ++ * Attach iterator. After successful completion, @it points to record with ++ * smallest key not larger than @k. ++ * ++ * Return value: 0: positioned on existing record, ++ * -ve: error. ++ * ++ * precondition: it_state(it) == IAM_IT_DETACHED ++ * postcondition: ergo(result == 0, ++ * (it_state(it) == IAM_IT_ATTACHED && ++ * it_keycmp(it, iam_it_key_get(it, *), k) < 0)) + */ -+void iam_container_fini(struct iam_container *c) ++int iam_it_get(struct iam_iterator *it, struct iam_key *k) +{ -+ if (c->ic_object != NULL) { -+ iput(c->ic_object); -+ c->ic_object = NULL; -+ } -+} -+EXPORT_SYMBOL(iam_container_fini); ++ int result; ++ assert(it_state(it) == IAM_IT_DETACHED); + -+void iam_path_init(struct iam_path *path, struct iam_container *c, -+ struct iam_path_descr *pd) -+{ -+ memset(path, 0, sizeof *path); -+ path->ip_container = c; -+ path->ip_frame = path->ip_frames; -+ path->ip_data = pd; ++ it->ii_path.ip_key_target = k; ++ iam_it_lock(it); ++ result = iam_path_lookup(&it->ii_path); ++ if (result == 0 || result == -ENOENT) ++ it->ii_state = IAM_IT_ATTACHED; ++ else ++ iam_it_unlock(it); ++ assert(ergo(result == 0, ++ it_keycmp(it, ++ iam_it_key_get(it, it_scratch_key(it, 0)), ++ k) <= 0)); ++ return result; +} + -+static void iam_leaf_fini(struct iam_path *path); -+void iam_path_fini(struct iam_path *path) ++/* ++ * Duplicates iterator. ++ * ++ * postcondition: it_state(dst) == it_state(src) && ++ * iam_it_container(dst) == iam_it_container(src) && ++ * dst->ii_flags = src->ii_flags && ++ * ergo(it_state(src) == IAM_IT_ATTACHED, ++ * iam_it_rec_get(dst) == iam_it_rec_get(src) && ++ * iam_it_key_get(dst, *1) == iam_it_key_get(src, *2)) ++ */ ++void iam_it_dup(struct iam_iterator *dst, struct iam_iterator *src) +{ -+ int i; ++ dst->ii_flags = src->ii_flags; ++ dst->ii_state = src->ii_state; ++ /* XXX not yet. iam_path_dup(&dst->ii_path, &src->ii_path); */ ++ /* ++ * XXX: duplicate lock. ++ */ ++ assert(it_state(dst) == it_state(src)); ++ assert(iam_it_container(dst) == iam_it_container(src)); ++ assert(dst->ii_flags = src->ii_flags); ++ assert(ergo(it_state(src) == IAM_IT_ATTACHED, ++ iam_it_rec_get(dst) == iam_it_rec_get(src) && ++ iam_it_key_get(dst, it_scratch_key(dst, 0)) == ++ iam_it_key_get(src, it_scratch_key(src, 0)))); + -+ iam_leaf_fini(path); -+ for (i = 0; i < ARRAY_SIZE(path->ip_frames); i++) { -+ if (path->ip_frames[i].bh != NULL) { -+ brelse(path->ip_frames[i].bh); -+ path->ip_frames[i].bh = NULL; -+ } -+ } +} -+ -+extern struct iam_descr htree_compat_param; -+void iam_path_compat_init(struct iam_path_compat *path, struct inode *inode) ++/* ++ * Detach iterator. Does nothing it detached state. ++ * ++ * postcondition: it_state(it) == IAM_IT_DETACHED ++ */ ++void iam_it_put(struct iam_iterator *it) +{ -+ int i; -+ -+ for (i = 0; i < ARRAY_SIZE(path->ipc_scratch); ++i) -+ 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_path_init(&path->ipc_path, &path->ipc_container, &path->ipc_descr); ++ if (it->ii_state == IAM_IT_ATTACHED) { ++ it->ii_state = IAM_IT_DETACHED; ++ iam_leaf_fini(&it->ii_path.ip_leaf); ++ iam_it_unlock(it); ++ } +} + -+void iam_path_compat_fini(struct iam_path_compat *path) ++/* ++ * Move iterator one record right. ++ * ++ * Return value: 0: success, ++ * +1: end of container reached ++ * -ve: error ++ * ++ * precondition: it_state(it) == IAM_IT_ATTACHED && it->ii_flags&IAM_IT_MOVE ++ * postcondition: ergo(result == 0, it_state(it) == IAM_IT_ATTACHED) ++ */ ++int iam_it_next(struct iam_iterator *it) +{ -+ iam_path_fini(&path->ipc_path); -+ iam_container_fini(&path->ipc_container); ++ int result; ++ struct iam_container *c; ++ ++ assert(it_state(it) == IAM_IT_ATTACHED && it->ii_flags&IAM_IT_MOVE); ++ ++ c = iam_it_container(it); ++ if (iam_leaf_at_end(&it->ii_path.ip_leaf)) { ++ /* advance index portion of the path */ ++ result = 0; /* XXX not yet iam_index_next(&it->ii_path); */ ++ if (result == 0) { ++ result = 0; /* XXX not yet ++ * iam_read_leaf(&it->ii_path); */ ++ if (result == 0) ++ iam_leaf_start(&it->ii_path.ip_leaf); ++ } else if (result > 0) ++ /* end of container reached */ ++ result = +1; ++ if (result < 0) ++ iam_it_put(it); ++ } else { ++ /* advance within leaf node */ ++ iam_leaf_next(&it->ii_path.ip_leaf); ++ result = 0; ++ } ++ assert(ergo(result >= 0, it_state(it) == IAM_IT_ATTACHED)); ++ return result; +} + -+static int iam_leaf_load(struct iam_path *path) ++/* ++ * Return pointer to the record under iterator. ++ * ++ * precondition: it_state(it) == IAM_IT_ATTACHED ++ * postcondition: it_state(it) == IAM_IT_ATTACHED ++ */ ++struct iam_rec *iam_it_rec_get(struct iam_iterator *it) +{ -+ int block; -+ int err; -+ struct iam_container *c; -+ struct buffer_head *bh; -+ struct iam_leaf *leaf; -+ struct iam_descr *descr; -+ -+ c = path->ip_container; -+ leaf = &path->ip_leaf; -+ descr = iam_path_descr(path); -+ block = dx_get_block(path, path->ip_frame->at); -+ err = descr->id_ops->id_node_read(c, block, NULL, &bh); -+ if (err == 0) { -+ leaf->il_bh = bh; -+ err = descr->id_leaf_ops->init(c, leaf); -+ } -+ return err; ++ assert(it_state(it) == IAM_IT_ATTACHED); ++ return iam_leaf_rec(&it->ii_path.ip_leaf); +} + -+static void iam_leaf_fini(struct iam_path *path) ++static void iam_it_reccpy(struct iam_iterator *it, struct iam_rec *r) +{ -+ iam_path_descr(path)->id_leaf_ops->fini(path->ip_container, -+ &path->ip_leaf); -+ if (path && path->ip_leaf.il_bh) { -+ brelse(path->ip_leaf.il_bh); -+ path->ip_leaf.il_bh = NULL; -+ } ++ memcpy(iam_leaf_rec(&it->ii_path.ip_leaf), r, ++ iam_it_container(it)->ic_descr->id_rec_size); +} + -+static void iam_leaf_start(struct iam_container *c, struct iam_leaf *folio) ++static void iam_it_keycpy(struct iam_iterator *it, struct iam_key *k) +{ -+ c->ic_descr->id_leaf_ops->start(c, folio); ++ memcpy(iam_leaf_key(&it->ii_path.ip_leaf, NULL), k, ++ iam_it_container(it)->ic_descr->id_key_size); +} + -+static void iam_leaf_next(struct iam_container *c, struct iam_leaf *folio) ++ ++/* ++ * Replace contents of record under iterator. ++ * ++ * precondition: it_state(it) == IAM_IT_ATTACHED && it->ii_flags&IAM_IT_WRITE ++ * postcondition: it_state(it) == IAM_IT_ATTACHED && ++ * ergo(result == 0, !memcmp(iam_it_rec_get(it), r, ...)) ++ */ ++int iam_it_rec_set(handle_t *h, struct iam_iterator *it, struct iam_rec *r) +{ -+ c->ic_descr->id_leaf_ops->next(c, folio); ++ int result; ++ ++ assert(it_state(it) == IAM_IT_ATTACHED && it->ii_flags&IAM_IT_WRITE); ++ ++ result = ext3_journal_get_write_access(h, it->ii_path.ip_leaf.il_bh); ++ if (result == 0) ++ iam_it_reccpy(it, r); ++ return result; +} + -+static void iam_rec_add (struct iam_path *path, struct iam_key *key, -+ struct iam_rec *rec) ++/* ++ * Return pointer to the key under iterator. ++ * ++ * precondition: it_state(it) == IAM_IT_ATTACHED ++ * postcondition: it_state(it) == IAM_IT_ATTACHED ++ */ ++struct iam_key *iam_it_key_get(struct iam_iterator *it, struct iam_key *k) +{ -+ iam_path_descr(path)->id_leaf_ops->rec_add(path, key, rec); ++ assert(it_state(it) == IAM_IT_ATTACHED); ++ return iam_leaf_key(&it->ii_path.ip_leaf, k); +} + -+static void iam_rec_del (struct iam_path *path) ++static int iam_leaf_rec_add(handle_t *handle, struct iam_path *path) +{ -+ iam_path_descr(path)->id_leaf_ops->rec_del(path); ++ int err; ++ ++ err = ext3_journal_get_write_access(handle, path->ip_leaf.il_bh); ++ if (err) ++ goto journal_error; ++ iam_rec_add(&path->ip_leaf, NULL, NULL); ++ err = ext3_journal_dirty_metadata(handle, path->ip_leaf.il_bh); ++journal_error: ++ if (err) ++ ext3_std_error(iam_path_obj(path)->i_sb, err); ++ return err; +} + -+static int iam_leaf_at_end(struct iam_container *c, struct iam_leaf *l) ++int iam_add_rec(handle_t *handle, struct iam_path *path, ++ struct iam_key *k, struct iam_rec *r) +{ -+ return iam_container_descr(c)->id_leaf_ops->at_end(c, l); ++ int err; ++ ++ if (iam_leaf_can_add(&path->ip_leaf, k, r)) { ++ err = iam_leaf_rec_add(handle, path); ++ } else { ++ err = split_index_node(handle, path); ++ if (err == 0) { ++ err = iam_leaf_split(handle, &path->ip_leaf); ++ if (err == 0) ++ err = iam_leaf_rec_add(handle, path); ++ } ++ } ++ return err; +} ++ +/* -+ * Helper wrapper around iam_it_get(): returns 0 (success) only when record -+ * with exactly the same key as asked is found. ++ * Insert new record with key @k and contents from @r, shifting records to the ++ * right. ++ * ++ * precondition: it_state(it) == IAM_IT_ATTACHED && ++ * it->ii_flags&IAM_IT_WRITE && ++ * it_keycmp(it, iam_it_key_get(it, *), k) < 0 ++ * postcondition: it_state(it) == IAM_IT_ATTACHED && ++ * ergo(result == 0, ++ * it_keycmp(it, iam_it_key_get(it, *), k) == 0 && ++ * !memcmp(iam_it_rec_get(it), r, ...)) + */ -+static int iam_it_get_exact(struct iam_iterator *it, struct iam_key *k) ++int iam_it_rec_insert(handle_t *h, struct iam_iterator *it, ++ struct iam_key *k, struct iam_rec *r) +{ + int result; + -+ result = iam_it_get(it, k); -+ if (result == 0 && -+ (it_keycmp(it, k, iam_it_key_get(it, it_scratch_key(it, 0))) != 0)) ++ assert(it_state(it) == IAM_IT_ATTACHED && it->ii_flags&IAM_IT_WRITE); ++#if 0 ++ /*XXX remove this assert temporarily, since if the il_at point to the hearder, ++ * this assert might has some problems*/ ++ assert(it_keycmp(it, iam_it_key_get(it, it_scratch_key(it, 0)), k) < 0); ++#endif ++ result = iam_add_rec(h, &it->ii_path, k, r); ++ if (result == 0) { ++ /* place record and key info freed space. Leaf node is already ++ * in transaction. */ ++ iam_it_reccpy(it, r); ++ iam_it_keycpy(it, k); ++ iam_keycpy(it->ii_path.ip_container, it_scratch_key(it, 0), k); + /* -+ * Return -ENOENT if cursor is located above record with a key -+ * different from one specified. -+ * -+ * XXX returning -ENOENT only works if iam_it_get never -+ * returns -ENOENT as a legitimate error. -+ */ -+ result = -ENOENT; ++ * XXX TBD. ++ */ ++ } ++ assert(it_state(it) == IAM_IT_ATTACHED); ++ assert(ergo(result == 0, ++ it_keycmp(it, ++ iam_it_key_get(it, ++ it_scratch_key(it, 0)), k) == 0 && ++ !memcmp(iam_it_rec_get(it), r, ++ iam_it_container(it)->ic_descr->id_rec_size))); + return result; +} + -+/***********************************************************************/ -+/* iterator interface */ -+/***********************************************************************/ -+ -+static enum iam_it_state it_state(struct iam_iterator *it) ++static int iam_leaf_rec_remove(handle_t *handle, struct iam_leaf *leaf) +{ -+ return it->ii_state; -+} ++ int err; + -+void iam_container_write_lock(struct iam_container *ic) -+{ -+ down(&ic->ic_object->i_sem); ++ iam_rec_del(leaf); ++ err = ext3_journal_dirty_metadata(handle, leaf->il_bh); ++ if (err) ++ ext3_std_error(iam_path_obj(iam_leaf_path(leaf))->i_sb, err); ++ return err; +} + -+void iam_container_write_unlock(struct iam_container *ic) ++/* ++ * Delete record under iterator. ++ * ++ * precondition: it_state(it) == IAM_IT_ATTACHED && it->ii_flags&IAM_IT_WRITE ++ * postcondition: it_state(it) == IAM_IT_ATTACHED ++ */ ++int iam_it_rec_delete(handle_t *h, struct iam_iterator *it) +{ -+ up(&ic->ic_object->i_sem); ++ int result; ++ ++ assert(it_state(it) == IAM_IT_ATTACHED && it->ii_flags&IAM_IT_WRITE); ++ ++ result = ext3_journal_get_write_access(h, it->ii_path.ip_leaf.il_bh); ++ /* ++ * no compaction for now. ++ */ ++ if (result == 0) ++ iam_leaf_rec_remove(h, &it->ii_path.ip_leaf); ++ ++ return result; +} + -+void iam_container_read_lock(struct iam_container *ic) ++/* ++ * Convert iterator to cookie. ++ * ++ * precondition: it_state(it) == IAM_IT_ATTACHED && ++ * iam_path_descr(it->ii_path)->id_key_size <= sizeof(iam_pos_t) ++ * postcondition: it_state(it) == IAM_IT_ATTACHED ++ */ ++iam_pos_t iam_it_store(struct iam_iterator *it) +{ -+ down(&ic->ic_object->i_sem); ++ iam_pos_t result; ++ ++ assert(it_state(it) == IAM_IT_ATTACHED); ++ assert(iam_it_container(it)->ic_descr->id_key_size <= sizeof result); ++ ++ result = 0; ++ iam_it_key_get(it, (struct iam_key *)&result); ++ return result; +} + -+void iam_container_read_unlock(struct iam_container *ic) ++/* ++ * Restore iterator from cookie. ++ * ++ * precondition: it_state(it) == IAM_IT_DETACHED && it->ii_flags&IAM_IT_MOVE && ++ * iam_path_descr(it->ii_path)->id_key_size <= sizeof(iam_pos_t) ++ * postcondition: ergo(result == 0, it_state(it) == IAM_IT_ATTACHED && ++ * iam_it_store(it) == pos) ++ */ ++int iam_it_load(struct iam_iterator *it, iam_pos_t pos) +{ -+ up(&ic->ic_object->i_sem); ++ assert(it_state(it) == IAM_IT_DETACHED && it->ii_flags&IAM_IT_MOVE); ++ assert(iam_it_container(it)->ic_descr->id_key_size <= sizeof pos); ++ return iam_it_get(it, (struct iam_key *)&pos); +} + -+static void iam_it_lock(struct iam_iterator *it) ++/***********************************************************************/ ++/* invariants */ ++/***********************************************************************/ ++ ++static inline int ptr_inside(void *base, size_t size, void *ptr) +{ -+ if (it->ii_flags&IAM_IT_WRITE) -+ iam_container_write_lock(iam_it_container(it)); -+ else -+ iam_container_read_lock(iam_it_container(it)); ++ return (base <= ptr) && (ptr < base + size); +} + -+static void iam_it_unlock(struct iam_iterator *it) ++int iam_frame_invariant(struct iam_frame *f) +{ -+ if (it->ii_flags&IAM_IT_WRITE) -+ iam_container_write_unlock(iam_it_container(it)); -+ else -+ iam_container_read_unlock(iam_it_container(it)); ++ return ++ (f->bh != NULL && ++ f->bh->b_data != NULL && ++ ptr_inside(f->bh->b_data, f->bh->b_size, f->entries) && ++ ptr_inside(f->bh->b_data, f->bh->b_size, f->at) && ++ f->entries <= f->at); +} -+ -+/* -+ * Initialize iterator to IAM_IT_DETACHED state. -+ * -+ * postcondition: it_state(it) == IAM_IT_DETACHED -+ */ -+int iam_it_init(struct iam_iterator *it, struct iam_container *c, __u32 flags, -+ struct iam_path_descr *pd) ++int iam_leaf_invariant(struct iam_leaf *l) +{ -+ memset(it, 0, sizeof *it); -+ it->ii_flags = flags; -+ it->ii_state = IAM_IT_DETACHED; -+ iam_path_init(&it->ii_path, c, pd); -+ return 0; ++ return ++ l->il_bh != NULL && ++ l->il_bh->b_data != NULL && ++ ptr_inside(l->il_bh->b_data, l->il_bh->b_size, l->il_entries) && ++ ptr_inside(l->il_bh->b_data, l->il_bh->b_size, l->il_at) && ++ l->il_entries <= l->il_at; +} + -+/* -+ * Finalize iterator and release all resources. -+ * -+ * precondition: it_state(it) == IAM_IT_DETACHED -+ */ -+void iam_it_fini(struct iam_iterator *it) ++int iam_path_invariant(struct iam_path *p) +{ -+ assert(it_state(it) == IAM_IT_DETACHED); -+ iam_path_fini(&it->ii_path); ++ int i; ++ ++ if (p->ip_container == NULL || ++ p->ip_indirect < 0 || p->ip_indirect > DX_MAX_TREE_HEIGHT - 1 || ++ p->ip_frame != p->ip_frames + p->ip_indirect || ++ !iam_leaf_invariant(&p->ip_leaf)) ++ return 0; ++ for (i = 0; i < ARRAY_SIZE(p->ip_frames); ++i) { ++ if (i <= p->ip_indirect) { ++ if (!iam_frame_invariant(&p->ip_frames[i])) ++ return 0; ++ } ++ } ++ return 1; +} + -+int iam_path_lookup(struct iam_path *path) ++int iam_it_invariant(struct iam_iterator *it) +{ -+ struct iam_container *c; -+ struct iam_descr *descr; -+ struct iam_leaf *leaf; -+ int result; -+ -+ c = path->ip_container; -+ leaf = &path->ip_leaf; -+ descr = iam_path_descr(path); -+ result = dx_lookup(path); -+ if (result == 0) { -+ result = iam_leaf_load(path); -+ if (result == 0) -+ result = descr->id_leaf_ops->lookup(c, path, leaf, -+ path->ip_key_target); -+ } -+ return result; ++ return ++ (it->ii_state == IAM_IT_DETACHED || ++ it->ii_state == IAM_IT_ATTACHED) && ++ !(it->ii_flags & ~(IAM_IT_MOVE | IAM_IT_WRITE)) && ++ ergo(it->ii_state == IAM_IT_ATTACHED, ++ iam_path_invariant(&it->ii_path)); +} + +/* -+ * Attach iterator. After successful completion, @it points to record with -+ * smallest key not larger than @k. ++ * Search container @c for record with key @k. If record is found, its data ++ * are moved into @r. + * -+ * Return value: 0: positioned on existing record, -+ * -ve: error. + * -+ * precondition: it_state(it) == IAM_IT_DETACHED -+ * postcondition: ergo(result == 0, -+ * (it_state(it) == IAM_IT_ATTACHED && -+ * it_keycmp(it, iam_it_key_get(it, *), k) < 0)) ++ * ++ * Return values: +ve: found, 0: not-found, -ve: error + */ -+int iam_it_get(struct iam_iterator *it, struct iam_key *k) ++int iam_lookup(struct iam_container *c, struct iam_key *k, struct iam_rec *r, ++ struct iam_path_descr *pd) +{ ++ struct iam_iterator it; + int result; -+ assert(it_state(it) == IAM_IT_DETACHED); + -+ it->ii_path.ip_key_target = k; -+ iam_it_lock(it); -+ result = iam_path_lookup(&it->ii_path); -+ if (result == 0 || result == -ENOENT) -+ it->ii_state = IAM_IT_ATTACHED; -+ else -+ iam_it_unlock(it); -+ assert(ergo(result == 0, -+ it_keycmp(it, -+ iam_it_key_get(it, it_scratch_key(it, 0)), -+ k) <= 0)); ++ iam_it_init(&it, c, 0, pd); ++ ++ result = iam_it_get_exact(&it, k); ++ if (result == 0) ++ /* ++ * record with required key found, copy it into user buffer ++ */ ++ iam_reccpy(&it.ii_path, r, iam_it_rec_get(&it)); ++ iam_it_put(&it); ++ iam_it_fini(&it); + return result; +} ++EXPORT_SYMBOL(iam_lookup); + +/* -+ * Duplicates iterator. ++ * Insert new record @r with key @k into container @c (within context of ++ * transaction @h. + * -+ * postcondition: it_state(dst) == it_state(src) && -+ * iam_it_container(dst) == iam_it_container(src) && -+ * dst->ii_flags = src->ii_flags && -+ * ergo(it_state(src) == IAM_IT_ATTACHED, -+ * iam_it_rec_get(dst) == iam_it_rec_get(src) && -+ * iam_it_key_get(dst, *1) == iam_it_key_get(src, *2)) ++ * Return values: 0: success, -ve: error, including -EEXIST when record with ++ * given key is already present. ++ * ++ * postcondition: ergo(result == 0 || result == -EEXIST, ++ * iam_lookup(c, k, r2) > 0 && ++ * !memcmp(r, r2, c->ic_descr->id_rec_size)); + */ -+void iam_it_dup(struct iam_iterator *dst, struct iam_iterator *src) ++int iam_insert(handle_t *h, struct iam_container *c, ++ struct iam_key *k, struct iam_rec *r, struct iam_path_descr *pd) +{ -+ dst->ii_flags = src->ii_flags; -+ dst->ii_state = src->ii_state; -+ /* XXX not yet. iam_path_dup(&dst->ii_path, &src->ii_path); */ -+ /* -+ * XXX: duplicate lock. -+ */ -+ assert(it_state(dst) == it_state(src)); -+ assert(iam_it_container(dst) == iam_it_container(src)); -+ assert(dst->ii_flags = src->ii_flags); -+ assert(ergo(it_state(src) == IAM_IT_ATTACHED, -+ iam_it_rec_get(dst) == iam_it_rec_get(src) && -+ iam_it_key_get(dst, it_scratch_key(dst, 0)) == -+ iam_it_key_get(src, it_scratch_key(src, 0)))); ++ struct iam_iterator it; ++ int result; ++ ++ iam_it_init(&it, c, IAM_IT_WRITE, pd); + ++ result = iam_it_get_exact(&it, k); ++ if (result == -ENOENT) ++ result = iam_it_rec_insert(h, &it, k, r); ++ else if (result == 0) ++ result = -EEXIST; ++ iam_it_put(&it); ++ iam_it_fini(&it); ++ return result; +} -+/* -+ * Detach iterator. Does nothing it detached state. -+ * -+ * postcondition: it_state(it) == IAM_IT_DETACHED -+ */ -+void iam_it_put(struct iam_iterator *it) ++EXPORT_SYMBOL(iam_insert); ++ ++int iam_update(handle_t *h, struct iam_container *c, ++ struct iam_key *k, struct iam_rec *r, struct iam_path_descr *pd) +{ -+ if (it->ii_state == IAM_IT_ATTACHED) { -+ it->ii_state = IAM_IT_DETACHED; -+ iam_leaf_fini(&it->ii_path); -+ iam_it_unlock(it); -+ } ++ struct iam_iterator it; ++ int result; ++ ++ iam_it_init(&it, c, IAM_IT_WRITE, pd); ++ ++ result = iam_it_get_exact(&it, k); ++ if (result == 0) ++ iam_it_rec_set(h, &it, r); ++ iam_it_put(&it); ++ iam_it_fini(&it); ++ return result; +} ++EXPORT_SYMBOL(iam_update); + +/* -+ * Move iterator one record right. ++ * Delete existing record with key @k. + * -+ * Return value: 0: success, -+ * +1: end of container reached -+ * -ve: error ++ * Return values: 0: success, -ENOENT: not-found, -ve: other error. + * -+ * precondition: it_state(it) == IAM_IT_ATTACHED && it->ii_flags&IAM_IT_MOVE -+ * postcondition: ergo(result == 0, it_state(it) == IAM_IT_ATTACHED) ++ * postcondition: ergo(result == 0 || result == -ENOENT, ++ * !iam_lookup(c, k, *)); + */ -+int iam_it_next(struct iam_iterator *it) ++int iam_delete(handle_t *h, struct iam_container *c, struct iam_key *k, ++ struct iam_path_descr *pd) +{ ++ struct iam_iterator it; + int result; -+ struct iam_container *c; + -+ assert(it_state(it) == IAM_IT_ATTACHED && it->ii_flags&IAM_IT_MOVE); ++ iam_it_init(&it, c, IAM_IT_WRITE, pd); + -+ c = iam_it_container(it); -+ if (iam_leaf_at_end(c, &it->ii_path.ip_leaf)) { -+ /* advance index portion of the path */ -+ result = 0; /* XXX not yet iam_index_next(&it->ii_path); */ -+ if (result == 0) { -+ result = 0; /* XXX not yet iam_read_leaf(&it->ii_path); */ -+ if (result == 0) -+ iam_leaf_start(c, &it->ii_path.ip_leaf); -+ } else if (result > 0) -+ /* end of container reached */ -+ result = +1; -+ if (result < 0) -+ iam_it_put(it); -+ } else { -+ /* advance within leaf node */ -+ iam_leaf_next(c, &it->ii_path.ip_leaf); -+ result = 0; -+ } -+ assert(ergo(result >= 0, it_state(it) == IAM_IT_ATTACHED)); ++ result = iam_it_get_exact(&it, k); ++ if (result == 0) ++ iam_it_rec_delete(h, &it); ++ iam_it_put(&it); ++ iam_it_fini(&it); + return result; +} ++EXPORT_SYMBOL(iam_delete); + -+/* -+ * Return pointer to the record under iterator. +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-05-27 21:26:51.000000000 +0400 +@@ -0,0 +1,313 @@ ++/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- ++ * vim:expandtab:shiftwidth=8:tabstop=8: + * -+ * precondition: it_state(it) == IAM_IT_ATTACHED -+ * postcondition: it_state(it) == IAM_IT_ATTACHED ++ * iam_lfix.c ++ * implementation of iam format for fixed size records. ++ * ++ * Copyright (c) 2006 Cluster File Systems, Inc. ++ * Author: Wang Di ++ * Author: Nikita Danilov ++ * ++ * This file is part of the Lustre file system, http://www.lustre.org ++ * Lustre is a trademark of Cluster File Systems, Inc. ++ * ++ * You may have signed or agreed to another license before downloading ++ * this software. If so, you are bound by the terms and conditions ++ * of that agreement, and the following does not apply to you. See the ++ * LICENSE file included with this distribution for more information. ++ * ++ * If you did not agree to a different license, then this copy of Lustre ++ * is open source software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * In either case, Lustre is distributed in the hope that it will be ++ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty ++ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * license text for more details. + */ -+struct iam_rec *iam_it_rec_get(struct iam_iterator *it) ++ ++#include ++#include ++ ++#include ++ ++#include ++#include ++ ++static inline int iam_lfix_entry_size(const struct iam_leaf *l) +{ -+ assert(it_state(it) == IAM_IT_ATTACHED); -+ return iam_leaf_rec(iam_it_container(it), &it->ii_path.ip_leaf); ++ return iam_leaf_descr(l)->id_key_size + iam_leaf_descr(l)->id_rec_size; +} + -+static void iam_it_reccpy(struct iam_iterator *it, struct iam_rec *r) ++static inline struct iam_lentry * ++iam_lfix_shift(const struct iam_leaf *l, struct iam_lentry *entry, int shift) +{ -+ memcpy(iam_leaf_rec(iam_it_container(it), &it->ii_path.ip_leaf), r, -+ iam_it_container(it)->ic_descr->id_rec_size); ++ void *e = entry; ++ return e + shift * iam_lfix_entry_size(l); +} + -+static void iam_it_keycpy(struct iam_iterator *it, struct iam_key *k) ++static inline const struct iam_key * ++iam_leaf_key_at(const struct iam_container *c, const struct iam_lentry *entry) +{ -+ memcpy(iam_leaf_key(iam_it_container(it), &it->ii_path.ip_leaf, NULL), k, -+ iam_it_container(it)->ic_descr->id_key_size); ++ const void *e = entry; ++ return e; +} + -+ -+/* -+ * Replace contents of record under iterator. -+ * -+ * precondition: it_state(it) == IAM_IT_ATTACHED && it->ii_flags&IAM_IT_WRITE -+ * postcondition: it_state(it) == IAM_IT_ATTACHED && -+ * ergo(result == 0, !memcmp(iam_it_rec_get(it), r, ...)) -+ */ -+int iam_it_rec_set(handle_t *h, struct iam_iterator *it, struct iam_rec *r) ++static struct iam_lentry *iam_get_lentries(const struct iam_leaf *l) +{ -+ int result; -+ -+ assert(it_state(it) == IAM_IT_ATTACHED && it->ii_flags&IAM_IT_WRITE); -+ -+ result = ext3_journal_get_write_access(h, it->ii_path.ip_leaf.il_bh); -+ if (result == 0) -+ iam_it_reccpy(it, r); -+ return result; ++ return (void *)l->il_bh->b_data + iam_leaf_descr(l)->id_node_gap; +} + -+/* -+ * Return pointer to the key under iterator. -+ * -+ * precondition: it_state(it) == IAM_IT_ATTACHED -+ * postcondition: it_state(it) == IAM_IT_ATTACHED -+ */ -+struct iam_key *iam_it_key_get(struct iam_iterator *it, struct iam_key *k) ++static int lentry_count_get(const struct iam_leaf *leaf) +{ -+ assert(it_state(it) == IAM_IT_ATTACHED); -+ return iam_leaf_key(iam_it_container(it), &it->ii_path.ip_leaf, k); ++ struct iam_lentry *lentry = leaf->il_entries; ++ return le16_to_cpu(((struct iam_leaf_head *)lentry)->ill_count); +} + -+static int iam_leaf_rec_add(handle_t *handle, struct iam_path *path) ++static void lentry_count_set(struct iam_leaf *leaf, unsigned count) +{ -+ int err; ++ struct iam_lentry *lentry = leaf->il_entries; ++ ((struct iam_leaf_head *)lentry)->ill_count = cpu_to_le16(count); ++} + -+ err = ext3_journal_get_write_access(handle, path->ip_leaf.il_bh); -+ if (err) -+ goto journal_error; -+ iam_rec_add(path, NULL, NULL); -+ err = ext3_journal_dirty_metadata(handle, path->ip_leaf.il_bh); -+journal_error: -+ if (err) -+ ext3_std_error(iam_path_obj(path)->i_sb, err); -+ return err; ++/*This func is for flat key, for those keys, ++ *which are not stored explicitly ++ *it would be decrypt in the key buffer ++ */ ++struct iam_key* ++iam_lfix_key(struct iam_leaf *l, struct iam_key *key) ++{ ++ void *ie = l->il_at; ++ return (struct iam_key*)ie; +} + -+static int iam_leaf_can_add (struct iam_container *c, struct iam_leaf *l, -+ struct iam_key *k, struct iam_rec *r) ++static void ++iam_lfix_start(struct iam_leaf *l) +{ -+ return iam_container_descr(c)->id_leaf_ops->can_add(c, l, k, r); ++ l->il_at = iam_get_lentries(l); +} + -+static int split_leaf_node(handle_t *handle, struct iam_path *path) ++static inline ptrdiff_t iam_lfix_diff(struct iam_leaf *l, struct iam_lentry *e1, ++ struct iam_lentry *e2) +{ -+#if 0 -+ struct inode *dir = iam_path_obj(path); -+ unsigned continued = 0; -+ struct buffer_head *bh2; -+ u32 newblock, hash_split; -+ char *data2; -+ unsigned split; -+ int err; ++ ptrdiff_t diff; ++ int esize; + -+ bh2 = ext3_append (handle, dir, &newblock, &err); -+ if (!(bh2)) -+ return -ENOSPC; -+ -+ err = iam_leaf_load(path); -+ if (err) -+ goto errout; ++ esize = iam_lfix_entry_size(l); ++ diff = (void *)e1 - (void *)e2; ++ assert(diff / esize * esize == diff); ++ return diff / esize; ++} + -+ BUFFER_TRACE(path->ip_leaf.il_bh, "get_write_access"); -+ err = ext3_journal_get_write_access(handle, path->ip_leaf.il_bh); -+ if (err) { -+ journal_error: -+ iam_leaf_fini(path); -+ brelse(bh2); -+ ext3_std_error(dir->i_sb, err); -+ err = -EIO; -+ goto errout; -+ } -+ data2 = bh2->b_data; -+ split = dx_get_count((struct iam_entry*)iam_leaf_entries(path))/2; -+ hash_split = *(__u32*)iam_leaf_key_at(path, -+ iam_lentry_shift(path, iam_leaf_entries(path), -+ split)); -+ if (iam_keycmp(path->ip_container, iam_leaf_key_at(path, -+ iam_lentry_shift(path, iam_leaf_entries(path), split)), -+ iam_leaf_key_at(path, -+ iam_lentry_shift(path, iam_leaf_entries(path), split -1))) == 0) -+ continued = 1; ++static int iam_lfix_init(struct iam_leaf *l) ++{ ++ struct iam_leaf_head *ill; + -+ memcpy(iam_lentry_shift(path, (struct iam_lentry *)data2, 1), -+ iam_lentry_shift(path, iam_leaf_entries(path), split), -+ split * iam_lfix_entry_size(path)); ++ assert(l->il_bh != NULL); + -+ /* Which block gets the new entry? */ -+ dx_insert_block(path, path->ip_frame, hash_split + continued, newblock); -+ err = ext3_journal_dirty_metadata (handle, bh2); -+ if (err) -+ goto journal_error; -+ err = ext3_journal_dirty_metadata (handle, path->ip_leaf.il_bh); -+ if (err) -+ goto journal_error; -+errout: -+ brelse (bh2); -+ return err; -+#endif ++ ill = (struct iam_leaf_head*)l->il_bh->b_data; ++ assert(ill->ill_magic == IAM_LEAF_HEADER_MAGIC); ++ ++ l->il_at = l->il_entries = iam_get_lentries(l); + return 0; +} + -+int iam_add_rec(handle_t *handle, struct iam_path *path, -+ struct iam_key *k, struct iam_rec *r) ++static void iam_lfix_fini(struct iam_leaf *l) +{ -+ int err; -+ -+ if (iam_leaf_can_add(path->ip_container, &path->ip_leaf, k, r)) { -+ err = iam_leaf_rec_add(handle, path); -+ } else { -+ err = split_index_node(handle, path); -+ if (err == 0) { -+ err = split_leaf_node(handle, path); -+ if (err == 0) -+ err = iam_leaf_rec_add(handle, path); -+ } -+ } -+ return err; ++ l->il_entries = l->il_at = NULL; ++ return; +} + -+/* -+ * Insert new record with key @k and contents from @r, shifting records to the -+ * right. -+ * -+ * precondition: it_state(it) == IAM_IT_ATTACHED && -+ * it->ii_flags&IAM_IT_WRITE && -+ * it_keycmp(it, iam_it_key_get(it, *), k) < 0 -+ * postcondition: it_state(it) == IAM_IT_ATTACHED && -+ * ergo(result == 0, -+ * it_keycmp(it, iam_it_key_get(it, *), k) == 0 && -+ * !memcmp(iam_it_rec_get(it), r, ...)) -+ */ -+int iam_it_rec_insert(handle_t *h, struct iam_iterator *it, -+ struct iam_key *k, struct iam_rec *r) ++static struct iam_lentry * ++iam_lfix_get_end(const struct iam_leaf *l) +{ -+ int result; ++ int count = lentry_count_get(l); ++ struct iam_lentry *ile = iam_lfix_shift(l, l->il_entries, count); + -+ assert(it_state(it) == IAM_IT_ATTACHED && it->ii_flags&IAM_IT_WRITE); -+#if 0 -+ /*XXX remove this assert temporarily, since if the il_at point to the hearder, -+ * this assert might has some problems*/ -+ assert(it_keycmp(it, iam_it_key_get(it, it_scratch_key(it, 0)), k) < 0); -+#endif -+ result = iam_add_rec(h, &it->ii_path, k, r); -+ if (result == 0) { -+ /* place record and key info freed space. Leaf node is already -+ * in transaction. */ -+ iam_it_reccpy(it, r); -+ iam_it_keycpy(it, k); -+ iam_keycpy(it->ii_path.ip_container, it_scratch_key(it, 0), k); -+ /* -+ * XXX TBD. -+ */ -+ } -+ assert(it_state(it) == IAM_IT_ATTACHED); -+ assert(ergo(result == 0, -+ it_keycmp(it, -+ iam_it_key_get(it, -+ it_scratch_key(it, 0)), k) == 0 && -+ !memcmp(iam_it_rec_get(it), r, -+ iam_it_container(it)->ic_descr->id_rec_size))); -+ return result; ++ return ile; +} + -+static int iam_leaf_rec_remove(handle_t *handle, struct iam_container *c, -+ struct iam_path *path) ++struct iam_rec* ++iam_lfix_rec(struct iam_leaf *l) +{ -+ int err; ++ void *e = l->il_at; ++ return e + iam_leaf_descr(l)->id_key_size; ++} + -+ iam_rec_del(path); -+ err = ext3_journal_dirty_metadata(handle, path->ip_leaf.il_bh); -+ if (err) -+ ext3_std_error(iam_path_obj(path)->i_sb, err); -+ return err; ++static void ++iam_lfix_next(struct iam_leaf *l) ++{ ++ assert(!iam_leaf_at_end(l)); ++ l->il_at = iam_lfix_shift(l, l->il_at, 1); +} + -+/* -+ * Delete record under iterator. -+ * -+ * precondition: it_state(it) == IAM_IT_ATTACHED && it->ii_flags&IAM_IT_WRITE -+ * postcondition: it_state(it) == IAM_IT_ATTACHED -+ */ -+int iam_it_rec_delete(handle_t *h, struct iam_iterator *it) ++static int ++iam_lfix_lookup(struct iam_leaf *l, struct iam_key *k) +{ -+ int result; ++ struct iam_lentry *p, *q, *m; ++ struct iam_container *c; ++ int count; + -+ assert(it_state(it) == IAM_IT_ATTACHED && it->ii_flags&IAM_IT_WRITE); ++ count = lentry_count_get(l); ++ c = iam_leaf_container(l); + -+ result = ext3_journal_get_write_access(h, it->ii_path.ip_leaf.il_bh); -+ /* -+ * no compaction for now. -+ */ -+ if (result == 0) -+ iam_leaf_rec_remove(h, iam_it_container(it), &it->ii_path); ++ p = iam_lfix_shift(l, l->il_entries, 1); ++ q = iam_lfix_shift(l, l->il_entries, count - 1); + -+ return result; ++ while (p <= q) { ++ m = iam_lfix_shift(l, p, iam_lfix_diff(l, q, p) / 2); ++ if (iam_keycmp(c, iam_leaf_key_at(c, m), k) > 0) ++ q = iam_lfix_shift(l, m, -1); ++ else ++ p = iam_lfix_shift(l, m, +1); ++ } ++ l->il_at = iam_lfix_shift(l, p, -1); ++ iam_keycpy(c, iam_path_key(iam_leaf_path(l), 0), iam_leaf_key_at(c, q)); ++ ++ if (l->il_at == l->il_entries || ++ iam_keycmp(c, iam_leaf_key_at(c, q), k) != 0) ++ return -ENOENT; ++ else ++ return 0; +} + -+/* -+ * Convert iterator to cookie. -+ * -+ * precondition: it_state(it) == IAM_IT_ATTACHED && -+ * iam_path_descr(it->ii_path)->id_key_size <= sizeof(iam_pos_t) -+ * postcondition: it_state(it) == IAM_IT_ATTACHED -+ */ -+iam_pos_t iam_it_store(struct iam_iterator *it) ++static void iam_lfix_rec_add(struct iam_leaf *leaf, ++ struct iam_key *k, struct iam_rec *r) +{ -+ iam_pos_t result; -+ -+ assert(it_state(it) == IAM_IT_ATTACHED); -+ assert(iam_it_container(it)->ic_descr->id_key_size <= sizeof result); ++ struct iam_lentry *end, *next, *cur, *nnext; ++ ptrdiff_t diff; ++ int count; + -+ result = 0; -+ iam_it_key_get(it, (struct iam_key *)&result); -+ return result; ++ count = lentry_count_get(leaf); ++ end = iam_lfix_get_end(leaf); ++ cur = leaf->il_at; ++ if (cur != end) { ++ next = iam_lfix_shift(leaf, cur, 1); ++ if (next != end) { ++ nnext = iam_lfix_shift(leaf, next, 1); ++ diff = (void *)end - (void *)next; ++ memmove(nnext, next, diff); ++ } ++ iam_lfix_next(leaf); ++ } ++ lentry_count_set(leaf, count + 1); +} + -+/* -+ * Restore iterator from cookie. -+ * -+ * precondition: it_state(it) == IAM_IT_DETACHED && it->ii_flags&IAM_IT_MOVE && -+ * iam_path_descr(it->ii_path)->id_key_size <= sizeof(iam_pos_t) -+ * postcondition: ergo(result == 0, it_state(it) == IAM_IT_ATTACHED && -+ * iam_it_store(it) == pos) -+ */ -+int iam_it_load(struct iam_iterator *it, iam_pos_t pos) ++static void iam_lfix_rec_del(struct iam_leaf *leaf) +{ -+ assert(it_state(it) == IAM_IT_DETACHED && it->ii_flags&IAM_IT_MOVE); -+ assert(iam_it_container(it)->ic_descr->id_key_size <= sizeof pos); -+ return iam_it_get(it, (struct iam_key *)&pos); -+} ++ struct iam_lentry *next, *end; ++ int count; ++ ptrdiff_t diff; + -+/***********************************************************************/ -+/* invariants */ -+/***********************************************************************/ ++ count = lentry_count_get(leaf); ++ end = iam_lfix_get_end(leaf); ++ next = iam_lfix_shift(leaf, leaf->il_at, 1); ++ diff = (void *)end - (void *)next; ++ memmove(leaf->il_at, next, diff); + -+static inline int ptr_inside(void *base, size_t size, void *ptr) -+{ -+ return (base <= ptr) && (ptr < base + size); ++ lentry_count_set(leaf, count - 1); +} + -+int iam_frame_invariant(struct iam_frame *f) ++static int iam_lfix_can_add(struct iam_leaf *l, ++ struct iam_key *k, struct iam_rec *r) +{ -+ return -+ (f->bh != NULL && -+ f->bh->b_data != NULL && -+ ptr_inside(f->bh->b_data, f->bh->b_size, f->entries) && -+ ptr_inside(f->bh->b_data, f->bh->b_size, f->at) && -+ f->entries <= f->at); ++ struct iam_lentry *end; ++ int block_size = iam_leaf_container(l)->ic_object->i_sb->s_blocksize; ++ unsigned long left, entry_size; ++ ++ end = iam_lfix_get_end(l); ++ ++ left = block_size - iam_leaf_descr(l)->id_node_gap; ++ ++ left -= (unsigned long)((void*)end - (void*)l->il_entries); ++ ++ entry_size = iam_lfix_entry_size(l); ++ ++ if (left >= entry_size) ++ return 1; ++ ++ return 0; +} -+int iam_leaf_invariant(struct iam_leaf *l) ++ ++static int iam_lfix_at_end(const struct iam_leaf *folio) +{ -+ return -+ l->il_bh != NULL && -+ l->il_bh->b_data != NULL && -+ ptr_inside(l->il_bh->b_data, l->il_bh->b_size, l->il_entries) && -+ ptr_inside(l->il_bh->b_data, l->il_bh->b_size, l->il_at) && -+ l->il_entries <= l->il_at; ++ struct iam_lentry *ile = iam_lfix_get_end(folio); ++ ++ return (folio->il_at == ile); +} + -+int iam_path_invariant(struct iam_path *p) -+{ -+ int i; ++struct iam_leaf_operations iam_lfix_leaf_ops = { ++ .init = iam_lfix_init, ++ .fini = iam_lfix_fini, ++ .start = iam_lfix_start, ++ .next = iam_lfix_next, ++ .key = iam_lfix_key, ++ .rec = iam_lfix_rec, ++ .lookup = iam_lfix_lookup, ++ .at_end = iam_lfix_at_end, ++ .rec_add = iam_lfix_rec_add, ++ .rec_del = iam_lfix_rec_del, ++ .can_add = iam_lfix_can_add ++}; ++EXPORT_SYMBOL(iam_lfix_leaf_ops); ++ ++static int split_leaf_node(handle_t *handle, struct iam_path *path) ++{ ++#if 0 ++ struct inode *dir = iam_path_obj(path); ++ unsigned continued = 0; ++ struct buffer_head *bh2; ++ u32 newblock, hash_split; ++ char *data2; ++ unsigned split; ++ int err; ++ ++ bh2 = ext3_append (handle, dir, &newblock, &err); ++ if (!(bh2)) ++ return -ENOSPC; ++ ++ err = iam_leaf_load(path); ++ if (err) ++ goto errout; + -+ if (p->ip_container == NULL || -+ p->ip_indirect < 0 || p->ip_indirect > DX_MAX_TREE_HEIGHT - 1 || -+ p->ip_frame != p->ip_frames + p->ip_indirect || -+ !iam_leaf_invariant(&p->ip_leaf)) -+ return 0; -+ for (i = 0; i < ARRAY_SIZE(p->ip_frames); ++i) { -+ if (i <= p->ip_indirect) { -+ if (!iam_frame_invariant(&p->ip_frames[i])) -+ return 0; -+ } -+ } -+ return 1; -+} ++ BUFFER_TRACE(path->ip_leaf.il_bh, "get_write_access"); ++ err = ext3_journal_get_write_access(handle, path->ip_leaf.il_bh); ++ if (err) { ++ journal_error: ++ iam_leaf_fini(path); ++ brelse(bh2); ++ ext3_std_error(dir->i_sb, err); ++ err = -EIO; ++ goto errout; ++ } ++ data2 = bh2->b_data; ++ split = dx_get_count((struct iam_entry*)iam_leaf_entries(path))/2; ++ hash_split = *(__u32*)iam_leaf_key_at(path, ++ iam_lfix_shift(path, iam_leaf_entries(path), ++ split)); ++ if (iam_keycmp(path->ip_container, iam_leaf_key_at(path, ++ iam_lfix_shift(path, iam_leaf_entries(path), split)), ++ iam_leaf_key_at(path, ++ iam_lfix_shift(path, iam_leaf_entries(path), split -1))) == 0) ++ continued = 1; + -+int iam_it_invariant(struct iam_iterator *it) -+{ -+ return -+ (it->ii_state == IAM_IT_DETACHED || -+ it->ii_state == IAM_IT_ATTACHED) && -+ !(it->ii_flags & ~(IAM_IT_MOVE | IAM_IT_WRITE)) && -+ ergo(it->ii_state == IAM_IT_ATTACHED, -+ iam_path_invariant(&it->ii_path)); ++ memcpy(iam_lfix_shift(path, (struct iam_lentry *)data2, 1), ++ iam_lfix_shift(path, iam_leaf_entries(path), split), ++ split * iam_lfix_entry_size(path)); ++ ++ /* Which block gets the new entry? */ ++ dx_insert_block(path, path->ip_frame, hash_split + continued, newblock); ++ err = ext3_journal_dirty_metadata (handle, bh2); ++ if (err) ++ goto journal_error; ++ err = ext3_journal_dirty_metadata (handle, path->ip_leaf.il_bh); ++ if (err) ++ goto journal_error; ++errout: ++ brelse (bh2); ++ return err; ++#endif ++ return 0; +} + +Index: iam/fs/ext3/namei.c +=================================================================== +--- iam.orig/fs/ext3/namei.c 2006-05-27 19:58:44.000000000 +0400 ++++ iam/fs/ext3/namei.c 2006-05-27 21:30:42.000000000 +0400 +@@ -24,81 +24,6 @@ + * Theodore Ts'o, 2002 + */ + +-/* +- * iam: big theory statement. +- * +- * iam (Index Access Module) is a module providing abstraction of persistent +- * transactional container on top of generalized ext3 htree. +- * +- * iam supports: +- * +- * - key, pointer, and record size specifiable per container. +- * +- * - trees taller than 2 index levels. +- * +- * - read/write to existing ext3 htree directories as iam containers. +- * +- * iam container is a tree, consisting of leaf nodes containing keys and +- * records stored in this container, and index nodes, containing keys and +- * pointers to leaf or index nodes. +- * +- * iam does not work with keys directly, instead it calls user-supplied key +- * comparison function (->dpo_keycmp()). +- * +- * Pointers are (currently) interpreted as logical offsets (measured in +- * blocksful) within underlying flat file on top of which iam tree lives. +- * +- * On-disk format: +- * +- * iam mostly tries to reuse existing htree formats. +- * +- * Format of index node: +- * +- * +-----+-------+-------+-------+------+-------+------------+ +- * | | count | | | | | | +- * | gap | / | entry | entry | .... | entry | free space | +- * | | limit | | | | | | +- * +-----+-------+-------+-------+------+-------+------------+ +- * +- * gap this part of node is never accessed by iam code. It +- * exists for binary compatibility with ext3 htree (that, +- * in turn, stores fake struct ext2_dirent for ext2 +- * compatibility), and to keep some unspecified per-node +- * data. Gap can be different for root and non-root index +- * nodes. Gap size can be specified for each container +- * (gap of 0 is allowed). +- * +- * count/limit current number of entries in this node, and the maximal +- * number of entries that can fit into node. count/limit +- * has the same size as entry, and is itself counted in +- * count. +- * +- * entry index entry: consists of a key immediately followed by +- * a pointer to a child node. Size of a key and size of a +- * pointer depends on container. Entry has neither +- * alignment nor padding. +- * +- * free space portion of node new entries are added to +- * +- * Entries in index node are sorted by their key value. +- * +- * Format of leaf node: +- * +- * +-----+-------+-------+-------+------+-------+------------+ +- * | | count | | | | | | +- * | gap | / | leaf | leaf | .... | leaf | free space | +- * | | limit | | | | | | +- * +-----+-------+-------+-------+------+-------+------------+ +- +- * leaf For leaf entry: consists of a rec immediately followd by +- * a key. size of a key and size of a rec depends on container. +- * +- * +- * +- * +- * +- */ +- + #include + #include + #include +@@ -112,10 +37,10 @@ + #include + #include + #include ++#include + #include "xattr.h" + #include "iopen.h" + #include "acl.h" +-#include + /* + * define how far ahead to read directories while searching them. + */ +@@ -125,9 +50,9 @@ + #define NAMEI_RA_INDEX(c,b) (((c) * NAMEI_RA_BLOCKS) + (b)) + + +-static struct buffer_head *ext3_append(handle_t *handle, +- struct inode *inode, +- u32 *block, int *err) ++struct buffer_head *ext3_append(handle_t *handle, ++ struct inode *inode, ++ u32 *block, int *err) + { + struct buffer_head *bh; + +@@ -141,9 +66,6 @@ static struct buffer_head *ext3_append(h + return bh; + } + +-#ifndef assert +-#define assert(test) J_ASSERT(test) +-#endif + + #ifndef swap + #define swap(x, y) do { typeof(x) z = x; x = y; y = z; } while (0) +@@ -162,10 +84,6 @@ struct fake_dirent { + 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,242 +121,10 @@ struct dx_map_entry + }; + + +-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, +- struct buffer_head *bh, int root); +-static int htree_keycmp(struct iam_container *c, +- struct iam_key *k1, struct iam_key *k2); +-static int htree_node_read(struct iam_container *c, iam_ptr_t ptr, +- handle_t *h, struct buffer_head **bh); +- +-/* +- * Parameters describing iam compatibility mode in which existing ext3 htrees +- * can be manipulated. +- */ +-static 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_root_ptr = htree_root_ptr, +- .id_node_check = htree_node_check, +- .id_node_init = htree_node_init, +- .id_node_read = htree_node_read, +- .id_keycmp = htree_keycmp +-}; +- +- +-struct iam_key; +-struct iam_rec; +-struct iam_descr; +-struct iam_container; +-struct iam_path; +- +- +- +-/* +- * iam cursor (iterator) api. +- */ +- +-/* +- * Flags controlling iterator functionality. +- */ +-enum iam_it_flags { +- /* +- * this iterator will move (iam_it_{prev,next}() will be called on it) +- */ +- IAM_IT_MOVE = (1 << 0), +- /* +- * tree can be updated through this iterator. +- */ +- IAM_IT_WRITE = (1 << 1) +-}; +- +-/* +- * States of iterator state machine. +- */ +-enum iam_it_state { +- /* initial state */ +- IAM_IT_DETACHED, +- /* iterator is above particular record in the container */ +- IAM_IT_ATTACHED +-}; +- +-struct htree_cookie { +- struct dx_hash_info *hinfo; +- struct dentry *dentry; +-}; +- +-/* +- * Iterator. +- * +- * Immediately after call to iam_it_init() iterator is in "detached" +- * (IAM_IT_DETACHED) state: it is associated with given parent container, but +- * doesn't point to any particular record in this container. +- * +- * After successful call to iam_it_get() and until corresponding call to +- * iam_it_put() iterator is in "attached" state (IAM_IT_ATTACHED). +- * +- * Attached iterator can move through records in a container (provided +- * IAM_IT_MOVE permission) in a key order, can get record and key values as it +- * passes over them, and can modify container (provided IAM_IT_WRITE +- * permission). +- * +- * Concurrency: iterators are supposed to be local to thread. Interfaces below +- * do no internal serialization. +- * +- */ +-struct iam_iterator { +- /* +- * iterator flags, taken from enum iam_it_flags. +- */ +- __u32 ii_flags; +- enum iam_it_state ii_state; +- /* +- * path to the record. Valid in IAM_IT_ATTACHED state. +- */ +- struct iam_path ii_path; +-}; +- +-static inline struct iam_key *keycpy(struct iam_container *c, +- struct iam_key *k1, struct iam_key *k2) +-{ +- return memcpy(k1, k2, c->ic_descr->id_key_size); +-} +- +-static inline int keycmp(struct iam_container *c, +- struct iam_key *k1, struct iam_key *k2) +-{ +- return c->ic_descr->id_keycmp(c, k1, k2); +-} +- +-static struct iam_container *iam_it_container(struct iam_iterator *it) +-{ +- return it->ii_path.ip_container; +-} +- +-static inline int it_keycmp(struct iam_iterator *it, +- struct iam_key *k1, struct iam_key *k2) +-{ +- return keycmp(iam_it_container(it), k1, k2); +-} +- +-/* +- * Initialize iterator to IAM_IT_DETACHED state. +- * +- * postcondition: it_state(it) == IAM_IT_DETACHED +- */ +-int iam_it_init(struct iam_iterator *it, struct iam_container *c, __u32 flags); +-/* +- * Finalize iterator and release all resources. +- * +- * precondition: it_state(it) == IAM_IT_DETACHED +- */ +-void iam_it_fini(struct iam_iterator *it); +- +-/* +- * Attach iterator. After successful completion, @it points to record with the +- * largest key not larger than @k. Semantics of ->id_create() method guarantee +- * that such record will always be found. +- * +- * Return value: 0: positioned on existing record, +- * -ve: error. +- * +- * precondition: it_state(it) == IAM_IT_DETACHED +- * postcondition: ergo(result == 0, +- * (it_state(it) == IAM_IT_ATTACHED && +- * it_keycmp(it, iam_it_key_get(it, *), k) < 0)) +- */ +-int iam_it_get(struct iam_iterator *it, struct iam_key *k); +- +-/* +- * Duplicates iterator. +- * +- * postcondition: it_state(dst) == it_state(src) && +- * iam_it_container(dst) == iam_it_container(src) && +- * dst->ii_flags = src->ii_flags && +- * ergo(it_state(it) == IAM_IT_ATTACHED, +- * iam_it_rec_get(dst) == iam_it_rec_get(src) && +- * iam_it_key_get(dst, *1) == iam_it_key_get(src, *2)) +- */ +-void iam_it_dup(struct iam_iterator *dst, struct iam_iterator *src); +- +-/* +- * Detach iterator. Does nothing it detached state. +- * +- * postcondition: it_state(it) == IAM_IT_DETACHED +- */ +-void iam_it_put(struct iam_iterator *it); +- +-/* +- * Move iterator one record right. +- * +- * Return value: 0: success, +- * +1: end of container reached +- * -ve: error +- * +- * precondition: it_state(it) == IAM_IT_ATTACHED && it->ii_flags&IAM_IT_MOVE +- * postcondition: ergo(result >= 0, it_state(it) == IAM_IT_ATTACHED) +- */ +-int iam_it_next(struct iam_iterator *it); +- +-/* +- * Return pointer to the record under iterator. +- * +- * precondition: it_state(it) == IAM_IT_ATTACHED +- * postcondition: it_state(it) == IAM_IT_ATTACHED +- */ +-const struct iam_rec *iam_it_rec_get(struct iam_iterator *it); +- +-/* +- * Replace contents of record under iterator. +- * +- * precondition: it_state(it) == IAM_IT_ATTACHED && it->ii_flags&IAM_IT_WRITE +- * postcondition: it_state(it) == IAM_IT_ATTACHED && +- * ergo(result == 0, !memcmp(iam_it_rec_get(it), r, ...)) +- */ +-int iam_it_rec_set(handle_t *h, struct iam_iterator *it, struct iam_rec *r); +- +-/* +- * Place key under iterator in @k, return @k +- * +- * precondition: it_state(it) == IAM_IT_ATTACHED +- * postcondition: it_state(it) == IAM_IT_ATTACHED +- */ +-const struct iam_key *iam_it_key_get(struct iam_iterator *it, +- struct iam_key *k); +- +-/* +- * Insert new record with key @k and contents from @r, shifting records to the +- * right. +- * +- * precondition: it_state(it) == IAM_IT_ATTACHED && +- * it->ii_flags&IAM_IT_WRITE && +- * it_keycmp(it, iam_it_key_get(it, *), k) < 0 +- * postcondition: it_state(it) == IAM_IT_ATTACHED && +- * ergo(result == 0, +- * it_keycmp(it, iam_it_key_get(it, *), k) == 0 && +- * !memcmp(iam_it_rec_get(it), r, ...)) +- */ +-int iam_it_rec_insert(handle_t *h, struct iam_iterator *it, +- struct iam_key *k, struct iam_rec *r); +-/* +- * Delete record under iterator. +- * +- * precondition: it_state(it) == IAM_IT_ATTACHED && it->ii_flags&IAM_IT_WRITE +- * postcondition: it_state(it) == IAM_IT_ATTACHED +- */ +-int iam_it_rec_delete(handle_t *h, struct iam_iterator *it); +- + #ifdef CONFIG_EXT3_INDEX + static inline unsigned dx_get_block(struct iam_path *p, struct iam_entry *entry); + static void dx_set_block(struct iam_path *p, + struct iam_entry *entry, unsigned value); +-static inline struct iam_key *dx_get_key(struct iam_path *p, +- struct iam_entry *entry, +- struct iam_key *key); + static void dx_set_key(struct iam_path *p, struct iam_entry *entry, + struct iam_key *key); + static unsigned dx_get_count(struct iam_entry *entries); +@@ -457,80 +143,29 @@ 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); +-static void dx_insert_block (struct iam_path *path, +- struct iam_frame *frame, u32 hash, u32 block); +-static int ext3_htree_next_block(struct inode *dir, __u32 hash, +- struct iam_path *path, __u32 *start_hash); + static struct buffer_head * ext3_dx_find_entry(struct dentry *dentry, + struct ext3_dir_entry_2 **res_dir, int *err); + static int ext3_dx_add_entry(handle_t *handle, struct dentry *dentry, + struct inode *inode); + +-static inline void iam_path_init(struct iam_path *path, +- struct iam_container *c, struct htree_cookie *hc); +-static inline void iam_path_fini(struct iam_path *path); +- +- +-/* +- * Future: use high four bits of block for coalesce-on-delete flags +- * Mask them off for now. +- */ +- +-static inline void *entry_off(struct iam_entry *entry, ptrdiff_t off) +-{ +- return (void *)((char *)entry + off); +-} +- +-static inline struct iam_descr *path_descr(struct iam_path *p) +-{ +- return p->ip_container->ic_descr; +-} +- +-static inline struct inode *path_obj(struct iam_path *p) +-{ +- return p->ip_container->ic_object; +-} +- + 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, +- struct iam_entry *entry, int shift) ++ struct iam_entry *entry, ++ int shift) + { + 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) +-{ +- 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); +-} +- +-static inline unsigned dx_get_block(struct iam_path *p, struct iam_entry *entry) ++static inline struct iam_key *iam_get_key(struct iam_path *p, ++ struct iam_entry *entry, ++ struct iam_key *key) + { +- return le32_to_cpu(*(u32 *)entry_off(entry, path_descr(p)->id_key_size)) +- & 0x00ffffff; +-} +- +-static inline void dx_set_block(struct iam_path *p, +- struct iam_entry *entry, unsigned value) +-{ +- *(u32*)entry_off(entry, +- path_descr(p)->id_key_size) = cpu_to_le32(value); +-} +- +-static inline struct iam_key *dx_get_key(struct iam_path *p, +- struct iam_entry *entry, +- struct iam_key *key) +-{ +- memcpy(key, entry, path_descr(p)->id_key_size); ++ memcpy(key, entry, iam_path_descr(p)->id_key_size); + return key; + } + +@@ -540,68 +175,70 @@ static inline struct iam_key *iam_key_at + return (struct iam_key *)entry; + } + +-static inline void dx_set_key(struct iam_path *p, +- struct iam_entry *entry, struct iam_key *key) +-{ +- memcpy(entry, key, path_descr(p)->id_key_size); +-} +- +-static inline unsigned dx_get_count (struct iam_entry *entries) +-{ +- return le16_to_cpu(((struct dx_countlimit *) entries)->count); +-} +- +-static inline unsigned dx_get_limit (struct iam_entry *entries) ++static inline ptrdiff_t iam_entry_diff(struct iam_path *p, ++ struct iam_entry *e1, ++ struct iam_entry *e2) + { +- return le16_to_cpu(((struct dx_countlimit *) entries)->limit); +-} ++ ptrdiff_t diff; + +-static inline void dx_set_count (struct iam_entry *entries, unsigned value) +-{ +- ((struct dx_countlimit *) entries)->count = cpu_to_le16(value); ++ diff = (void *)e1 - (void *)e2; ++ assert(diff / iam_entry_size(p) * iam_entry_size(p) == diff); ++ return diff / iam_entry_size(p); + } + +-static inline void dx_set_limit (struct iam_entry *entries, unsigned value) ++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) + { +- struct iam_descr *param = path_descr(p); +- unsigned entry_space = path_obj(p)->i_sb->s_blocksize - ++ struct iam_descr *param = iam_path_descr(p); ++ unsigned entry_space = iam_path_obj(p)->i_sb->s_blocksize - + param->id_root_gap; + return entry_space / (param->id_key_size + param->id_ptr_size); + } + +-static inline unsigned dx_node_limit(struct iam_path *p) +-{ +- 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); +-} +/* -+ * Search container @c for record with key @k. If record is found, its data -+ * are moved into @r. -+ * ++ * 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. + * -+ * Return values: +ve: found, 0: not-found, -ve: error + */ -+int iam_lookup(struct iam_container *c, struct iam_key *k, struct iam_rec *r, -+ struct iam_path_descr *pd) -+{ -+ struct iam_iterator it; -+ int result; -+ -+ iam_it_init(&it, c, 0, pd); -+ -+ result = iam_it_get_exact(&it, k); -+ if (result == 0) -+ /* -+ * record with required key found, copy it into user buffer -+ */ -+ iam_reccpy(&it.ii_path, r, iam_it_rec_get(&it)); -+ iam_it_put(&it); -+ iam_it_fini(&it); -+ return result; -+} -+EXPORT_SYMBOL(iam_lookup); + +-static inline int dx_index_is_compat(struct iam_path *path) +-{ +- return path_descr(path) == &htree_compat_param; +-} ++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, 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_entry *dx_get_entries(struct iam_path *path, void *data, +- int root) +-{ +- return data + +- (root ? +- path_descr(path)->id_root_gap : path_descr(path)->id_node_gap); +-} ++struct iam_operations htree_operation = { ++ .id_root_ptr = htree_root_ptr, ++ .id_node_check = htree_node_check, ++ .id_node_init = htree_node_init, ++ .id_node_read = iam_node_read, ++ .id_keycmp = htree_keycmp ++}; + +/* -+ * Insert new record @r with key @k into container @c (within context of -+ * transaction @h. -+ * -+ * Return values: 0: success, -ve: error, including -EEXIST when record with -+ * given key is already present. -+ * -+ * postcondition: ergo(result == 0 || result == -EEXIST, -+ * iam_lookup(c, k, r2) > 0 && -+ * !memcmp(r, r2, c->ic_descr->id_rec_size)); ++ * Parameters describing iam compatibility mode in which existing ext3 htrees ++ * can be manipulated. + */ -+int iam_insert(handle_t *h, struct iam_container *c, -+ struct iam_key *k, struct iam_rec *r, struct iam_path_descr *pd) -+{ -+ struct iam_iterator it; -+ int result; -+ -+ iam_it_init(&it, c, IAM_IT_WRITE, pd); -+ -+ result = iam_it_get_exact(&it, k); -+ if (result == -ENOENT) -+ result = iam_it_rec_insert(h, &it, k, r); -+ else if (result == 0) -+ result = -EEXIST; -+ iam_it_put(&it); -+ iam_it_fini(&it); -+ return result; -+} -+EXPORT_SYMBOL(iam_insert); -+ -+int iam_update(handle_t *h, struct iam_container *c, -+ struct iam_key *k, struct iam_rec *r, struct iam_path_descr *pd) -+{ -+ struct iam_iterator it; -+ int result; ++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 ++}; + +-static struct iam_entry *dx_node_get_entries(struct iam_path *path, +- struct iam_frame *frame) ++static inline 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; + } + + -+ iam_it_init(&it, c, IAM_IT_WRITE, pd); + static int dx_node_check(struct iam_path *p, struct iam_frame *f) + { + struct iam_entry *e; +@@ -614,10 +251,10 @@ static int dx_node_check(struct iam_path + count = dx_get_count(e); + e = iam_entry_shift(p, e, 1); + for (i = 0; i < count - 1; ++i, e = iam_entry_shift(p, e, 1)) { +- keycpy(c, p->ip_key_scratch[0], p->ip_key_scratch[1]); +- dx_get_key(p, e, p->ip_key_scratch[1]); ++ iam_keycpy(c, iam_path_key(p, 0), iam_path_key(p, 1)); ++ iam_get_key(p, e, iam_path_key(p, 1)); + if (i > 0 && +- 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) + return 0; + } + return 1; +@@ -636,13 +273,17 @@ static int htree_node_check(struct iam_p + + 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; +- 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); + -+ result = iam_it_get_exact(&it, k); -+ if (result == 0) -+ iam_it_rec_set(h, &it, r); -+ iam_it_put(&it); -+ iam_it_fini(&it); -+ return result; -+} -+EXPORT_SYMBOL(iam_update); + if (root->info.hash_version > DX_HASH_MAX) { + ext3_warning(sb, __FUNCTION__, + "Unrecognised inode hash code %d", +@@ -669,15 +310,16 @@ static int htree_node_check(struct iam_p + 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 = (struct iam_key *)&ipc->ipc_hinfo->hash; + } 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)); + } + frame->entries = frame->at = entries; +@@ -697,8 +339,8 @@ static int htree_node_init(struct iam_co + 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 +350,8 @@ static int htree_node_read(struct iam_co + 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 +442,7 @@ 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 +452,11 @@ static int dx_lookup(struct iam_path *pa + 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, +- ptr = param->id_root_ptr(path->ip_container); ++ ptr = param->id_ops->id_root_ptr(path->ip_container); + i <= path->ip_indirect; + ptr = dx_get_block(path, frame->at), ++frame, ++i) { + struct iam_entry *entries; +@@ -823,10 +465,11 @@ static int dx_lookup(struct iam_path *pa + 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; +- err = param->id_node_check(path, frame); ++ err = param->id_ops->id_node_check(path, frame); + if (err != 0) + break; + +@@ -841,8 +484,8 @@ static int dx_lookup(struct iam_path *pa + 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 +500,12 @@ static int dx_lookup(struct iam_path *pa + 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", +- 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 +534,20 @@ static int dx_probe(struct dentry *dentr + struct dx_hash_info *hinfo, struct iam_path *path) + { + int err; +- struct htree_cookie hc = { +- .dentry = dentry, +- .hinfo = hinfo +- }; ++ struct iam_path_compat *ipc; + -+/* -+ * Delete existing record with key @k. -+ * -+ * Return values: 0: success, -ENOENT: not-found, -ve: other error. -+ * -+ * postcondition: ergo(result == 0 || result == -ENOENT, -+ * !iam_lookup(c, k, *)); -+ */ -+int iam_delete(handle_t *h, struct iam_container *c, struct iam_key *k, -+ struct iam_path_descr *pd) ++ 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)); +- path->ip_descr_data = &hc; + 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, +- struct iam_descr *descr, struct inode *inode) +-{ +- memset(c, 0, sizeof *c); +- c->ic_descr = descr; +- c->ic_object = igrab(inode); +- if (c->ic_object != NULL) +- return 0; +- else +- return -ENOENT; +-} +- +-/* +- * Finalize container @c, release all resources. +- */ +-void iam_container_fini(struct iam_container *c) +-{ +- if (c->ic_object != NULL) { +- iput(c->ic_object); +- c->ic_object = NULL; +- } +-} +- +-static inline void iam_path_init(struct iam_path *path, struct iam_container *c, +- struct htree_cookie *hc) +-{ +- memset(path, 0, sizeof *path); +- path->ip_container = c; +- path->ip_frame = path->ip_frames; +- path->ip_descr_data = hc; +-} +- +-static inline void iam_path_fini(struct iam_path *path) +-{ +- int i; +- +- for (i = 0; i < ARRAY_SIZE(path->ip_frames); i++) { +- if (path->ip_frames[i].bh != NULL) { +- brelse(path->ip_frames[i].bh); +- path->ip_frames[i].bh = NULL; +- } +- } +-} +- +-static void iam_path_compat_init(struct iam_path_compat *path, +- struct inode *inode) +-{ +- int 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_path_init(&path->ipc_path, &path->ipc_container, NULL); +- for (i = 0; i < ARRAY_SIZE(path->ipc_path.ip_key_scratch); ++i) +- path->ipc_path.ip_key_scratch[i] = +- (struct iam_key *)&path->ipc_scrach[i]; +-} +- +-static void iam_path_compat_fini(struct iam_path_compat *path) +-{ +- iam_path_fini(&path->ipc_path); +- iam_container_fini(&path->ipc_container); +-} +- +-static int iam_leaf_init(struct iam_path *path, struct iam_leaf *leaf) +-{ +- int block, err; +- struct buffer_head *bh; +- +- block = dx_get_block(path, path->ip_frame->at); +- err = path_descr(path)->id_node_read(path->ip_container, block, +- NULL, &bh); +- if (err) +- return err; +- +- leaf->bh = bh; +- leaf->entries = (struct iam_leaf_entry *)bh->b_data; +- return 0; +-} +- +-static void iam_leaf_fini(struct iam_leaf *leaf) +-{ +- if (leaf->bh) +- brelse(leaf->bh); +-} +- +-/* +- * Search container @c for record with key @k. If record is found, its data +- * are moved into @r. +- * +- * +- * +- * Return values: +ve: found, 0: not-found, -ve: error +- */ +- +-int iam_lookup(struct iam_container *c, struct iam_key *k, struct iam_rec *r) +-{ +- struct dx_hash_info hinfo; +- struct iam_path_compat cpath; +- struct iam_path *path = &cpath.ipc_path; +- struct htree_cookie hc = { +- .hinfo = &hinfo +- }; +- int err, i; +- +- iam_path_init(path, c, &hc); +- 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); +- do { +- struct iam_leaf leaf; +- err = iam_leaf_init(path, &leaf); +- if (err) +- goto errout; +- +- for (path_descr(path)->id_leaf.start(c, &leaf); +- !path_descr(path)->id_leaf.at_end(c, &leaf); +- path_descr(path)->id_leaf.next(c, &leaf)) { +- struct iam_key *key; +- +- key = kmalloc(path_descr(path)->id_key_size, GFP_KERNEL); +- path_descr(path)->id_leaf.key(c, &leaf, key); +- if (keycmp(c, k, key) == 0) { +- memcpy(r, path_descr(path)->id_leaf.rec(c, &leaf), +- path_descr(path)->id_rec_size); +- iam_path_fini(path); +- iam_leaf_fini(&leaf); +- return 0; +- } +- } +- +- iam_leaf_fini(&leaf); +- /* Check to see if we should continue to search */ +- err = ext3_htree_next_block(c->ic_object, hinfo.hash, path, NULL); +- if (err < 0) +- goto errout; +- } while (err == 1); +-errout: +- iam_path_fini(path); +- return(err); +-} +-EXPORT_SYMBOL(iam_lookup); +- +-static inline size_t iam_leaf_entry_size(struct iam_path *p) +-{ +- return path_descr(p)->id_rec_size + path_descr(p)->id_key_size; +-} +- +-static inline ptrdiff_t iam_leaf_entry_diff(struct iam_path *p, +- struct iam_leaf_entry *e1, struct iam_leaf_entry *e2) +-{ +- ptrdiff_t diff; +- +- diff = (void *)e1 - (void *)e2; +- assert(diff / iam_leaf_entry_size(p) * iam_leaf_entry_size(p) == diff); +- return diff / iam_leaf_entry_size(p); +-} +- +-static inline struct iam_leaf_entry* +-iam_leaf_entry_shift(struct iam_path *p, struct iam_leaf_entry *entry, int shift) +-{ +- void *e = entry; +- return e + shift * iam_leaf_entry_size(p); +-} +- +-static inline struct iam_key * +-dx_leaf_get_key(struct iam_path *p, struct iam_leaf_entry *e, struct iam_key *key) +-{ +- memcpy(key, e, path_descr(p)->id_key_size); +- return key; +-} +- +-static inline struct iam_key * +-iam_leaf_key_at(struct iam_path *p, struct iam_leaf_entry *entry) +-{ +- void *e = entry; +- return e + path_descr(p)->id_rec_size; +-} +-static inline struct iam_leaf_entry * +-iam_leaf_entry_at(struct iam_path *p, struct iam_leaf_entry *entry) +-{ +- return entry; +-} +- +-static int iam_leaf_lookup(struct iam_path *path, struct iam_leaf *leaf, +- struct iam_key *k) +-{ +- struct iam_leaf_entry *p, *q, *m; +- struct iam_leaf_entry *entries = leaf->entries; +- int count = dx_get_count((struct iam_entry *)entries); +- +- p = iam_leaf_entry_shift(path, entries, 1); +- q = iam_leaf_entry_shift(path, entries, count - 1); +- while (p <= q) { +- m = iam_leaf_entry_shift(path, +- p, iam_leaf_entry_diff(path, q, p) / 2); +- dxtrace(printk(".")); +- if (keycmp(path->ip_container, iam_leaf_key_at(path, m), +- path->ip_key_target) > 0) +- q = iam_leaf_entry_shift(path, m, -1); +- else +- p = iam_leaf_entry_shift(path, m, +1); +- } +- leaf->at = q; +- return 0; +-} +- +-/*XXX what kind of lock should this entry be locked: WangDi */ +-static int iam_leaf_insert(handle_t *handle, struct iam_path *path, +- struct iam_key *k, struct iam_rec *r) +-{ +- struct iam_leaf leaf; +- struct iam_leaf_entry *p, *q; +- int err, count; +- +- err = iam_leaf_init(path, &leaf); +- if (err) +- goto errout; +- path_descr(path)->id_leaf.start(path->ip_container, &leaf); +- count = dx_get_count((struct iam_entry *)leaf.entries); +- if (dx_get_count((struct iam_entry *)leaf.entries) >= +- dx_get_limit((struct iam_entry *)leaf.entries)){ +- err = -ENOSPC; +- goto errout; +- } +- +- err = iam_leaf_lookup(path, &leaf, k); +- if (err) +- goto errout; +- +- /*insert the k/r to leaf entries*/ +- p = iam_leaf_entry_shift(path, leaf.at, 1); +- q = iam_leaf_entry_shift(path, leaf.entries, count - 1); +- while (q < p) { +- memcpy(iam_leaf_entry_shift(path, q, 1), q, iam_leaf_entry_size(path)); +- q = iam_leaf_entry_shift(path, q, -1); +- } +- memcpy(iam_leaf_entry_at(path, p), r, path_descr(path)->id_rec_size); +- memcpy(iam_leaf_key_at(path, p), k, path_descr(path)->id_key_size); +- +- dx_set_count((struct iam_entry*)leaf.entries, count + 1); +- err = ext3_journal_dirty_metadata(handle, leaf.bh); +- if (err) +- ext3_std_error(path->ip_container->ic_object->i_sb, err); +-errout: +- iam_leaf_fini(&leaf); +- return err; +-} +- +-static int split_leaf_node(handle_t *handle, struct iam_path *path) +-{ +- struct inode *dir = path_obj(path); +- unsigned continued = 0; +- struct buffer_head *bh2; +- u32 newblock, hash_split; +- char *data2; +- struct iam_leaf leaf; +- unsigned split; +- int err; +- +- bh2 = ext3_append (handle, dir, &newblock, &err); +- if (!(bh2)) { +- err = -ENOSPC; +- goto errout; +- } +- err = iam_leaf_init(path, &leaf); +- if (err) +- goto errout; +- +- BUFFER_TRACE(leaf.bh, "get_write_access"); +- err = ext3_journal_get_write_access(handle, leaf.bh); +- if (err) { +- journal_error: +- iam_leaf_fini(&leaf); +- brelse(bh2); +- ext3_std_error(dir->i_sb, err); +- err = -EIO; +- goto errout; +- } +- data2 = bh2->b_data; +- split = dx_get_count((struct iam_entry*)leaf.entries)/2; +- hash_split = *(__u32*)iam_leaf_key_at(path, iam_leaf_entry_shift(path, leaf.entries, split)); +- if (keycmp(path->ip_container, iam_leaf_key_at(path, iam_leaf_entry_shift(path, leaf.entries, split)), +- iam_leaf_key_at(path, iam_leaf_entry_shift(path, leaf.entries, split -1))) == 0) +- continued = 1; +- +- memcpy(iam_leaf_entry_shift(path, (struct iam_leaf_entry *)data2, 1), +- iam_leaf_entry_shift(path, leaf.entries, split), +- split * iam_leaf_entry_size(path)); +- +- /* Which block gets the new entry? */ +- dx_insert_block(path, path->ip_frame, hash_split + continued, newblock); +- err = ext3_journal_dirty_metadata (handle, bh2); +- if (err) +- goto journal_error; +- err = ext3_journal_dirty_metadata (handle, leaf.bh); +- if (err) +- goto journal_error; +- brelse (bh2); +- iam_leaf_fini(&leaf); +-errout: +- return err; +-} +- +-static int split_index_node(handle_t *handle, struct iam_path *path); +-/* +- * Insert new record @r with key @k into container @c (within context of +- * transaction @h. +- * +- * Return values: 0: success, -ve: error, including -EEXIST when record with +- * given key is already present. +- * +- * postcondition: ergo(result == 0 || result == -EEXIST, +- * iam_lookup(c, k, r2) > 0 && +- * !memcmp(r, r2, c->ic_descr->id_rec_size)); +- */ +-int iam_insert(handle_t *handle, struct iam_container *c, struct iam_key *k, +- struct iam_rec *r) +-{ +- struct dx_hash_info hinfo; +- struct iam_path_compat cpath; +- struct iam_path *path = &cpath.ipc_path; +- struct htree_cookie hc = { +- .hinfo = &hinfo +- }; +- int err, i; +- +- iam_path_init(path, c, &hc); +- 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); +- if (err) +- goto errout; +- +- err = iam_leaf_insert(handle, path, k, r); +- +- if (err != -ENOSPC) +- goto errout; +- +- err = split_index_node(handle, path); +- if (err) +- goto errout; +- +- err = split_leaf_node(handle, path); +- if (err) +- goto errout; +- +- err = iam_leaf_insert(handle, path, k, r); +-errout: +- iam_path_fini(path); +- return(err); +-} +- +-EXPORT_SYMBOL(iam_insert); +-static int iam_leaf_delete(handle_t *handle, struct iam_path *path, +- struct iam_key *k) +-{ +- struct iam_leaf leaf; +- struct iam_leaf_entry *p, *q; +- int err, count; +- +- err = iam_leaf_init(path, &leaf); +- if (err) +- goto errout; +- +- err = iam_leaf_lookup(path, &leaf, k); +- if (err) +- goto errout; +- +- count = dx_get_count((struct iam_entry*)leaf.entries); +- /*delete the k to leaf entries*/ +- p = iam_leaf_entry_shift(path, leaf.at, 1); +- q = iam_leaf_entry_shift(path, leaf.entries, count - 1); +- while (p < q) { +- memcpy(p, iam_leaf_entry_shift(path, p, 1), iam_leaf_entry_size(path)); +- p = iam_leaf_entry_shift(path, p, 1); +- } +- dx_set_count((struct iam_entry*)leaf.entries, count - 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; +-} +- +-/* +- * Delete existing record with key @k. +- * +- * Return values: 0: success, -ENOENT: not-found, -ve: other error. +- * +- * postcondition: ergo(result == 0 || result == -ENOENT, +- * !iam_lookup(c, k, *)); +- */ +-int iam_delete(handle_t *h, struct iam_container *c, struct iam_key *k) +-{ +- struct dx_hash_info hinfo; +- struct iam_path_compat cpath; +- struct iam_path *path = &cpath.ipc_path; +- struct htree_cookie hc = { +- .hinfo = &hinfo +- }; +- int err, i; +- +- iam_path_init(path, c, &hc); +- 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); +- if (err) +- goto errout; +- +- err = iam_leaf_delete(h, path, k); +-errout: +- iam_path_fini(path); +- return err; +-} +- +-EXPORT_SYMBOL(iam_delete); +- +-static int iam_leaf_update(handle_t *handle, struct iam_path *path, +- struct iam_key *k, struct iam_rec *r) +-{ +- struct iam_leaf leaf; +- int err; +- +- err = iam_leaf_init(path, &leaf); +- if (err) +- goto errout; +- +- err = iam_leaf_lookup(path, &leaf, k); +- if (err) +- goto errout; +- +- 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); +- +- 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; +-} +-/* +- * Replace existing record with key @k, or insert new one. New record data are +- * in @r. +- * +- * Return values: 0: success, -ve: error. +- * +- * postcondition: ergo(result == 0, iam_lookup(c, k, r2) > 0 && +- * !memcmp(r, r2, c->ic_descr->id_rec_size)); +- */ +-int iam_update(handle_t *h, struct iam_container *c, +- struct iam_key *k, struct iam_rec *r) +-{ +- struct dx_hash_info hinfo; +- struct iam_path_compat cpath; +- struct iam_path *path = &cpath.ipc_path; +- struct htree_cookie hc = { +- .hinfo = &hinfo +- }; +- int err, i; +- +- iam_path_init(path, c, &hc); +- 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); +- if (err) +- goto errout; +- +- err = iam_leaf_update(h, path, k, r); +-errout: +- iam_path_fini(path); +- 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,8 +564,8 @@ EXPORT_SYMBOL(iam_update); + * If start_hash is non-null, it will be filled in with the starting + * hash of the next page. + */ +-static int ext3_htree_next_block(struct inode *dir, __u32 hash, +- struct iam_path *path, __u32 *start_hash) ++int ext3_htree_next_block(struct inode *dir, __u32 hash, ++ struct iam_path *path, __u32 *start_hash) + { + struct iam_frame *p; + struct buffer_head *bh; +@@ -1445,7 +600,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. + */ +- dx_get_key(path, p->at, (struct iam_key *)&bhash); ++ iam_get_key(path, p->at, (struct iam_key *)&bhash); + if (start_hash) + *start_hash = bhash; + if ((hash & 1) == 0) { +@@ -1457,9 +612,10 @@ static int ext3_htree_next_block(struct + * block so no check is necessary + */ + while (num_frames--) { +- err = path_descr(path)->id_node_read(path->ip_container, +- (iam_ptr_t)dx_get_block(path, p->at), +- NULL, &bh); ++ err = iam_path_descr(path)->id_ops-> ++ id_node_read(path->ip_container, ++ (iam_ptr_t)dx_get_block(path, p->at), ++ NULL, &bh); + if (err != 0) + return err; /* Failure */ + ++p; +@@ -1662,8 +818,8 @@ static void dx_sort_map (struct dx_map_e + } while(more); + } + +-static void dx_insert_block(struct iam_path *path, +- struct iam_frame *frame, u32 hash, u32 block) ++void dx_insert_block(struct iam_path *path, struct iam_frame *frame, ++ u32 hash, u32 block) + { + struct iam_entry *entries = frame->entries; + struct iam_entry *old = frame->at, *new = iam_entry_shift(path, old, +1); +@@ -1897,14 +1053,15 @@ static struct buffer_head * ext3_dx_find + if (*err != 0) + return NULL; + } else { +- path->ip_frame->bh = NULL; /* for iam_path_fini() */ ++ path->ip_frame->bh = NULL; /* for iam_path_fini() */ + path->ip_frame->at = (void *)&dummy_dot;/* hack for zero entry*/ + } + hash = hinfo.hash; + do { + block = dx_get_block(path, path->ip_frame->at); +- *err = path_descr(path)->id_node_read(path->ip_container, (iam_ptr_t)block, +- NULL, &bh); ++ *err = iam_path_descr(path)->id_ops->id_node_read(path->ip_container, ++ (iam_ptr_t)block, ++ NULL, &bh); + if (*err != 0) + goto errout; + de = (struct ext3_dir_entry_2 *) bh->b_data; +@@ -2067,7 +1224,7 @@ static struct ext3_dir_entry_2 *do_split + struct buffer_head **bh,struct iam_frame *frame, + struct dx_hash_info *hinfo, int *error) + { +- struct inode *dir = path_obj(path); ++ struct inode *dir = iam_path_obj(path); + unsigned blocksize = dir->i_sb->s_blocksize; + unsigned count, continued; + struct buffer_head *bh2; +@@ -2392,15 +1549,15 @@ static int ext3_add_entry (handle_t *han + } + + #ifdef CONFIG_EXT3_INDEX +-static int split_index_node(handle_t *handle, struct iam_path *path) +-{ ++int split_index_node(handle_t *handle, struct iam_path *path) +{ -+ struct iam_iterator it; -+ int result; -+ -+ iam_it_init(&it, c, IAM_IT_WRITE, pd); -+ -+ result = iam_it_get_exact(&it, k); -+ if (result == 0) -+ iam_it_rec_delete(h, &it); -+ iam_it_put(&it); -+ iam_it_fini(&it); -+ return result; -+} -+EXPORT_SYMBOL(iam_delete); -+ -Index: linux-2.6.9/fs/ext3/Makefile -=================================================================== ---- linux-2.6.9.orig/fs/ext3/Makefile 2006-05-26 16:47:48.000000000 +0800 -+++ linux-2.6.9/fs/ext3/Makefile 2006-05-26 16:47:50.000000000 +0800 -@@ -6,7 +6,7 @@ - ext3-y := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o iopen.o \ - ioctl.o namei.o super.o symlink.o hash.o resize.o \ -- extents.o mballoc.o -+ extents.o mballoc.o iam.o + struct iam_entry *entries; /* old block contents */ + struct iam_entry *entries2; /* new block contents */ + struct iam_frame *frame, *safe; + struct buffer_head *bh_new[DX_MAX_TREE_HEIGHT] = {0}; + u32 newblock[DX_MAX_TREE_HEIGHT] = {0}; +- struct inode *dir = path_obj(path); ++ struct inode *dir = iam_path_obj(path); + int nr_splet; + int i, err; - ext3-$(CONFIG_EXT3_FS_XATTR) += xattr.o xattr_user.o xattr_trusted.o - ext3-$(CONFIG_EXT3_FS_POSIX_ACL) += acl.o -Index: linux-2.6.9/include/linux/lustre_iam.h +@@ -2442,7 +1599,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] || +- path_descr(path)->id_node_init(path->ip_container, bh_new[i], 0) != 0) ++ iam_path_descr(path)->id_ops->id_node_init(path->ip_container, ++ bh_new[i], 0) != 0) + goto cleanup; + BUFFER_TRACE(frame->bh, "get_write_access"); + err = ext3_journal_get_write_access(handle, frame->bh); +@@ -2516,9 +1674,9 @@ static int split_index_node(handle_t *ha + unsigned count1 = count/2, count2 = count - count1; + unsigned hash2; + +- dx_get_key(path, +- iam_entry_shift(path, entries, count1), +- (struct iam_key *)&hash2); ++ iam_get_key(path, ++ iam_entry_shift(path, entries, count1), ++ (struct iam_key *)&hash2); + + dxtrace(printk("Split index %i/%i\n", count1, count2)); + +@@ -2578,7 +1736,7 @@ static int ext3_dx_add_entry(handle_t *h + size_t isize; + + iam_path_compat_init(&cpath, dir); +- param = path_descr(path); ++ param = iam_path_descr(path); + + err = dx_probe(dentry, NULL, &hinfo, path); + if (err != 0) +@@ -2588,8 +1746,9 @@ static int ext3_dx_add_entry(handle_t *h + /* XXX nikita: global serialization! */ + isize = dir->i_size; + +- err = param->id_node_read(path->ip_container, (iam_ptr_t)dx_get_block(path, frame->at), +- handle, &bh); ++ err = param->id_ops->id_node_read(path->ip_container, ++ (iam_ptr_t)dx_get_block(path, frame->at), ++ handle, &bh); + if (err != 0) + goto cleanup; + +@@ -2724,12 +1883,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 +- * with d_instantiate(). ++ * with d_instantiate(). + */ + static int ext3_create (struct inode * dir, struct dentry * dentry, int mode, + struct nameidata *nd) + { +- handle_t *handle; ++ handle_t *handle; + struct inode * inode; + int err, retries = 0; + +Index: iam/include/linux/lustre_iam.h =================================================================== ---- linux-2.6.9.orig/include/linux/lustre_iam.h 2006-05-26 16:47:50.000000000 +0800 -+++ linux-2.6.9/include/linux/lustre_iam.h 2006-05-26 16:47:50.000000000 +0800 +--- iam.orig/include/linux/lustre_iam.h 2006-05-27 19:58:44.000000000 +0400 ++++ iam/include/linux/lustre_iam.h 2006-05-27 21:33:22.000000000 +0400 @@ -1,3 +1,39 @@ +/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- + * vim:expandtab:shiftwidth=8:tabstop=8: @@ -2640,7 +2721,7 @@ Index: linux-2.6.9/include/linux/lustre_iam.h /* * Maximal number of non-leaf levels in htree. In the stock ext3 this is 2. */ -@@ -30,6 +66,11 @@ +@@ -30,6 +66,11 @@ struct iam_key; /* Incomplete type use to refer to the records stored in iam containers. */ struct iam_rec; @@ -2652,26 +2733,21 @@ Index: linux-2.6.9/include/linux/lustre_iam.h typedef __u64 iam_ptr_t; /* -@@ -41,45 +82,23 @@ +@@ -41,45 +82,25 @@ struct iam_frame { struct iam_entry *at; /* target entry, found by binary search */ }; -+/* -+ * Opaque entry in the leaf node. -+ */ -+struct iam_lentry; -+ - /* leaf node reached by tree lookup */ +-/* leaf node reached by tree lookup */ -#define iam_leaf_entry iam_rec - struct iam_leaf { +-struct iam_leaf { - struct buffer_head *bh; - struct iam_leaf_entry *entries; - struct iam_leaf_entry *at; -+ struct buffer_head *il_bh; -+ struct iam_lentry *il_entries; -+ struct iam_lentry *il_at; -+ void *il_descr_data; - }; +-}; ++/* ++ * Opaque entry in the leaf node. ++ */ ++struct iam_lentry; struct iam_path; struct iam_container; @@ -2703,12 +2779,32 @@ Index: linux-2.6.9/include/linux/lustre_iam.h - * bytes. Used for compatibility with ext3. - */ - size_t id_root_gap; -- + ++/* leaf node reached by tree lookup */ ++struct iam_leaf { ++ struct iam_path *il_path; ++ struct buffer_head *il_bh; ++ struct iam_lentry *il_entries; ++ struct iam_lentry *il_at; ++ void *il_descr_data; ++}; ++ +struct iam_operations { /* * Returns pointer (in the same sense as pointer in index entry) to * the root node. -@@ -111,25 +130,107 @@ +@@ -102,8 +123,8 @@ struct iam_descr { + /* + * Key comparison function. Returns -1, 0, +1. + */ +- int (*id_keycmp)(struct iam_container *c, +- struct iam_key *k1, struct iam_key *k2); ++ int (*id_keycmp)(const struct iam_container *c, ++ const struct iam_key *k1, const struct iam_key *k2); + /* + * Create new container. + * +@@ -111,25 +132,115 @@ struct iam_descr { * contains single record with the smallest possible key. */ int (*id_create)(struct iam_container *c); @@ -2741,19 +2837,19 @@ Index: linux-2.6.9/include/linux/lustre_iam.h + /* + * initialize just loaded leaf node. + */ -+ int (*init)(struct iam_container *c, struct iam_leaf *p); ++ int (*init)(struct iam_leaf *p); + /* + * Release resources. + */ -+ void (*fini)(struct iam_container *c, struct iam_leaf *l); ++ void (*fini)(struct iam_leaf *l); + /* + * returns true iff leaf is positioned at the last entry. + */ -+ int (*at_end)(struct iam_container *c, struct iam_leaf *l); ++ int (*at_end)(const struct iam_leaf *l); + /* position leaf at the first entry */ -+ void (*start)(struct iam_container *c, struct iam_leaf *l); ++ void (*start)(struct iam_leaf *l); + /* more leaf to the next entry. */ -+ void (*next)(struct iam_container *c, struct iam_leaf *l); ++ void (*next)(struct iam_leaf *l); + /* return key of current leaf record. This method may return + * either pointer to the key stored in node, or copy key into + * @k buffer supplied by caller and return pointer to this @@ -2763,12 +2859,10 @@ Index: linux-2.6.9/include/linux/lustre_iam.h + * + * Caller should assume that returned pointer is only valid + * while leaf node is pinned and locked.*/ -+ struct iam_key *(*key)(struct iam_container *c, -+ struct iam_leaf *l, struct iam_key *k); ++ struct iam_key *(*key)(struct iam_leaf *l, struct iam_key *k); + /* return pointer to entry body. Pointer is valid while + corresponding leaf node is locked and pinned. */ -+ struct iam_rec *(*rec)(struct iam_container *c, -+ struct iam_leaf *l); ++ struct iam_rec *(*rec)(struct iam_leaf *l); + + /* + * Search leaf @l for a record with key @k or for a place @@ -2776,18 +2870,28 @@ Index: linux-2.6.9/include/linux/lustre_iam.h + * + * Scratch keys from @path can be used. + */ -+ int (*lookup)(struct iam_container *c, struct iam_path *path, -+ struct iam_leaf *l, struct iam_key *k); -+ -+ int (*can_add) (struct iam_container *c, struct iam_leaf *l, ++ int (*lookup)(struct iam_leaf *l, struct iam_key *k); ++ ++ int (*can_add)(struct iam_leaf *l, ++ struct iam_key *k, struct iam_rec *r); ++ /* ++ * add rec for a leaf ++ */ ++ void (*rec_add)(struct iam_leaf *l, + struct iam_key *k, struct iam_rec *r); -+ /*add rec for a leaf*/ -+ void (*rec_add)(struct iam_path *path, struct iam_key *k, -+ struct iam_rec *r); -+ /*remove rec for a leaf*/ -+ void (*rec_del)(struct iam_path *path); ++ /* ++ * remove rec for a leaf ++ */ ++ void (*rec_del)(struct iam_leaf *l); ++ /* ++ * split leaf node ++ */ ++ int (*split)(handle_t *h, struct iam_leaf *l); +}; + ++struct iam_path *iam_leaf_path(const struct iam_leaf *leaf); ++struct iam_container *iam_leaf_container(const struct iam_leaf *leaf); ++ +struct iam_root { + struct iam_root_info { + u8 indirect_levels; @@ -2835,7 +2939,7 @@ Index: linux-2.6.9/include/linux/lustre_iam.h }; struct iam_container { -@@ -149,6 +250,17 @@ +@@ -149,6 +260,17 @@ struct iam_container { }; /* @@ -2853,7 +2957,7 @@ Index: linux-2.6.9/include/linux/lustre_iam.h * Structure to keep track of a path drilled through htree. */ struct iam_path { -@@ -172,34 +284,232 @@ +@@ -172,34 +294,232 @@ struct iam_path { /* * Leaf node: a child of ->ip_frame. */ @@ -2865,12 +2969,12 @@ Index: linux-2.6.9/include/linux/lustre_iam.h struct iam_key *ip_key_target; /* - * Scratch-pad area for temporary keys. -+ * Description-specific data. - */ +- */ - struct iam_key *ip_key_scratch[DX_SCRATCH_KEYS]; - /* - * pointer to flavor-specific per-container data. -- */ ++ * Description-specific data. + */ - void *ip_descr_data; + struct iam_path_descr *ip_data; }; @@ -3100,7 +3204,7 @@ Index: linux-2.6.9/include/linux/lustre_iam.h /* * Initialize container @c, acquires additional reference on @inode. */ -@@ -210,3 +520,143 @@ +@@ -210,3 +530,152 @@ int iam_container_init(struct iam_contai */ void iam_container_fini(struct iam_container *c); @@ -3123,14 +3227,14 @@ Index: linux-2.6.9/include/linux/lustre_iam.h + return p->ip_container->ic_object; +} + -+static inline void iam_keycpy(struct iam_container *c, struct iam_key *k1, -+ struct iam_key *k2) ++static inline void iam_keycpy(const struct iam_container *c, ++ struct iam_key *k1, const struct iam_key *k2) +{ + memcpy(k1, k2, c->ic_descr->id_key_size); +} + -+static inline int iam_keycmp(struct iam_container *c, -+ struct iam_key *k1, struct iam_key *k2) ++static inline int iam_keycmp(const struct iam_container *c, ++ const struct iam_key *k1, const struct iam_key *k2) +{ + return c->ic_descr->id_ops->id_keycmp(c, k1, k2); +} @@ -3238,9 +3342,18 @@ Index: linux-2.6.9/include/linux/lustre_iam.h +int iam_index_next(struct iam_path *p); +int iam_read_leaf(struct iam_path *p); + -+int iam_keycmp(struct iam_container *c, struct iam_key *k1, struct iam_key *k2); +int iam_node_read(struct iam_container *c, iam_ptr_t ptr, + handle_t *handle, struct buffer_head **bh); + ++int iam_leaf_at_end(const struct iam_leaf *l); ++void iam_leaf_next(struct iam_leaf *folio); ++ ++struct iam_path *iam_leaf_path(const struct iam_leaf *leaf); ++struct iam_container *iam_leaf_container(const struct iam_leaf *leaf); ++struct iam_descr *iam_leaf_descr(const struct iam_leaf *leaf); ++struct iam_leaf_operations *iam_leaf_ops(const struct iam_leaf *leaf); ++ ++extern struct iam_leaf_operations iam_lfix_leaf_ops; ++ +/* __LINUX_LUSTRE_IAM_H__ */ +#endif diff --git a/lustre/ldiskfs/Makefile.in b/lustre/ldiskfs/Makefile.in index 4a76335..df5199d 100644 --- a/lustre/ldiskfs/Makefile.in +++ b/lustre/ldiskfs/Makefile.in @@ -11,7 +11,7 @@ ext3_headers := $(wildcard @LINUX@/fs/ext3/*.h) linux_headers := $(wildcard @LINUX@/include/linux/ext3*.h) ext3_sources := $(filter-out %.mod.c,$(wildcard @LINUX@/fs/ext3/*.c)) -new_sources := iopen.c iopen.h extents.c mballoc.c iam.c +new_sources := iopen.c iopen.h extents.c mballoc.c iam.c iam_lfix.c new_headers := ext3_extents.h ldiskfs_patched_sources := $(notdir $(ext3_sources) $(ext3_headers)) $(new_sources) $(new_headers) ldiskfs_sources := $(ldiskfs_patched_sources)