linux/drivers/md/persistent-data/dm-bitset.c
<<
>>
Prefs
   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