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