Whamcloud - gitweb
mkfs_lustre.c
authorfanyong <fanyong>
Mon, 7 Aug 2006 03:08:57 +0000 (03:08 +0000)
committerfanyong <fanyong>
Mon, 7 Aug 2006 03:08:57 +0000 (03:08 +0000)
lustre/utils/mkfs_lustre.c

index 114fd04..6d28548 100644 (file)
@@ -853,6 +853,10 @@ static char *convert_hostnames(char *s1)
         lnet_nid_t nid;
         
         converted = malloc(left);
+        if (converted == NULL) {
+                return NULL;
+        }
+
         c = converted;
         while ((left > 0) && ((s2 = strsep(&s1, ",: \0")))) {
                 nid = libcfs_str2nid(s2);
@@ -1060,6 +1064,644 @@ int parse_opts(int argc, char *const argv[], struct mkfs_opts *mop,
         return 0;
 }
 
+
+#include <errno.h>
+#include <assert.h>
+
+#ifdef HAVE_ENDIAN_H
+#include <endian.h>
+#endif
+
+#include <libcfs/libcfs.h>
+
+/* Move from create_iam.c */
+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;
+};
+
+typedef __u32 lvar_hash_t;
+
+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))
+        };
+}
+
+enum iam_fmt_t {
+        FMT_LFIX,
+        FMT_LVAR
+};
+
+static int create_iam(enum iam_fmt_t fmt, int keysize, int recsize,
+                      char *target)
+{
+        int rc;
+        int blocksize = 4096;
+        int ptrsize   = 4;
+        int fd = -1;
+        void *buf = NULL;
+
+        if ((fmt != FMT_LFIX) && (fmt != FMT_LVAR)) {
+                fprintf(stderr, "Wrong format %i\n", (int)fmt);
+                return 1;
+        }
+
+        if (keysize <= 0) {
+                keysize = 8;
+        }
+
+        if (recsize <= 0) {
+                recsize = 8;
+        }
+
+        if (target == NULL) {
+                fprintf(stderr, "Target must not be NULL\n");
+                return 1;
+        }
+
+        if (keysize + recsize + sizeof(struct iam_leaf_head) > blocksize / 3) {
+                fprintf(stderr, "Too large (record, key) or too small block\n");
+                return 1;
+        }
+
+        vprint("fmt: %i, key: %i, rec: %i, ptr: %i, block: %i\n",
+               (int)fmt, keysize, recsize, ptrsize, blocksize);
+
+        fd = open(target, O_WRONLY | O_TRUNC | O_CREAT, 0600);
+        if (fd < 0) {
+                fprintf(stderr, "%s: failed to open %s, errno = %d\n",
+                        __FUNCTION__, target, errno);
+                return 1;
+        }
+
+        buf = malloc(blocksize);
+        if (buf == NULL) {
+                fprintf(stderr, "Unable to allocate %i bytes\n", blocksize);
+                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);
+        }
+
+        rc = write(fd, buf, blocksize);
+        if (rc != blocksize) {
+                fprintf(stderr, "Unable to write root node: %m (%i)\n", rc);
+                rc = 1;
+                goto out;
+        }
+
+        /* form leaf */
+        memset(buf, 0, blocksize);
+        if (fmt == FMT_LFIX) {
+                lfix_leaf(buf, blocksize, keysize, ptrsize, recsize);
+        } else {
+                lvar_leaf(buf, blocksize, keysize, ptrsize, recsize);
+        }
+
+        rc = write(fd, buf, blocksize);
+        if (rc != blocksize) {
+                fprintf(stderr, "Unable to write leaf node: %m (%i)\n", rc);
+                rc = 1;
+                goto out;
+        }
+
+        rc = 0;
+
+out:
+        close(fd);
+        free(buf);
+        return rc;
+}
+/* End of create_iam.c */
+
+/* Copy from iam_ut.c */
+enum {
+        /*
+         * Maximal format name length.
+         */
+        DX_FMT_NAME_LEN    = 16
+};
+
+struct iam_uapi_info {
+        __u16 iui_keysize;
+        __u16 iui_recsize;
+        __u16 iui_ptrsize;
+        __u16 iui_height;
+        char  iui_fmt_name[DX_FMT_NAME_LEN];
+};
+
+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_POLYMORPH = _IOR('i', 9, unsigned long)
+};
+
+static int doop(int fd, const void *key, const void *rec,
+                int cmd, const char *name)
+{
+        int result;
+
+        struct iam_uapi_op op = {
+                .iul_key = key,
+                .iul_rec = rec
+        };
+        result = ioctl(fd, cmd, &op);
+        if (result != 0)
+                fprintf(stderr, "ioctl(%s): %i/%i (%m)\n", name, result, errno);
+        return result;
+}
+
+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 {
+                fprintf(stderr, "Wrong hex digit '%c'\n", hex);
+                exit(1);
+        }
+}
+
+static unsigned char *packdigit(unsigned char *number)
+{
+        unsigned char *area;
+        unsigned char *scan;
+
+        area = calloc(strlen(number) / 2 + 2, sizeof area[0]);
+        if (area != NULL) {
+                for (scan = area; *number; number += 2, scan++)
+                        *scan = (hex2dec(number[0]) << 4) | hex2dec(number[1]);
+        }
+        return area;
+}
+
+static int iam_insert(int key_need_convert, char *keybuf,
+                      int rec_need_convert, char *recbuf, char *source)
+{
+        int rc;
+        int keysize;
+        int recsize;
+        int fd = -1;
+        char *key_opt;
+        char *rec_opt;
+        char *key = NULL;
+        char *rec = NULL;
+        void *(*copier)(void *, void *, size_t);
+        struct iam_uapi_info ua;
+
+        if (key_need_convert) {
+                key_opt = packdigit(keybuf);
+        } else {
+                key_opt = keybuf;
+        }
+
+        if (rec_need_convert) {
+                rec_opt = packdigit(recbuf);
+        } else {
+                rec_opt = recbuf;
+        }
+
+        if (source == NULL) {
+                fprintf(stderr, "source must not be NULL\n");
+                return 1;
+        }
+
+        fd = open(source, O_RDONLY);
+        if (fd < 0) {
+                fprintf(stderr, "%s: failed to open %s, errno = %d\n",
+                        __FUNCTION__, source, errno);
+                rc = 1;
+                goto out;
+        }
+
+        rc = ioctl(fd, IAM_IOC_INIT, &ua);
+        if (rc != 0) {
+                fprintf(stderr, "ioctl(IAM_IOC_INIT): %i (%m)\n", rc);
+                rc = 1;
+                goto out;
+        }
+
+        rc = ioctl(fd, IAM_IOC_GETINFO, &ua);
+        if (rc != 0) {
+                fprintf(stderr, "ioctl(IAM_IOC_GETATTR): %i (%m)\n", rc);
+                rc = 1;
+                goto out;
+        }
+
+        keysize = ua.iui_keysize;
+        recsize = ua.iui_recsize;
+        vprint("keysize: %i, recsize: %i, ptrsize: %i, "
+               "height: %i, name: %s\n",
+               keysize, recsize, ua.iui_ptrsize,
+               ua.iui_height, ua.iui_fmt_name);
+
+        key = calloc(keysize + 1, sizeof key[0]);
+        rec = calloc(recsize + 1, sizeof rec[0]);
+        if ((key == NULL) || (rec == NULL)) {
+                fprintf(stderr, "cannot allocate memory\n");
+                rc = 1;
+                goto out;
+        }
+
+        copier = (key_need_convert == 0) ? &strncpy : &memcpy;
+        copier(key, key_opt ? : "RIVERRUN", keysize + 1);
+        if (key_need_convert) {
+                free(key_opt);
+                key_opt = NULL;
+        }
+
+        copier = (rec_need_convert == 0) ? &strncpy : &memcpy;
+        copier(rec, rec_opt ? : "PALEFIRE", recsize + 1);
+        if (rec_need_convert) {
+                free(rec_opt);
+                rec_opt = NULL;
+        }
+
+        rc = doop(fd, key, rec, IAM_IOC_INSERT, "IAM_IOC_INSERT");
+
+out:
+        if (fd >= 0) {
+                close(fd);
+        }
+        if (key != NULL) {
+                free(key);
+        }
+        if (rec != NULL) {
+                free(rec);
+        }
+        return rc;
+}
+/* End of iam_ut.c */
+
+#define LDISKFS_IOC_GETVERSION _IOR('f', 3, long)
+
+static int touch_file(char *filename)
+{
+        int fd;
+
+        if (filename == NULL) {
+                return 1;
+        }
+
+        fd = open(filename, O_CREAT | O_TRUNC, 0600);
+        if (fd < 0) {
+                return 1;
+        } else {
+                close(fd);
+                return 0;
+        }
+}
+
+static int get_generation(char *filename, unsigned long *result)
+{
+        int fd;
+        int ret;
+
+        if (filename == NULL) {
+                return 1;
+        }
+
+        fd = open(filename, O_RDONLY);
+        if (fd < 0) {
+                fprintf(stderr, "%s: failed to open %s\n",
+                        __FUNCTION__, filename);
+                return 1;
+        }
+
+        ret = ioctl(fd, LDISKFS_IOC_GETVERSION, result);
+        close(fd);
+
+        return ((ret < 0) ? ret : 0);
+}
+
+static int mkfs_mdt(struct mkfs_opts *mop)
+{
+        char mntpt[] = "/tmp/mntXXXXXX";
+        char fstype[] = "ldiskfs";
+        char filepnm[128];
+        char recbuf[64];
+        char *source;
+        int ret;
+        int fd;
+        unsigned long generation;
+        struct stat st;
+
+        source = mop->mo_device;
+        if (mop->mo_flags & MO_IS_LOOP) { 
+                source = mop->mo_loopdev;
+        }
+
+        if ((source == NULL) || (*source == 0)) {
+                return 1;
+        }
+
+        if (!mkdtemp(mntpt)) {
+                fprintf(stderr, "%s: failed to mkdtemp %s\n",
+                        __FUNCTION__, mntpt);
+                return errno;
+        }
+
+        ret = mount(source, mntpt, fstype, 0, NULL);
+        if (ret) {
+                goto out_rmdir;
+        }
+
+        snprintf(filepnm, sizeof(filepnm) - 1, "%s/%s", mntpt, "seq");
+        ret = touch_file(filepnm);
+        if (ret) {
+                goto out_umount;
+        }
+
+        snprintf(filepnm, sizeof(filepnm) - 1, "%s/%s", mntpt, "last_rcvd");
+        ret = touch_file(filepnm);
+        if (ret) {
+                goto out_umount;
+        }
+
+        snprintf(filepnm, sizeof(filepnm) - 1, "%s/%s", mntpt, "lov_objid");
+        ret = touch_file(filepnm);
+        if (ret) {
+                goto out_umount;
+        }
+
+        snprintf(filepnm, sizeof(filepnm) - 1, "%s/%s", mntpt, "root");
+        ret = create_iam(FMT_LVAR, 0, 16, filepnm);
+        if (ret) {
+                goto out_umount;
+        }
+
+        snprintf(filepnm, sizeof(filepnm) - 1, "%s/%s", mntpt, "fld");
+        ret = create_iam(FMT_LFIX, 8, 8, filepnm);
+        if (ret) {
+                goto out_umount;
+        }
+
+        snprintf(filepnm, sizeof(filepnm) - 1, "%s/%s", mntpt, "oi");
+        ret = create_iam(FMT_LFIX, 16, 16, filepnm);
+        if (ret) {
+                goto out_umount;
+        }
+
+        umount(mntpt);
+        ret = mount(source, mntpt, fstype, 0, NULL);
+        if (ret) {
+                goto out_rmdir;
+        }
+
+        snprintf(filepnm, sizeof(filepnm) - 1, "%s/%s", mntpt, "root");
+        fd = open(filepnm, O_RDONLY);
+        if (fd < 0) {
+                fprintf(stderr, "%s: failed to open %s, errno = %d\n",
+                        __FUNCTION__, filepnm, errno);
+                ret = 1;
+                goto out_umount;
+        }
+
+        ret = ioctl(fd, IAM_IOC_POLYMORPH, 040700);
+        close(fd);
+        if (ret) {
+                perror("IAM_IOC_POLYMORPH");
+                goto out_umount;
+        }
+
+        umount(mntpt);
+        ret = mount(source, mntpt, fstype, 0, NULL);
+        if (ret) {
+                goto out_rmdir;
+        }
+
+        snprintf(filepnm, sizeof(filepnm) - 1, "%s/%s", mntpt, "fld");
+        ret = iam_insert(1, "0000000000000002", 1, "0000000000000000", filepnm);
+        if (ret) {
+                goto out_umount;
+        }
+
+        ret = iam_insert(1, "0000000000000001", 1, "0000000000000000", filepnm);
+        if (ret) {
+                goto out_umount;
+        }
+
+        snprintf(filepnm, sizeof(filepnm) - 1, "%s/%s", mntpt, "root");
+        ret = stat(filepnm, &st);
+        if (ret) {
+                goto out_umount;
+        }
+
+        ret = get_generation(filepnm, &generation);
+        if (ret) {
+                goto out_umount;
+        }
+
+        snprintf(recbuf, sizeof(recbuf) - 1, "0000000000000001%8.8x%8.8x",
+                 (unsigned int)generation, (unsigned int)st.st_ino);
+        ret = iam_insert(0, ".", 1, recbuf, filepnm);
+        if (ret) {
+                goto out_umount;
+        }
+
+        ret = iam_insert(0, "..", 1, recbuf, filepnm);
+        if (ret) {
+                goto out_umount;
+        }
+
+out_umount:
+        umount(mntpt);
+out_rmdir:
+        rmdir(mntpt);
+        return ret;
+}
+
 int main(int argc, char *const argv[])
 {
         struct mkfs_opts mop;
@@ -1275,6 +1917,14 @@ int main(int argc, char *const argv[])
                 goto out;
         }
 
+        if (IS_MDT(ldd)) {
+                ret = mkfs_mdt(&mop);
+                if (ret != 0) {
+                        fprintf(stderr, "failed to mkfs_mdt\n");
+                        goto out;
+                }
+        }
+
 out:
         loop_cleanup(&mop);      
         return ret;