17a87edfeSJoe Thornber /* 27a87edfeSJoe Thornber * Copyright (C) 2012 Red Hat, Inc. 37a87edfeSJoe Thornber * 47a87edfeSJoe Thornber * This file is released under the GPL. 57a87edfeSJoe Thornber */ 67a87edfeSJoe Thornber 77a87edfeSJoe Thornber #include "dm-bitset.h" 87a87edfeSJoe Thornber #include "dm-transaction-manager.h" 97a87edfeSJoe Thornber 107a87edfeSJoe Thornber #include <linux/export.h> 117a87edfeSJoe Thornber #include <linux/device-mapper.h> 127a87edfeSJoe Thornber 137a87edfeSJoe Thornber #define DM_MSG_PREFIX "bitset" 147a87edfeSJoe Thornber #define BITS_PER_ARRAY_ENTRY 64 157a87edfeSJoe Thornber 167a87edfeSJoe Thornber /*----------------------------------------------------------------*/ 177a87edfeSJoe Thornber 187a87edfeSJoe Thornber static struct dm_btree_value_type bitset_bvt = { 197a87edfeSJoe Thornber .context = NULL, 207a87edfeSJoe Thornber .size = sizeof(__le64), 217a87edfeSJoe Thornber .inc = NULL, 227a87edfeSJoe Thornber .dec = NULL, 237a87edfeSJoe Thornber .equal = NULL, 247a87edfeSJoe Thornber }; 257a87edfeSJoe Thornber 267a87edfeSJoe Thornber /*----------------------------------------------------------------*/ 277a87edfeSJoe Thornber 287a87edfeSJoe Thornber void dm_disk_bitset_init(struct dm_transaction_manager *tm, 297a87edfeSJoe Thornber struct dm_disk_bitset *info) 307a87edfeSJoe Thornber { 317a87edfeSJoe Thornber dm_array_info_init(&info->array_info, tm, &bitset_bvt); 327a87edfeSJoe Thornber info->current_index_set = false; 337a87edfeSJoe Thornber } 347a87edfeSJoe Thornber EXPORT_SYMBOL_GPL(dm_disk_bitset_init); 357a87edfeSJoe Thornber 367a87edfeSJoe Thornber int dm_bitset_empty(struct dm_disk_bitset *info, dm_block_t *root) 377a87edfeSJoe Thornber { 387a87edfeSJoe Thornber return dm_array_empty(&info->array_info, root); 397a87edfeSJoe Thornber } 407a87edfeSJoe Thornber EXPORT_SYMBOL_GPL(dm_bitset_empty); 417a87edfeSJoe Thornber 427a87edfeSJoe Thornber int dm_bitset_resize(struct dm_disk_bitset *info, dm_block_t root, 437a87edfeSJoe Thornber uint32_t old_nr_entries, uint32_t new_nr_entries, 447a87edfeSJoe Thornber bool default_value, dm_block_t *new_root) 457a87edfeSJoe Thornber { 467a87edfeSJoe Thornber uint32_t old_blocks = dm_div_up(old_nr_entries, BITS_PER_ARRAY_ENTRY); 477a87edfeSJoe Thornber uint32_t new_blocks = dm_div_up(new_nr_entries, BITS_PER_ARRAY_ENTRY); 487a87edfeSJoe Thornber __le64 value = default_value ? cpu_to_le64(~0) : cpu_to_le64(0); 497a87edfeSJoe Thornber 507a87edfeSJoe Thornber __dm_bless_for_disk(&value); 517a87edfeSJoe Thornber return dm_array_resize(&info->array_info, root, old_blocks, new_blocks, 527a87edfeSJoe Thornber &value, new_root); 537a87edfeSJoe Thornber } 547a87edfeSJoe Thornber EXPORT_SYMBOL_GPL(dm_bitset_resize); 557a87edfeSJoe Thornber 567a87edfeSJoe Thornber int dm_bitset_del(struct dm_disk_bitset *info, dm_block_t root) 577a87edfeSJoe Thornber { 587a87edfeSJoe Thornber return dm_array_del(&info->array_info, root); 597a87edfeSJoe Thornber } 607a87edfeSJoe Thornber EXPORT_SYMBOL_GPL(dm_bitset_del); 617a87edfeSJoe Thornber 627a87edfeSJoe Thornber int dm_bitset_flush(struct dm_disk_bitset *info, dm_block_t root, 637a87edfeSJoe Thornber dm_block_t *new_root) 647a87edfeSJoe Thornber { 657a87edfeSJoe Thornber int r; 667a87edfeSJoe Thornber __le64 value; 677a87edfeSJoe Thornber 68428e4698SJoe Thornber if (!info->current_index_set || !info->dirty) 697a87edfeSJoe Thornber return 0; 707a87edfeSJoe Thornber 717a87edfeSJoe Thornber value = cpu_to_le64(info->current_bits); 727a87edfeSJoe Thornber 737a87edfeSJoe Thornber __dm_bless_for_disk(&value); 747a87edfeSJoe Thornber r = dm_array_set_value(&info->array_info, root, info->current_index, 757a87edfeSJoe Thornber &value, new_root); 767a87edfeSJoe Thornber if (r) 777a87edfeSJoe Thornber return r; 787a87edfeSJoe Thornber 797a87edfeSJoe Thornber info->current_index_set = false; 80428e4698SJoe Thornber info->dirty = false; 81428e4698SJoe Thornber 827a87edfeSJoe Thornber return 0; 837a87edfeSJoe Thornber } 847a87edfeSJoe Thornber EXPORT_SYMBOL_GPL(dm_bitset_flush); 857a87edfeSJoe Thornber 867a87edfeSJoe Thornber static int read_bits(struct dm_disk_bitset *info, dm_block_t root, 877a87edfeSJoe Thornber uint32_t array_index) 887a87edfeSJoe Thornber { 897a87edfeSJoe Thornber int r; 907a87edfeSJoe Thornber __le64 value; 917a87edfeSJoe Thornber 927a87edfeSJoe Thornber r = dm_array_get_value(&info->array_info, root, array_index, &value); 937a87edfeSJoe Thornber if (r) 947a87edfeSJoe Thornber return r; 957a87edfeSJoe Thornber 967a87edfeSJoe Thornber info->current_bits = le64_to_cpu(value); 977a87edfeSJoe Thornber info->current_index_set = true; 987a87edfeSJoe Thornber info->current_index = array_index; 99428e4698SJoe Thornber info->dirty = false; 100428e4698SJoe Thornber 1017a87edfeSJoe Thornber return 0; 1027a87edfeSJoe Thornber } 1037a87edfeSJoe Thornber 1047a87edfeSJoe Thornber static int get_array_entry(struct dm_disk_bitset *info, dm_block_t root, 1057a87edfeSJoe Thornber uint32_t index, dm_block_t *new_root) 1067a87edfeSJoe Thornber { 1077a87edfeSJoe Thornber int r; 1087a87edfeSJoe Thornber unsigned array_index = index / BITS_PER_ARRAY_ENTRY; 1097a87edfeSJoe Thornber 1107a87edfeSJoe Thornber if (info->current_index_set) { 1117a87edfeSJoe Thornber if (info->current_index == array_index) 1127a87edfeSJoe Thornber return 0; 1137a87edfeSJoe Thornber 1147a87edfeSJoe Thornber r = dm_bitset_flush(info, root, new_root); 1157a87edfeSJoe Thornber if (r) 1167a87edfeSJoe Thornber return r; 1177a87edfeSJoe Thornber } 1187a87edfeSJoe Thornber 1197a87edfeSJoe Thornber return read_bits(info, root, array_index); 1207a87edfeSJoe Thornber } 1217a87edfeSJoe Thornber 1227a87edfeSJoe Thornber int dm_bitset_set_bit(struct dm_disk_bitset *info, dm_block_t root, 1237a87edfeSJoe Thornber uint32_t index, dm_block_t *new_root) 1247a87edfeSJoe Thornber { 1257a87edfeSJoe Thornber int r; 1267a87edfeSJoe Thornber unsigned b = index % BITS_PER_ARRAY_ENTRY; 1277a87edfeSJoe Thornber 1287a87edfeSJoe Thornber r = get_array_entry(info, root, index, new_root); 1297a87edfeSJoe Thornber if (r) 1307a87edfeSJoe Thornber return r; 1317a87edfeSJoe Thornber 1327a87edfeSJoe Thornber set_bit(b, (unsigned long *) &info->current_bits); 133428e4698SJoe Thornber info->dirty = true; 134428e4698SJoe Thornber 1357a87edfeSJoe Thornber return 0; 1367a87edfeSJoe Thornber } 1377a87edfeSJoe Thornber EXPORT_SYMBOL_GPL(dm_bitset_set_bit); 1387a87edfeSJoe Thornber 1397a87edfeSJoe Thornber int dm_bitset_clear_bit(struct dm_disk_bitset *info, dm_block_t root, 1407a87edfeSJoe Thornber uint32_t index, dm_block_t *new_root) 1417a87edfeSJoe Thornber { 1427a87edfeSJoe Thornber int r; 1437a87edfeSJoe Thornber unsigned b = index % BITS_PER_ARRAY_ENTRY; 1447a87edfeSJoe Thornber 1457a87edfeSJoe Thornber r = get_array_entry(info, root, index, new_root); 1467a87edfeSJoe Thornber if (r) 1477a87edfeSJoe Thornber return r; 1487a87edfeSJoe Thornber 1497a87edfeSJoe Thornber clear_bit(b, (unsigned long *) &info->current_bits); 150428e4698SJoe Thornber info->dirty = true; 151428e4698SJoe Thornber 1527a87edfeSJoe Thornber return 0; 1537a87edfeSJoe Thornber } 1547a87edfeSJoe Thornber EXPORT_SYMBOL_GPL(dm_bitset_clear_bit); 1557a87edfeSJoe Thornber 1567a87edfeSJoe Thornber int dm_bitset_test_bit(struct dm_disk_bitset *info, dm_block_t root, 1577a87edfeSJoe Thornber uint32_t index, dm_block_t *new_root, bool *result) 1587a87edfeSJoe Thornber { 1597a87edfeSJoe Thornber int r; 1607a87edfeSJoe Thornber unsigned b = index % BITS_PER_ARRAY_ENTRY; 1617a87edfeSJoe Thornber 1627a87edfeSJoe Thornber r = get_array_entry(info, root, index, new_root); 1637a87edfeSJoe Thornber if (r) 1647a87edfeSJoe Thornber return r; 1657a87edfeSJoe Thornber 1667a87edfeSJoe Thornber *result = test_bit(b, (unsigned long *) &info->current_bits); 1677a87edfeSJoe Thornber return 0; 1687a87edfeSJoe Thornber } 1697a87edfeSJoe Thornber EXPORT_SYMBOL_GPL(dm_bitset_test_bit); 1707a87edfeSJoe Thornber 171*6fe28dbfSJoe Thornber static int cursor_next_array_entry(struct dm_bitset_cursor *c) 172*6fe28dbfSJoe Thornber { 173*6fe28dbfSJoe Thornber int r; 174*6fe28dbfSJoe Thornber __le64 *value; 175*6fe28dbfSJoe Thornber 176*6fe28dbfSJoe Thornber r = dm_array_cursor_next(&c->cursor); 177*6fe28dbfSJoe Thornber if (r) 178*6fe28dbfSJoe Thornber return r; 179*6fe28dbfSJoe Thornber 180*6fe28dbfSJoe Thornber dm_array_cursor_get_value(&c->cursor, (void **) &value); 181*6fe28dbfSJoe Thornber c->array_index++; 182*6fe28dbfSJoe Thornber c->bit_index = 0; 183*6fe28dbfSJoe Thornber c->current_bits = le64_to_cpu(*value); 184*6fe28dbfSJoe Thornber return 0; 185*6fe28dbfSJoe Thornber } 186*6fe28dbfSJoe Thornber 187*6fe28dbfSJoe Thornber int dm_bitset_cursor_begin(struct dm_disk_bitset *info, 188*6fe28dbfSJoe Thornber dm_block_t root, uint32_t nr_entries, 189*6fe28dbfSJoe Thornber struct dm_bitset_cursor *c) 190*6fe28dbfSJoe Thornber { 191*6fe28dbfSJoe Thornber int r; 192*6fe28dbfSJoe Thornber __le64 *value; 193*6fe28dbfSJoe Thornber 194*6fe28dbfSJoe Thornber if (!nr_entries) 195*6fe28dbfSJoe Thornber return -ENODATA; 196*6fe28dbfSJoe Thornber 197*6fe28dbfSJoe Thornber c->info = info; 198*6fe28dbfSJoe Thornber c->entries_remaining = nr_entries; 199*6fe28dbfSJoe Thornber 200*6fe28dbfSJoe Thornber r = dm_array_cursor_begin(&info->array_info, root, &c->cursor); 201*6fe28dbfSJoe Thornber if (r) 202*6fe28dbfSJoe Thornber return r; 203*6fe28dbfSJoe Thornber 204*6fe28dbfSJoe Thornber dm_array_cursor_get_value(&c->cursor, (void **) &value); 205*6fe28dbfSJoe Thornber c->array_index = 0; 206*6fe28dbfSJoe Thornber c->bit_index = 0; 207*6fe28dbfSJoe Thornber c->current_bits = le64_to_cpu(*value); 208*6fe28dbfSJoe Thornber 209*6fe28dbfSJoe Thornber return r; 210*6fe28dbfSJoe Thornber } 211*6fe28dbfSJoe Thornber EXPORT_SYMBOL_GPL(dm_bitset_cursor_begin); 212*6fe28dbfSJoe Thornber 213*6fe28dbfSJoe Thornber void dm_bitset_cursor_end(struct dm_bitset_cursor *c) 214*6fe28dbfSJoe Thornber { 215*6fe28dbfSJoe Thornber return dm_array_cursor_end(&c->cursor); 216*6fe28dbfSJoe Thornber } 217*6fe28dbfSJoe Thornber EXPORT_SYMBOL_GPL(dm_bitset_cursor_end); 218*6fe28dbfSJoe Thornber 219*6fe28dbfSJoe Thornber int dm_bitset_cursor_next(struct dm_bitset_cursor *c) 220*6fe28dbfSJoe Thornber { 221*6fe28dbfSJoe Thornber int r = 0; 222*6fe28dbfSJoe Thornber 223*6fe28dbfSJoe Thornber if (!c->entries_remaining) 224*6fe28dbfSJoe Thornber return -ENODATA; 225*6fe28dbfSJoe Thornber 226*6fe28dbfSJoe Thornber c->entries_remaining--; 227*6fe28dbfSJoe Thornber if (++c->bit_index > 63) 228*6fe28dbfSJoe Thornber r = cursor_next_array_entry(c); 229*6fe28dbfSJoe Thornber 230*6fe28dbfSJoe Thornber return r; 231*6fe28dbfSJoe Thornber } 232*6fe28dbfSJoe Thornber EXPORT_SYMBOL_GPL(dm_bitset_cursor_next); 233*6fe28dbfSJoe Thornber 234*6fe28dbfSJoe Thornber bool dm_bitset_cursor_get_value(struct dm_bitset_cursor *c) 235*6fe28dbfSJoe Thornber { 236*6fe28dbfSJoe Thornber return test_bit(c->bit_index, (unsigned long *) &c->current_bits); 237*6fe28dbfSJoe Thornber } 238*6fe28dbfSJoe Thornber EXPORT_SYMBOL_GPL(dm_bitset_cursor_get_value); 239*6fe28dbfSJoe Thornber 2407a87edfeSJoe Thornber /*----------------------------------------------------------------*/ 241