1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2 * vim:expandtab:shiftwidth=8:tabstop=8:
5 * iam user level library
7 * Copyright (c) 2006 Cluster File Systems, Inc.
8 * Author: Wang Di <wangdi@clusterfs.com>
9 * Author: Nikita Danilov <nikita@clusterfs.com>
10 * Author: Fan Yong <fanyong@clusterfs.com>
12 * This file is part of the Lustre file system, http://www.lustre.org
13 * Lustre is a trademark of Cluster File Systems, Inc.
15 * You may have signed or agreed to another license before downloading
16 * this software. If so, you are bound by the terms and conditions
17 * of that agreement, and the following does not apply to you. See the
18 * LICENSE file included with this distribution for more information.
20 * If you did not agree to a different license, then this copy of Lustre
21 * is open source software; you can redistribute it and/or modify it
22 * under the terms of version 2 of the GNU General Public License as
23 * published by the Free Software Foundation.
25 * In either case, Lustre is distributed in the hope that it will be
26 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
27 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * license text for more details.
39 #include <sys/types.h>
45 #include <libcfs/libcfs.h>
46 #include <liblustre.h>
47 #include <lustre/libiam.h>
49 typedef __u32 lvar_hash_t;
52 IAM_LFIX_ROOT_MAGIC = 0xbedabb1edULL,
53 IAM_LVAR_ROOT_MAGIC = 0xb01dface
56 struct iam_lfix_root {
58 u_int16_t ilr_keysize;
59 u_int16_t ilr_recsize;
60 u_int16_t ilr_ptrsize;
61 u_int16_t ilr_indirect_levels;
65 IAM_LEAF_HEADER_MAGIC = 0x1976,
66 IAM_LVAR_LEAF_MAGIC = 0x1973
69 struct iam_leaf_head {
74 struct dx_countlimit {
79 struct lvar_leaf_header {
80 u_int16_t vlh_magic; /* magic number IAM_LVAR_LEAF_MAGIC */
81 u_int16_t vlh_used; /* used bytes, including header */
88 u_int8_t vr_indirect_levels;
90 u_int16_t vr_padding1;
93 struct lvar_leaf_entry {
95 u_int16_t vle_keysize;
101 LVAR_ROUND = LVAR_PAD - 1
105 * Stores \a val at \a dst, where the latter is possibly unaligned. Uses
106 * memcpy(). This macro is needed to avoid dependency of user level tools on
107 * the kernel headers.
109 #define STORE_UNALIGNED(val, dst) \
111 typeof(*(dst)) __val = (val); \
113 memcpy(dst, &__val, sizeof *(dst)); \
116 static int root_limit(int rootgap, int blocksize, int size)
121 limit = (blocksize - rootgap) / size;
122 nlimit = blocksize / size;
128 static int lfix_root_limit(int blocksize, int size)
130 return root_limit(sizeof(struct iam_lfix_root), blocksize, size);
133 static void lfix_root(void *buf,
134 int blocksize, int keysize, int ptrsize, int recsize)
136 struct iam_lfix_root *root;
137 struct dx_countlimit *limit;
141 *root = (typeof(*root)) {
142 .ilr_magic = cpu_to_le64(IAM_LFIX_ROOT_MAGIC),
143 .ilr_keysize = cpu_to_le16(keysize),
144 .ilr_recsize = cpu_to_le16(recsize),
145 .ilr_ptrsize = cpu_to_le16(ptrsize),
146 .ilr_indirect_levels = 0
149 limit = (void *)(root + 1);
150 *limit = (typeof(*limit)){
152 * limit itself + one pointer to the leaf.
154 .count = cpu_to_le16(2),
155 .limit = lfix_root_limit(blocksize, keysize + ptrsize)
162 entry += keysize + ptrsize;
165 * Entry format is <key> followed by <ptr>. In the minimal tree
166 * consisting of a root and single node, <key> is a minimal possible
169 * XXX: this key is hard-coded to be a sequence of 0's.
172 /* now @entry points to <ptr> */
174 STORE_UNALIGNED(cpu_to_le32(1), (u_int32_t *)entry);
176 STORE_UNALIGNED(cpu_to_le64(1), (u_int64_t *)entry);
179 static void lfix_leaf(void *buf,
180 int blocksize, int keysize, int ptrsize, int recsize)
182 struct iam_leaf_head *head;
186 *head = (typeof(*head)) {
187 .ill_magic = cpu_to_le16(IAM_LEAF_HEADER_MAGIC),
189 * Leaf contains an entry with the smallest possible key
190 * (created by zeroing).
192 .ill_count = cpu_to_le16(1),
196 static int lvar_root_limit(int blocksize, int size)
198 return root_limit(sizeof(struct lvar_root), blocksize, size);
201 static void lvar_root(void *buf,
202 int blocksize, int keysize, int ptrsize, int recsize)
204 struct lvar_root *root;
205 struct dx_countlimit *limit;
209 isize = sizeof(lvar_hash_t) + ptrsize;
211 *root = (typeof(*root)) {
212 .vr_magic = cpu_to_le32(IAM_LVAR_ROOT_MAGIC),
213 .vr_recsize = cpu_to_le16(recsize),
214 .vr_ptrsize = cpu_to_le16(ptrsize),
215 .vr_indirect_levels = 0
218 limit = (void *)(root + 1);
219 *limit = (typeof(*limit)) {
221 * limit itself + one pointer to the leaf.
223 .count = cpu_to_le16(2),
224 .limit = lvar_root_limit(blocksize, keysize + ptrsize)
234 * Entry format is <key> followed by <ptr>. In the minimal tree
235 * consisting of a root and single node, <key> is a minimal possible
238 * XXX: this key is hard-coded to be a sequence of 0's.
240 entry += sizeof(lvar_hash_t);
241 /* now @entry points to <ptr> */
243 STORE_UNALIGNED(cpu_to_le32(1), (u_int32_t *)entry);
245 STORE_UNALIGNED(cpu_to_le64(1), (u_int64_t *)entry);
248 static int lvar_esize(int namelen, int recsize)
250 return (offsetof(struct lvar_leaf_entry, vle_key) +
251 namelen + recsize + LVAR_ROUND) & ~LVAR_ROUND;
254 static void lvar_leaf(void *buf,
255 int blocksize, int keysize, int ptrsize, int recsize)
257 struct lvar_leaf_header *head;
262 *head = (typeof(*head)) {
263 .vlh_magic = cpu_to_le16(IAM_LVAR_LEAF_MAGIC),
264 .vlh_used = cpu_to_le16(sizeof *head + lvar_esize(0, recsize))
266 rec = (void *)(head + 1);
267 rec[offsetof(struct lvar_leaf_entry, vle_key)] = recsize;
277 struct iam_uapi_op iui_op;
282 IAM_IOC_INIT = _IOW('i', 1, struct iam_uapi_info),
283 IAM_IOC_GETINFO = _IOR('i', 2, struct iam_uapi_info),
284 IAM_IOC_INSERT = _IOR('i', 3, struct iam_uapi_op),
285 IAM_IOC_LOOKUP = _IOWR('i', 4, struct iam_uapi_op),
286 IAM_IOC_DELETE = _IOR('i', 5, struct iam_uapi_op),
287 IAM_IOC_IT_START = _IOR('i', 6, struct iam_uapi_it),
288 IAM_IOC_IT_NEXT = _IOW('i', 7, struct iam_uapi_it),
289 IAM_IOC_IT_STOP = _IOR('i', 8, struct iam_uapi_it),
290 IAM_IOC_POLYMORPH = _IOR('i', 9, unsigned long)
293 static unsigned char hex2dec(unsigned char hex)
295 if (('0' <= hex) && (hex <= '9'))
297 else if (('a' <= hex) && (hex <= 'f'))
298 return hex - 'a' + 10;
299 else if (('A' <= hex) && (hex <= 'F'))
300 return hex - 'A' + 10;
305 static unsigned char *packdigit(unsigned char *number)
310 area = calloc(strlen(number) / 2 + 2, sizeof(char));
312 for (scan = area; *number; number += 2, scan++)
313 *scan = (hex2dec(number[0]) << 4) | hex2dec(number[1]);
318 static char *iam_convert(int size, int need_convert, char *source)
326 ptr = calloc(size + 1, sizeof(char));
331 opt = packdigit(source);
336 memcpy(ptr, opt, size + 1);
340 strncpy(ptr, source, size + 1);
346 static int iam_doop(int fd, struct iam_uapi_info *ua, int cmd,
347 int key_need_convert, char *key_buf,
348 int *keysize, char *save_key,
349 int rec_need_convert, char *rec_buf,
350 int *recsize, char *save_rec)
355 struct iam_uapi_op op;
357 key = iam_convert(ua->iui_keysize, key_need_convert, key_buf);
361 rec = iam_convert(ua->iui_recsize, rec_need_convert, rec_buf);
369 ret = ioctl(fd, cmd, &op);
371 if ((keysize != NULL) && (*keysize > 0) && (save_key != NULL)) {
372 if (*keysize > ua->iui_keysize)
373 *keysize = ua->iui_keysize;
374 memcpy(save_key, key, *keysize);
376 if ((recsize != NULL) && (*recsize > 0) && (save_rec != NULL)) {
377 if (*recsize > ua->iui_recsize)
378 *recsize = ua->iui_recsize;
379 memcpy(save_rec, rec, *recsize);
389 * Creat an iam file, but do NOT open it.
390 * Return 0 if success, else -1.
392 int iam_creat(char *filename, enum iam_fmt_t fmt,
393 int blocksize, int keysize, int recsize, int ptrsize)
398 if (filename == NULL) {
403 if ((fmt != FMT_LFIX) && (fmt != FMT_LVAR)) {
408 if (blocksize <= 100) {
423 if (ptrsize != 4 && ptrsize != 8) {
428 if (keysize + recsize + sizeof(struct iam_leaf_head) > blocksize / 3) {
433 fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT, 0600);
438 buf = malloc(blocksize);
444 memset(buf, 0, blocksize);
446 lfix_root(buf, blocksize, keysize, ptrsize, recsize);
448 lvar_root(buf, blocksize, keysize, ptrsize, recsize);
450 if (write(fd, buf, blocksize) != blocksize) {
456 memset(buf, 0, blocksize);
458 lfix_leaf(buf, blocksize, keysize, ptrsize, recsize);
460 lvar_leaf(buf, blocksize, keysize, ptrsize, recsize);
462 if (write(fd, buf, blocksize) != blocksize) {
474 * Open an iam file, but do NOT creat it if the file doesn't exist.
475 * Please use iam_creat for creating the file before use iam_open.
476 * Return file id (fd) if success, else -1.
478 int iam_open(char *filename, struct iam_uapi_info *ua)
482 if (filename == NULL) {
492 fd = open(filename, O_RDONLY);
497 if (ioctl(fd, IAM_IOC_INIT, ua) != 0) {
502 if (ioctl(fd, IAM_IOC_GETINFO, ua) != 0) {
511 * Close file opened by iam_open.
513 int iam_close(int fd)
519 * Please use iam_open before use this function.
521 int iam_insert(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_INSERT,
526 key_need_convert, key_buf, NULL, NULL,
527 rec_need_convert, rec_buf, NULL, NULL);
531 * Please use iam_open before use this function.
533 int iam_lookup(int fd, struct iam_uapi_info *ua,
534 int key_need_convert, char *key_buf,
535 int *keysize, char *save_key,
536 int rec_need_convert, char *rec_buf,
537 int *recsize, char *save_rec)
539 return iam_doop(fd, ua, IAM_IOC_LOOKUP,
540 key_need_convert, key_buf, keysize, save_key,
541 rec_need_convert, rec_buf, recsize, save_rec);
545 * Please use iam_open before use this function.
547 int iam_delete(int fd, struct iam_uapi_info *ua,
548 int key_need_convert, char *key_buf,
549 int rec_need_convert, char *rec_buf)
551 return iam_doop(fd, ua, IAM_IOC_DELETE,
552 key_need_convert, key_buf, NULL, NULL,
553 rec_need_convert, rec_buf, NULL, NULL);
557 * Please use iam_open before use this function.
559 int iam_it_start(int fd, struct iam_uapi_info *ua,
560 int key_need_convert, char *key_buf,
561 int *keysize, char *save_key,
562 int rec_need_convert, char *rec_buf,
563 int *recsize, char *save_rec)
565 return iam_doop(fd, ua, IAM_IOC_IT_START,
566 key_need_convert, key_buf, keysize, save_key,
567 rec_need_convert, rec_buf, recsize, save_rec);
571 * Please use iam_open before use this function.
573 int iam_it_next(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_NEXT,
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_stop(int fd, struct iam_uapi_info *ua,
588 int key_need_convert, char *key_buf,
589 int rec_need_convert, char *rec_buf)
591 return iam_doop(fd, ua, IAM_IOC_IT_STOP,
592 key_need_convert, key_buf, NULL, NULL,
593 rec_need_convert, rec_buf, NULL, NULL);
597 * Change iam file mode.
599 int iam_polymorph(char *filename, unsigned long mode)
604 if (filename == NULL) {
609 fd = open(filename, O_RDONLY);
614 ret = ioctl(fd, IAM_IOC_POLYMORPH, mode);