Whamcloud - gitweb
LU-6245 libcfs: remove byteorder.h
[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 <endian.h>
48 #include <errno.h>
49
50 #include <sys/types.h>
51
52 void usage(void)
53 {
54         printf("usage: create_iam "
55                "[-h] [-k <keysize>] [-r recsize] [-b <blocksize] [-p <ptrsize>] [-v]\n");
56 }
57
58 enum {
59         IAM_LFIX_ROOT_MAGIC = 0xbedabb1edULL,
60         IAM_LVAR_ROOT_MAGIC = 0xb01dface
61 };
62
63 struct iam_lfix_root {
64         u_int64_t  ilr_magic;
65         u_int16_t  ilr_keysize;
66         u_int16_t  ilr_recsize;
67         u_int16_t  ilr_ptrsize;
68         u_int16_t  ilr_indirect_levels;
69 };
70
71 enum {
72         IAM_LEAF_HEADER_MAGIC = 0x1976,
73         IAM_LVAR_LEAF_MAGIC   = 0x1973
74 };
75
76 struct iam_leaf_head {
77         u_int16_t ill_magic;
78         u_int16_t ill_count;
79 };
80
81 struct dx_countlimit {
82         u_int16_t limit;
83         u_int16_t count;
84 };
85
86 typedef __u32 lvar_hash_t;
87
88 struct lvar_leaf_header {
89         u_int16_t vlh_magic; /* magic number IAM_LVAR_LEAF_MAGIC */
90         u_int16_t vlh_used;  /* used bytes, including header */
91 };
92
93 struct lvar_root {
94         u_int32_t vr_magic;
95         u_int16_t vr_recsize;
96         u_int16_t vr_ptrsize;
97         u_int8_t  vr_indirect_levels;
98         u_int8_t  vr_padding0;
99         u_int16_t vr_padding1;
100 };
101
102 struct lvar_leaf_entry {
103         u_int32_t vle_hash;
104         u_int16_t vle_keysize;
105         u_int8_t  vle_key[0];
106 };
107
108 enum {
109         LVAR_PAD   = 4,
110         LVAR_ROUND = LVAR_PAD - 1
111 };
112
113 /**
114  * Stores \a val at \a dst, where the latter is possibly unaligned. Uses
115  * memcpy(). This macro is needed to avoid dependency of user level tools on
116  * the kernel headers.
117  */
118 #define STORE_UNALIGNED(val, dst)                       \
119 ({                                                      \
120         typeof(val) __val = (val);                      \
121                                                         \
122         CLASSERT(sizeof(val) == sizeof(*(dst)));        \
123         memcpy(dst, &__val, sizeof(*(dst)));            \
124 })
125
126 static void lfix_root(void *buf,
127                       int blocksize, int keysize, int ptrsize, int recsize)
128 {
129         struct iam_lfix_root *root;
130         struct dx_countlimit *limit;
131         void                 *entry;
132
133         root = buf;
134         *root = (typeof(*root)) {
135                 .ilr_magic           = cpu_to_le64(IAM_LFIX_ROOT_MAGIC),
136                 .ilr_keysize         = cpu_to_le16(keysize),
137                 .ilr_recsize         = cpu_to_le16(recsize),
138                 .ilr_ptrsize         = cpu_to_le16(ptrsize),
139                 .ilr_indirect_levels = 0
140         };
141
142         limit = (void *)(root + 1);
143         *limit = (typeof(*limit)){
144                 /*
145                  * limit itself + one pointer to the leaf.
146                  */
147                 .count = cpu_to_le16(2),
148                 .limit = (blocksize - sizeof *root) / (keysize + ptrsize)
149         };
150
151         entry = root + 1;
152         /*
153          * Skip over @limit.
154          */
155         entry += keysize + ptrsize;
156
157         /*
158          * Entry format is <key> followed by <ptr>. In the minimal tree
159          * consisting of a root and single node, <key> is a minimal possible
160          * key.
161          *
162          * XXX: this key is hard-coded to be a sequence of 0's.
163          */
164         entry += keysize;
165         /* now @entry points to <ptr> */
166         if (ptrsize == 4)
167                 STORE_UNALIGNED(cpu_to_le32(1), (u_int32_t *)entry);
168         else
169                 STORE_UNALIGNED(cpu_to_le64(1), (u_int64_t *)entry);
170 }
171
172 static void lfix_leaf(void *buf,
173                       int blocksize, int keysize, int ptrsize, int recsize)
174 {
175         struct iam_leaf_head *head;
176
177         /* form leaf */
178         head = buf;
179         *head = (struct iam_leaf_head) {
180                 .ill_magic = cpu_to_le16(IAM_LEAF_HEADER_MAGIC),
181                 /*
182                  * Leaf contains an entry with the smallest possible key
183                  * (created by zeroing).
184                  */
185                 .ill_count = cpu_to_le16(1),
186         };
187 }
188
189 static void lvar_root(void *buf,
190                       int blocksize, int keysize, int ptrsize, int recsize)
191 {
192         struct lvar_root *root;
193         struct dx_countlimit *limit;
194         void                 *entry;
195         int isize;
196
197         isize = sizeof(lvar_hash_t) + ptrsize;
198         root = buf;
199         *root = (typeof(*root)) {
200                 .vr_magic            = cpu_to_le32(IAM_LVAR_ROOT_MAGIC),
201                 .vr_recsize          = cpu_to_le16(recsize),
202                 .vr_ptrsize          = cpu_to_le16(ptrsize),
203                 .vr_indirect_levels  = 0
204         };
205
206         limit = (void *)(root + 1);
207         *limit = (typeof(*limit)){
208                 /*
209                  * limit itself + one pointer to the leaf.
210                  */
211                 .count = cpu_to_le16(2),
212                 .limit = (blocksize - sizeof *root) / isize
213         };
214
215         entry = root + 1;
216         /*
217          * Skip over @limit.
218          */
219         entry += isize;
220
221         /*
222          * Entry format is <key> followed by <ptr>. In the minimal tree
223          * consisting of a root and single node, <key> is a minimal possible
224          * key.
225          *
226          * XXX: this key is hard-coded to be a sequence of 0's.
227          */
228         entry += sizeof(lvar_hash_t);
229         /* now @entry points to <ptr> */
230         if (ptrsize == 4)
231                 STORE_UNALIGNED(cpu_to_le32(1), (u_int32_t *)entry);
232         else
233                 STORE_UNALIGNED(cpu_to_le64(1), (u_int64_t *)entry);
234 }
235
236 static int lvar_esize(int namelen, int recsize)
237 {
238         return (offsetof(struct lvar_leaf_entry, vle_key) +
239                 namelen + recsize + LVAR_ROUND) & ~LVAR_ROUND;
240 }
241
242 static void lvar_leaf(void *buf,
243                       int blocksize, int keysize, int ptrsize, int recsize)
244 {
245         struct lvar_leaf_header *head;
246
247         /* form leaf */
248         head = buf;
249         *head = (typeof(*head)) {
250                 .vlh_magic = cpu_to_le16(IAM_LVAR_LEAF_MAGIC),
251                 .vlh_used  = cpu_to_le16(sizeof *head + lvar_esize(0, recsize))
252         };
253 }
254
255 enum iam_fmt_t {
256         FMT_LFIX,
257         FMT_LVAR
258 };
259
260 int main(int argc, char **argv)
261 {
262         int rc;
263         int opt;
264         int blocksize = 4096;
265         int keysize   = 8;
266         int recsize   = 8;
267         int ptrsize   = 4;
268         int verbose   = 0;
269         void *buf;
270         char *fmtstr = "lfix";
271         enum iam_fmt_t fmt;
272
273         do {
274                 opt = getopt(argc, argv, "hb:k:r:p:vf:");
275                 switch (opt) {
276                 case 'v':
277                         verbose++;
278                 case -1:
279                         break;
280                 case 'b':
281                         blocksize = atoi(optarg);
282                         break;
283                 case 'k':
284                         keysize = atoi(optarg);
285                         break;
286                 case 'r':
287                         recsize = atoi(optarg);
288                         break;
289                 case 'p':
290                         ptrsize = atoi(optarg);
291                         break;
292                 case 'f':
293                         fmtstr = optarg;
294                         break;
295                 case '?':
296                 default:
297                         fprintf(stderr, "Unable to parse options.");
298                 case 'h':
299                         usage();
300                         return 0;
301                 }
302         } while (opt != -1);
303
304         if (ptrsize != 4 && ptrsize != 8) {
305                 fprintf(stderr, "Invalid ptrsize (%i). "
306                         "Only 4 and 8 are supported\n", ptrsize);
307                 return 1;
308         }
309
310         if (blocksize <= 100 || keysize < 1 || recsize < 0) {
311                 fprintf(stderr, "Too small record, key or block block\n");
312                 return 1;
313         }
314
315         if (keysize + recsize + sizeof(struct iam_leaf_head) > blocksize / 3) {
316                 fprintf(stderr, "Too large (record, key) or too small block\n");
317                 return 1;
318         }
319
320         if (!strcmp(fmtstr, "lfix"))
321                 fmt = FMT_LFIX;
322         else if (!strcmp(fmtstr, "lvar"))
323                 fmt = FMT_LVAR;
324         else {
325                 fprintf(stderr, "Wrong format `%s'\n", fmtstr);
326                 return 1;
327         }
328
329         if (verbose > 0) {
330                 fprintf(stderr,
331                         "fmt: %s, key: %i, rec: %i, ptr: %i, block: %i\n",
332                         fmtstr, keysize, recsize, ptrsize, blocksize);
333         }
334         buf = malloc(blocksize);
335         if (buf == NULL) {
336                 fprintf(stderr, "Unable to allocate %i bytes\n", blocksize);
337                 return 1;
338         }
339
340         memset(buf, 0, blocksize);
341
342         if (fmt == FMT_LFIX)
343                 lfix_root(buf, blocksize, keysize, ptrsize, recsize);
344         else
345                 lvar_root(buf, blocksize, keysize, ptrsize, recsize);
346
347         rc = write(1, buf, blocksize);
348         if (rc != blocksize) {
349                 fprintf(stderr, "Unable to write root node: %m (%i)\n", rc);
350                 free(buf);
351                 return 1;
352         }
353
354         /* form leaf */
355         memset(buf, 0, blocksize);
356
357         if (fmt == FMT_LFIX)
358                 lfix_leaf(buf, blocksize, keysize, ptrsize, recsize);
359         else
360                 lvar_leaf(buf, blocksize, keysize, ptrsize, recsize);
361
362         rc = write(1, buf, blocksize);
363         free(buf);
364         if (rc != blocksize) {
365                 fprintf(stderr, "Unable to write leaf node: %m (%i)\n", rc);
366                 return 1;
367         }
368         if (verbose > 0)
369                 fprintf(stderr, "Don't forget to umount/mount "
370                         "before accessing iam from the kernel!\n");
371         return 0;
372 }