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 42int 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} 54EXPORT_SYMBOL_GPL(dm_bitset_resize); 55 56int dm_bitset_del(struct dm_disk_bitset *info, dm_block_t root) 57{ 58 return dm_array_del(&info->array_info, root); 59} 60EXPORT_SYMBOL_GPL(dm_bitset_del); 61 62int 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} 84EXPORT_SYMBOL_GPL(dm_bitset_flush); 85 86static 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 104static 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 122int 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} 137EXPORT_SYMBOL_GPL(dm_bitset_set_bit); 138 139int 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} 154EXPORT_SYMBOL_GPL(dm_bitset_clear_bit); 155 156int 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} 169EXPORT_SYMBOL_GPL(dm_bitset_test_bit); 170 171/*----------------------------------------------------------------*/ 172