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