From b5435bd46153e73984e02fa35cae6072fe3a458b Mon Sep 17 00:00:00 2001 From: nikita Date: Thu, 8 Jun 2006 22:13:29 +0000 Subject: [PATCH] cleanup of iam code: add explicit states for leaves. --- .../kernel_patches/patches/ext3-iam-separate.patch | 189 ++++++++++------ lustre/kernel_patches/patches/ext3-iam-uapi.patch | 248 +++++++++++++++++---- lustre/tests/iam_ut | Bin 59583 -> 61622 bytes lustre/tests/iam_ut.c | 95 ++++++-- 4 files changed, 399 insertions(+), 133 deletions(-) diff --git a/lustre/kernel_patches/patches/ext3-iam-separate.patch b/lustre/kernel_patches/patches/ext3-iam-separate.patch index e6af788..0ac62184 100644 --- a/lustre/kernel_patches/patches/ext3-iam-separate.patch +++ b/lustre/kernel_patches/patches/ext3-iam-separate.patch @@ -1,7 +1,7 @@ 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 \ @@ -14,8 +14,8 @@ Index: iam/fs/ext3/Makefile 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: + * @@ -599,7 +599,7 @@ Index: iam/fs/ext3/iam.c + 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; @@ -615,8 +615,8 @@ Index: iam/fs/ext3/iam.c + 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; +} @@ -629,9 +629,8 @@ Index: iam/fs/ext3/iam.c + * -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) +{ @@ -641,14 +640,30 @@ Index: iam/fs/ext3/iam.c + 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; +} + @@ -686,7 +701,7 @@ Index: iam/fs/ext3/iam.c + */ +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); @@ -706,39 +721,44 @@ Index: iam/fs/ext3/iam.c +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; +} + @@ -797,12 +817,14 @@ Index: iam/fs/ext3/iam.c +/* + * 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); +} @@ -873,11 +895,18 @@ Index: iam/fs/ext3/iam.c + * 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, ...)) + */ @@ -889,25 +918,20 @@ Index: iam/fs/ext3/iam.c + + 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, @@ -915,38 +939,46 @@ Index: iam/fs/ext3/iam.c + 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; +} + @@ -1035,10 +1067,16 @@ Index: iam/fs/ext3/iam.c +{ + 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))); +} + +/* @@ -1144,8 +1182,8 @@ Index: iam/fs/ext3/iam.c 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: + * @@ -1351,11 +1389,13 @@ Index: iam/fs/ext3/iam_lfix.c + 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; @@ -1365,6 +1405,7 @@ Index: iam/fs/ext3/iam_lfix.c + * @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 { @@ -1392,7 +1433,7 @@ Index: iam/fs/ext3/iam_lfix.c + } + 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) @@ -3392,7 +3433,7 @@ Index: iam/fs/ext3/namei.c 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: diff --git a/lustre/kernel_patches/patches/ext3-iam-uapi.patch b/lustre/kernel_patches/patches/ext3-iam-uapi.patch index 8a66ab0..9209dfb 100644 --- a/lustre/kernel_patches/patches/ext3-iam-uapi.patch +++ b/lustre/kernel_patches/patches/ext3-iam-uapi.patch @@ -1,7 +1,7 @@ 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 \ @@ -13,8 +13,8 @@ Index: iam/fs/ext3/Makefile 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 #include @@ -50,8 +50,8 @@ Index: iam/fs/ext3/file.c 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: + * @@ -94,6 +94,7 @@ Index: iam/fs/ext3/iam-uapi.c +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; +}; + @@ -106,6 +107,48 @@ Index: iam/fs/ext3/iam-uapi.c + 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) +{ @@ -151,6 +194,8 @@ Index: iam/fs/ext3/iam-uapi.c + 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); @@ -207,8 +252,9 @@ Index: iam/fs/ext3/iam-uapi.c +} + +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, @@ -256,15 +302,39 @@ Index: iam/fs/ext3/iam-uapi.c + 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; @@ -272,35 +342,58 @@ Index: iam/fs/ext3/iam-uapi.c + 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; @@ -310,8 +403,8 @@ Index: iam/fs/ext3/iam-uapi.c +} 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__ @@ -350,7 +443,29 @@ Index: iam/include/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); /* @@ -368,7 +483,7 @@ Index: iam/include/linux/lustre_iam.h * 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); @@ -379,7 +494,7 @@ Index: iam/include/linux/lustre_iam.h /* * 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). */ @@ -389,7 +504,22 @@ Index: iam/include/linux/lustre_iam.h }; 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. * @@ -398,7 +528,7 @@ Index: iam/include/linux/lustre_iam.h * 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. * @@ -409,7 +539,7 @@ Index: iam/include/linux/lustre_iam.h * 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 * @@ -418,7 +548,7 @@ Index: iam/include/linux/lustre_iam.h * 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 && @@ -428,7 +558,7 @@ Index: iam/include/linux/lustre_iam.h * 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. * @@ -439,7 +569,7 @@ Index: iam/include/linux/lustre_iam.h * 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 && @@ -449,7 +579,25 @@ Index: iam/include/linux/lustre_iam.h * 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); } @@ -465,7 +613,7 @@ Index: iam/include/linux/lustre_iam.h 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); @@ -474,7 +622,7 @@ Index: iam/include/linux/lustre_iam.h 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); @@ -505,12 +653,20 @@ Index: iam/include/linux/lustre_iam.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) +}; + /* __LINUX_LUSTRE_IAM_H__ */ diff --git a/lustre/tests/iam_ut b/lustre/tests/iam_ut index 28097e9f48a37402c23ddcc6e503fc21c5e6bac3..01431972946d55c18b2d85d4a8a7f4a00ab5a89a 100755 GIT binary patch delta 29121 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 R`(Fb#`!an;=&Q%%{{iQKC+q+K delta 27208 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 NzWHtYpWp73{~t$J)1UwV diff --git a/lustre/tests/iam_ut.c b/lustre/tests/iam_ut.c index b4a4ac2..3af3d1f 100644 --- a/lustre/tests/iam_ut.c +++ b/lustre/tests/iam_ut.c @@ -32,6 +32,7 @@ #include #include #include +#include #include @@ -61,12 +62,20 @@ struct iam_uapi_op { 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) @@ -89,6 +98,29 @@ static int doop(int fd, const void *key, const void *rec, 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"); @@ -120,7 +152,10 @@ enum op { 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) @@ -130,7 +165,9 @@ int main(int argc, char **argv) int opt; int keysize; int recsize; + int N = 0x10000; int verbose = 0; + int doinit = 1; enum op op; @@ -151,7 +188,7 @@ int main(int argc, char **argv) op = OP_TEST; do { - opt = getopt(argc, argv, "vilk:r:d"); + opt = getopt(argc, argv, "vilk:N:r:dsSn"); switch (opt) { case 'v': verbose++; @@ -160,6 +197,9 @@ int main(int argc, char **argv) case 'k': key_opt = optarg; break; + case 'N': + N = atoi(optarg); + break; case 'r': rec_opt = optarg; break; @@ -172,6 +212,17 @@ int main(int argc, char **argv) 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."); @@ -181,10 +232,12 @@ int main(int argc, char **argv) } } 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) { @@ -212,14 +265,30 @@ int main(int argc, char **argv) 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); @@ -243,11 +312,11 @@ int main(int argc, char **argv) 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; -- 1.8.3.1