===================================================================
--- iam.orig/fs/ext3/iam.c
+++ iam/fs/ext3/iam.c
-@@ -0,0 +1,1430 @@
+@@ -0,0 +1,1432 @@
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+
+static int iam_leaf_load(struct iam_path *path)
+{
-+ int block;
++ iam_ptr_t block;
+ int err;
+ struct iam_container *c;
+ struct buffer_head *bh;
+ c = path->ip_container;
+ leaf = &path->ip_leaf;
+ descr = iam_path_descr(path);
-+ block = dx_get_block(path, path->ip_frame->at);
++ block = path->ip_frame->leaf;
+ if (block == 0) {
+ /* XXX bug 11027 */
-+ printk(KERN_EMERG "wrong leaf: %p %d [%p %p %p]\n",
-+ path->ip_frame->at,
++ printk(KERN_EMERG "wrong leaf: %lu %d [%p %p %p]\n",
++ (long unsigned)path->ip_frame->leaf,
+ dx_get_count(dx_node_get_entries(path, path->ip_frame)),
+ path->ip_frames[0].bh, path->ip_frames[1].bh,
+ path->ip_frames[2].bh);
+ err = descr->id_ops->id_node_read(c, block, NULL, &bh);
+ if (err == 0) {
+ leaf->il_bh = bh;
++ leaf->il_curidx = block;
+ err = iam_leaf_ops(leaf)->init(leaf);
+ assert_inv(ergo(err == 0, iam_leaf_check(leaf)));
+ }
+ if (leaf->il_bh) {
+ brelse(leaf->il_bh);
+ leaf->il_bh = NULL;
++ leaf->il_curidx = 0;
+ }
+ }
+}
===================================================================
--- iam.orig/fs/ext3/iam_htree.c
+++ iam/fs/ext3/iam_htree.c
-@@ -0,0 +1,683 @@
+@@ -0,0 +1,684 @@
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ * insertion point moves into new leaf.
+ */
+ assert_corr(delim_hash >= old_hash);
++ l->il_curidx = new_blknr;
+ iam_htree_lookup(l, (void *)&old_hash);
+ }
+ iam_insert_key_lock(path,
===================================================================
--- iam.orig/fs/ext3/iam_lfix.c
+++ iam/fs/ext3/iam_lfix.c
-@@ -0,0 +1,727 @@
+@@ -0,0 +1,728 @@
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ shift = iam_lfix_diff(l, l->il_at, start);
+ *bh = l->il_bh;
+ l->il_bh = new_leaf;
++ l->il_curidx = new_blknr;
+ result = iam_lfix_init(l);
+ /*
+ * init cannot fail, as node was just initialized.
===================================================================
--- iam.orig/fs/ext3/iam_lvar.c
+++ iam/fs/ext3/iam_lvar.c
-@@ -0,0 +1,1028 @@
+@@ -0,0 +1,1040 @@
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+static void lvar_next(struct iam_leaf *l)
+{
+ assert_corr(n_at_rec(l));
++ assert_corr(iam_leaf_is_locked(l));
+ l->il_at = lvar_lentry(e_next(l, n_cur(l)));
+}
+
+{
+ assert_corr(n_at_rec(l));
+ assert_corr(strlen(kchar(k)) == e_keysize(n_cur(l)));
++ assert_corr(iam_leaf_is_locked(l));
+ memcpy(e_key(n_cur(l)), k, e_keysize(n_cur(l)));
+ assert_inv(n_invariant(l));
+}
+static void lvar_rec_set(struct iam_leaf *l, const struct iam_rec *r)
+{
+ assert_corr(n_at_rec(l));
++ assert_corr(iam_leaf_is_locked(l));
+ iam_reccpy(iam_leaf_path(l), e_rec(n_cur(l)), r);
+ assert_inv(n_invariant(l));
+}
+static int lvar_can_add(const struct iam_leaf *l,
+ const struct iam_key *k, const struct iam_rec *r)
+{
++ assert_corr(iam_leaf_is_locked(l));
+ return h_used(n_head(l)) + getsize(l, strlen(kchar(k))) <= blocksize(l);
+}
+
+static int lvar_at_end(const struct iam_leaf *folio)
+{
++ assert_corr(iam_leaf_is_locked(folio));
+ return n_cur(folio) == n_end(folio);
+}
+
+
+ assert_corr(lvar_can_add(leaf, k, r));
+ assert_inv(n_invariant(leaf));
++ assert_corr(iam_leaf_is_locked(leaf));
+
+ key = kchar(k);
+ ksize = strlen(key);
+
+ assert_corr(n_at_rec(leaf));
+ assert_inv(n_invariant(leaf));
++ assert_corr(iam_leaf_is_locked(leaf));
+
+ end = n_end(leaf);
+ next = e_next(leaf, n_cur(leaf));
+ lvar_hash_t hash;
+
+ assert_inv(n_invariant(leaf));
++ assert_corr(iam_leaf_is_locked(leaf));
+
+ new_leaf = *bh;
+ path = iam_leaf_path(leaf);
+ shift = PDIFF(leaf->il_at, first_to_move);
+ *bh = leaf->il_bh;
+ leaf->il_bh = new_leaf;
++ leaf->il_curidx = new_blknr;
++
++ assert_corr(iam_leaf_is_locked(leaf));
+ result = lvar_init(leaf);
+ /*
+ * init cannot fail, as node was just initialized.
+ struct lvar_root *root;
+ struct iam_entry *entries;
+
++ assert_corr(iam_frame_is_locked(path, frame));
+ entries = frame->entries;
+
+ dx_set_count(entries, 2);
* there's no point to read in the successive index pages.
*/
iam_get_ikey(path, p->at, (struct iam_ikey *)&bhash);
-@@ -425,25 +665,96 @@ static int ext3_htree_advance(struct ino
+@@ -425,25 +665,92 @@ static int ext3_htree_advance(struct ino
* block so no check is necessary
*/
while (num_frames--) {
-+ /*
-+ * XXX hmm... don't we need dx_{,un}lock_bh() and
-+ * dx_path_check() calls here? -- nikita.
-+ */
+ iam_ptr_t idx;
+
+ do_corr(schedule());
}
int ext3_htree_next_block(struct inode *dir, __u32 hash,
-@@ -657,6 +968,15 @@ void iam_insert_key(struct iam_path *pat
+@@ -657,6 +964,15 @@ void iam_insert_key(struct iam_path *pat
dx_set_ikey(path, new, key);
dx_set_block(path, new, ptr);
dx_set_count(entries, count + 1);
}
void dx_insert_block(struct iam_path *path, struct iam_frame *frame,
-@@ -882,7 +1202,7 @@ static struct buffer_head * ext3_dx_find
+@@ -882,7 +1198,7 @@ static struct buffer_head * ext3_dx_find
sb = dir->i_sb;
/* NFS may look up ".." - look at dx_root directory block */
if (namelen > 2 || name[0] != '.'||(name[1] != '.' && name[1] != '\0')){
if (*err != 0)
return NULL;
} else {
-@@ -1114,7 +1434,7 @@ struct ext3_dir_entry_2 *move_entries(st
+@@ -1114,7 +1430,7 @@ struct ext3_dir_entry_2 *move_entries(st
hash2 = map[split].hash;
continued = hash2 == map[split - 1].hash;
dxtrace(printk("Split block %i at %x, %i/%i\n",
/* Fancy dance to stay within two buffers */
de2 = dx_move_dirents(data1, data2, map + split, count - split);
-@@ -1484,16 +1804,38 @@ static int shift_entries(struct iam_path
+@@ -1484,16 +1800,38 @@ static int shift_entries(struct iam_path
(char *) iam_entry_shift(path, entries, count1),
count2 * iam_entry_size(path));
{
struct iam_entry *entries; /* old block contents */
-@@ -1501,6 +1843,8 @@ int split_index_node(handle_t *handle, s
+@@ -1501,6 +1839,8 @@ int split_index_node(handle_t *handle, s
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 = iam_path_obj(path);
struct iam_descr *descr;
int nr_splet;
-@@ -1523,12 +1867,14 @@ int split_index_node(handle_t *handle, s
+@@ -1523,12 +1863,14 @@ int split_index_node(handle_t *handle, s
* - first allocate all necessary blocks
*
* - insert pointers into them atomically.
dxtrace(printk("using %u of %u node entries\n",
dx_get_count(entries), dx_get_limit(entries)));
-@@ -1536,6 +1882,7 @@ int split_index_node(handle_t *handle, s
+@@ -1536,6 +1878,7 @@ int split_index_node(handle_t *handle, s
for (nr_splet = 0; frame >= path->ip_frames &&
dx_get_count(frame->entries) == dx_get_limit(frame->entries);
--frame, ++nr_splet) {
if (nr_splet == DX_MAX_TREE_HEIGHT) {
ext3_warning(dir->i_sb, __FUNCTION__,
"Directory index full!\n");
-@@ -1545,14 +1892,53 @@ int split_index_node(handle_t *handle, s
+@@ -1545,14 +1888,53 @@ int split_index_node(handle_t *handle, s
}
safe = frame;
BUFFER_TRACE(frame->bh, "get_write_access");
err = ext3_journal_get_write_access(handle, frame->bh);
if (err)
-@@ -1560,6 +1946,7 @@ int split_index_node(handle_t *handle, s
+@@ -1560,6 +1942,7 @@ int split_index_node(handle_t *handle, s
}
/* Add "safe" node to transaction too */
if (safe + 1 != path->ip_frames) {
err = ext3_journal_get_write_access(handle, safe->bh);
if (err)
goto journal_error;
-@@ -1596,16 +1983,21 @@ int split_index_node(handle_t *handle, s
+@@ -1596,16 +1979,21 @@ int split_index_node(handle_t *handle, s
assert_corr(i == 0);
/* Shift frames in the path */
memmove(frames + 2, frames + 1,
(sizeof path->ip_frames) - 2 * sizeof frames[0]);
-@@ -1613,18 +2005,22 @@ int split_index_node(handle_t *handle, s
+@@ -1613,18 +2001,22 @@ int split_index_node(handle_t *handle, s
frames[1].at = iam_entry_shift(path, entries2, idx);
frames[1].entries = entries = entries2;
frames[1].bh = bh2;
count = shift_entries(path, frame, count,
entries, entries2, newblock[i]);
/* Which index block gets the new entry? */
-@@ -1635,32 +2031,42 @@ int split_index_node(handle_t *handle, s
+@@ -1635,32 +2027,42 @@ int split_index_node(handle_t *handle, s
idx - count + d);
frame->entries = entries = entries2;
swap(frame->bh, bh2);
if (nr_splet > 0) {
/*
* Log ->i_size modification.
-@@ -1674,6 +2080,10 @@ journal_error:
+@@ -1674,6 +2076,10 @@ journal_error:
ext3_std_error(dir->i_sb, err);
cleanup:
for (i = 0; i < ARRAY_SIZE(bh_new); ++i) {
if (bh_new[i] != NULL)
brelse(bh_new[i]);
-@@ -1695,18 +2105,18 @@ static int ext3_dx_add_entry(handle_t *h
+@@ -1695,18 +2101,18 @@ static int ext3_dx_add_entry(handle_t *h
struct buffer_head * bh = NULL;
struct inode *dir = dentry->d_parent->d_inode;
struct ext3_dir_entry_2 *de;
isize = dir->i_size;
err = param->id_ops->id_node_read(path->ip_container,
-@@ -1726,7 +2136,7 @@ static int ext3_dx_add_entry(handle_t *h
+@@ -1726,7 +2132,7 @@ static int ext3_dx_add_entry(handle_t *h
goto cleanup;
}
if (err)
goto cleanup;
-@@ -1736,12 +2146,14 @@ static int ext3_dx_add_entry(handle_t *h
+@@ -1736,12 +2142,14 @@ static int ext3_dx_add_entry(handle_t *h
goto cleanup;
assert_inv(dx_node_check(path, frame));
};
/*
-@@ -205,6 +215,10 @@ struct iam_leaf {
+@@ -205,6 +215,11 @@ struct iam_leaf {
struct buffer_head *il_bh;
struct iam_lentry *il_entries;
struct iam_lentry *il_at;
+ * Lock on a leaf node.
+ */
+ struct dynlock_handle *il_lock;
++ iam_ptr_t il_curidx; /* logical offset of leaf node. */
void *il_descr_data;
};
-@@ -215,19 +229,23 @@ enum iam_lookup_t {
+@@ -215,19 +230,23 @@ enum iam_lookup_t {
/*
* lookup found a record with the key requested
*/
};
/*
-@@ -271,8 +289,7 @@ struct iam_operations {
+@@ -271,8 +290,7 @@ struct iam_operations {
struct iam_frame *frame);
struct iam_path_descr *(*id_ipd_alloc)(const struct iam_container *c);
/*
* Format name.
*/
-@@ -331,6 +348,7 @@ struct iam_leaf_operations {
+@@ -331,6 +349,7 @@ struct iam_leaf_operations {
void (*rec_set)(struct iam_leaf *l, const struct iam_rec *r);
int (*key_cmp)(const struct iam_leaf *l, const struct iam_key *k);
int (*key_size)(const struct iam_leaf *l);
/*
-@@ -473,7 +491,7 @@ struct iam_path_compat {
+@@ -473,7 +492,7 @@ struct iam_path_compat {
struct iam_container ipc_container;
__u32 ipc_scratch[DX_SCRATCH_KEYS];
struct dx_hash_info *ipc_hinfo;
struct iam_path_descr ipc_descr;
struct dx_hash_info ipc_hinfo_area;
};
-@@ -848,7 +866,9 @@ static inline struct iam_ikey *iam_path_
+@@ -848,7 +867,36 @@ static inline struct iam_ikey *iam_path_
return path->ip_data->ipd_key_scratch[nr];
}
-int dx_lookup(struct iam_path *path);
++static inline struct dynlock *path_dynlock(struct iam_path *path)
++{
++ return &EXT3_I(iam_path_obj(path))->i_htree_lock;
++}
++
++static inline int iam_leaf_is_locked(const struct iam_leaf *leaf)
++{
++ int result;
++
++ result = dynlock_is_locked(path_dynlock(leaf->il_path),
++ leaf->il_curidx);
++ if (!result)
++ dump_stack();
++ return result;
++}
++
++static inline int iam_frame_is_locked(struct iam_path *path,
++ const struct iam_frame *frame)
++{
++ int result;
++
++ result = dynlock_is_locked(path_dynlock(path), frame->curidx);
++ if (!result)
++ dump_stack();
++ return result;
++}
++
+int dx_lookup_lock(struct iam_path *path,
+ struct dynlock_handle **dl, enum dynlock_type lt);
+
void dx_insert_block(struct iam_path *path, struct iam_frame *frame,
u32 hash, u32 block);
int dx_index_is_compat(struct iam_path *path);
-@@ -858,7 +878,8 @@ int ext3_htree_next_block(struct inode *
+@@ -858,7 +906,8 @@ int ext3_htree_next_block(struct inode *
struct buffer_head *ext3_append(handle_t *handle, struct inode *inode,
u32 *block, int *err);
struct ext3_dir_entry_2 *split_entry(struct inode *dir,
struct ext3_dir_entry_2 *de,
unsigned long ino, mode_t mode,
-@@ -874,6 +895,10 @@ struct ext3_dir_entry_2 *move_entries(st
+@@ -874,6 +923,10 @@ struct ext3_dir_entry_2 *move_entries(st
extern struct iam_descr iam_htree_compat_param;
/*
* external
*/
-@@ -889,7 +914,7 @@ int iam_read_leaf(struct iam_path *p);
+@@ -889,7 +942,7 @@ int iam_read_leaf(struct iam_path *p);
int iam_node_read(struct iam_container *c, iam_ptr_t ptr,
handle_t *handle, struct buffer_head **bh);