--- /dev/null
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ * libiam.h
+ * iam user level library
+ *
+ * Copyright (c) 2006 Cluster File Systems, Inc.
+ * Author: Wang Di <wangdi@clusterfs.com>
+ * Author: Nikita Danilov <nikita@clusterfs.com>
+ * Author: Fan Yong <fanyong@clusterfs.com>
+ *
+ * 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.
+ */
+
+/*
+ * lustre/libiam.h
+ */
+
+#ifndef __IAM_ULIB_H__
+#define __IAM_ULIB_H__
+
+
+#define SET_DEFAULT -1
+#define DX_FMT_NAME_LEN 16
+
+enum iam_fmt_t {
+ FMT_LFIX,
+ FMT_LVAR
+};
+
+struct iam_uapi_info {
+ __u16 iui_keysize;
+ __u16 iui_recsize;
+ __u16 iui_ptrsize;
+ __u16 iui_height;
+ char iui_fmt_name[DX_FMT_NAME_LEN];
+};
+
+/*
+ * Creat an iam file, but do NOT open it.
+ * Return 0 if success, else -1.
+ */
+int iam_creat(char *filename, enum iam_fmt_t fmt,
+ int blocksize, int keysize, int recsize, int ptrsize);
+
+/*
+ * Open an iam file, but do NOT creat it if the file doesn't exist.
+ * Please use iam_creat for creating the file before use iam_open.
+ * Return file id (fd) if success, else -1.
+ */
+int iam_open(char *filename, struct iam_uapi_info *ua);
+
+/*
+ * Close file opened by iam_open.
+ */
+int iam_close(int fd);
+
+/*
+ * Please use iam_open before use this function.
+ */
+int iam_insert(int fd, struct iam_uapi_info *ua,
+ int key_need_convert, char *keybuf,
+ int rec_need_convert, char *recbuf);
+
+/*
+ * Please use iam_open before use this function.
+ */
+int iam_lookup(int fd, struct iam_uapi_info *ua,
+ int key_need_convert, char *key_buf,
+ int *keysize, char *save_key,
+ int rec_need_convert, char *rec_buf,
+ int *recsize, char *save_rec);
+
+/*
+ * Please use iam_open before use this function.
+ */
+int iam_delete(int fd, struct iam_uapi_info *ua,
+ int key_need_convert, char *keybuf,
+ int rec_need_convert, char *recbuf);
+
+/*
+ * Please use iam_open before use this function.
+ */
+int iam_it_start(int fd, struct iam_uapi_info *ua,
+ int key_need_convert, char *key_buf,
+ int *keysize, char *save_key,
+ int rec_need_convert, char *rec_buf,
+ int *recsize, char *save_rec);
+
+/*
+ * Please use iam_open before use this function.
+ */
+int iam_it_next(int fd, struct iam_uapi_info *ua,
+ int key_need_convert, char *key_buf,
+ int *keysize, char *save_key,
+ int rec_need_convert, char *rec_buf,
+ int *recsize, char *save_rec);
+
+/*
+ * Please use iam_open before use this function.
+ */
+int iam_it_stop(int fd, struct iam_uapi_info *ua,
+ int key_need_convert, char *keybuf,
+ int rec_need_convert, char *recbuf);
+
+/*
+ * Change iam file mode.
+ */
+int iam_polymorph(char *filename, unsigned long mode);
+
+
+#endif
--- /dev/null
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ * libiam.c
+ * iam user level library
+ *
+ * Copyright (c) 2006 Cluster File Systems, Inc.
+ * Author: Wang Di <wangdi@clusterfs.com>
+ * Author: Nikita Danilov <nikita@clusterfs.com>
+ * Author: Fan Yong <fanyong@clusterfs.com>
+ *
+ * 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.
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+
+#include <sys/types.h>
+
+#ifdef HAVE_ENDIAN_H
+#include <endian.h>
+#endif
+
+#include <libcfs/libcfs.h>
+
+#include <lustre/libiam.h>
+
+typedef __u32 lvar_hash_t;
+
+enum {
+ IAM_LFIX_ROOT_MAGIC = 0xbedabb1edULL,
+ IAM_LVAR_ROOT_MAGIC = 0xb01dface
+};
+
+struct iam_lfix_root {
+ u_int64_t ilr_magic;
+ u_int16_t ilr_keysize;
+ u_int16_t ilr_recsize;
+ u_int16_t ilr_ptrsize;
+ u_int16_t ilr_indirect_levels;
+};
+
+enum {
+ IAM_LEAF_HEADER_MAGIC = 0x1976,
+ IAM_LVAR_LEAF_MAGIC = 0x1973
+};
+
+struct iam_leaf_head {
+ u_int16_t ill_magic;
+ u_int16_t ill_count;
+};
+
+struct dx_countlimit {
+ u_int16_t limit;
+ u_int16_t count;
+};
+
+struct lvar_leaf_header {
+ u_int16_t vlh_magic; /* magic number IAM_LVAR_LEAF_MAGIC */
+ u_int16_t vlh_used; /* used bytes, including header */
+};
+
+struct lvar_root {
+ u_int32_t vr_magic;
+ u_int16_t vr_recsize;
+ u_int16_t vr_ptrsize;
+ u_int8_t vr_indirect_levels;
+ u_int8_t vr_padding0;
+ u_int16_t vr_padding1;
+};
+
+struct lvar_leaf_entry {
+ u_int32_t vle_hash;
+ u_int16_t vle_keysize;
+ u_int8_t vle_key[0];
+};
+
+enum {
+ LVAR_PAD = 4,
+ LVAR_ROUND = LVAR_PAD - 1
+};
+
+static void lfix_root(void *buf,
+ int blocksize, int keysize, int ptrsize, int recsize)
+{
+ struct iam_lfix_root *root;
+ struct dx_countlimit *limit;
+ void *entry;
+
+ root = buf;
+ *root = (typeof(*root)) {
+ .ilr_magic = cpu_to_le64(IAM_LFIX_ROOT_MAGIC),
+ .ilr_keysize = cpu_to_le16(keysize),
+ .ilr_recsize = cpu_to_le16(recsize),
+ .ilr_ptrsize = cpu_to_le16(ptrsize),
+ .ilr_indirect_levels = 0
+ };
+
+ limit = (void *)(root + 1);
+ *limit = (typeof(*limit)){
+ /*
+ * limit itself + one pointer to the leaf.
+ */
+ .count = cpu_to_le16(2),
+ .limit = (blocksize - sizeof *root) / (keysize + ptrsize)
+ };
+
+ entry = root + 1;
+ /*
+ * Skip over @limit.
+ */
+ entry += keysize + ptrsize;
+
+ /*
+ * Entry format is <key> followed by <ptr>. In the minimal tree
+ * consisting of a root and single node, <key> is a minimal possible
+ * key.
+ *
+ * XXX: this key is hard-coded to be a sequence of 0's.
+ */
+ entry += keysize;
+ /* now @entry points to <ptr> */
+ if (ptrsize == 4)
+ *(u_int32_t *)entry = cpu_to_le32(1);
+ else
+ *(u_int64_t *)entry = cpu_to_le64(1);
+}
+
+static void lfix_leaf(void *buf,
+ int blocksize, int keysize, int ptrsize, int recsize)
+{
+ struct iam_leaf_head *head;
+
+ /* form leaf */
+ head = buf;
+ *head = (struct iam_leaf_head) {
+ .ill_magic = cpu_to_le16(IAM_LEAF_HEADER_MAGIC),
+ /*
+ * Leaf contains an entry with the smallest possible key
+ * (created by zeroing).
+ */
+ .ill_count = cpu_to_le16(1),
+ };
+}
+
+static void lvar_root(void *buf,
+ int blocksize, int keysize, int ptrsize, int recsize)
+{
+ struct lvar_root *root;
+ struct dx_countlimit *limit;
+ void *entry;
+ int isize;
+
+ isize = sizeof(lvar_hash_t) + ptrsize;
+ root = buf;
+ *root = (typeof(*root)) {
+ .vr_magic = cpu_to_le32(IAM_LVAR_ROOT_MAGIC),
+ .vr_recsize = cpu_to_le16(recsize),
+ .vr_ptrsize = cpu_to_le16(ptrsize),
+ .vr_indirect_levels = 0
+ };
+
+ limit = (void *)(root + 1);
+ *limit = (typeof(*limit)){
+ /*
+ * limit itself + one pointer to the leaf.
+ */
+ .count = cpu_to_le16(2),
+ .limit = (blocksize - sizeof *root) / isize
+ };
+
+ entry = root + 1;
+ /*
+ * Skip over @limit.
+ */
+ entry += isize;
+
+ /*
+ * Entry format is <key> followed by <ptr>. In the minimal tree
+ * consisting of a root and single node, <key> is a minimal possible
+ * key.
+ *
+ * XXX: this key is hard-coded to be a sequence of 0's.
+ */
+ entry += sizeof(lvar_hash_t);
+ /* now @entry points to <ptr> */
+ if (ptrsize == 4)
+ *(u_int32_t *)entry = cpu_to_le32(1);
+ else
+ *(u_int64_t *)entry = cpu_to_le64(1);
+}
+
+static int lvar_esize(int namelen, int recsize)
+{
+ return (offsetof(struct lvar_leaf_entry, vle_key) +
+ namelen + recsize + LVAR_ROUND) & ~LVAR_ROUND;
+}
+
+static void lvar_leaf(void *buf,
+ int blocksize, int keysize, int ptrsize, int recsize)
+{
+ struct lvar_leaf_header *head;
+
+ /* form leaf */
+ head = buf;
+ *head = (typeof(*head)) {
+ .vlh_magic = cpu_to_le16(IAM_LVAR_LEAF_MAGIC),
+ .vlh_used = cpu_to_le16(sizeof *head + lvar_esize(0, recsize))
+ };
+}
+
+
+struct iam_uapi_op {
+ void *iul_key;
+ 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_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),
+ IAM_IOC_POLYMORPH = _IOR('i', 9, unsigned long)
+};
+
+static unsigned char hex2dec(unsigned char hex)
+{
+ if (('0' <= hex) && (hex <= '9'))
+ return hex - '0';
+ else if (('a' <= hex) && (hex <= 'f'))
+ return hex - 'a' + 10;
+ else if (('A' <= hex) && (hex <= 'F'))
+ return hex - 'A' + 10;
+ else
+ exit(1);
+}
+
+static unsigned char *packdigit(unsigned char *number)
+{
+ unsigned char *area;
+ unsigned char *scan;
+
+ area = calloc(strlen(number) / 2 + 2, sizeof(char));
+ if (area != NULL) {
+ for (scan = area; *number; number += 2, scan++)
+ *scan = (hex2dec(number[0]) << 4) | hex2dec(number[1]);
+ }
+ return area;
+}
+
+
+static char *iam_convert(int size, int need_convert, char *source)
+{
+ char *ptr;
+ char *opt;
+
+ if (source == NULL)
+ return NULL;
+
+ ptr = calloc(size + 1, sizeof(char));
+ if (ptr == NULL)
+ return NULL;
+
+ if (need_convert) {
+ opt = packdigit(source);
+ if (opt == NULL) {
+ free(ptr);
+ return NULL;
+ } else {
+ memcpy(ptr, opt, size + 1);
+ free(opt);
+ }
+ } else {
+ strncpy(ptr, source, size + 1);
+ }
+
+ return ptr;
+}
+
+static int iam_doop(int fd, struct iam_uapi_info *ua, int cmd,
+ int key_need_convert, char *key_buf,
+ int *keysize, char *save_key,
+ int rec_need_convert, char *rec_buf,
+ int *recsize, char *save_rec)
+{
+ int ret;
+ char *key;
+ char *rec;
+ struct iam_uapi_op op;
+
+ key = iam_convert(ua->iui_keysize, key_need_convert, key_buf);
+ if (key == NULL)
+ return -1;
+
+ rec = iam_convert(ua->iui_recsize, rec_need_convert, rec_buf);
+ if (rec == NULL) {
+ free(key);
+ return -1;
+ }
+
+ op.iul_key = key;
+ op.iul_rec = rec;
+ ret = ioctl(fd, cmd, &op);
+ if (ret == 0) {
+ if ((keysize != NULL) && (*keysize > 0) && (save_key != NULL)) {
+ if (*keysize > ua->iui_keysize)
+ *keysize = ua->iui_keysize;
+ memcpy(save_key, key, *keysize);
+ }
+ if ((recsize != NULL) && (*recsize > 0) && (save_rec != NULL)) {
+ if (*recsize > ua->iui_recsize)
+ *recsize = ua->iui_recsize;
+ memcpy(save_rec, rec, *recsize);
+ }
+ }
+ free(key);
+ free(rec);
+ return ret;
+}
+
+
+/*
+ * Creat an iam file, but do NOT open it.
+ * Return 0 if success, else -1.
+ */
+int iam_creat(char *filename, enum iam_fmt_t fmt,
+ int blocksize, int keysize, int recsize, int ptrsize)
+{
+ int fd;
+ char *buf;
+
+ if (filename == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if ((fmt != FMT_LFIX) && (fmt != FMT_LVAR)) {
+ errno = EOPNOTSUPP;
+ return -1;
+ }
+
+ if (blocksize == SET_DEFAULT) {
+ blocksize = 4096;
+ } else if (blocksize <= 100) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (keysize == SET_DEFAULT) {
+ keysize = 8;
+ } else if (keysize < 1) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (recsize == SET_DEFAULT) {
+ recsize = 8;
+ } else if (recsize < 0) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (ptrsize == SET_DEFAULT) {
+ ptrsize = 4;
+ } else if ((ptrsize != 4) && (ptrsize != 8)) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if ((keysize + recsize + sizeof(struct iam_leaf_head)) > (blocksize / 3)) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT, 0600);
+ if (fd < 0) {
+ return -1;
+ }
+
+ buf = malloc(blocksize);
+ if (buf == NULL) {
+ close(fd);
+ return -1;
+ }
+
+ memset(buf, 0, blocksize);
+ if (fmt == FMT_LFIX)
+ lfix_root(buf, blocksize, keysize, ptrsize, recsize);
+ else
+ lvar_root(buf, blocksize, keysize, ptrsize, recsize);
+
+ if (write(fd, buf, blocksize) != blocksize) {
+ close(fd);
+ free(buf);
+ return -1;
+ }
+
+ memset(buf, 0, blocksize);
+ if (fmt == FMT_LFIX)
+ lfix_leaf(buf, blocksize, keysize, ptrsize, recsize);
+ else
+ lvar_leaf(buf, blocksize, keysize, ptrsize, recsize);
+
+ if (write(fd, buf, blocksize) != blocksize) {
+ close(fd);
+ free(buf);
+ return -1;
+ }
+
+ close(fd);
+ free(buf);
+ return 0;
+}
+
+/*
+ * Open an iam file, but do NOT creat it if the file doesn't exist.
+ * Please use iam_creat for creating the file before use iam_open.
+ * Return file id (fd) if success, else -1.
+ */
+int iam_open(char *filename, struct iam_uapi_info *ua)
+{
+ int fd;
+
+ if (filename == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (ua == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ fd = open(filename, O_RDONLY);
+ if (fd < 0) {
+ return -1;
+ }
+
+ if (ioctl(fd, IAM_IOC_INIT, ua) != 0) {
+ close(fd);
+ return -1;
+ }
+
+ if (ioctl(fd, IAM_IOC_GETINFO, ua) != 0) {
+ close(fd);
+ return -1;
+ }
+
+ return fd;
+}
+
+/*
+ * Close file opened by iam_open.
+ */
+int iam_close(int fd)
+{
+ return close(fd);
+}
+
+/*
+ * Please use iam_open before use this function.
+ */
+int iam_insert(int fd, struct iam_uapi_info *ua,
+ int key_need_convert, char *key_buf,
+ int rec_need_convert, char *rec_buf)
+{
+ return iam_doop(fd, ua, IAM_IOC_INSERT,
+ key_need_convert, key_buf, NULL, NULL,
+ rec_need_convert, rec_buf, NULL, NULL);
+}
+
+/*
+ * Please use iam_open before use this function.
+ */
+int iam_lookup(int fd, struct iam_uapi_info *ua,
+ int key_need_convert, char *key_buf,
+ int *keysize, char *save_key,
+ int rec_need_convert, char *rec_buf,
+ int *recsize, char *save_rec)
+{
+ return iam_doop(fd, ua, IAM_IOC_LOOKUP,
+ key_need_convert, key_buf, keysize, save_key,
+ rec_need_convert, rec_buf, recsize, save_rec);
+}
+
+/*
+ * Please use iam_open before use this function.
+ */
+int iam_delete(int fd, struct iam_uapi_info *ua,
+ int key_need_convert, char *key_buf,
+ int rec_need_convert, char *rec_buf)
+{
+ return iam_doop(fd, ua, IAM_IOC_DELETE,
+ key_need_convert, key_buf, NULL, NULL,
+ rec_need_convert, rec_buf, NULL, NULL);
+}
+
+/*
+ * Please use iam_open before use this function.
+ */
+int iam_it_start(int fd, struct iam_uapi_info *ua,
+ int key_need_convert, char *key_buf,
+ int *keysize, char *save_key,
+ int rec_need_convert, char *rec_buf,
+ int *recsize, char *save_rec)
+{
+ return iam_doop(fd, ua, IAM_IOC_IT_START,
+ key_need_convert, key_buf, keysize, save_key,
+ rec_need_convert, rec_buf, recsize, save_rec);
+}
+
+/*
+ * Please use iam_open before use this function.
+ */
+int iam_it_next(int fd, struct iam_uapi_info *ua,
+ int key_need_convert, char *key_buf,
+ int *keysize, char *save_key,
+ int rec_need_convert, char *rec_buf,
+ int *recsize, char *save_rec)
+{
+ return iam_doop(fd, ua, IAM_IOC_IT_NEXT,
+ key_need_convert, key_buf, keysize, save_key,
+ rec_need_convert, rec_buf, recsize, save_rec);
+}
+
+/*
+ * Please use iam_open before use this function.
+ */
+int iam_it_stop(int fd, struct iam_uapi_info *ua,
+ int key_need_convert, char *key_buf,
+ int rec_need_convert, char *rec_buf)
+{
+ return iam_doop(fd, ua, IAM_IOC_IT_STOP,
+ key_need_convert, key_buf, NULL, NULL,
+ rec_need_convert, rec_buf, NULL, NULL);
+}
+
+/*
+ * Change iam file mode.
+ */
+int iam_polymorph(char *filename, unsigned long mode)
+{
+ int fd;
+ int ret;
+
+ if (filename == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ fd = open(filename, O_RDONLY);
+ if (fd < 0) {
+ return -1;
+ }
+
+ ret = ioctl(fd, IAM_IOC_POLYMORPH, mode);
+ close(fd);
+ return ret;
+}