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