Whamcloud - gitweb
b=13934
[fs/lustre-release.git] / lustre / utils / create_iam.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  *  create_iam.c
5  *  User-level tool for creation of iam files.
6  *
7  *  Copyright (c) 2006 Cluster File Systems, Inc.
8  *   Author: Wang Di <wangdi@clusterfs.com>
9  *   Author: Nikita Danilov <nikita@clusterfs.com>
10  *
11  *   This file is part of the Lustre file system, http://www.lustre.org
12  *   Lustre is a trademark of Cluster File Systems, Inc.
13  *
14  *   You may have signed or agreed to another license before downloading
15  *   this software.  If so, you are bound by the terms and conditions
16  *   of that agreement, and the following does not apply to you.  See the
17  *   LICENSE file included with this distribution for more information.
18  *
19  *   If you did not agree to a different license, then this copy of Lustre
20  *   is open source software; you can redistribute it and/or modify it
21  *   under the terms of version 2 of the GNU General Public License as
22  *   published by the Free Software Foundation.
23  *
24  *   In either case, Lustre is distributed in the hope that it will be
25  *   useful, but WITHOUT ANY WARRANTY; without even the implied warranty
26  *   of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
27  *   license text for more details.
28  */
29
30 #include <unistd.h>
31 #include <stdlib.h>
32 #include <stdio.h>
33 #include <fcntl.h>
34 #include <string.h>
35 #include <errno.h>
36
37 #include <sys/types.h>
38
39 #ifdef HAVE_ENDIAN_H
40 #include <endian.h>
41 #endif
42
43 #include <libcfs/libcfs.h>
44
45 void usage(void)
46 {
47         printf("usage: create_iam "
48                "[-h] [-k <keysize>] [-r recsize] [-b <blocksize] [-p <ptrsize>] [-v]\n");
49 }
50
51 enum {
52         IAM_LFIX_ROOT_MAGIC = 0xbedabb1edULL,
53         IAM_LVAR_ROOT_MAGIC = 0xb01dface
54 };
55
56 struct iam_lfix_root {
57         u_int64_t  ilr_magic;
58         u_int16_t  ilr_keysize;
59         u_int16_t  ilr_recsize;
60         u_int16_t  ilr_ptrsize;
61         u_int16_t  ilr_indirect_levels;
62 };
63
64 enum {
65         IAM_LEAF_HEADER_MAGIC = 0x1976,
66         IAM_LVAR_LEAF_MAGIC   = 0x1973
67 };
68
69 struct iam_leaf_head {
70         u_int16_t ill_magic;
71         u_int16_t ill_count;
72 };
73
74 struct dx_countlimit {
75         u_int16_t limit;
76         u_int16_t count;
77 };
78
79 typedef __u32 lvar_hash_t;
80
81 struct lvar_leaf_header {
82         u_int16_t vlh_magic; /* magic number IAM_LVAR_LEAF_MAGIC */
83         u_int16_t vlh_used;  /* used bytes, including header */
84 };
85
86 struct lvar_root {
87         u_int32_t vr_magic;
88         u_int16_t vr_recsize;
89         u_int16_t vr_ptrsize;
90         u_int8_t  vr_indirect_levels;
91         u_int8_t  vr_padding0;
92         u_int16_t vr_padding1;
93 };
94
95 struct lvar_leaf_entry {
96         u_int32_t vle_hash;
97         u_int16_t vle_keysize;
98         u_int8_t  vle_key[0];
99 };
100
101 enum {
102         LVAR_PAD   = 4,
103         LVAR_ROUND = LVAR_PAD - 1
104 };
105
106 /**
107  * Stores \a val at \a dst, where the latter is possibly unaligned. Uses
108  * memcpy(). This macro is needed to avoid dependency of user level tools on
109  * the kernel headers.
110  */
111 #define STORE_UNALIGNED(val, dst)                       \
112 ({                                                      \
113         typeof(val) __val = (val);                      \
114                                                         \
115         CLASSERT(sizeof(val) == sizeof(*(dst)));        \
116         memcpy(dst, &__val, sizeof(*(dst)));            \
117 })
118
119 static void lfix_root(void *buf,
120                       int blocksize, int keysize, int ptrsize, int recsize)
121 {
122         struct iam_lfix_root *root;
123         struct dx_countlimit *limit;
124         void                 *entry;
125
126         root = buf;
127         *root = (typeof(*root)) {
128                 .ilr_magic           = cpu_to_le64(IAM_LFIX_ROOT_MAGIC),
129                 .ilr_keysize         = cpu_to_le16(keysize),
130                 .ilr_recsize         = cpu_to_le16(recsize),
131                 .ilr_ptrsize         = cpu_to_le16(ptrsize),
132                 .ilr_indirect_levels = 0
133         };
134
135         limit = (void *)(root + 1);
136         *limit = (typeof(*limit)){
137                 /*
138                  * limit itself + one pointer to the leaf.
139                  */
140                 .count = cpu_to_le16(2),
141                 .limit = (blocksize - sizeof *root) / (keysize + ptrsize)
142         };
143
144         entry = root + 1;
145         /*
146          * Skip over @limit.
147          */
148         entry += keysize + ptrsize;
149
150         /*
151          * Entry format is <key> followed by <ptr>. In the minimal tree
152          * consisting of a root and single node, <key> is a minimal possible
153          * key.
154          *
155          * XXX: this key is hard-coded to be a sequence of 0's.
156          */
157         entry += keysize;
158         /* now @entry points to <ptr> */
159         if (ptrsize == 4)
160                 STORE_UNALIGNED(cpu_to_le32(1), (u_int32_t *)entry);
161         else
162                 STORE_UNALIGNED(cpu_to_le64(1), (u_int64_t *)entry);
163 }
164
165 static void lfix_leaf(void *buf,
166                       int blocksize, int keysize, int ptrsize, int recsize)
167 {
168         struct iam_leaf_head *head;
169
170         /* form leaf */
171         head = buf;
172         *head = (struct iam_leaf_head) {
173                 .ill_magic = cpu_to_le16(IAM_LEAF_HEADER_MAGIC),
174                 /*
175                  * Leaf contains an entry with the smallest possible key
176                  * (created by zeroing).
177                  */
178                 .ill_count = cpu_to_le16(1),
179         };
180 }
181
182 static void lvar_root(void *buf,
183                       int blocksize, int keysize, int ptrsize, int recsize)
184 {
185         struct lvar_root *root;
186         struct dx_countlimit *limit;
187         void                 *entry;
188         int isize;
189
190         isize = sizeof(lvar_hash_t) + ptrsize;
191         root = buf;
192         *root = (typeof(*root)) {
193                 .vr_magic            = cpu_to_le32(IAM_LVAR_ROOT_MAGIC),
194                 .vr_recsize          = cpu_to_le16(recsize),
195                 .vr_ptrsize          = cpu_to_le16(ptrsize),
196                 .vr_indirect_levels  = 0
197         };
198
199         limit = (void *)(root + 1);
200         *limit = (typeof(*limit)){
201                 /*
202                  * limit itself + one pointer to the leaf.
203                  */
204                 .count = cpu_to_le16(2),
205                 .limit = (blocksize - sizeof *root) / isize
206         };
207
208         entry = root + 1;
209         /*
210          * Skip over @limit.
211          */
212         entry += isize;
213
214         /*
215          * Entry format is <key> followed by <ptr>. In the minimal tree
216          * consisting of a root and single node, <key> is a minimal possible
217          * key.
218          *
219          * XXX: this key is hard-coded to be a sequence of 0's.
220          */
221         entry += sizeof(lvar_hash_t);
222         /* now @entry points to <ptr> */
223         if (ptrsize == 4)
224                 STORE_UNALIGNED(cpu_to_le32(1), (u_int32_t *)entry);
225         else
226                 STORE_UNALIGNED(cpu_to_le64(1), (u_int64_t *)entry);
227 }
228
229 static int lvar_esize(int namelen, int recsize)
230 {
231         return (offsetof(struct lvar_leaf_entry, vle_key) +
232                 namelen + recsize + LVAR_ROUND) & ~LVAR_ROUND;
233 }
234
235 static void lvar_leaf(void *buf,
236                       int blocksize, int keysize, int ptrsize, int recsize)
237 {
238         struct lvar_leaf_header *head;
239
240         /* form leaf */
241         head = buf;
242         *head = (typeof(*head)) {
243                 .vlh_magic = cpu_to_le16(IAM_LVAR_LEAF_MAGIC),
244                 .vlh_used  = cpu_to_le16(sizeof *head + lvar_esize(0, recsize))
245         };
246 }
247
248 enum iam_fmt_t {
249         FMT_LFIX,
250         FMT_LVAR
251 };
252
253 int main(int argc, char **argv)
254 {
255         int rc;
256         int opt;
257         int blocksize = 4096;
258         int keysize   = 8;
259         int recsize   = 8;
260         int ptrsize   = 4;
261         int verbose   = 0;
262         void *buf;
263         char *fmtstr = "lfix";
264         enum iam_fmt_t fmt;
265
266         do {
267                 opt = getopt(argc, argv, "hb:k:r:p:vf:");
268                 switch (opt) {
269                 case 'v':
270                         verbose++;
271                 case -1:
272                         break;
273                 case 'b':
274                         blocksize = atoi(optarg);
275                         break;
276                 case 'k':
277                         keysize = atoi(optarg);
278                         break;
279                 case 'r':
280                         recsize = atoi(optarg);
281                         break;
282                 case 'p':
283                         ptrsize = atoi(optarg);
284                         break;
285                 case 'f':
286                         fmtstr = optarg;
287                         break;
288                 case '?':
289                 default:
290                         fprintf(stderr, "Unable to parse options.");
291                 case 'h':
292                         usage();
293                         return 0;
294                 }
295         } while (opt != -1);
296
297         if (ptrsize != 4 && ptrsize != 8) {
298                 fprintf(stderr, "Invalid ptrsize (%i). "
299                         "Only 4 and 8 are supported\n", ptrsize);
300                 return 1;
301         }
302
303         if (blocksize <= 100 || keysize < 1 || recsize < 0) {
304                 fprintf(stderr, "Too small record, key or block block\n");
305                 return 1;
306         }
307
308         if (keysize + recsize + sizeof(struct iam_leaf_head) > blocksize / 3) {
309                 fprintf(stderr, "Too large (record, key) or too small block\n");
310                 return 1;
311         }
312
313         if (!strcmp(fmtstr, "lfix"))
314                 fmt = FMT_LFIX;
315         else if (!strcmp(fmtstr, "lvar"))
316                 fmt = FMT_LVAR;
317         else {
318                 fprintf(stderr, "Wrong format `%s'\n", fmtstr);
319                 return 1;
320         }
321
322         if (verbose > 0) {
323                 fprintf(stderr,
324                         "fmt: %s, key: %i, rec: %i, ptr: %i, block: %i\n",
325                         fmtstr, keysize, recsize, ptrsize, blocksize);
326         }
327         buf = malloc(blocksize);
328         if (buf == NULL) {
329                 fprintf(stderr, "Unable to allocate %i bytes\n", blocksize);
330                 return 1;
331         }
332
333         memset(buf, 0, blocksize);
334
335         if (fmt == FMT_LFIX)
336                 lfix_root(buf, blocksize, keysize, ptrsize, recsize);
337         else
338                 lvar_root(buf, blocksize, keysize, ptrsize, recsize);
339
340         rc = write(1, buf, blocksize);
341         if (rc != blocksize) {
342                 fprintf(stderr, "Unable to write root node: %m (%i)\n", rc);
343                 free(buf);
344                 return 1;
345         }
346
347         /* form leaf */
348         memset(buf, 0, blocksize);
349
350         if (fmt == FMT_LFIX)
351                 lfix_leaf(buf, blocksize, keysize, ptrsize, recsize);
352         else
353                 lvar_leaf(buf, blocksize, keysize, ptrsize, recsize);
354
355         rc = write(1, buf, blocksize);
356         free(buf);
357         if (rc != blocksize) {
358                 fprintf(stderr, "Unable to write leaf node: %m (%i)\n", rc);
359                 return 1;
360         }
361         if (verbose > 0)
362                 fprintf(stderr, "Don't forget to umount/mount "
363                         "before accessing iam from the kernel!\n");
364         return 0;
365 }