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