4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
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.
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).
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
23 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Use is subject to license terms.
26 * Copyright (c) 2014, 2015, Intel Corporation.
29 * This file is part of Lustre, http://www.lustre.org/
31 * lustre/utils/libiam.c
33 * iam user level library
35 * Author: Wang Di <wangdi@clusterfs.com>
36 * Author: Nikita Danilov <nikita@clusterfs.com>
37 * Author: Fan Yong <fanyong@clusterfs.com>
47 #include <sys/ioctl.h>
48 #include <sys/types.h>
50 #include <libcfs/util/string.h>
51 #include <lustre/libiam.h>
53 typedef __u32 lvar_hash_t;
56 * Stores \a val at \a dst, where the latter is possibly unaligned. Uses
57 * memcpy(). This macro is needed to avoid dependency of user level tools on
60 #define STORE_UNALIGNED(val, dst) \
62 typeof(*(dst)) __val = (val); \
64 memcpy(dst, &__val, sizeof *(dst)); \
68 static int lfix_root_limit(int blocksize, int size)
70 return root_limit(sizeof(struct iam_lfix_root), 0, blocksize, size);
73 static void lfix_root(void *buf,
74 int blocksize, int keysize, int ptrsize, int recsize)
76 struct iam_lfix_root *root;
77 struct dx_countlimit *limit;
81 *root = (typeof(*root)) {
82 .ilr_magic = htole64(IAM_LFIX_ROOT_MAGIC),
83 .ilr_keysize = htole16(keysize),
84 .ilr_recsize = htole16(recsize),
85 .ilr_ptrsize = htole16(ptrsize),
86 .ilr_indirect_levels = 0
89 limit = (void *)(root + 1);
90 *limit = (typeof(*limit)){
92 * limit itself + one pointer to the leaf.
95 .limit = lfix_root_limit(blocksize, keysize + ptrsize)
102 entry += keysize + ptrsize;
105 * Entry format is <key> followed by <ptr>. In the minimal tree
106 * consisting of a root and single node, <key> is a minimal possible
109 * XXX: this key is hard-coded to be a sequence of 0's.
112 /* now @entry points to <ptr> */
114 STORE_UNALIGNED(htole32(1), (u_int32_t *)entry);
116 STORE_UNALIGNED(htole64(1), (u_int64_t *)entry);
119 static void lfix_leaf(void *buf,
120 int blocksize, int keysize, int ptrsize, int recsize)
122 struct iam_leaf_head *head;
126 *head = (typeof(*head)) {
127 .ill_magic = htole16(IAM_LEAF_HEADER_MAGIC),
129 * Leaf contains an entry with the smallest possible key
130 * (created by zeroing).
132 .ill_count = htole16(1),
136 static int lvar_root_limit(int blocksize, int size)
138 return root_limit(sizeof(struct lvar_root), 0, blocksize, size);
141 static void lvar_root(void *buf,
142 int blocksize, int keysize, int ptrsize, int recsize)
144 struct lvar_root *root;
145 struct dx_countlimit *limit;
149 isize = sizeof(lvar_hash_t) + ptrsize;
151 *root = (typeof(*root)) {
152 .vr_magic = htole32(IAM_LVAR_ROOT_MAGIC),
153 .vr_recsize = htole16(recsize),
154 .vr_ptrsize = htole16(ptrsize),
155 .vr_indirect_levels = 0
158 limit = (void *)(root + 1);
159 *limit = (typeof(*limit)) {
161 * limit itself + one pointer to the leaf.
164 .limit = lvar_root_limit(blocksize, keysize + ptrsize)
174 * Entry format is <key> followed by <ptr>. In the minimal tree
175 * consisting of a root and single node, <key> is a minimal possible
178 * XXX: this key is hard-coded to be a sequence of 0's.
180 entry += sizeof(lvar_hash_t);
181 /* now @entry points to <ptr> */
183 STORE_UNALIGNED(htole32(1), (u_int32_t *)entry);
185 STORE_UNALIGNED(htole64(1), (u_int64_t *)entry);
188 static int lvar_esize(int namelen, int recsize)
190 return (offsetof(struct lvar_leaf_entry, vle_key) +
191 namelen + recsize + LVAR_ROUND) & ~LVAR_ROUND;
194 static void lvar_leaf(void *buf,
195 int blocksize, int keysize, int ptrsize, int recsize)
197 struct lvar_leaf_header *head;
202 *head = (typeof(*head)) {
203 .vlh_magic = htole16(IAM_LVAR_LEAF_MAGIC),
204 .vlh_used = htole16(sizeof(*head) + lvar_esize(0, recsize))
206 rec = (void *)(head + 1);
207 rec[offsetof(struct lvar_leaf_entry, vle_key)] = recsize;
216 struct iam_uapi_op iui_op;
221 IAM_IOC_INIT = _IOW('i', 1, struct iam_uapi_info),
222 IAM_IOC_GETINFO = _IOR('i', 2, struct iam_uapi_info),
223 IAM_IOC_INSERT = _IOR('i', 3, struct iam_uapi_op),
224 IAM_IOC_LOOKUP = _IOWR('i', 4, struct iam_uapi_op),
225 IAM_IOC_DELETE = _IOR('i', 5, struct iam_uapi_op),
226 IAM_IOC_IT_START = _IOR('i', 6, struct iam_uapi_it),
227 IAM_IOC_IT_NEXT = _IOW('i', 7, struct iam_uapi_it),
228 IAM_IOC_IT_STOP = _IOR('i', 8, struct iam_uapi_it),
229 IAM_IOC_POLYMORPH = _IOR('i', 9, unsigned long)
232 static unsigned char hex2dec(unsigned char hex)
234 if (('0' <= hex) && (hex <= '9'))
236 else if (('a' <= hex) && (hex <= 'f'))
237 return hex - 'a' + 10;
238 else if (('A' <= hex) && (hex <= 'F'))
239 return hex - 'A' + 10;
243 static unsigned char *packdigit(unsigned char *number)
248 area = calloc(strlen((char *)number) / 2 + 2, sizeof(char));
250 for (scan = area; *number; number += 2, scan++)
251 *scan = (hex2dec(number[0]) << 4) | hex2dec(number[1]);
256 static char *iam_convert(int size, int need_convert, char *source)
265 ptr = calloc(size + 1, sizeof(char));
269 opt = packdigit((unsigned char *)source);
274 memcpy(ptr, opt, size + 1);
277 ptr = strdup(source);
283 static int iam_doop(int fd, struct iam_uapi_info *ua, int cmd,
284 int key_need_convert, char *key_buf,
285 int *keysize, char *save_key,
286 int rec_need_convert, char *rec_buf,
287 int *recsize, char *save_rec)
292 struct iam_uapi_op op;
294 key = iam_convert(ua->iui_keysize, key_need_convert, key_buf);
298 rec = iam_convert(ua->iui_recsize, rec_need_convert, rec_buf);
306 ret = ioctl(fd, cmd, &op);
308 if ((keysize) && (*keysize > 0) && (save_key)) {
309 if (*keysize > ua->iui_keysize)
310 *keysize = ua->iui_keysize;
311 memcpy(save_key, key, *keysize);
313 if ((recsize) && (*recsize > 0) && (save_rec)) {
314 if (*recsize > ua->iui_recsize)
315 *recsize = ua->iui_recsize;
316 memcpy(save_rec, rec, *recsize);
325 * Creat an iam file, but do NOT open it.
326 * Return 0 if success, else -1.
328 int iam_creat(char *filename, enum iam_fmt_t fmt,
329 int blocksize, int keysize, int recsize, int ptrsize)
339 if ((fmt != FMT_LFIX) && (fmt != FMT_LVAR)) {
344 if (blocksize <= 100) {
359 if (ptrsize != 4 && ptrsize != 8) {
364 if (keysize + recsize + sizeof(struct iam_leaf_head) > blocksize / 3) {
369 fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT, 0600);
373 buf = malloc(blocksize);
379 memset(buf, 0, blocksize);
381 lfix_root(buf, blocksize, keysize, ptrsize, recsize);
383 lvar_root(buf, blocksize, keysize, ptrsize, recsize);
385 if (write(fd, buf, blocksize) != blocksize) {
391 memset(buf, 0, blocksize);
393 lfix_leaf(buf, blocksize, keysize, ptrsize, recsize);
395 lvar_leaf(buf, blocksize, keysize, ptrsize, recsize);
397 if (write(fd, buf, blocksize) != blocksize) {
409 * Open an iam file, but do NOT creat it if the file doesn't exist.
410 * Please use iam_creat for creating the file before use iam_open.
411 * Return file id (fd) if success, else -1.
413 int iam_open(char *filename, struct iam_uapi_info *ua)
427 fd = open(filename, O_RDONLY);
431 if (ioctl(fd, IAM_IOC_INIT, ua) != 0) {
436 if (ioctl(fd, IAM_IOC_GETINFO, ua) != 0) {
445 * Close file opened by iam_open.
447 int iam_close(int fd)
453 * Please use iam_open before use this function.
455 int iam_insert(int fd, struct iam_uapi_info *ua,
456 int key_need_convert, char *key_buf,
457 int rec_need_convert, char *rec_buf)
459 return iam_doop(fd, ua, IAM_IOC_INSERT,
460 key_need_convert, key_buf, NULL, NULL,
461 rec_need_convert, rec_buf, NULL, NULL);
465 * Please use iam_open before use this function.
467 int iam_lookup(int fd, struct iam_uapi_info *ua,
468 int key_need_convert, char *key_buf,
469 int *keysize, char *save_key,
470 int rec_need_convert, char *rec_buf,
471 int *recsize, char *save_rec)
473 return iam_doop(fd, ua, IAM_IOC_LOOKUP,
474 key_need_convert, key_buf, keysize, save_key,
475 rec_need_convert, rec_buf, recsize, save_rec);
479 * Please use iam_open before use this function.
481 int iam_delete(int fd, struct iam_uapi_info *ua,
482 int key_need_convert, char *key_buf,
483 int rec_need_convert, char *rec_buf)
485 return iam_doop(fd, ua, IAM_IOC_DELETE,
486 key_need_convert, key_buf, NULL, NULL,
487 rec_need_convert, rec_buf, NULL, NULL);
491 * Please use iam_open before use this function.
493 int iam_it_start(int fd, struct iam_uapi_info *ua,
494 int key_need_convert, char *key_buf,
495 int *keysize, char *save_key,
496 int rec_need_convert, char *rec_buf,
497 int *recsize, char *save_rec)
499 return iam_doop(fd, ua, IAM_IOC_IT_START,
500 key_need_convert, key_buf, keysize, save_key,
501 rec_need_convert, rec_buf, recsize, save_rec);
505 * Please use iam_open before use this function.
507 int iam_it_next(int fd, struct iam_uapi_info *ua,
508 int key_need_convert, char *key_buf,
509 int *keysize, char *save_key,
510 int rec_need_convert, char *rec_buf,
511 int *recsize, char *save_rec)
513 return iam_doop(fd, ua, IAM_IOC_IT_NEXT,
514 key_need_convert, key_buf, keysize, save_key,
515 rec_need_convert, rec_buf, recsize, save_rec);
519 * Please use iam_open before use this function.
521 int iam_it_stop(int fd, struct iam_uapi_info *ua,
522 int key_need_convert, char *key_buf,
523 int rec_need_convert, char *rec_buf)
525 return iam_doop(fd, ua, IAM_IOC_IT_STOP,
526 key_need_convert, key_buf, NULL, NULL,
527 rec_need_convert, rec_buf, NULL, NULL);
531 * Change iam file mode.
533 int iam_polymorph(char *filename, unsigned long mode)
543 fd = open(filename, O_RDONLY);
547 ret = ioctl(fd, IAM_IOC_POLYMORPH, mode);