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 || !info->dirty) 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 info->dirty = false; 81 82 return 0; 83 } 84 EXPORT_SYMBOL_GPL(dm_bitset_flush); 85 86 static int read_bits(struct dm_disk_bitset *info, dm_block_t root, 87 uint32_t array_index) 88 { 89 int r; 90 __le64 value; 91 92 r = dm_array_get_value(&info->array_info, root, array_index, &value); 93 if (r) 94 return r; 95 96 info->current_bits = le64_to_cpu(value); 97 info->current_index_set = true; 98 info->current_index = array_index; 99 info->dirty = false; 100 101 return 0; 102 } 103 104 static int get_array_entry(struct dm_disk_bitset *info, dm_block_t root, 105 uint32_t index, dm_block_t *new_root) 106 { 107 int r; 108 unsigned array_index = index / BITS_PER_ARRAY_ENTRY; 109 110 if (info->current_index_set) { 111 if (info->current_index == array_index) 112 return 0; 113 114 r = dm_bitset_flush(info, root, new_root); 115 if (r) 116 return r; 117 } 118 119 return read_bits(info, root, array_index); 120 } 121 122 int dm_bitset_set_bit(struct dm_disk_bitset *info, dm_block_t root, 123 uint32_t index, dm_block_t *new_root) 124 { 125 int r; 126 unsigned b = index % BITS_PER_ARRAY_ENTRY; 127 128 r = get_array_entry(info, root, index, new_root); 129 if (r) 130 return r; 131 132 set_bit(b, (unsigned long *) &info->current_bits); 133 info->dirty = true; 134 135 return 0; 136 } 137 EXPORT_SYMBOL_GPL(dm_bitset_set_bit); 138 139 int dm_bitset_clear_bit(struct dm_disk_bitset *info, dm_block_t root, 140 uint32_t index, dm_block_t *new_root) 141 { 142 int r; 143 unsigned b = index % BITS_PER_ARRAY_ENTRY; 144 145 r = get_array_entry(info, root, index, new_root); 146 if (r) 147 return r; 148 149 clear_bit(b, (unsigned long *) &info->current_bits); 150 info->dirty = true; 151 152 return 0; 153 } 154 EXPORT_SYMBOL_GPL(dm_bitset_clear_bit); 155 156 int dm_bitset_test_bit(struct dm_disk_bitset *info, dm_block_t root, 157 uint32_t index, dm_block_t *new_root, bool *result) 158 { 159 int r; 160 unsigned b = index % BITS_PER_ARRAY_ENTRY; 161 162 r = get_array_entry(info, root, index, new_root); 163 if (r) 164 return r; 165 166 *result = test_bit(b, (unsigned long *) &info->current_bits); 167 return 0; 168 } 169 EXPORT_SYMBOL_GPL(dm_bitset_test_bit); 170 171 /*----------------------------------------------------------------*/ 172