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