Whamcloud - gitweb
LU-14475 log: Rewrite some log messages
[fs/lustre-release.git] / lustre / utils / libiam.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  * Copyright (c) 2014, 2015, Intel Corporation.
27  */
28 /*
29  * This file is part of Lustre, http://www.lustre.org/
30  *
31  * lustre/utils/libiam.c
32  *
33  * iam user level library
34  *
35  * Author: Wang Di <wangdi@clusterfs.com>
36  * Author: Nikita Danilov <nikita@clusterfs.com>
37  * Author: Fan Yong <fanyong@clusterfs.com>
38  */
39
40 #include <unistd.h>
41 #include <stdlib.h>
42 #include <stdio.h>
43 #include <fcntl.h>
44 #include <string.h>
45 #include <endian.h>
46 #include <errno.h>
47 #include <sys/ioctl.h>
48 #include <sys/types.h>
49
50 #include <libcfs/util/string.h>
51 #include <lustre/libiam.h>
52
53 typedef __u32 lvar_hash_t;
54
55 enum {
56         IAM_LFIX_ROOT_MAGIC = 0xbedabb1edULL,
57         IAM_LVAR_ROOT_MAGIC = 0xb01dface
58 };
59
60 struct iam_lfix_root {
61         u_int64_t  ilr_magic;
62         u_int16_t  ilr_keysize;
63         u_int16_t  ilr_recsize;
64         u_int16_t  ilr_ptrsize;
65         u_int16_t  ilr_indirect_levels;
66 };
67
68 enum {
69         IAM_LEAF_HEADER_MAGIC = 0x1976,
70         IAM_LVAR_LEAF_MAGIC   = 0x1973
71 };
72
73 struct iam_leaf_head {
74         u_int16_t ill_magic;
75         u_int16_t ill_count;
76 };
77
78 struct dx_countlimit {
79         u_int16_t limit;
80         u_int16_t count;
81 };
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(*(dst)) __val = (val);           \
116                                                 \
117         memcpy(dst, &__val, sizeof *(dst));     \
118 })
119
120 static int root_limit(int rootgap, int blocksize, int size)
121 {
122         int limit;
123         int nlimit;
124
125         limit = (blocksize - rootgap) / size;
126         nlimit = blocksize / size;
127         if (limit == nlimit)
128                 limit--;
129         return limit;
130 }
131
132 static int lfix_root_limit(int blocksize, int size)
133 {
134         return root_limit(sizeof(struct iam_lfix_root), blocksize, size);
135 }
136
137 static void lfix_root(void *buf,
138                       int blocksize, int keysize, int ptrsize, int recsize)
139 {
140         struct iam_lfix_root *root;
141         struct dx_countlimit *limit;
142         void *entry;
143
144         root = buf;
145         *root = (typeof(*root)) {
146                 .ilr_magic           = htole64(IAM_LFIX_ROOT_MAGIC),
147                 .ilr_keysize         = htole16(keysize),
148                 .ilr_recsize         = htole16(recsize),
149                 .ilr_ptrsize         = htole16(ptrsize),
150                 .ilr_indirect_levels = 0
151         };
152
153         limit = (void *)(root + 1);
154         *limit = (typeof(*limit)){
155                 /*
156                  * limit itself + one pointer to the leaf.
157                  */
158                 .count = htole16(2),
159                 .limit = lfix_root_limit(blocksize, keysize + ptrsize)
160         };
161
162         entry = root + 1;
163         /*
164          * Skip over @limit.
165          */
166         entry += keysize + ptrsize;
167
168         /*
169          * Entry format is <key> followed by <ptr>. In the minimal tree
170          * consisting of a root and single node, <key> is a minimal possible
171          * key.
172          *
173          * XXX: this key is hard-coded to be a sequence of 0's.
174          */
175         entry += keysize;
176         /* now @entry points to <ptr> */
177         if (ptrsize == 4)
178                 STORE_UNALIGNED(htole32(1), (u_int32_t *)entry);
179         else
180                 STORE_UNALIGNED(htole64(1), (u_int64_t *)entry);
181 }
182
183 static void lfix_leaf(void *buf,
184                       int blocksize, int keysize, int ptrsize, int recsize)
185 {
186         struct iam_leaf_head *head;
187
188         /* form leaf */
189         head = buf;
190         *head = (typeof(*head)) {
191                 .ill_magic = htole16(IAM_LEAF_HEADER_MAGIC),
192                 /*
193                  * Leaf contains an entry with the smallest possible key
194                  * (created by zeroing).
195                  */
196                 .ill_count = htole16(1),
197         };
198 }
199
200 static int lvar_root_limit(int blocksize, int size)
201 {
202         return root_limit(sizeof(struct lvar_root), blocksize, size);
203 }
204
205 static void lvar_root(void *buf,
206                       int blocksize, int keysize, int ptrsize, int recsize)
207 {
208         struct lvar_root *root;
209         struct dx_countlimit *limit;
210         void *entry;
211         int isize;
212
213         isize = sizeof(lvar_hash_t) + ptrsize;
214         root = buf;
215         *root = (typeof(*root)) {
216                 .vr_magic            = htole32(IAM_LVAR_ROOT_MAGIC),
217                 .vr_recsize          = htole16(recsize),
218                 .vr_ptrsize          = htole16(ptrsize),
219                 .vr_indirect_levels  = 0
220         };
221
222         limit = (void *)(root + 1);
223         *limit = (typeof(*limit)) {
224                 /*
225                  * limit itself + one pointer to the leaf.
226                  */
227                 .count = htole16(2),
228                 .limit = lvar_root_limit(blocksize, keysize + ptrsize)
229         };
230
231         entry = root + 1;
232         /*
233          * Skip over @limit.
234          */
235         entry += isize;
236
237         /*
238          * Entry format is <key> followed by <ptr>. In the minimal tree
239          * consisting of a root and single node, <key> is a minimal possible
240          * key.
241          *
242          * XXX: this key is hard-coded to be a sequence of 0's.
243          */
244         entry += sizeof(lvar_hash_t);
245         /* now @entry points to <ptr> */
246         if (ptrsize == 4)
247                 STORE_UNALIGNED(htole32(1), (u_int32_t *)entry);
248         else
249                 STORE_UNALIGNED(htole64(1), (u_int64_t *)entry);
250 }
251
252 static int lvar_esize(int namelen, int recsize)
253 {
254         return (offsetof(struct lvar_leaf_entry, vle_key) +
255                 namelen + recsize + LVAR_ROUND) & ~LVAR_ROUND;
256 }
257
258 static void lvar_leaf(void *buf,
259                       int blocksize, int keysize, int ptrsize, int recsize)
260 {
261         struct lvar_leaf_header *head;
262         char *rec;
263
264         /* form leaf */
265         head = buf;
266         *head = (typeof(*head)) {
267                 .vlh_magic = htole16(IAM_LVAR_LEAF_MAGIC),
268                 .vlh_used  = htole16(sizeof(*head) + lvar_esize(0, recsize))
269         };
270         rec = (void *)(head + 1);
271         rec[offsetof(struct lvar_leaf_entry, vle_key)] = recsize;
272 }
273
274 struct iam_uapi_op {
275         void *iul_key;
276         void *iul_rec;
277 };
278
279 struct iam_uapi_it {
280         struct iam_uapi_op iui_op;
281         __u16 iui_state;
282 };
283
284 enum iam_ioctl_cmd {
285         IAM_IOC_INIT      = _IOW('i', 1, struct iam_uapi_info),
286         IAM_IOC_GETINFO   = _IOR('i', 2, struct iam_uapi_info),
287         IAM_IOC_INSERT    = _IOR('i', 3, struct iam_uapi_op),
288         IAM_IOC_LOOKUP    = _IOWR('i', 4, struct iam_uapi_op),
289         IAM_IOC_DELETE    = _IOR('i', 5, struct iam_uapi_op),
290         IAM_IOC_IT_START  = _IOR('i', 6, struct iam_uapi_it),
291         IAM_IOC_IT_NEXT   = _IOW('i', 7, struct iam_uapi_it),
292         IAM_IOC_IT_STOP   = _IOR('i', 8, struct iam_uapi_it),
293         IAM_IOC_POLYMORPH = _IOR('i', 9, unsigned long)
294 };
295
296 static unsigned char hex2dec(unsigned char hex)
297 {
298         if (('0' <= hex) && (hex <= '9'))
299                 return hex - '0';
300         else if (('a' <= hex) && (hex <= 'f'))
301                 return hex - 'a' + 10;
302         else if (('A' <= hex) && (hex <= 'F'))
303                 return hex - 'A' + 10;
304         exit(1);
305 }
306
307 static unsigned char *packdigit(unsigned char *number)
308 {
309         unsigned char *area;
310         unsigned char *scan;
311
312         area = calloc(strlen((char *)number) / 2 + 2, sizeof(char));
313         if (area) {
314                 for (scan = area; *number; number += 2, scan++)
315                         *scan = (hex2dec(number[0]) << 4) | hex2dec(number[1]);
316         }
317         return area;
318 }
319
320 static char *iam_convert(int size, int need_convert, char *source)
321 {
322         char *ptr;
323         unsigned char *opt;
324
325         if (!source)
326                 return NULL;
327
328         if (need_convert) {
329                 ptr = calloc(size + 1, sizeof(char));
330                 if (!ptr)
331                         return NULL;
332
333                 opt = packdigit((unsigned char *)source);
334                 if (!opt) {
335                         free(ptr);
336                         return NULL;
337                 }
338                 memcpy(ptr, opt, size + 1);
339                 free(opt);
340         } else {
341                 ptr = strdup(source);
342         }
343
344         return ptr;
345 }
346
347 static int iam_doop(int fd, struct iam_uapi_info *ua, int cmd,
348                     int key_need_convert, char *key_buf,
349                     int *keysize, char *save_key,
350                     int rec_need_convert, char *rec_buf,
351                     int *recsize, char *save_rec)
352 {
353         int ret;
354         char *key;
355         char *rec;
356         struct iam_uapi_op op;
357
358         key = iam_convert(ua->iui_keysize, key_need_convert, key_buf);
359         if (!key)
360                 return -1;
361
362         rec = iam_convert(ua->iui_recsize, rec_need_convert, rec_buf);
363         if (!rec) {
364                 free(key);
365                 return -1;
366         }
367
368         op.iul_key = key;
369         op.iul_rec = rec;
370         ret = ioctl(fd, cmd, &op);
371         if (ret == 0) {
372                 if ((keysize) && (*keysize > 0) && (save_key)) {
373                         if (*keysize > ua->iui_keysize)
374                                 *keysize = ua->iui_keysize;
375                         memcpy(save_key, key, *keysize);
376                 }
377                 if ((recsize) && (*recsize > 0) && (save_rec)) {
378                         if (*recsize > ua->iui_recsize)
379                                 *recsize = ua->iui_recsize;
380                         memcpy(save_rec, rec, *recsize);
381                 }
382         }
383         free(key);
384         free(rec);
385         return ret;
386 }
387
388 /*
389  * Creat an iam file, but do NOT open it.
390  * Return 0 if success, else -1.
391  */
392 int iam_creat(char *filename, enum iam_fmt_t fmt,
393               int blocksize, int keysize, int recsize, int ptrsize)
394 {
395         int fd;
396         char *buf;
397
398         if (!filename) {
399                 errno = EINVAL;
400                 return -1;
401         }
402
403         if ((fmt != FMT_LFIX) && (fmt != FMT_LVAR)) {
404                 errno = EOPNOTSUPP;
405                 return -1;
406         }
407
408         if (blocksize <= 100) {
409                 errno = EINVAL;
410                 return -1;
411         }
412
413         if (keysize < 1) {
414                 errno = EINVAL;
415                 return -1;
416         }
417
418         if (recsize < 0) {
419                 errno = EINVAL;
420                 return -1;
421         }
422
423         if (ptrsize != 4 && ptrsize != 8) {
424                 errno = EINVAL;
425                 return -1;
426         }
427
428         if (keysize + recsize + sizeof(struct iam_leaf_head) > blocksize / 3) {
429                 errno = EINVAL;
430                 return -1;
431         }
432
433         fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT, 0600);
434         if (fd < 0)
435                 return -1;
436
437         buf = malloc(blocksize);
438         if (!buf) {
439                 close(fd);
440                 return -1;
441         }
442
443         memset(buf, 0, blocksize);
444         if (fmt == FMT_LFIX)
445                 lfix_root(buf, blocksize, keysize, ptrsize, recsize);
446         else
447                 lvar_root(buf, blocksize, keysize, ptrsize, recsize);
448
449         if (write(fd, buf, blocksize) != blocksize) {
450                 close(fd);
451                 free(buf);
452                 return -1;
453         }
454
455         memset(buf, 0, blocksize);
456         if (fmt == FMT_LFIX)
457                 lfix_leaf(buf, blocksize, keysize, ptrsize, recsize);
458         else
459                 lvar_leaf(buf, blocksize, keysize, ptrsize, recsize);
460
461         if (write(fd, buf, blocksize) != blocksize) {
462                 close(fd);
463                 free(buf);
464                 return -1;
465         }
466
467         close(fd);
468         free(buf);
469         return 0;
470 }
471
472 /*
473  * Open an iam file, but do NOT creat it if the file doesn't exist.
474  * Please use iam_creat for creating the file before use iam_open.
475  * Return file id (fd) if success, else -1.
476  */
477 int iam_open(char *filename, struct iam_uapi_info *ua)
478 {
479         int fd;
480
481         if (!filename) {
482                 errno = EINVAL;
483                 return -1;
484         }
485
486         if (!ua) {
487                 errno = EINVAL;
488                 return -1;
489         }
490
491         fd = open(filename, O_RDONLY);
492         if (fd < 0)
493                 return -1;
494
495         if (ioctl(fd, IAM_IOC_INIT, ua) != 0) {
496                 close(fd);
497                 return -1;
498         }
499
500         if (ioctl(fd, IAM_IOC_GETINFO, ua) != 0) {
501                 close(fd);
502                 return -1;
503         }
504
505         return fd;
506 }
507
508 /*
509  * Close file opened by iam_open.
510  */
511 int iam_close(int fd)
512 {
513         return close(fd);
514 }
515
516 /*
517  * Please use iam_open before use this function.
518  */
519 int iam_insert(int fd, struct iam_uapi_info *ua,
520                int key_need_convert, char *key_buf,
521                int rec_need_convert, char *rec_buf)
522 {
523         return iam_doop(fd, ua, IAM_IOC_INSERT,
524                         key_need_convert, key_buf, NULL, NULL,
525                         rec_need_convert, rec_buf, NULL, NULL);
526 }
527
528 /*
529  * Please use iam_open before use this function.
530  */
531 int iam_lookup(int fd, struct iam_uapi_info *ua,
532                int key_need_convert, char *key_buf,
533                int *keysize, char *save_key,
534                int rec_need_convert, char *rec_buf,
535                int *recsize, char *save_rec)
536 {
537         return iam_doop(fd, ua, IAM_IOC_LOOKUP,
538                         key_need_convert, key_buf, keysize, save_key,
539                         rec_need_convert, rec_buf, recsize, save_rec);
540 }
541
542 /*
543  * Please use iam_open before use this function.
544  */
545 int iam_delete(int fd, struct iam_uapi_info *ua,
546                int key_need_convert, char *key_buf,
547                int rec_need_convert, char *rec_buf)
548 {
549         return iam_doop(fd, ua, IAM_IOC_DELETE,
550                         key_need_convert, key_buf, NULL, NULL,
551                         rec_need_convert, rec_buf, NULL, NULL);
552 }
553
554 /*
555  * Please use iam_open before use this function.
556  */
557 int iam_it_start(int fd, struct iam_uapi_info *ua,
558                  int key_need_convert, char *key_buf,
559                  int *keysize, char *save_key,
560                  int rec_need_convert, char *rec_buf,
561                  int *recsize, char *save_rec)
562 {
563         return iam_doop(fd, ua, IAM_IOC_IT_START,
564                         key_need_convert, key_buf, keysize, save_key,
565                         rec_need_convert, rec_buf, recsize, save_rec);
566 }
567
568 /*
569  * Please use iam_open before use this function.
570  */
571 int iam_it_next(int fd, struct iam_uapi_info *ua,
572                 int key_need_convert, char *key_buf,
573                 int *keysize, char *save_key,
574                 int rec_need_convert, char *rec_buf,
575                 int *recsize, char *save_rec)
576 {
577         return iam_doop(fd, ua, IAM_IOC_IT_NEXT,
578                         key_need_convert, key_buf, keysize, save_key,
579                         rec_need_convert, rec_buf, recsize, save_rec);
580 }
581
582 /*
583  * Please use iam_open before use this function.
584  */
585 int iam_it_stop(int fd, struct iam_uapi_info *ua,
586                 int key_need_convert, char *key_buf,
587                 int rec_need_convert, char *rec_buf)
588 {
589         return iam_doop(fd, ua, IAM_IOC_IT_STOP,
590                         key_need_convert, key_buf, NULL, NULL,
591                         rec_need_convert, rec_buf, NULL, NULL);
592 }
593
594 /*
595  * Change iam file mode.
596  */
597 int iam_polymorph(char *filename, unsigned long mode)
598 {
599         int fd;
600         int ret;
601
602         if (!filename) {
603                 errno = EINVAL;
604                 return -1;
605         }
606
607         fd = open(filename, O_RDONLY);
608         if (fd < 0)
609                 return -1;
610
611         ret = ioctl(fd, IAM_IOC_POLYMORPH, mode);
612         close(fd);
613         return ret;
614 }