Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

dm persistent data: add bitset

Add a persistent bitset as a wrapper around dm-array.

Signed-off-by: Joe Thornber <ejt@redhat.com>
Signed-off-by: Alasdair G Kergon <agk@redhat.com>

authored by

Joe Thornber and committed by
Alasdair G Kergon
7a87edfe 6513c29f

+329
+1
drivers/md/persistent-data/Makefile
··· 1 1 obj-$(CONFIG_DM_PERSISTENT_DATA) += dm-persistent-data.o 2 2 dm-persistent-data-objs := \ 3 3 dm-array.o \ 4 + dm-bitset.o \ 4 5 dm-block-manager.o \ 5 6 dm-space-map-common.o \ 6 7 dm-space-map-disk.o \
+163
drivers/md/persistent-data/dm-bitset.c
··· 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 + /*----------------------------------------------------------------*/
+165
drivers/md/persistent-data/dm-bitset.h
··· 1 + /* 2 + * Copyright (C) 2012 Red Hat, Inc. 3 + * 4 + * This file is released under the GPL. 5 + */ 6 + #ifndef _LINUX_DM_BITSET_H 7 + #define _LINUX_DM_BITSET_H 8 + 9 + #include "dm-array.h" 10 + 11 + /*----------------------------------------------------------------*/ 12 + 13 + /* 14 + * This bitset type is a thin wrapper round a dm_array of 64bit words. It 15 + * uses a tiny, one word cache to reduce the number of array lookups and so 16 + * increase performance. 17 + * 18 + * Like the dm-array that it's based on, the caller needs to keep track of 19 + * the size of the bitset separately. The underlying dm-array implicitly 20 + * knows how many words it's storing and will return -ENODATA if you try 21 + * and access an out of bounds word. However, an out of bounds bit in the 22 + * final word will _not_ be detected, you have been warned. 23 + * 24 + * Bits are indexed from zero. 25 + 26 + * Typical use: 27 + * 28 + * a) Initialise a dm_disk_bitset structure with dm_disk_bitset_init(). 29 + * This describes the bitset and includes the cache. It's not called it 30 + * dm_bitset_info in line with other data structures because it does 31 + * include instance data. 32 + * 33 + * b) Get yourself a root. The root is the index of a block of data on the 34 + * disk that holds a particular instance of an bitset. You may have a 35 + * pre existing root in your metadata that you wish to use, or you may 36 + * want to create a brand new, empty bitset with dm_bitset_empty(). 37 + * 38 + * Like the other data structures in this library, dm_bitset objects are 39 + * immutable between transactions. Update functions will return you the 40 + * root for a _new_ array. If you've incremented the old root, via 41 + * dm_tm_inc(), before calling the update function you may continue to use 42 + * it in parallel with the new root. 43 + * 44 + * Even read operations may trigger the cache to be flushed and as such 45 + * return a root for a new, updated bitset. 46 + * 47 + * c) resize a bitset with dm_bitset_resize(). 48 + * 49 + * d) Set a bit with dm_bitset_set_bit(). 50 + * 51 + * e) Clear a bit with dm_bitset_clear_bit(). 52 + * 53 + * f) Test a bit with dm_bitset_test_bit(). 54 + * 55 + * g) Flush all updates from the cache with dm_bitset_flush(). 56 + * 57 + * h) Destroy the bitset with dm_bitset_del(). This tells the transaction 58 + * manager that you're no longer using this data structure so it can 59 + * recycle it's blocks. (dm_bitset_dec() would be a better name for it, 60 + * but del is in keeping with dm_btree_del()). 61 + */ 62 + 63 + /* 64 + * Opaque object. Unlike dm_array_info, you should have one of these per 65 + * bitset. Initialise with dm_disk_bitset_init(). 66 + */ 67 + struct dm_disk_bitset { 68 + struct dm_array_info array_info; 69 + 70 + uint32_t current_index; 71 + uint64_t current_bits; 72 + 73 + bool current_index_set:1; 74 + }; 75 + 76 + /* 77 + * Sets up a dm_disk_bitset structure. You don't need to do anything with 78 + * this structure when you finish using it. 79 + * 80 + * tm - the transaction manager that should supervise this structure 81 + * info - the structure being initialised 82 + */ 83 + void dm_disk_bitset_init(struct dm_transaction_manager *tm, 84 + struct dm_disk_bitset *info); 85 + 86 + /* 87 + * Create an empty, zero length bitset. 88 + * 89 + * info - describes the bitset 90 + * new_root - on success, points to the new root block 91 + */ 92 + int dm_bitset_empty(struct dm_disk_bitset *info, dm_block_t *new_root); 93 + 94 + /* 95 + * Resize the bitset. 96 + * 97 + * info - describes the bitset 98 + * old_root - the root block of the array on disk 99 + * old_nr_entries - the number of bits in the old bitset 100 + * new_nr_entries - the number of bits you want in the new bitset 101 + * default_value - the value for any new bits 102 + * new_root - on success, points to the new root block 103 + */ 104 + int dm_bitset_resize(struct dm_disk_bitset *info, dm_block_t old_root, 105 + uint32_t old_nr_entries, uint32_t new_nr_entries, 106 + bool default_value, dm_block_t *new_root); 107 + 108 + /* 109 + * Frees the bitset. 110 + */ 111 + int dm_bitset_del(struct dm_disk_bitset *info, dm_block_t root); 112 + 113 + /* 114 + * Set a bit. 115 + * 116 + * info - describes the bitset 117 + * root - the root block of the bitset 118 + * index - the bit index 119 + * new_root - on success, points to the new root block 120 + * 121 + * -ENODATA will be returned if the index is out of bounds. 122 + */ 123 + int dm_bitset_set_bit(struct dm_disk_bitset *info, dm_block_t root, 124 + uint32_t index, dm_block_t *new_root); 125 + 126 + /* 127 + * Clears a bit. 128 + * 129 + * info - describes the bitset 130 + * root - the root block of the bitset 131 + * index - the bit index 132 + * new_root - on success, points to the new root block 133 + * 134 + * -ENODATA will be returned if the index is out of bounds. 135 + */ 136 + int dm_bitset_clear_bit(struct dm_disk_bitset *info, dm_block_t root, 137 + uint32_t index, dm_block_t *new_root); 138 + 139 + /* 140 + * Tests a bit. 141 + * 142 + * info - describes the bitset 143 + * root - the root block of the bitset 144 + * index - the bit index 145 + * new_root - on success, points to the new root block (cached values may have been written) 146 + * result - the bit value you're after 147 + * 148 + * -ENODATA will be returned if the index is out of bounds. 149 + */ 150 + int dm_bitset_test_bit(struct dm_disk_bitset *info, dm_block_t root, 151 + uint32_t index, dm_block_t *new_root, bool *result); 152 + 153 + /* 154 + * Flush any cached changes to disk. 155 + * 156 + * info - describes the bitset 157 + * root - the root block of the bitset 158 + * new_root - on success, points to the new root block 159 + */ 160 + int dm_bitset_flush(struct dm_disk_bitset *info, dm_block_t root, 161 + dm_block_t *new_root); 162 + 163 + /*----------------------------------------------------------------*/ 164 + 165 + #endif /* _LINUX_DM_BITSET_H */