···11+/*22+ * Copyright (C) 2012 Red Hat, Inc.33+ *44+ * This file is released under the GPL.55+ */66+77+#include "dm-bitset.h"88+#include "dm-transaction-manager.h"99+1010+#include <linux/export.h>1111+#include <linux/device-mapper.h>1212+1313+#define DM_MSG_PREFIX "bitset"1414+#define BITS_PER_ARRAY_ENTRY 641515+1616+/*----------------------------------------------------------------*/1717+1818+static struct dm_btree_value_type bitset_bvt = {1919+ .context = NULL,2020+ .size = sizeof(__le64),2121+ .inc = NULL,2222+ .dec = NULL,2323+ .equal = NULL,2424+};2525+2626+/*----------------------------------------------------------------*/2727+2828+void dm_disk_bitset_init(struct dm_transaction_manager *tm,2929+ struct dm_disk_bitset *info)3030+{3131+ dm_array_info_init(&info->array_info, tm, &bitset_bvt);3232+ info->current_index_set = false;3333+}3434+EXPORT_SYMBOL_GPL(dm_disk_bitset_init);3535+3636+int dm_bitset_empty(struct dm_disk_bitset *info, dm_block_t *root)3737+{3838+ return dm_array_empty(&info->array_info, root);3939+}4040+EXPORT_SYMBOL_GPL(dm_bitset_empty);4141+4242+int dm_bitset_resize(struct dm_disk_bitset *info, dm_block_t root,4343+ uint32_t old_nr_entries, uint32_t new_nr_entries,4444+ bool default_value, dm_block_t *new_root)4545+{4646+ uint32_t old_blocks = dm_div_up(old_nr_entries, BITS_PER_ARRAY_ENTRY);4747+ uint32_t new_blocks = dm_div_up(new_nr_entries, BITS_PER_ARRAY_ENTRY);4848+ __le64 value = default_value ? cpu_to_le64(~0) : cpu_to_le64(0);4949+5050+ __dm_bless_for_disk(&value);5151+ return dm_array_resize(&info->array_info, root, old_blocks, new_blocks,5252+ &value, new_root);5353+}5454+EXPORT_SYMBOL_GPL(dm_bitset_resize);5555+5656+int dm_bitset_del(struct dm_disk_bitset *info, dm_block_t root)5757+{5858+ return dm_array_del(&info->array_info, root);5959+}6060+EXPORT_SYMBOL_GPL(dm_bitset_del);6161+6262+int dm_bitset_flush(struct dm_disk_bitset *info, dm_block_t root,6363+ dm_block_t *new_root)6464+{6565+ int r;6666+ __le64 value;6767+6868+ if (!info->current_index_set)6969+ return 0;7070+7171+ value = cpu_to_le64(info->current_bits);7272+7373+ __dm_bless_for_disk(&value);7474+ r = dm_array_set_value(&info->array_info, root, info->current_index,7575+ &value, new_root);7676+ if (r)7777+ return r;7878+7979+ info->current_index_set = false;8080+ return 0;8181+}8282+EXPORT_SYMBOL_GPL(dm_bitset_flush);8383+8484+static int read_bits(struct dm_disk_bitset *info, dm_block_t root,8585+ uint32_t array_index)8686+{8787+ int r;8888+ __le64 value;8989+9090+ r = dm_array_get_value(&info->array_info, root, array_index, &value);9191+ if (r)9292+ return r;9393+9494+ info->current_bits = le64_to_cpu(value);9595+ info->current_index_set = true;9696+ info->current_index = array_index;9797+ return 0;9898+}9999+100100+static int get_array_entry(struct dm_disk_bitset *info, dm_block_t root,101101+ uint32_t index, dm_block_t *new_root)102102+{103103+ int r;104104+ unsigned array_index = index / BITS_PER_ARRAY_ENTRY;105105+106106+ if (info->current_index_set) {107107+ if (info->current_index == array_index)108108+ return 0;109109+110110+ r = dm_bitset_flush(info, root, new_root);111111+ if (r)112112+ return r;113113+ }114114+115115+ return read_bits(info, root, array_index);116116+}117117+118118+int dm_bitset_set_bit(struct dm_disk_bitset *info, dm_block_t root,119119+ uint32_t index, dm_block_t *new_root)120120+{121121+ int r;122122+ unsigned b = index % BITS_PER_ARRAY_ENTRY;123123+124124+ r = get_array_entry(info, root, index, new_root);125125+ if (r)126126+ return r;127127+128128+ set_bit(b, (unsigned long *) &info->current_bits);129129+ return 0;130130+}131131+EXPORT_SYMBOL_GPL(dm_bitset_set_bit);132132+133133+int dm_bitset_clear_bit(struct dm_disk_bitset *info, dm_block_t root,134134+ uint32_t index, dm_block_t *new_root)135135+{136136+ int r;137137+ unsigned b = index % BITS_PER_ARRAY_ENTRY;138138+139139+ r = get_array_entry(info, root, index, new_root);140140+ if (r)141141+ return r;142142+143143+ clear_bit(b, (unsigned long *) &info->current_bits);144144+ return 0;145145+}146146+EXPORT_SYMBOL_GPL(dm_bitset_clear_bit);147147+148148+int dm_bitset_test_bit(struct dm_disk_bitset *info, dm_block_t root,149149+ uint32_t index, dm_block_t *new_root, bool *result)150150+{151151+ int r;152152+ unsigned b = index % BITS_PER_ARRAY_ENTRY;153153+154154+ r = get_array_entry(info, root, index, new_root);155155+ if (r)156156+ return r;157157+158158+ *result = test_bit(b, (unsigned long *) &info->current_bits);159159+ return 0;160160+}161161+EXPORT_SYMBOL_GPL(dm_bitset_test_bit);162162+163163+/*----------------------------------------------------------------*/
+165
drivers/md/persistent-data/dm-bitset.h
···11+/*22+ * Copyright (C) 2012 Red Hat, Inc.33+ *44+ * This file is released under the GPL.55+ */66+#ifndef _LINUX_DM_BITSET_H77+#define _LINUX_DM_BITSET_H88+99+#include "dm-array.h"1010+1111+/*----------------------------------------------------------------*/1212+1313+/*1414+ * This bitset type is a thin wrapper round a dm_array of 64bit words. It1515+ * uses a tiny, one word cache to reduce the number of array lookups and so1616+ * increase performance.1717+ *1818+ * Like the dm-array that it's based on, the caller needs to keep track of1919+ * the size of the bitset separately. The underlying dm-array implicitly2020+ * knows how many words it's storing and will return -ENODATA if you try2121+ * and access an out of bounds word. However, an out of bounds bit in the2222+ * final word will _not_ be detected, you have been warned.2323+ *2424+ * Bits are indexed from zero.2525+2626+ * Typical use:2727+ *2828+ * a) Initialise a dm_disk_bitset structure with dm_disk_bitset_init().2929+ * This describes the bitset and includes the cache. It's not called it3030+ * dm_bitset_info in line with other data structures because it does3131+ * include instance data.3232+ *3333+ * b) Get yourself a root. The root is the index of a block of data on the3434+ * disk that holds a particular instance of an bitset. You may have a3535+ * pre existing root in your metadata that you wish to use, or you may3636+ * want to create a brand new, empty bitset with dm_bitset_empty().3737+ *3838+ * Like the other data structures in this library, dm_bitset objects are3939+ * immutable between transactions. Update functions will return you the4040+ * root for a _new_ array. If you've incremented the old root, via4141+ * dm_tm_inc(), before calling the update function you may continue to use4242+ * it in parallel with the new root.4343+ *4444+ * Even read operations may trigger the cache to be flushed and as such4545+ * return a root for a new, updated bitset.4646+ *4747+ * c) resize a bitset with dm_bitset_resize().4848+ *4949+ * d) Set a bit with dm_bitset_set_bit().5050+ *5151+ * e) Clear a bit with dm_bitset_clear_bit().5252+ *5353+ * f) Test a bit with dm_bitset_test_bit().5454+ *5555+ * g) Flush all updates from the cache with dm_bitset_flush().5656+ *5757+ * h) Destroy the bitset with dm_bitset_del(). This tells the transaction5858+ * manager that you're no longer using this data structure so it can5959+ * recycle it's blocks. (dm_bitset_dec() would be a better name for it,6060+ * but del is in keeping with dm_btree_del()).6161+ */6262+6363+/*6464+ * Opaque object. Unlike dm_array_info, you should have one of these per6565+ * bitset. Initialise with dm_disk_bitset_init().6666+ */6767+struct dm_disk_bitset {6868+ struct dm_array_info array_info;6969+7070+ uint32_t current_index;7171+ uint64_t current_bits;7272+7373+ bool current_index_set:1;7474+};7575+7676+/*7777+ * Sets up a dm_disk_bitset structure. You don't need to do anything with7878+ * this structure when you finish using it.7979+ *8080+ * tm - the transaction manager that should supervise this structure8181+ * info - the structure being initialised8282+ */8383+void dm_disk_bitset_init(struct dm_transaction_manager *tm,8484+ struct dm_disk_bitset *info);8585+8686+/*8787+ * Create an empty, zero length bitset.8888+ *8989+ * info - describes the bitset9090+ * new_root - on success, points to the new root block9191+ */9292+int dm_bitset_empty(struct dm_disk_bitset *info, dm_block_t *new_root);9393+9494+/*9595+ * Resize the bitset.9696+ *9797+ * info - describes the bitset9898+ * old_root - the root block of the array on disk9999+ * old_nr_entries - the number of bits in the old bitset100100+ * new_nr_entries - the number of bits you want in the new bitset101101+ * default_value - the value for any new bits102102+ * new_root - on success, points to the new root block103103+ */104104+int dm_bitset_resize(struct dm_disk_bitset *info, dm_block_t old_root,105105+ uint32_t old_nr_entries, uint32_t new_nr_entries,106106+ bool default_value, dm_block_t *new_root);107107+108108+/*109109+ * Frees the bitset.110110+ */111111+int dm_bitset_del(struct dm_disk_bitset *info, dm_block_t root);112112+113113+/*114114+ * Set a bit.115115+ *116116+ * info - describes the bitset117117+ * root - the root block of the bitset118118+ * index - the bit index119119+ * new_root - on success, points to the new root block120120+ *121121+ * -ENODATA will be returned if the index is out of bounds.122122+ */123123+int dm_bitset_set_bit(struct dm_disk_bitset *info, dm_block_t root,124124+ uint32_t index, dm_block_t *new_root);125125+126126+/*127127+ * Clears a bit.128128+ *129129+ * info - describes the bitset130130+ * root - the root block of the bitset131131+ * index - the bit index132132+ * new_root - on success, points to the new root block133133+ *134134+ * -ENODATA will be returned if the index is out of bounds.135135+ */136136+int dm_bitset_clear_bit(struct dm_disk_bitset *info, dm_block_t root,137137+ uint32_t index, dm_block_t *new_root);138138+139139+/*140140+ * Tests a bit.141141+ *142142+ * info - describes the bitset143143+ * root - the root block of the bitset144144+ * index - the bit index145145+ * new_root - on success, points to the new root block (cached values may have been written)146146+ * result - the bit value you're after147147+ *148148+ * -ENODATA will be returned if the index is out of bounds.149149+ */150150+int dm_bitset_test_bit(struct dm_disk_bitset *info, dm_block_t root,151151+ uint32_t index, dm_block_t *new_root, bool *result);152152+153153+/*154154+ * Flush any cached changes to disk.155155+ *156156+ * info - describes the bitset157157+ * root - the root block of the bitset158158+ * new_root - on success, points to the new root block159159+ */160160+int dm_bitset_flush(struct dm_disk_bitset *info, dm_block_t root,161161+ dm_block_t *new_root);162162+163163+/*----------------------------------------------------------------*/164164+165165+#endif /* _LINUX_DM_BITSET_H */