1 1.2 christos /* $NetBSD: cdbr.c,v 1.2 2017/01/10 23:06:06 christos Exp $ */ 2 1.1 joerg /*- 3 1.1 joerg * Copyright (c) 2010 The NetBSD Foundation, Inc. 4 1.1 joerg * All rights reserved. 5 1.1 joerg * 6 1.1 joerg * This code is derived from software contributed to The NetBSD Foundation 7 1.1 joerg * by Joerg Sonnenberger. 8 1.1 joerg * 9 1.1 joerg * Redistribution and use in source and binary forms, with or without 10 1.1 joerg * modification, are permitted provided that the following conditions 11 1.1 joerg * are met: 12 1.1 joerg * 13 1.1 joerg * 1. Redistributions of source code must retain the above copyright 14 1.1 joerg * notice, this list of conditions and the following disclaimer. 15 1.1 joerg * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 joerg * notice, this list of conditions and the following disclaimer in 17 1.1 joerg * the documentation and/or other materials provided with the 18 1.1 joerg * distribution. 19 1.1 joerg * 20 1.1 joerg * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 1.1 joerg * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 1.1 joerg * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 1.1 joerg * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24 1.1 joerg * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 1.1 joerg * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 26 1.1 joerg * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 27 1.1 joerg * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 28 1.1 joerg * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 1.1 joerg * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 30 1.1 joerg * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 1.1 joerg * SUCH DAMAGE. 32 1.1 joerg */ 33 1.1 joerg 34 1.1 joerg #if HAVE_NBTOOL_CONFIG_H 35 1.1 joerg #include "nbtool_config.h" 36 1.1 joerg #endif 37 1.1 joerg 38 1.1 joerg #include <sys/cdefs.h> 39 1.2 christos __RCSID("$NetBSD: cdbr.c,v 1.2 2017/01/10 23:06:06 christos Exp $"); 40 1.1 joerg 41 1.1 joerg #if !defined(_KERNEL) && !defined(_STANDALONE) 42 1.1 joerg #include "namespace.h" 43 1.1 joerg #endif 44 1.1 joerg 45 1.1 joerg #if !HAVE_NBTOOL_CONFIG_H 46 1.1 joerg #include <sys/bitops.h> 47 1.1 joerg #endif 48 1.1 joerg #if !HAVE_NBTOOL_CONFIG_H || HAVE_SYS_ENDIAN_H 49 1.1 joerg #include <sys/endian.h> 50 1.1 joerg #endif 51 1.1 joerg 52 1.1 joerg #if defined(_KERNEL) || defined(_STANDALONE) 53 1.1 joerg #include <sys/cdbr.h> 54 1.1 joerg #include <sys/kmem.h> 55 1.1 joerg #include <sys/systm.h> 56 1.1 joerg #include <lib/libkern/libkern.h> 57 1.1 joerg #define SET_ERRNO(val) 58 1.1 joerg #define malloc(size) kmem_alloc(size, KM_SLEEP) 59 1.1 joerg #define free(ptr) kmem_free(ptr, sizeof(struct cdbr)) 60 1.1 joerg #else 61 1.1 joerg #include <sys/mman.h> 62 1.1 joerg #include <sys/stat.h> 63 1.1 joerg #include <cdbr.h> 64 1.1 joerg #include <errno.h> 65 1.1 joerg #include <fcntl.h> 66 1.1 joerg #include <inttypes.h> 67 1.1 joerg #include <limits.h> 68 1.1 joerg #include <stdlib.h> 69 1.1 joerg #include <string.h> 70 1.1 joerg #include <unistd.h> 71 1.1 joerg #define SET_ERRNO(val) errno = (val) 72 1.1 joerg #endif 73 1.1 joerg 74 1.1 joerg #if !defined(_KERNEL) && !defined(_STANDALONE) 75 1.1 joerg #ifdef __weak_alias 76 1.1 joerg __weak_alias(cdbr_close,_cdbr_close) 77 1.1 joerg __weak_alias(cdbr_find,_cdbr_find) 78 1.1 joerg __weak_alias(cdbr_get,_cdbr_get) 79 1.1 joerg __weak_alias(cdbr_open,_cdbr_open) 80 1.1 joerg __weak_alias(cdbr_open_mem,_cdbr_open_mem) 81 1.1 joerg #endif 82 1.1 joerg #endif 83 1.1 joerg 84 1.1 joerg #if HAVE_NBTOOL_CONFIG_H 85 1.1 joerg #define fast_divide32_prepare(d,m,s1,s2) (void)0 86 1.1 joerg #define fast_remainder32(v,d,m,s1,s2) (v%d) 87 1.1 joerg #endif 88 1.1 joerg 89 1.1 joerg struct cdbr { 90 1.1 joerg void (*unmap)(void *, void *, size_t); 91 1.1 joerg void *cookie; 92 1.1 joerg uint8_t *mmap_base; 93 1.1 joerg size_t mmap_size; 94 1.1 joerg 95 1.1 joerg uint8_t *hash_base; 96 1.1 joerg uint8_t *offset_base; 97 1.1 joerg uint8_t *data_base; 98 1.1 joerg 99 1.1 joerg uint32_t data_size; 100 1.1 joerg uint32_t entries; 101 1.1 joerg uint32_t entries_index; 102 1.1 joerg uint32_t seed; 103 1.1 joerg 104 1.1 joerg uint8_t offset_size; 105 1.1 joerg uint8_t index_size; 106 1.1 joerg 107 1.1 joerg uint32_t entries_m; 108 1.1 joerg uint32_t entries_index_m; 109 1.1 joerg uint8_t entries_s1, entries_s2; 110 1.1 joerg uint8_t entries_index_s1, entries_index_s2; 111 1.1 joerg }; 112 1.1 joerg 113 1.1 joerg #if !defined(_KERNEL) && !defined(_STANDALONE) 114 1.1 joerg static void 115 1.1 joerg cdbr_unmap(void *cookie __unused, void *base, size_t size) 116 1.1 joerg { 117 1.1 joerg munmap(base, size); 118 1.1 joerg } 119 1.1 joerg 120 1.1 joerg /* ARGSUSED */ 121 1.1 joerg struct cdbr * 122 1.1 joerg cdbr_open(const char *path, int flags) 123 1.1 joerg { 124 1.1 joerg void *base; 125 1.1 joerg size_t size; 126 1.1 joerg int fd; 127 1.1 joerg struct cdbr *cdbr; 128 1.1 joerg struct stat sb; 129 1.1 joerg 130 1.1 joerg if ((fd = open(path, O_RDONLY)) == -1) 131 1.1 joerg return NULL; 132 1.1 joerg if (fstat(fd, &sb) == -1) { 133 1.1 joerg close(fd); 134 1.1 joerg return NULL; 135 1.1 joerg } 136 1.1 joerg 137 1.1 joerg if (sb.st_size >= SSIZE_MAX) { 138 1.1 joerg close(fd); 139 1.1 joerg SET_ERRNO(EINVAL); 140 1.1 joerg return NULL; 141 1.1 joerg } 142 1.1 joerg 143 1.1 joerg 144 1.1 joerg size = (size_t)sb.st_size; 145 1.1 joerg base = mmap(NULL, size, PROT_READ, MAP_FILE|MAP_SHARED, fd, 0); 146 1.1 joerg close(fd); 147 1.1 joerg 148 1.1 joerg if (base == MAP_FAILED) 149 1.1 joerg return NULL; 150 1.1 joerg 151 1.1 joerg cdbr = cdbr_open_mem(base, size, flags, cdbr_unmap, NULL); 152 1.1 joerg if (cdbr == NULL) 153 1.1 joerg munmap(base, size); 154 1.1 joerg return cdbr; 155 1.1 joerg } 156 1.1 joerg #endif 157 1.1 joerg 158 1.1 joerg struct cdbr * 159 1.2 christos cdbr_open_mem(void *base, size_t size, int flags __unused, 160 1.1 joerg void (*unmap)(void *, void *, size_t), void *cookie) 161 1.1 joerg { 162 1.1 joerg struct cdbr *cdbr; 163 1.1 joerg uint8_t *buf = base; 164 1.1 joerg if (size < 40 || memcmp(buf, "NBCDB\n\0\001", 8)) { 165 1.1 joerg SET_ERRNO(EINVAL); 166 1.1 joerg return NULL; 167 1.1 joerg } 168 1.1 joerg 169 1.1 joerg cdbr = malloc(sizeof(*cdbr)); 170 1.1 joerg cdbr->unmap = unmap; 171 1.1 joerg cdbr->cookie = cookie; 172 1.1 joerg 173 1.1 joerg cdbr->data_size = le32dec(buf + 24); 174 1.1 joerg cdbr->entries = le32dec(buf + 28); 175 1.1 joerg cdbr->entries_index = le32dec(buf + 32); 176 1.1 joerg cdbr->seed = le32dec(buf + 36); 177 1.1 joerg 178 1.1 joerg if (cdbr->data_size < 0x100) 179 1.1 joerg cdbr->offset_size = 1; 180 1.1 joerg else if (cdbr->data_size < 0x10000) 181 1.1 joerg cdbr->offset_size = 2; 182 1.1 joerg else 183 1.1 joerg cdbr->offset_size = 4; 184 1.1 joerg 185 1.1 joerg if (cdbr->entries_index < 0x100) 186 1.1 joerg cdbr->index_size = 1; 187 1.1 joerg else if (cdbr->entries_index < 0x10000) 188 1.1 joerg cdbr->index_size = 2; 189 1.1 joerg else 190 1.1 joerg cdbr->index_size = 4; 191 1.1 joerg 192 1.1 joerg cdbr->mmap_base = base; 193 1.1 joerg cdbr->mmap_size = size; 194 1.1 joerg 195 1.1 joerg cdbr->hash_base = cdbr->mmap_base + 40; 196 1.1 joerg cdbr->offset_base = cdbr->hash_base + cdbr->entries_index * cdbr->index_size; 197 1.1 joerg if (cdbr->entries_index * cdbr->index_size % cdbr->offset_size) 198 1.1 joerg cdbr->offset_base += cdbr->offset_size - 199 1.1 joerg cdbr->entries_index * cdbr->index_size % cdbr->offset_size; 200 1.1 joerg cdbr->data_base = cdbr->offset_base + (cdbr->entries + 1) * cdbr->offset_size; 201 1.1 joerg 202 1.1 joerg if (cdbr->hash_base < cdbr->mmap_base || 203 1.1 joerg cdbr->offset_base < cdbr->mmap_base || 204 1.1 joerg cdbr->data_base < cdbr->mmap_base || 205 1.1 joerg cdbr->data_base + cdbr->data_size < cdbr->mmap_base || 206 1.1 joerg cdbr->data_base + cdbr->data_size > 207 1.1 joerg cdbr->mmap_base + cdbr->mmap_size) { 208 1.1 joerg SET_ERRNO(EINVAL); 209 1.1 joerg free(cdbr); 210 1.1 joerg return NULL; 211 1.1 joerg } 212 1.1 joerg 213 1.1 joerg if (cdbr->entries) { 214 1.1 joerg fast_divide32_prepare(cdbr->entries, &cdbr->entries_m, 215 1.1 joerg &cdbr->entries_s1, &cdbr->entries_s2); 216 1.1 joerg } 217 1.1 joerg if (cdbr->entries_index) { 218 1.1 joerg fast_divide32_prepare(cdbr->entries_index, 219 1.1 joerg &cdbr->entries_index_m, 220 1.1 joerg &cdbr->entries_index_s1, &cdbr->entries_index_s2); 221 1.1 joerg } 222 1.1 joerg 223 1.1 joerg return cdbr; 224 1.1 joerg } 225 1.1 joerg 226 1.1 joerg static inline uint32_t 227 1.1 joerg get_uintX(const uint8_t *addr, uint32_t idx, int size) 228 1.1 joerg { 229 1.1 joerg addr += idx * size; 230 1.1 joerg 231 1.1 joerg if (size == 4) 232 1.1 joerg return /* LINTED */le32toh(*(const uint32_t *)addr); 233 1.1 joerg else if (size == 2) 234 1.1 joerg return /* LINTED */le16toh(*(const uint16_t *)addr); 235 1.1 joerg else 236 1.1 joerg return *addr; 237 1.1 joerg } 238 1.1 joerg 239 1.1 joerg uint32_t 240 1.1 joerg cdbr_entries(struct cdbr *cdbr) 241 1.1 joerg { 242 1.1 joerg 243 1.1 joerg return cdbr->entries; 244 1.1 joerg } 245 1.1 joerg 246 1.1 joerg int 247 1.1 joerg cdbr_get(struct cdbr *cdbr, uint32_t idx, const void **data, size_t *data_len) 248 1.1 joerg { 249 1.1 joerg uint32_t start, end; 250 1.1 joerg 251 1.1 joerg if (idx >= cdbr->entries) { 252 1.1 joerg SET_ERRNO(EINVAL); 253 1.1 joerg return -1; 254 1.1 joerg } 255 1.1 joerg 256 1.1 joerg start = get_uintX(cdbr->offset_base, idx, cdbr->offset_size); 257 1.1 joerg end = get_uintX(cdbr->offset_base, idx + 1, cdbr->offset_size); 258 1.1 joerg 259 1.1 joerg if (start > end) { 260 1.1 joerg SET_ERRNO(EIO); 261 1.1 joerg return -1; 262 1.1 joerg } 263 1.1 joerg 264 1.1 joerg if (end > cdbr->data_size) { 265 1.1 joerg SET_ERRNO(EIO); 266 1.1 joerg return -1; 267 1.1 joerg } 268 1.1 joerg 269 1.1 joerg *data = cdbr->data_base + start; 270 1.1 joerg *data_len = end - start; 271 1.1 joerg 272 1.1 joerg return 0; 273 1.1 joerg } 274 1.1 joerg 275 1.1 joerg int 276 1.1 joerg cdbr_find(struct cdbr *cdbr, const void *key, size_t key_len, 277 1.1 joerg const void **data, size_t *data_len) 278 1.1 joerg { 279 1.1 joerg uint32_t hashes[3], idx; 280 1.1 joerg 281 1.1 joerg if (cdbr->entries_index == 0) { 282 1.1 joerg SET_ERRNO(EINVAL); 283 1.1 joerg return -1; 284 1.1 joerg } 285 1.1 joerg 286 1.1 joerg mi_vector_hash(key, key_len, cdbr->seed, hashes); 287 1.1 joerg 288 1.1 joerg hashes[0] = fast_remainder32(hashes[0], cdbr->entries_index, 289 1.1 joerg cdbr->entries_index_m, cdbr->entries_index_s1, 290 1.1 joerg cdbr->entries_index_s2); 291 1.1 joerg hashes[1] = fast_remainder32(hashes[1], cdbr->entries_index, 292 1.1 joerg cdbr->entries_index_m, cdbr->entries_index_s1, 293 1.1 joerg cdbr->entries_index_s2); 294 1.1 joerg hashes[2] = fast_remainder32(hashes[2], cdbr->entries_index, 295 1.1 joerg cdbr->entries_index_m, cdbr->entries_index_s1, 296 1.1 joerg cdbr->entries_index_s2); 297 1.1 joerg 298 1.1 joerg idx = get_uintX(cdbr->hash_base, hashes[0], cdbr->index_size); 299 1.1 joerg idx += get_uintX(cdbr->hash_base, hashes[1], cdbr->index_size); 300 1.1 joerg idx += get_uintX(cdbr->hash_base, hashes[2], cdbr->index_size); 301 1.1 joerg 302 1.1 joerg return cdbr_get(cdbr, fast_remainder32(idx, cdbr->entries, 303 1.1 joerg cdbr->entries_m, cdbr->entries_s1, cdbr->entries_s2), data, 304 1.1 joerg data_len); 305 1.1 joerg } 306 1.1 joerg 307 1.1 joerg void 308 1.1 joerg cdbr_close(struct cdbr *cdbr) 309 1.1 joerg { 310 1.1 joerg if (cdbr->unmap) 311 1.1 joerg (*cdbr->unmap)(cdbr->cookie, cdbr->mmap_base, cdbr->mmap_size); 312 1.1 joerg free(cdbr); 313 1.1 joerg } 314