Index: iam/fs/ext3/Makefile
===================================================================
--- iam.orig/fs/ext3/Makefile 2006-05-31 20:24:32.000000000 +0400
-+++ iam/fs/ext3/Makefile 2006-06-08 01:08:10.000000000 +0400
++++ iam/fs/ext3/Makefile 2006-06-08 21:50:42.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 \
Index: iam/fs/ext3/iam.c
===================================================================
--- iam.orig/fs/ext3/iam.c 2004-04-06 17:27:52.000000000 +0400
-+++ iam/fs/ext3/iam.c 2006-06-08 01:08:07.000000000 +0400
-@@ -0,0 +1,1125 @@
++++ iam/fs/ext3/iam.c 2006-06-08 19:42:19.000000000 +0400
+@@ -0,0 +1,1163 @@
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ iam_path_fini(&it->ii_path);
+}
+
-+int iam_path_lookup(struct iam_path *path)
++static int iam_path_lookup(struct iam_path *path)
+{
+ struct iam_container *c;
+ struct iam_descr *descr;
+ result = iam_leaf_load(path);
+ assert(ergo(result == 0, iam_leaf_check(leaf)));
+ if (result == 0)
-+ result = iam_leaf_ops(leaf)->lookup(leaf,
-+ path->ip_key_target);
++ result = iam_leaf_ops(leaf)->
++ lookup(leaf, path->ip_key_target);
+ }
+ return result;
+}
+ * -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))
++ * 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, const struct iam_key *k)
+{
+ 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
++ if (result >= 0) {
++ switch (result) {
++ case IAM_LOOKUP_OK:
++ it->ii_state = IAM_IT_ATTACHED;
++ break;
++ case IAM_LOOKUP_EMPTY:
++ it->ii_state = IAM_IT_EMPTY;
++ break;
++ case IAM_LOOKUP_BEFORE:
++ it->ii_state = IAM_IT_BEFORE;
++ break;
++ default:
++ assert(0);
++ }
++ result = 0;
++ } else
+ iam_it_unlock(it);
-+ assert(ergo(result == 0,
-+ it_keycmp(it,
-+ iam_it_key_get(it, it_scratch_key(it, 0)),
++ assert(ergo(result == 0 && it_state(it) == IAM_IT_ATTACHED,
++ it_keycmp(it, iam_it_key_get(it, it_scratch_key(it, 0)),
+ k) <= 0));
++ /*
++ * See iam_it_get_exact() for explanation.
++ */
++ assert(result != -ENOENT);
+ return result;
+}
+
+ */
+void iam_it_put(struct iam_iterator *it)
+{
-+ if (it->ii_state == IAM_IT_ATTACHED) {
++ if (it->ii_state > IAM_IT_DETACHED) {
+ it->ii_state = IAM_IT_DETACHED;
+ iam_leaf_fini(&it->ii_path.ip_leaf);
+ iam_it_unlock(it);
+int iam_it_next(struct iam_iterator *it)
+{
+ int result;
-+ struct iam_container *c;
+ struct iam_path *path;
+ struct iam_leaf *leaf;
+
-+ assert(it_state(it) == IAM_IT_ATTACHED && it->ii_flags&IAM_IT_MOVE);
++ assert(it->ii_flags&IAM_IT_MOVE);
++ assert(it_state(it) == IAM_IT_ATTACHED ||
++ it_state(it) == IAM_IT_BEFORE || it_state(it) == IAM_IT_EMPTY);
+
-+ c = iam_it_container(it);
+ path = &it->ii_path;
+ leaf = &path->ip_leaf;
+
-+ if (!iam_leaf_at_end(leaf)) {
-+ /* advance within leaf node */
-+ iam_leaf_next(leaf);
-+ result = 0;
++ result = 0;
++ if (it_state(it) == IAM_IT_BEFORE) {
++ assert(!iam_leaf_at_end(leaf));
++ it->ii_state = IAM_IT_ATTACHED;
+ } else {
++ if (!iam_leaf_at_end(leaf))
++ /* advance within leaf node */
++ iam_leaf_next(leaf);
+ /*
+ * multiple iterations may be necessary due to empty leaves.
+ */
-+ do {
++ while (result == 0 && iam_leaf_at_end(leaf)) {
+ /* advance index portion of the path */
-+ result = iam_index_next(c, path);
++ result = iam_index_next(iam_it_container(it), path);
+ if (result == 1) {
+ result = iam_leaf_load(path);
+ if (result == 0)
+ iam_leaf_start(leaf);
-+ } else if (result == 0)
++ } else if (result == 0) {
+ /* end of container reached */
++ it->ii_state = IAM_IT_EOC;
+ result = +1;
++ }
+ if (result < 0)
+ iam_it_put(it);
-+ } while (result == 0 && iam_leaf_at_end(leaf));
++ }
+ }
-+ assert(ergo(result >= 0, it_state(it) == IAM_IT_ATTACHED));
++ assert(ergo(result == 0, it_state(it) == IAM_IT_ATTACHED));
+ return result;
+}
+
+/*
+ * Return pointer to the key under iterator.
+ *
-+ * precondition: it_state(it) == IAM_IT_ATTACHED && it_at_rec(it)
++ * precondition: it_state(it) == IAM_IT_ATTACHED ||
++ * it_state(it) == IAM_IT_BEFORE
+ * postcondition: it_state(it) == IAM_IT_ATTACHED
+ */
+struct iam_key *iam_it_key_get(const struct iam_iterator *it, struct iam_key *k)
+{
-+ assert(it_state(it) == IAM_IT_ATTACHED);
++ assert(it_state(it) == IAM_IT_ATTACHED ||
++ it_state(it) == IAM_IT_BEFORE);
+ assert(it_at_rec(it));
+ return iam_leaf_key(&it->ii_path.ip_leaf, 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,
++ * precondition: it->ii_flags&IAM_IT_WRITE &&
++ * (it_state(it) == IAM_IT_ATTACHED ||
++ * it_state(it) == IAM_IT_BEFORE ||
++ * it_state(it) == IAM_IT_EMPTY) &&
++ * ergo(it_state(it) == IAM_IT_ATTACHED,
++ * it_keycmp(it, iam_it_key_get(it, it_scratch_key(it, 0)),
++ * k) < 0) &&
++ * ergo(it_state(it) == IAM_IT_BEFORE,
++ * it_keycmp(it, iam_it_key_get(it, it_scratch_key(it, 0)),
++ * k) > 0));
++ * postcondition: ergo(result == 0,
++ * it_state(it) == IAM_IT_ATTACHED &&
+ * it_keycmp(it, iam_it_key_get(it, *), k) == 0 &&
+ * !memcmp(iam_it_rec_get(it), r, ...))
+ */
+
+ path = &it->ii_path;
+
-+ assert(it_state(it) == IAM_IT_ATTACHED && it->ii_flags&IAM_IT_WRITE);
-+ /*
-+ * if insertion point is at the existing record...
-+ */
-+ assert(ergo(it_at_rec(it),
-+ /*
-+ * this record either has the key smaller then target
-+ * key...
-+ */
++ assert(it->ii_flags&IAM_IT_WRITE);
++ assert(it_state(it) == IAM_IT_ATTACHED ||
++ it_state(it) == IAM_IT_BEFORE || it_state(it) == IAM_IT_EMPTY);
++ assert(ergo(it_state(it) == IAM_IT_ATTACHED,
++ it_keycmp(it, iam_it_key_get(it, it_scratch_key(it, 0)),
++ k) < 0));
++ assert(ergo(it_state(it) == IAM_IT_BEFORE,
+ it_keycmp(it, iam_it_key_get(it, it_scratch_key(it, 0)),
-+ k) < 0 ||
-+ /*
-+ * or we landed into leaf where the smallest key is larger
-+ * than the target key.
-+ */
-+ path->ip_leaf.il_at == path->ip_leaf.il_entries));
++ k) > 0));
+ result = iam_add_rec(h, path, k, r);
-+ assert(it_state(it) == IAM_IT_ATTACHED);
++ if (result == 0)
++ it->ii_state = IAM_IT_ATTACHED;
+ assert(ergo(result == 0,
++ it_state(it) == IAM_IT_ATTACHED &&
+ it_keycmp(it, iam_it_key_get(it, it_scratch_key(it, 0)),
+ k) == 0 &&
+ !memcmp(iam_it_rec_get(it), r,
+ return result;
+}
+
-+static int iam_leaf_rec_remove(handle_t *handle, struct iam_leaf *leaf)
-+{
-+ assert(iam_leaf_check(leaf));
-+ assert(iam_path_check(iam_leaf_path(leaf)));
-+ iam_rec_del(leaf);
-+ assert(iam_leaf_check(leaf));
-+ assert(iam_path_check(iam_leaf_path(leaf)));
-+ return iam_txn_dirty(handle, iam_leaf_path(leaf), leaf->il_bh);
-+}
-+
+/*
+ * Delete record under iterator.
+ *
+ * precondition: it_state(it) == IAM_IT_ATTACHED &&
+ * it->ii_flags&IAM_IT_WRITE &&
+ * it_at_rec(it)
-+ * postcondition: it_state(it) == IAM_IT_ATTACHED
++ * postcondition: it_state(it) == IAM_IT_ATTACHED || it_state(it) == IAM_IT_EOC
+ */
+int iam_it_rec_delete(handle_t *h, struct iam_iterator *it)
+{
+ int result;
++ struct iam_leaf *leaf;
++ struct iam_path *path;
+
+ assert(it_state(it) == IAM_IT_ATTACHED && it->ii_flags&IAM_IT_WRITE);
+ assert(it_at_rec(it));
+
-+ result = iam_txn_add(h, &it->ii_path, it->ii_path.ip_leaf.il_bh);
++ path = &it->ii_path;
++ leaf = &path->ip_leaf;
++
++ assert(iam_leaf_check(leaf));
++ assert(iam_path_check(path));
++
++ result = iam_txn_add(h, path, leaf->il_bh);
+ /*
+ * no compaction for now.
+ */
-+ if (result == 0)
-+ iam_leaf_rec_remove(h, &it->ii_path.ip_leaf);
-+
++ if (result == 0) {
++ iam_rec_del(leaf);
++ result = iam_txn_dirty(h, path, leaf->il_bh);
++ if (result == 0 && iam_leaf_at_end(leaf) &&
++ it->ii_flags&IAM_IT_MOVE) {
++ result = iam_it_next(it);
++ if (result > 0)
++ result = 0;
++ }
++ }
++ assert(iam_leaf_check(leaf));
++ assert(iam_path_check(path));
++ assert(it_state(it) == IAM_IT_ATTACHED || it_state(it) == IAM_IT_EOC);
+ return result;
+}
+
+{
+ return
+ (it->ii_state == IAM_IT_DETACHED ||
-+ it->ii_state == IAM_IT_ATTACHED) &&
++ it->ii_state == IAM_IT_ATTACHED ||
++ it->ii_state == IAM_IT_EMPTY ||
++ it->ii_state == IAM_IT_BEFORE ||
++ it->ii_state == IAM_IT_EOC) &&
+ !(it->ii_flags & ~(IAM_IT_MOVE | IAM_IT_WRITE)) &&
-+ ergo(it->ii_state == IAM_IT_ATTACHED,
-+ iam_path_invariant(&it->ii_path));
++ ergo(it->ii_state == IAM_IT_ATTACHED ||
++ it->ii_state == IAM_IT_EMPTY ||
++ it->ii_state == IAM_IT_BEFORE,
++ iam_path_invariant(&it->ii_path) &&
++ equi(it->ii_state == IAM_IT_EMPTY, !it_at_rec(it)));
+}
+
+/*
Index: iam/fs/ext3/iam_lfix.c
===================================================================
--- iam.orig/fs/ext3/iam_lfix.c 2004-04-06 17:27:52.000000000 +0400
-+++ iam/fs/ext3/iam_lfix.c 2006-06-08 00:36:08.000000000 +0400
-@@ -0,0 +1,610 @@
++++ iam/fs/ext3/iam_lfix.c 2006-06-08 17:34:38.000000000 +0400
+@@ -0,0 +1,613 @@
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ struct iam_lentry *p, *q, *m, *t;
+ struct iam_container *c;
+ int count;
++ int result;
+
+ count = lentry_count_get(l);
+ if (count == 0)
-+ return -ENOENT;
++ return IAM_LOOKUP_EMPTY;
+
++ result = IAM_LOOKUP_OK;
+ c = iam_leaf_container(l);
+
+ p = l->il_entries;
+ * @k is less than the smallest key in the leaf
+ */
+ l->il_at = p;
++ result = IAM_LOOKUP_BEFORE;
+ } else if (iam_keycmp(c, iam_leaf_key_at(q), k) <= 0) {
+ l->il_at = q;
+ } else {
+ }
+ assert(iam_leaf_at_rec(l));
+
-+ return iam_keycmp(c, iam_leaf_key_at(l->il_at), k) != 0 ? -ENOENT : 0;
++ return result;
+}
+
+static void iam_lfix_key_set(struct iam_leaf *l, const struct iam_key *k)
Index: iam/include/linux/lustre_iam.h
===================================================================
--- iam.orig/include/linux/lustre_iam.h 2006-05-31 20:24:32.000000000 +0400
-+++ iam/include/linux/lustre_iam.h 2006-06-08 01:08:10.000000000 +0400
++++ iam/include/linux/lustre_iam.h 2006-06-08 21:50:42.000000000 +0400
@@ -1,9 +1,68 @@
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
Index: iam/fs/ext3/Makefile
===================================================================
---- iam.orig/fs/ext3/Makefile 2006-06-08 01:08:10.000000000 +0400
-+++ iam/fs/ext3/Makefile 2006-06-08 01:08:11.000000000 +0400
+--- iam.orig/fs/ext3/Makefile 2006-06-08 21:50:42.000000000 +0400
++++ iam/fs/ext3/Makefile 2006-06-08 21:50:42.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 \
ext3-$(CONFIG_EXT3_FS_POSIX_ACL) += acl.o
Index: iam/fs/ext3/file.c
===================================================================
---- iam.orig/fs/ext3/file.c 2006-06-08 01:08:10.000000000 +0400
-+++ iam/fs/ext3/file.c 2006-06-08 01:08:11.000000000 +0400
+--- iam.orig/fs/ext3/file.c 2006-06-08 21:50:42.000000000 +0400
++++ iam/fs/ext3/file.c 2006-06-08 21:50:42.000000000 +0400
@@ -23,6 +23,7 @@
#include <linux/jbd.h>
#include <linux/ext3_fs.h>
Index: iam/fs/ext3/iam-uapi.c
===================================================================
--- iam.orig/fs/ext3/iam-uapi.c 2004-04-06 17:27:52.000000000 +0400
-+++ iam/fs/ext3/iam-uapi.c 2006-06-08 01:08:11.000000000 +0400
-@@ -0,0 +1,256 @@
++++ iam/fs/ext3/iam-uapi.c 2006-06-08 21:50:42.000000000 +0400
+@@ -0,0 +1,349 @@
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+struct iam_private_info {
+ struct iam_container ipi_bag;
+ struct iam_descr ipi_descr;
++ struct iam_iterator ipi_it;
+ struct iam_path_descr *ipi_ipd;
+};
+
+ return filp->private_data;
+}
+
++static int iam_uapi_it(int cmd, struct inode *inode,
++ struct file *filp, struct iam_uapi_it *itop)
++{
++ struct iam_private_info *ipi;
++ struct iam_iterator *it;
++ enum iam_it_state st;
++ int result = 0;
++
++ ipi = get_ipi(filp);
++ it = &ipi->ipi_it;
++ st = it->ii_state;
++ switch (cmd) {
++ case IAM_IOC_IT_START:
++ result = iam_it_init(it, &ipi->ipi_bag,
++ IAM_IT_MOVE, ipi->ipi_ipd);
++ if (result == 0)
++ result = iam_it_get(it, itop->iui_op.iul_key);
++ break;
++ case IAM_IOC_IT_NEXT:
++ if (st == IAM_IT_ATTACHED ||
++ st == IAM_IT_BEFORE || st == IAM_IT_EMPTY)
++ result = iam_it_next(it);
++ else
++ result = -EBUSY;
++ break;
++ case IAM_IOC_IT_STOP:
++ iam_it_put(it);
++ iam_it_fini(it);
++ result = 0;
++ break;
++ }
++ st = it->ii_state;
++ if (st == IAM_IT_ATTACHED || st == IAM_IT_BEFORE)
++ iam_keycpy0(&ipi->ipi_bag, itop->iui_op.iul_key,
++ iam_it_key_get(it, itop->iui_op.iul_key));
++ if (st == IAM_IT_ATTACHED)
++ iam_reccpy(&it->ii_path,
++ itop->iui_op.iul_rec, iam_it_rec_get(it));
++ itop->iui_state = st;
++ return result;
++}
++
+static int iam_uapi_op(int cmd, struct inode *inode,
+ struct file *filp, struct iam_uapi_op *op)
+{
+ struct iam_private_info *info;
+
+ info = filp->private_data;
++ iam_it_put(&info->ipi_it);
++ iam_it_fini(&info->ipi_it);
+ iam_container_fini(&info->ipi_bag);
+ if (info->ipi_ipd != NULL)
+ iam_ipd_free(info->ipi_ipd);
+}
+
+enum outop_t {
-+ KEY = 1 << 0,
-+ REC = 1 << 1
++ KEY = 1 << 0,
++ REC = 1 << 1,
++ STATE = 1 << 2
+};
+
+static int outop(struct iam_uapi_op *op, struct iam_uapi_op *uop,
+ return result;
+}
+
++static int outit(struct iam_uapi_it *it, struct iam_uapi_it *uit,
++ struct iam_descr *des, enum outop_t opt, unsigned long arg)
++{
++ int result;
++
++ result = outop(&it->iui_op, &uit->iui_op, des, opt);
++ if (result == 0 && (opt&STATE))
++ result = put_user(it->iui_state, (int __user *) arg);
++ return result;
++}
++
++static void putit(struct iam_uapi_it *it)
++{
++ putop(&it->iui_op);
++}
++
++static int getit(struct iam_uapi_it *it, struct iam_uapi_it *uit,
++ struct iam_descr *des, unsigned long arg)
++{
++ return getop(&it->iui_op, &uit->iui_op, des,
++ (unsigned long)&((struct iam_uapi_it *)arg)->iui_op);
++}
++
+int iam_uapi_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ int result;
-+ union {
-+ struct iam_uapi_info ua;
-+ struct iam_uapi_op op;
-+ } u;
-+ struct iam_uapi_op uop;
++ struct iam_uapi_info ua;
++ struct iam_uapi_op uop;
++ struct iam_uapi_op op;
++ struct iam_uapi_it uit;
++ struct iam_uapi_it it;
++ enum outop_t opt;
+
+ if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+ result = -EACCES;
+ result = -EBADF;
+ else if (cmd == IAM_IOC_INIT) {
+ if (filp->private_data == NULL) {
-+ result = getua(&u.ua, arg);
++ result = getua(&ua, arg);
+ if (result == 0)
-+ result = iam_uapi_init(inode, filp, &u.ua);
++ result = iam_uapi_init(inode, filp, &ua);
+ } else
+ result = -EBUSY;
+ } else if (is_dx(inode) && filp->private_data != NULL) {
+ struct iam_descr *des;
+
++ switch (cmd) {
++ case IAM_IOC_IT_START:
++ case IAM_IOC_IT_NEXT:
++ opt = KEY|REC|STATE;
++ break;
++ case IAM_IOC_LOOKUP:
++ opt = REC;
++ break;
++ default:
++ opt = 0;
++ break;
++ }
++
+ des = &get_ipi(filp)->ipi_descr;
+ if (cmd == IAM_IOC_GETINFO) {
-+ u.ua.iui_keysize = des->id_key_size;
-+ u.ua.iui_recsize = des->id_rec_size;
-+ u.ua.iui_ptrsize = des->id_ptr_size;
-+ u.ua.iui_height = 0; /* not yet */
-+ memcpy(u.ua.iui_fmt_name, des->id_ops->id_name,
-+ ARRAY_SIZE(u.ua.iui_fmt_name));
-+ result = putua(&u.ua, arg);
++ ua.iui_keysize = des->id_key_size;
++ ua.iui_recsize = des->id_rec_size;
++ ua.iui_ptrsize = des->id_ptr_size;
++ ua.iui_height = 0; /* not yet */
++ memcpy(ua.iui_fmt_name, des->id_ops->id_name,
++ ARRAY_SIZE(ua.iui_fmt_name));
++ result = putua(&ua, arg);
+ } else if (cmd == IAM_IOC_INSERT || cmd == IAM_IOC_LOOKUP ||
+ cmd == IAM_IOC_DELETE) {
-+ result = getop(&u.op, &uop, des, arg);
++ result = getop(&op, &uop, des, arg);
++ if (result == 0) {
++ int res2;
++ result = iam_uapi_op(cmd, inode, filp, &op);
++
++ res2 = outop(&op, &uop, des, opt);
++ result = result ? : res2;
++ putop(&op);
++ }
++ } else if (cmd == IAM_IOC_IT_START || cmd == IAM_IOC_IT_NEXT ||
++ cmd == IAM_IOC_IT_STOP) {
++ result = getit(&it, &uit, des, arg);
+ if (result == 0) {
-+ result = iam_uapi_op(cmd, inode, filp, &u.op);
-+ if (cmd == IAM_IOC_LOOKUP) {
-+ int res2;
-+
-+ res2 = outop(&u.op, &uop, des, REC);
-+ result = result ? : res2;
-+ }
-+ putop(&u.op);
++ int res2;
++
++ result = iam_uapi_it(cmd, inode, filp, &it);
++
++ res2 = outit(&it, &uit, des, opt, arg);
++ result = result ? : res2;
++ putit(&it);
+ }
+ } else
+ result = -EINVAL;
+}
Index: iam/include/linux/lustre_iam.h
===================================================================
---- iam.orig/include/linux/lustre_iam.h 2006-06-08 01:08:10.000000000 +0400
-+++ iam/include/linux/lustre_iam.h 2006-06-08 01:08:11.000000000 +0400
+--- iam.orig/include/linux/lustre_iam.h 2006-06-08 21:50:42.000000000 +0400
++++ iam/include/linux/lustre_iam.h 2006-06-08 21:50:42.000000000 +0400
@@ -30,9 +30,6 @@
#ifndef __LINUX_LUSTRE_IAM_H__
#define __LINUX_LUSTRE_IAM_H__
typedef __u64 iam_ptr_t;
/*
-@@ -131,11 +132,15 @@ struct iam_operations {
+@@ -123,6 +124,21 @@ struct iam_leaf {
+ void *il_descr_data;
+ };
+
++enum iam_lookup_t {
++ /*
++ * lookup positioned leaf on some record
++ */
++ IAM_LOOKUP_OK,
++ /*
++ * leaf was empty
++ */
++ IAM_LOOKUP_EMPTY,
++ /*
++ * lookup positioned leaf before first record
++ */
++ IAM_LOOKUP_BEFORE
++};
++
+ struct iam_operations {
+ /*
+ * Returns pointer (in the same sense as pointer in index entry) to
+@@ -131,11 +147,15 @@ struct iam_operations {
__u32 (*id_root_ptr)(struct iam_container *c);
/*
* Initialize new node (stored in @bh) that is going to be added into
* tree.
*/
-@@ -155,6 +160,10 @@ struct iam_operations {
+@@ -155,6 +175,10 @@ struct iam_operations {
* contains single record with the smallest possible key.
*/
int (*id_create)(struct iam_container *c);
/*
* Format name.
*/
-@@ -226,7 +235,8 @@ struct iam_leaf_operations {
+@@ -226,7 +250,8 @@ struct iam_leaf_operations {
* split leaf node, moving some entries into @bh (the latter currently
* is assumed to be empty).
*/
};
struct iam_path *iam_leaf_path(const struct iam_leaf *leaf);
-@@ -468,7 +478,7 @@ int iam_it_next(struct iam_iterator *it)
+@@ -347,7 +372,13 @@ enum iam_it_state {
+ /* initial state */
+ IAM_IT_DETACHED,
+ /* iterator is above particular record in the container */
+- IAM_IT_ATTACHED
++ IAM_IT_ATTACHED,
++ /* iterator landed into empty leaf */
++ IAM_IT_EMPTY,
++ /* iterator is positioned before first record in the leaf */
++ IAM_IT_BEFORE,
++ /* end of container reached */
++ IAM_IT_EOC
+ };
+
+ /*
+@@ -468,7 +499,7 @@ int iam_it_next(struct iam_iterator *it)
/*
* Return pointer to the record under iterator.
*
* postcondition: it_state(it) == IAM_IT_ATTACHED
*/
struct iam_rec *iam_it_rec_get(const struct iam_iterator *it);
-@@ -476,7 +486,9 @@ struct iam_rec *iam_it_rec_get(const str
+@@ -476,7 +507,9 @@ struct iam_rec *iam_it_rec_get(const str
/*
* Replace contents of record under iterator.
*
* postcondition: it_state(it) == IAM_IT_ATTACHED &&
* ergo(result == 0, !memcmp(iam_it_rec_get(it), r, ...))
*/
-@@ -485,7 +497,7 @@ int iam_it_rec_set(handle_t *h, struct i
+@@ -485,7 +518,7 @@ int iam_it_rec_set(handle_t *h, struct i
/*
* Place key under iterator in @k, return @k
*
* postcondition: it_state(it) == IAM_IT_ATTACHED
*/
struct iam_key *iam_it_key_get(const struct iam_iterator *it,
-@@ -497,7 +509,8 @@ struct iam_key *iam_it_key_get(const str
+@@ -497,7 +530,8 @@ struct iam_key *iam_it_key_get(const str
*
* precondition: it_state(it) == IAM_IT_ATTACHED &&
* it->ii_flags&IAM_IT_WRITE &&
* postcondition: it_state(it) == IAM_IT_ATTACHED &&
* ergo(result == 0,
* it_keycmp(it, iam_it_key_get(it, *), k) == 0 &&
-@@ -508,7 +521,9 @@ int iam_it_rec_insert(handle_t *h, struc
+@@ -508,7 +542,9 @@ int iam_it_rec_insert(handle_t *h, struc
/*
* Delete record under iterator.
*
* postcondition: it_state(it) == IAM_IT_ATTACHED
*/
int iam_it_rec_delete(handle_t *h, struct iam_iterator *it);
-@@ -519,7 +534,8 @@ typedef __u64 iam_pos_t;
+@@ -519,7 +555,8 @@ typedef __u64 iam_pos_t;
* Convert iterator to cookie.
*
* precondition: it_state(it) == IAM_IT_ATTACHED &&
* postcondition: it_state(it) == IAM_IT_ATTACHED
*/
iam_pos_t iam_it_store(const struct iam_iterator *it);
-@@ -650,6 +666,15 @@ static inline unsigned dx_node_limit(str
+@@ -583,6 +620,17 @@ static inline void iam_keycpy(const stru
+ memcpy(k1, k2, c->ic_descr->id_key_size);
+ }
+
++/*
++ * Helper for the frequent case, where key was already placed into @k1 by
++ * callback.
++ */
++static inline void iam_keycpy0(const struct iam_container *c,
++ struct iam_key *k1, const struct iam_key *k2)
++{
++ if (k1 != k2)
++ iam_keycpy(c, k1, k2);
++}
++
+ static inline int iam_keycmp(const struct iam_container *c,
+ const struct iam_key *k1, const struct iam_key *k2)
+ {
+@@ -650,6 +698,15 @@ static inline unsigned dx_node_limit(str
return entry_space / (param->id_key_size + param->id_ptr_size);
}
static inline struct iam_entry *dx_get_entries(struct iam_path *path,
void *data, int root)
{
-@@ -702,6 +727,8 @@ void iam_insert_key(struct iam_path *pat
+@@ -702,6 +759,8 @@ void iam_insert_key(struct iam_path *pat
int iam_leaf_at_end(const struct iam_leaf *l);
void iam_leaf_next(struct iam_leaf *folio);
struct iam_path *iam_leaf_path(const struct iam_leaf *leaf);
struct iam_container *iam_leaf_container(const struct iam_leaf *leaf);
-@@ -718,5 +745,40 @@ void iam_format_register(struct iam_form
+@@ -718,5 +777,48 @@ void iam_format_register(struct iam_form
void iam_lfix_format_init(void);
+ void *iul_rec;
+};
+
++struct iam_uapi_it {
++ struct iam_uapi_op iui_op;
++ __u16 iui_state;
++};
++
+enum iam_ioctl_cmd {
+ IAM_IOC_INIT = _IOW('i', 1, struct iam_uapi_info),
+ IAM_IOC_GETINFO = _IOR('i', 2, struct iam_uapi_info),
+ IAM_IOC_INSERT = _IOR('i', 3, struct iam_uapi_op),
+ IAM_IOC_LOOKUP = _IOWR('i', 4, struct iam_uapi_op),
-+ IAM_IOC_DELETE = _IOR('i', 5, struct iam_uapi_op)
++ IAM_IOC_DELETE = _IOR('i', 5, struct iam_uapi_op),
++ IAM_IOC_IT_START = _IOR('i', 6, struct iam_uapi_it),
++ IAM_IOC_IT_NEXT = _IOW('i', 7, struct iam_uapi_it),
++ IAM_IOC_IT_STOP = _IOR('i', 8, struct iam_uapi_it)
+};
+
/* __LINUX_LUSTRE_IAM_H__ */
#include <fcntl.h>
#include <string.h>
#include <errno.h>
+#include <assert.h>
#include <sys/types.h>
void *iul_rec;
};
+struct iam_uapi_it {
+ struct iam_uapi_op iui_op;
+ __u16 iui_state;
+};
+
enum iam_ioctl_cmd {
IAM_IOC_INIT = _IOW('i', 1, struct iam_uapi_info),
IAM_IOC_GETINFO = _IOR('i', 2, struct iam_uapi_info),
IAM_IOC_INSERT = _IOR('i', 3, struct iam_uapi_op),
IAM_IOC_LOOKUP = _IOWR('i', 4, struct iam_uapi_op),
- IAM_IOC_DELETE = _IOR('i', 5, struct iam_uapi_op)
+ IAM_IOC_DELETE = _IOR('i', 5, struct iam_uapi_op),
+ IAM_IOC_IT_START = _IOR('i', 6, struct iam_uapi_it),
+ IAM_IOC_IT_NEXT = _IOW('i', 7, struct iam_uapi_it),
+ IAM_IOC_IT_STOP = _IOR('i', 8, struct iam_uapi_it)
};
static void usage(void)
return result;
}
+static int doit(int fd, const void *key, const void *rec,
+ int cmd, const char *name)
+{
+ int result;
+
+ struct iam_uapi_it it = {
+ .iui_op = {
+ .iul_key = key,
+ .iul_rec = rec
+ },
+ .iui_state = 0
+ };
+
+ assert((void *)&it == (void *)&it.iui_op);
+
+ result = ioctl(fd, cmd, &it);
+ if (result != 0)
+ fprintf(stderr, "ioctl(%s): %i/%i (%m)\n", name, result, errno);
+ else
+ result = it.iui_state;
+ return result;
+}
+
static int insert(int fd, const void *key, const void *rec)
{
return doop(fd, key, rec, IAM_IOC_INSERT, "IAM_IOC_INSERT");
OP_TEST,
OP_INSERT,
OP_LOOKUP,
- OP_DELETE
+ OP_DELETE,
+ OP_IT_START,
+ OP_IT_NEXT,
+ OP_IT_STOP
};
int main(int argc, char **argv)
int opt;
int keysize;
int recsize;
+ int N = 0x10000;
int verbose = 0;
+ int doinit = 1;
enum op op;
op = OP_TEST;
do {
- opt = getopt(argc, argv, "vilk:r:d");
+ opt = getopt(argc, argv, "vilk:N:r:dsSn");
switch (opt) {
case 'v':
verbose++;
case 'k':
key_opt = optarg;
break;
+ case 'N':
+ N = atoi(optarg);
+ break;
case 'r':
rec_opt = optarg;
break;
case 'd':
op = OP_DELETE;
break;
+ case 's':
+ op = OP_IT_START;
+ break;
+ case 'S':
+ op = OP_IT_STOP;
+ doinit = 0;
+ break;
+ case 'n':
+ op = OP_IT_NEXT;
+ doinit = 0;
+ break;
case '?':
default:
fprintf(stderr, "Unable to parse options.");
}
} while (opt != -1);
- rc = ioctl(0, IAM_IOC_INIT, &ua);
- if (rc != 0) {
- fprintf(stderr, "ioctl(IAM_IOC_INIT): %i (%m)\n", rc);
- return 1;
+ if (doinit) {
+ rc = ioctl(0, IAM_IOC_INIT, &ua);
+ if (rc != 0) {
+ fprintf(stderr, "ioctl(IAM_IOC_INIT): %i (%m)\n", rc);
+ return 1;
+ }
}
rc = ioctl(0, IAM_IOC_GETINFO, &ua);
if (rc != 0) {
strncpy(rec, rec_opt ? : "PALEFIRE", recsize + 1);
if (op == OP_INSERT)
- return insert(0, key, rec);
+ return doop(0, key, rec, IAM_IOC_INSERT, "IAM_IOC_INSERT");
else if (op == OP_DELETE)
- return delete(0, key, rec);
+ return doop(0, key, rec, IAM_IOC_DELETE, "IAM_IOC_DELETE");
else if (op == OP_LOOKUP) {
- rc = lookup(0, key, rec);
+ rc = doop(0, key, rec, IAM_IOC_LOOKUP, "IAM_IOC_LOOKUP");
if (rc == 0)
print_rec(rec, recsize);
return rc;
+ } else if (op == OP_IT_START) {
+ rc = doop(0, key, rec, IAM_IOC_IT_START, "IAM_IOC_IT_START");
+ if (rc == 0) {
+ print_rec(key, keysize);
+ print_rec(rec, recsize);
+ }
+ return rc;
+ } else if (op == OP_IT_STOP) {
+ return doop(0, key, rec, IAM_IOC_IT_STOP, "IAM_IOC_IT_STOP");
+ } else if (op == OP_IT_NEXT) {
+ rc = doop(0, key, rec, IAM_IOC_IT_NEXT, "IAM_IOC_IT_NEXT");
+ if (rc == 0) {
+ print_rec(key, keysize);
+ print_rec(rec, recsize);
+ }
+ return rc;
}
rc = insert(0, key, rec);
print_rec(rec, recsize);
- for (i = 0; i < 0x10000; ++i) {
+ for (i = 0; i < N; ++i) {
memset(key, 0, keysize + 1);
memset(rec, 0, recsize + 1);
- snprintf(key, keysize, "y-%x-x", i);
- snprintf(rec, recsize, "p-%x-q", 1000 - i);
+ snprintf(key, keysize + 1, "y-%x-x", i);
+ snprintf(rec, recsize + 1, "p-%x-q", 1000 - i);
rc = insert(0, key, rec);
if (rc != 0)
return 1;