dm-bitset.c (7114B)
1/* 2 * Copyright (C) 2012 Red Hat, Inc. 3 * 4 * This file is released under the GPL. 5 */ 6 7#include "dm-bitset.h" 8#include "dm-transaction-manager.h" 9 10#include <linux/export.h> 11#include <linux/device-mapper.h> 12 13#define DM_MSG_PREFIX "bitset" 14#define BITS_PER_ARRAY_ENTRY 64 15 16/*----------------------------------------------------------------*/ 17 18static struct dm_btree_value_type bitset_bvt = { 19 .context = NULL, 20 .size = sizeof(__le64), 21 .inc = NULL, 22 .dec = NULL, 23 .equal = NULL, 24}; 25 26/*----------------------------------------------------------------*/ 27 28void dm_disk_bitset_init(struct dm_transaction_manager *tm, 29 struct dm_disk_bitset *info) 30{ 31 dm_array_info_init(&info->array_info, tm, &bitset_bvt); 32 info->current_index_set = false; 33} 34EXPORT_SYMBOL_GPL(dm_disk_bitset_init); 35 36int dm_bitset_empty(struct dm_disk_bitset *info, dm_block_t *root) 37{ 38 return dm_array_empty(&info->array_info, root); 39} 40EXPORT_SYMBOL_GPL(dm_bitset_empty); 41 42struct packer_context { 43 bit_value_fn fn; 44 unsigned nr_bits; 45 void *context; 46}; 47 48static int pack_bits(uint32_t index, void *value, void *context) 49{ 50 int r; 51 struct packer_context *p = context; 52 unsigned bit, nr = min(64u, p->nr_bits - (index * 64)); 53 uint64_t word = 0; 54 bool bv; 55 56 for (bit = 0; bit < nr; bit++) { 57 r = p->fn(index * 64 + bit, &bv, p->context); 58 if (r) 59 return r; 60 61 if (bv) 62 set_bit(bit, (unsigned long *) &word); 63 else 64 clear_bit(bit, (unsigned long *) &word); 65 } 66 67 *((__le64 *) value) = cpu_to_le64(word); 68 69 return 0; 70} 71 72int dm_bitset_new(struct dm_disk_bitset *info, dm_block_t *root, 73 uint32_t size, bit_value_fn fn, void *context) 74{ 75 struct packer_context p; 76 p.fn = fn; 77 p.nr_bits = size; 78 p.context = context; 79 80 return dm_array_new(&info->array_info, root, dm_div_up(size, 64), pack_bits, &p); 81} 82EXPORT_SYMBOL_GPL(dm_bitset_new); 83 84int dm_bitset_resize(struct dm_disk_bitset *info, dm_block_t root, 85 uint32_t old_nr_entries, uint32_t new_nr_entries, 86 bool default_value, dm_block_t *new_root) 87{ 88 uint32_t old_blocks = dm_div_up(old_nr_entries, BITS_PER_ARRAY_ENTRY); 89 uint32_t new_blocks = dm_div_up(new_nr_entries, BITS_PER_ARRAY_ENTRY); 90 __le64 value = default_value ? cpu_to_le64(~0) : cpu_to_le64(0); 91 92 __dm_bless_for_disk(&value); 93 return dm_array_resize(&info->array_info, root, old_blocks, new_blocks, 94 &value, new_root); 95} 96EXPORT_SYMBOL_GPL(dm_bitset_resize); 97 98int dm_bitset_del(struct dm_disk_bitset *info, dm_block_t root) 99{ 100 return dm_array_del(&info->array_info, root); 101} 102EXPORT_SYMBOL_GPL(dm_bitset_del); 103 104int dm_bitset_flush(struct dm_disk_bitset *info, dm_block_t root, 105 dm_block_t *new_root) 106{ 107 int r; 108 __le64 value; 109 110 if (!info->current_index_set || !info->dirty) 111 return 0; 112 113 value = cpu_to_le64(info->current_bits); 114 115 __dm_bless_for_disk(&value); 116 r = dm_array_set_value(&info->array_info, root, info->current_index, 117 &value, new_root); 118 if (r) 119 return r; 120 121 info->current_index_set = false; 122 info->dirty = false; 123 124 return 0; 125} 126EXPORT_SYMBOL_GPL(dm_bitset_flush); 127 128static int read_bits(struct dm_disk_bitset *info, dm_block_t root, 129 uint32_t array_index) 130{ 131 int r; 132 __le64 value; 133 134 r = dm_array_get_value(&info->array_info, root, array_index, &value); 135 if (r) 136 return r; 137 138 info->current_bits = le64_to_cpu(value); 139 info->current_index_set = true; 140 info->current_index = array_index; 141 info->dirty = false; 142 143 return 0; 144} 145 146static int get_array_entry(struct dm_disk_bitset *info, dm_block_t root, 147 uint32_t index, dm_block_t *new_root) 148{ 149 int r; 150 unsigned array_index = index / BITS_PER_ARRAY_ENTRY; 151 152 if (info->current_index_set) { 153 if (info->current_index == array_index) 154 return 0; 155 156 r = dm_bitset_flush(info, root, new_root); 157 if (r) 158 return r; 159 } 160 161 return read_bits(info, root, array_index); 162} 163 164int dm_bitset_set_bit(struct dm_disk_bitset *info, dm_block_t root, 165 uint32_t index, dm_block_t *new_root) 166{ 167 int r; 168 unsigned b = index % BITS_PER_ARRAY_ENTRY; 169 170 r = get_array_entry(info, root, index, new_root); 171 if (r) 172 return r; 173 174 set_bit(b, (unsigned long *) &info->current_bits); 175 info->dirty = true; 176 177 return 0; 178} 179EXPORT_SYMBOL_GPL(dm_bitset_set_bit); 180 181int dm_bitset_clear_bit(struct dm_disk_bitset *info, dm_block_t root, 182 uint32_t index, dm_block_t *new_root) 183{ 184 int r; 185 unsigned b = index % BITS_PER_ARRAY_ENTRY; 186 187 r = get_array_entry(info, root, index, new_root); 188 if (r) 189 return r; 190 191 clear_bit(b, (unsigned long *) &info->current_bits); 192 info->dirty = true; 193 194 return 0; 195} 196EXPORT_SYMBOL_GPL(dm_bitset_clear_bit); 197 198int dm_bitset_test_bit(struct dm_disk_bitset *info, dm_block_t root, 199 uint32_t index, dm_block_t *new_root, bool *result) 200{ 201 int r; 202 unsigned b = index % BITS_PER_ARRAY_ENTRY; 203 204 r = get_array_entry(info, root, index, new_root); 205 if (r) 206 return r; 207 208 *result = test_bit(b, (unsigned long *) &info->current_bits); 209 return 0; 210} 211EXPORT_SYMBOL_GPL(dm_bitset_test_bit); 212 213static int cursor_next_array_entry(struct dm_bitset_cursor *c) 214{ 215 int r; 216 __le64 *value; 217 218 r = dm_array_cursor_next(&c->cursor); 219 if (r) 220 return r; 221 222 dm_array_cursor_get_value(&c->cursor, (void **) &value); 223 c->array_index++; 224 c->bit_index = 0; 225 c->current_bits = le64_to_cpu(*value); 226 return 0; 227} 228 229int dm_bitset_cursor_begin(struct dm_disk_bitset *info, 230 dm_block_t root, uint32_t nr_entries, 231 struct dm_bitset_cursor *c) 232{ 233 int r; 234 __le64 *value; 235 236 if (!nr_entries) 237 return -ENODATA; 238 239 c->info = info; 240 c->entries_remaining = nr_entries; 241 242 r = dm_array_cursor_begin(&info->array_info, root, &c->cursor); 243 if (r) 244 return r; 245 246 dm_array_cursor_get_value(&c->cursor, (void **) &value); 247 c->array_index = 0; 248 c->bit_index = 0; 249 c->current_bits = le64_to_cpu(*value); 250 251 return r; 252} 253EXPORT_SYMBOL_GPL(dm_bitset_cursor_begin); 254 255void dm_bitset_cursor_end(struct dm_bitset_cursor *c) 256{ 257 return dm_array_cursor_end(&c->cursor); 258} 259EXPORT_SYMBOL_GPL(dm_bitset_cursor_end); 260 261int dm_bitset_cursor_next(struct dm_bitset_cursor *c) 262{ 263 int r = 0; 264 265 if (!c->entries_remaining) 266 return -ENODATA; 267 268 c->entries_remaining--; 269 if (++c->bit_index > 63) 270 r = cursor_next_array_entry(c); 271 272 return r; 273} 274EXPORT_SYMBOL_GPL(dm_bitset_cursor_next); 275 276int dm_bitset_cursor_skip(struct dm_bitset_cursor *c, uint32_t count) 277{ 278 int r; 279 __le64 *value; 280 uint32_t nr_array_skip; 281 uint32_t remaining_in_word = 64 - c->bit_index; 282 283 if (c->entries_remaining < count) 284 return -ENODATA; 285 286 if (count < remaining_in_word) { 287 c->bit_index += count; 288 c->entries_remaining -= count; 289 return 0; 290 291 } else { 292 c->entries_remaining -= remaining_in_word; 293 count -= remaining_in_word; 294 } 295 296 nr_array_skip = (count / 64) + 1; 297 r = dm_array_cursor_skip(&c->cursor, nr_array_skip); 298 if (r) 299 return r; 300 301 dm_array_cursor_get_value(&c->cursor, (void **) &value); 302 c->entries_remaining -= count; 303 c->array_index += nr_array_skip; 304 c->bit_index = count & 63; 305 c->current_bits = le64_to_cpu(*value); 306 307 return 0; 308} 309EXPORT_SYMBOL_GPL(dm_bitset_cursor_skip); 310 311bool dm_bitset_cursor_get_value(struct dm_bitset_cursor *c) 312{ 313 return test_bit(c->bit_index, (unsigned long *) &c->current_bits); 314} 315EXPORT_SYMBOL_GPL(dm_bitset_cursor_get_value); 316 317/*----------------------------------------------------------------*/