1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2 * vim:expandtab:shiftwidth=8:tabstop=8:
6 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 only,
10 * as published by the Free Software Foundation.
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License version 2 for more details (a copy is included
16 * in the LICENSE file that accompanied this code).
18 * You should have received a copy of the GNU General Public License
19 * version 2 along with this program; If not, see
20 * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
22 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
23 * CA 95054 USA or visit www.sun.com if you need additional information or
29 * Copyright 2008 Sun Microsystems, Inc. All rights reserved
30 * Use is subject to license terms.
33 * This file is part of Lustre, http://www.lustre.org/
34 * Lustre is a trademark of Sun Microsystems, Inc.
36 * lustre/utils/libiam.c
38 * iam user level library
40 * Author: Wang Di <wangdi@clusterfs.com>
41 * Author: Nikita Danilov <nikita@clusterfs.com>
42 * Author: Fan Yong <fanyong@clusterfs.com>
53 #include <sys/types.h>
59 #include <libcfs/libcfs.h>
60 #include <liblustre.h>
61 #include <lustre/libiam.h>
63 typedef __u32 lvar_hash_t;
66 IAM_LFIX_ROOT_MAGIC = 0xbedabb1edULL,
67 IAM_LVAR_ROOT_MAGIC = 0xb01dface
70 struct iam_lfix_root {
72 u_int16_t ilr_keysize;
73 u_int16_t ilr_recsize;
74 u_int16_t ilr_ptrsize;
75 u_int16_t ilr_indirect_levels;
79 IAM_LEAF_HEADER_MAGIC = 0x1976,
80 IAM_LVAR_LEAF_MAGIC = 0x1973
83 struct iam_leaf_head {
88 struct dx_countlimit {
93 struct lvar_leaf_header {
94 u_int16_t vlh_magic; /* magic number IAM_LVAR_LEAF_MAGIC */
95 u_int16_t vlh_used; /* used bytes, including header */
100 u_int16_t vr_recsize;
101 u_int16_t vr_ptrsize;
102 u_int8_t vr_indirect_levels;
103 u_int8_t vr_padding0;
104 u_int16_t vr_padding1;
107 struct lvar_leaf_entry {
109 u_int16_t vle_keysize;
115 LVAR_ROUND = LVAR_PAD - 1
119 * Stores \a val at \a dst, where the latter is possibly unaligned. Uses
120 * memcpy(). This macro is needed to avoid dependency of user level tools on
121 * the kernel headers.
123 #define STORE_UNALIGNED(val, dst) \
125 typeof(*(dst)) __val = (val); \
127 memcpy(dst, &__val, sizeof *(dst)); \
130 static int root_limit(int rootgap, int blocksize, int size)
135 limit = (blocksize - rootgap) / size;
136 nlimit = blocksize / size;
142 static int lfix_root_limit(int blocksize, int size)
144 return root_limit(sizeof(struct iam_lfix_root), blocksize, size);
147 static void lfix_root(void *buf,
148 int blocksize, int keysize, int ptrsize, int recsize)
150 struct iam_lfix_root *root;
151 struct dx_countlimit *limit;
155 *root = (typeof(*root)) {
156 .ilr_magic = cpu_to_le64(IAM_LFIX_ROOT_MAGIC),
157 .ilr_keysize = cpu_to_le16(keysize),
158 .ilr_recsize = cpu_to_le16(recsize),
159 .ilr_ptrsize = cpu_to_le16(ptrsize),
160 .ilr_indirect_levels = 0
163 limit = (void *)(root + 1);
164 *limit = (typeof(*limit)){
166 * limit itself + one pointer to the leaf.
168 .count = cpu_to_le16(2),
169 .limit = lfix_root_limit(blocksize, keysize + ptrsize)
176 entry += keysize + ptrsize;
179 * Entry format is <key> followed by <ptr>. In the minimal tree
180 * consisting of a root and single node, <key> is a minimal possible
183 * XXX: this key is hard-coded to be a sequence of 0's.
186 /* now @entry points to <ptr> */
188 STORE_UNALIGNED(cpu_to_le32(1), (u_int32_t *)entry);
190 STORE_UNALIGNED(cpu_to_le64(1), (u_int64_t *)entry);
193 static void lfix_leaf(void *buf,
194 int blocksize, int keysize, int ptrsize, int recsize)
196 struct iam_leaf_head *head;
200 *head = (typeof(*head)) {
201 .ill_magic = cpu_to_le16(IAM_LEAF_HEADER_MAGIC),
203 * Leaf contains an entry with the smallest possible key
204 * (created by zeroing).
206 .ill_count = cpu_to_le16(1),
210 static int lvar_root_limit(int blocksize, int size)
212 return root_limit(sizeof(struct lvar_root), blocksize, size);
215 static void lvar_root(void *buf,
216 int blocksize, int keysize, int ptrsize, int recsize)
218 struct lvar_root *root;
219 struct dx_countlimit *limit;
223 isize = sizeof(lvar_hash_t) + ptrsize;
225 *root = (typeof(*root)) {
226 .vr_magic = cpu_to_le32(IAM_LVAR_ROOT_MAGIC),
227 .vr_recsize = cpu_to_le16(recsize),
228 .vr_ptrsize = cpu_to_le16(ptrsize),
229 .vr_indirect_levels = 0
232 limit = (void *)(root + 1);
233 *limit = (typeof(*limit)) {
235 * limit itself + one pointer to the leaf.
237 .count = cpu_to_le16(2),
238 .limit = lvar_root_limit(blocksize, keysize + ptrsize)
248 * Entry format is <key> followed by <ptr>. In the minimal tree
249 * consisting of a root and single node, <key> is a minimal possible
252 * XXX: this key is hard-coded to be a sequence of 0's.
254 entry += sizeof(lvar_hash_t);
255 /* now @entry points to <ptr> */
257 STORE_UNALIGNED(cpu_to_le32(1), (u_int32_t *)entry);
259 STORE_UNALIGNED(cpu_to_le64(1), (u_int64_t *)entry);
262 static int lvar_esize(int namelen, int recsize)
264 return (offsetof(struct lvar_leaf_entry, vle_key) +
265 namelen + recsize + LVAR_ROUND) & ~LVAR_ROUND;
268 static void lvar_leaf(void *buf,
269 int blocksize, int keysize, int ptrsize, int recsize)
271 struct lvar_leaf_header *head;
276 *head = (typeof(*head)) {
277 .vlh_magic = cpu_to_le16(IAM_LVAR_LEAF_MAGIC),
278 .vlh_used = cpu_to_le16(sizeof *head + lvar_esize(0, recsize))
280 rec = (void *)(head + 1);
281 rec[offsetof(struct lvar_leaf_entry, vle_key)] = recsize;
291 struct iam_uapi_op iui_op;
296 IAM_IOC_INIT = _IOW('i', 1, struct iam_uapi_info),
297 IAM_IOC_GETINFO = _IOR('i', 2, struct iam_uapi_info),
298 IAM_IOC_INSERT = _IOR('i', 3, struct iam_uapi_op),
299 IAM_IOC_LOOKUP = _IOWR('i', 4, struct iam_uapi_op),
300 IAM_IOC_DELETE = _IOR('i', 5, struct iam_uapi_op),
301 IAM_IOC_IT_START = _IOR('i', 6, struct iam_uapi_it),
302 IAM_IOC_IT_NEXT = _IOW('i', 7, struct iam_uapi_it),
303 IAM_IOC_IT_STOP = _IOR('i', 8, struct iam_uapi_it),
304 IAM_IOC_POLYMORPH = _IOR('i', 9, unsigned long)
307 static unsigned char hex2dec(unsigned char hex)
309 if (('0' <= hex) && (hex <= '9'))
311 else if (('a' <= hex) && (hex <= 'f'))
312 return hex - 'a' + 10;
313 else if (('A' <= hex) && (hex <= 'F'))
314 return hex - 'A' + 10;
319 static unsigned char *packdigit(unsigned char *number)
324 area = calloc(strlen((char *)number) / 2 + 2, sizeof(char));
326 for (scan = area; *number; number += 2, scan++)
327 *scan = (hex2dec(number[0]) << 4) | hex2dec(number[1]);
332 static char *iam_convert(int size, int need_convert, char *source)
340 ptr = calloc(size + 1, sizeof(char));
345 opt = packdigit((unsigned char*)source);
350 memcpy(ptr, opt, size + 1);
354 strncpy(ptr, source, size + 1);
360 static int iam_doop(int fd, struct iam_uapi_info *ua, int cmd,
361 int key_need_convert, char *key_buf,
362 int *keysize, char *save_key,
363 int rec_need_convert, char *rec_buf,
364 int *recsize, char *save_rec)
369 struct iam_uapi_op op;
371 key = iam_convert(ua->iui_keysize, key_need_convert, key_buf);
375 rec = iam_convert(ua->iui_recsize, rec_need_convert, rec_buf);
383 ret = ioctl(fd, cmd, &op);
385 if ((keysize != NULL) && (*keysize > 0) && (save_key != NULL)) {
386 if (*keysize > ua->iui_keysize)
387 *keysize = ua->iui_keysize;
388 memcpy(save_key, key, *keysize);
390 if ((recsize != NULL) && (*recsize > 0) && (save_rec != NULL)) {
391 if (*recsize > ua->iui_recsize)
392 *recsize = ua->iui_recsize;
393 memcpy(save_rec, rec, *recsize);
403 * Creat an iam file, but do NOT open it.
404 * Return 0 if success, else -1.
406 int iam_creat(char *filename, enum iam_fmt_t fmt,
407 int blocksize, int keysize, int recsize, int ptrsize)
412 if (filename == NULL) {
417 if ((fmt != FMT_LFIX) && (fmt != FMT_LVAR)) {
422 if (blocksize <= 100) {
437 if (ptrsize != 4 && ptrsize != 8) {
442 if (keysize + recsize + sizeof(struct iam_leaf_head) > blocksize / 3) {
447 fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT, 0600);
452 buf = malloc(blocksize);
458 memset(buf, 0, blocksize);
460 lfix_root(buf, blocksize, keysize, ptrsize, recsize);
462 lvar_root(buf, blocksize, keysize, ptrsize, recsize);
464 if (write(fd, buf, blocksize) != blocksize) {
470 memset(buf, 0, blocksize);
472 lfix_leaf(buf, blocksize, keysize, ptrsize, recsize);
474 lvar_leaf(buf, blocksize, keysize, ptrsize, recsize);
476 if (write(fd, buf, blocksize) != blocksize) {
488 * Open an iam file, but do NOT creat it if the file doesn't exist.
489 * Please use iam_creat for creating the file before use iam_open.
490 * Return file id (fd) if success, else -1.
492 int iam_open(char *filename, struct iam_uapi_info *ua)
496 if (filename == NULL) {
506 fd = open(filename, O_RDONLY);
511 if (ioctl(fd, IAM_IOC_INIT, ua) != 0) {
516 if (ioctl(fd, IAM_IOC_GETINFO, ua) != 0) {
525 * Close file opened by iam_open.
527 int iam_close(int fd)
533 * Please use iam_open before use this function.
535 int iam_insert(int fd, struct iam_uapi_info *ua,
536 int key_need_convert, char *key_buf,
537 int rec_need_convert, char *rec_buf)
539 return iam_doop(fd, ua, IAM_IOC_INSERT,
540 key_need_convert, key_buf, NULL, NULL,
541 rec_need_convert, rec_buf, NULL, NULL);
545 * Please use iam_open before use this function.
547 int iam_lookup(int fd, struct iam_uapi_info *ua,
548 int key_need_convert, char *key_buf,
549 int *keysize, char *save_key,
550 int rec_need_convert, char *rec_buf,
551 int *recsize, char *save_rec)
553 return iam_doop(fd, ua, IAM_IOC_LOOKUP,
554 key_need_convert, key_buf, keysize, save_key,
555 rec_need_convert, rec_buf, recsize, save_rec);
559 * Please use iam_open before use this function.
561 int iam_delete(int fd, struct iam_uapi_info *ua,
562 int key_need_convert, char *key_buf,
563 int rec_need_convert, char *rec_buf)
565 return iam_doop(fd, ua, IAM_IOC_DELETE,
566 key_need_convert, key_buf, NULL, NULL,
567 rec_need_convert, rec_buf, NULL, NULL);
571 * Please use iam_open before use this function.
573 int iam_it_start(int fd, struct iam_uapi_info *ua,
574 int key_need_convert, char *key_buf,
575 int *keysize, char *save_key,
576 int rec_need_convert, char *rec_buf,
577 int *recsize, char *save_rec)
579 return iam_doop(fd, ua, IAM_IOC_IT_START,
580 key_need_convert, key_buf, keysize, save_key,
581 rec_need_convert, rec_buf, recsize, save_rec);
585 * Please use iam_open before use this function.
587 int iam_it_next(int fd, struct iam_uapi_info *ua,
588 int key_need_convert, char *key_buf,
589 int *keysize, char *save_key,
590 int rec_need_convert, char *rec_buf,
591 int *recsize, char *save_rec)
593 return iam_doop(fd, ua, IAM_IOC_IT_NEXT,
594 key_need_convert, key_buf, keysize, save_key,
595 rec_need_convert, rec_buf, recsize, save_rec);
599 * Please use iam_open before use this function.
601 int iam_it_stop(int fd, struct iam_uapi_info *ua,
602 int key_need_convert, char *key_buf,
603 int rec_need_convert, char *rec_buf)
605 return iam_doop(fd, ua, IAM_IOC_IT_STOP,
606 key_need_convert, key_buf, NULL, NULL,
607 rec_need_convert, rec_buf, NULL, NULL);
611 * Change iam file mode.
613 int iam_polymorph(char *filename, unsigned long mode)
618 if (filename == NULL) {
623 fd = open(filename, O_RDONLY);
628 ret = ioctl(fd, IAM_IOC_POLYMORPH, mode);