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