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 18 static 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 28 void 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 } 34 EXPORT_SYMBOL_GPL(dm_disk_bitset_init); 35 36 int dm_bitset_empty(struct dm_disk_bitset *info, dm_block_t *root) 37 { 38 return dm_array_empty(&info->array_info, root); 39 } 40 EXPORT_SYMBOL_GPL(dm_bitset_empty); 41 42 int dm_bitset_resize(struct dm_disk_bitset *info, dm_block_t root, 43 uint32_t old_nr_entries, uint32_t new_nr_entries, 44 bool default_value, dm_block_t *new_root) 45 { 46 uint32_t old_blocks = dm_div_up(old_nr_entries, BITS_PER_ARRAY_ENTRY); 47 uint32_t new_blocks = dm_div_up(new_nr_entries, BITS_PER_ARRAY_ENTRY); 48 __le64 value = default_value ? cpu_to_le64(~0) : cpu_to_le64(0); 49 50 __dm_bless_for_disk(&value); 51 return dm_array_resize(&info->array_info, root, old_blocks, new_blocks, 52 &value, new_root); 53 } 54 EXPORT_SYMBOL_GPL(dm_bitset_resize); 55 56 int dm_bitset_del(struct dm_disk_bitset *info, dm_block_t root) 57 { 58 return dm_array_del(&info->array_info, root); 59 } 60 EXPORT_SYMBOL_GPL(dm_bitset_del); 61 62 int dm_bitset_flush(struct dm_disk_bitset *info, dm_block_t root, 63 dm_block_t *new_root) 64 { 65 int r; 66 __le64 value; 67 68 if (!info->current_index_set) 69 return 0; 70 71 value = cpu_to_le64(info->current_bits); 72 73 __dm_bless_for_disk(&value); 74 r = dm_array_set_value(&info->array_info, root, info->current_index, 75 &value, new_root); 76 if (r) 77 return r; 78 79 info->current_index_set = false; 80 return 0; 81 } 82 EXPORT_SYMBOL_GPL(dm_bitset_flush); 83 84 static int read_bits(struct dm_disk_bitset *info, dm_block_t root, 85 uint32_t array_index) 86 { 87 int r; 88 __le64 value; 89 90 r = dm_array_get_value(&info->array_info, root, array_index, &value); 91 if (r) 92 return r; 93 94 info->current_bits = le64_to_cpu(value); 95 info->current_index_set = true; 96 info->current_index = array_index; 97 return 0; 98 } 99 100 static int get_array_entry(struct dm_disk_bitset *info, dm_block_t root, 101 uint32_t index, dm_block_t *new_root) 102 { 103 int r; 104 unsigned array_index = index / BITS_PER_ARRAY_ENTRY; 105 106 if (info->current_index_set) { 107 if (info->current_index == array_index) 108 return 0; 109 110 r = dm_bitset_flush(info, root, new_root); 111 if (r) 112 return r; 113 } 114 115 return read_bits(info, root, array_index); 116 } 117 118 int dm_bitset_set_bit(struct dm_disk_bitset *info, dm_block_t root, 119 uint32_t index, dm_block_t *new_root) 120 { 121 int r; 122 unsigned b = index % BITS_PER_ARRAY_ENTRY; 123 124 r = get_array_entry(info, root, index, new_root); 125 if (r) 126 return r; 127 128 set_bit(b, (unsigned long *) &info->current_bits); 129 return 0; 130 } 131 EXPORT_SYMBOL_GPL(dm_bitset_set_bit); 132 133 int dm_bitset_clear_bit(struct dm_disk_bitset *info, dm_block_t root, 134 uint32_t index, dm_block_t *new_root) 135 { 136 int r; 137 unsigned b = index % BITS_PER_ARRAY_ENTRY; 138 139 r = get_array_entry(info, root, index, new_root); 140 if (r) 141 return r; 142 143 clear_bit(b, (unsigned long *) &info->current_bits); 144 return 0; 145 } 146 EXPORT_SYMBOL_GPL(dm_bitset_clear_bit); 147 148 int dm_bitset_test_bit(struct dm_disk_bitset *info, dm_block_t root, 149 uint32_t index, dm_block_t *new_root, bool *result) 150 { 151 int r; 152 unsigned b = index % BITS_PER_ARRAY_ENTRY; 153 154 r = get_array_entry(info, root, index, new_root); 155 if (r) 156 return r; 157 158 *result = test_bit(b, (unsigned long *) &info->current_bits); 159 return 0; 160 } 161 EXPORT_SYMBOL_GPL(dm_bitset_test_bit); 162 163 /*----------------------------------------------------------------*/ 164