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 68*428e4698SJoe 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; 80*428e4698SJoe Thornber info->dirty = false; 81*428e4698SJoe 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; 99*428e4698SJoe Thornber info->dirty = false; 100*428e4698SJoe 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); 133*428e4698SJoe Thornber info->dirty = true; 134*428e4698SJoe 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); 150*428e4698SJoe Thornber info->dirty = true; 151*428e4698SJoe 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 1717a87edfeSJoe Thornber /*----------------------------------------------------------------*/ 172