18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Copyright (C) 2012 Red Hat, Inc.
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * This file is released under the GPL.
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#include "dm-bitset.h"
88c2ecf20Sopenharmony_ci#include "dm-transaction-manager.h"
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/export.h>
118c2ecf20Sopenharmony_ci#include <linux/device-mapper.h>
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#define DM_MSG_PREFIX "bitset"
148c2ecf20Sopenharmony_ci#define BITS_PER_ARRAY_ENTRY 64
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci/*----------------------------------------------------------------*/
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_cistatic struct dm_btree_value_type bitset_bvt = {
198c2ecf20Sopenharmony_ci	.context = NULL,
208c2ecf20Sopenharmony_ci	.size = sizeof(__le64),
218c2ecf20Sopenharmony_ci	.inc = NULL,
228c2ecf20Sopenharmony_ci	.dec = NULL,
238c2ecf20Sopenharmony_ci	.equal = NULL,
248c2ecf20Sopenharmony_ci};
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci/*----------------------------------------------------------------*/
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_civoid dm_disk_bitset_init(struct dm_transaction_manager *tm,
298c2ecf20Sopenharmony_ci			 struct dm_disk_bitset *info)
308c2ecf20Sopenharmony_ci{
318c2ecf20Sopenharmony_ci	dm_array_info_init(&info->array_info, tm, &bitset_bvt);
328c2ecf20Sopenharmony_ci	info->current_index_set = false;
338c2ecf20Sopenharmony_ci}
348c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dm_disk_bitset_init);
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ciint dm_bitset_empty(struct dm_disk_bitset *info, dm_block_t *root)
378c2ecf20Sopenharmony_ci{
388c2ecf20Sopenharmony_ci	return dm_array_empty(&info->array_info, root);
398c2ecf20Sopenharmony_ci}
408c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dm_bitset_empty);
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_cistruct packer_context {
438c2ecf20Sopenharmony_ci	bit_value_fn fn;
448c2ecf20Sopenharmony_ci	unsigned nr_bits;
458c2ecf20Sopenharmony_ci	void *context;
468c2ecf20Sopenharmony_ci};
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_cistatic int pack_bits(uint32_t index, void *value, void *context)
498c2ecf20Sopenharmony_ci{
508c2ecf20Sopenharmony_ci	int r;
518c2ecf20Sopenharmony_ci	struct packer_context *p = context;
528c2ecf20Sopenharmony_ci	unsigned bit, nr = min(64u, p->nr_bits - (index * 64));
538c2ecf20Sopenharmony_ci	uint64_t word = 0;
548c2ecf20Sopenharmony_ci	bool bv;
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	for (bit = 0; bit < nr; bit++) {
578c2ecf20Sopenharmony_ci		r = p->fn(index * 64 + bit, &bv, p->context);
588c2ecf20Sopenharmony_ci		if (r)
598c2ecf20Sopenharmony_ci			return r;
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci		if (bv)
628c2ecf20Sopenharmony_ci			set_bit(bit, (unsigned long *) &word);
638c2ecf20Sopenharmony_ci		else
648c2ecf20Sopenharmony_ci			clear_bit(bit, (unsigned long *) &word);
658c2ecf20Sopenharmony_ci	}
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci	*((__le64 *) value) = cpu_to_le64(word);
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	return 0;
708c2ecf20Sopenharmony_ci}
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ciint dm_bitset_new(struct dm_disk_bitset *info, dm_block_t *root,
738c2ecf20Sopenharmony_ci		  uint32_t size, bit_value_fn fn, void *context)
748c2ecf20Sopenharmony_ci{
758c2ecf20Sopenharmony_ci	struct packer_context p;
768c2ecf20Sopenharmony_ci	p.fn = fn;
778c2ecf20Sopenharmony_ci	p.nr_bits = size;
788c2ecf20Sopenharmony_ci	p.context = context;
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci	return dm_array_new(&info->array_info, root, dm_div_up(size, 64), pack_bits, &p);
818c2ecf20Sopenharmony_ci}
828c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dm_bitset_new);
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ciint dm_bitset_resize(struct dm_disk_bitset *info, dm_block_t root,
858c2ecf20Sopenharmony_ci		     uint32_t old_nr_entries, uint32_t new_nr_entries,
868c2ecf20Sopenharmony_ci		     bool default_value, dm_block_t *new_root)
878c2ecf20Sopenharmony_ci{
888c2ecf20Sopenharmony_ci	uint32_t old_blocks = dm_div_up(old_nr_entries, BITS_PER_ARRAY_ENTRY);
898c2ecf20Sopenharmony_ci	uint32_t new_blocks = dm_div_up(new_nr_entries, BITS_PER_ARRAY_ENTRY);
908c2ecf20Sopenharmony_ci	__le64 value = default_value ? cpu_to_le64(~0) : cpu_to_le64(0);
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	__dm_bless_for_disk(&value);
938c2ecf20Sopenharmony_ci	return dm_array_resize(&info->array_info, root, old_blocks, new_blocks,
948c2ecf20Sopenharmony_ci			       &value, new_root);
958c2ecf20Sopenharmony_ci}
968c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dm_bitset_resize);
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ciint dm_bitset_del(struct dm_disk_bitset *info, dm_block_t root)
998c2ecf20Sopenharmony_ci{
1008c2ecf20Sopenharmony_ci	return dm_array_del(&info->array_info, root);
1018c2ecf20Sopenharmony_ci}
1028c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dm_bitset_del);
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ciint dm_bitset_flush(struct dm_disk_bitset *info, dm_block_t root,
1058c2ecf20Sopenharmony_ci		    dm_block_t *new_root)
1068c2ecf20Sopenharmony_ci{
1078c2ecf20Sopenharmony_ci	int r;
1088c2ecf20Sopenharmony_ci	__le64 value;
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci	if (!info->current_index_set || !info->dirty)
1118c2ecf20Sopenharmony_ci		return 0;
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	value = cpu_to_le64(info->current_bits);
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci	__dm_bless_for_disk(&value);
1168c2ecf20Sopenharmony_ci	r = dm_array_set_value(&info->array_info, root, info->current_index,
1178c2ecf20Sopenharmony_ci			       &value, new_root);
1188c2ecf20Sopenharmony_ci	if (r)
1198c2ecf20Sopenharmony_ci		return r;
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	info->current_index_set = false;
1228c2ecf20Sopenharmony_ci	info->dirty = false;
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	return 0;
1258c2ecf20Sopenharmony_ci}
1268c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dm_bitset_flush);
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_cistatic int read_bits(struct dm_disk_bitset *info, dm_block_t root,
1298c2ecf20Sopenharmony_ci		     uint32_t array_index)
1308c2ecf20Sopenharmony_ci{
1318c2ecf20Sopenharmony_ci	int r;
1328c2ecf20Sopenharmony_ci	__le64 value;
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci	r = dm_array_get_value(&info->array_info, root, array_index, &value);
1358c2ecf20Sopenharmony_ci	if (r)
1368c2ecf20Sopenharmony_ci		return r;
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	info->current_bits = le64_to_cpu(value);
1398c2ecf20Sopenharmony_ci	info->current_index_set = true;
1408c2ecf20Sopenharmony_ci	info->current_index = array_index;
1418c2ecf20Sopenharmony_ci	info->dirty = false;
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	return 0;
1448c2ecf20Sopenharmony_ci}
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_cistatic int get_array_entry(struct dm_disk_bitset *info, dm_block_t root,
1478c2ecf20Sopenharmony_ci			   uint32_t index, dm_block_t *new_root)
1488c2ecf20Sopenharmony_ci{
1498c2ecf20Sopenharmony_ci	int r;
1508c2ecf20Sopenharmony_ci	unsigned array_index = index / BITS_PER_ARRAY_ENTRY;
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci	if (info->current_index_set) {
1538c2ecf20Sopenharmony_ci		if (info->current_index == array_index)
1548c2ecf20Sopenharmony_ci			return 0;
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci		r = dm_bitset_flush(info, root, new_root);
1578c2ecf20Sopenharmony_ci		if (r)
1588c2ecf20Sopenharmony_ci			return r;
1598c2ecf20Sopenharmony_ci	}
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	return read_bits(info, root, array_index);
1628c2ecf20Sopenharmony_ci}
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ciint dm_bitset_set_bit(struct dm_disk_bitset *info, dm_block_t root,
1658c2ecf20Sopenharmony_ci		      uint32_t index, dm_block_t *new_root)
1668c2ecf20Sopenharmony_ci{
1678c2ecf20Sopenharmony_ci	int r;
1688c2ecf20Sopenharmony_ci	unsigned b = index % BITS_PER_ARRAY_ENTRY;
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci	r = get_array_entry(info, root, index, new_root);
1718c2ecf20Sopenharmony_ci	if (r)
1728c2ecf20Sopenharmony_ci		return r;
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci	set_bit(b, (unsigned long *) &info->current_bits);
1758c2ecf20Sopenharmony_ci	info->dirty = true;
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci	return 0;
1788c2ecf20Sopenharmony_ci}
1798c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dm_bitset_set_bit);
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ciint dm_bitset_clear_bit(struct dm_disk_bitset *info, dm_block_t root,
1828c2ecf20Sopenharmony_ci			uint32_t index, dm_block_t *new_root)
1838c2ecf20Sopenharmony_ci{
1848c2ecf20Sopenharmony_ci	int r;
1858c2ecf20Sopenharmony_ci	unsigned b = index % BITS_PER_ARRAY_ENTRY;
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci	r = get_array_entry(info, root, index, new_root);
1888c2ecf20Sopenharmony_ci	if (r)
1898c2ecf20Sopenharmony_ci		return r;
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci	clear_bit(b, (unsigned long *) &info->current_bits);
1928c2ecf20Sopenharmony_ci	info->dirty = true;
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	return 0;
1958c2ecf20Sopenharmony_ci}
1968c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dm_bitset_clear_bit);
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ciint dm_bitset_test_bit(struct dm_disk_bitset *info, dm_block_t root,
1998c2ecf20Sopenharmony_ci		       uint32_t index, dm_block_t *new_root, bool *result)
2008c2ecf20Sopenharmony_ci{
2018c2ecf20Sopenharmony_ci	int r;
2028c2ecf20Sopenharmony_ci	unsigned b = index % BITS_PER_ARRAY_ENTRY;
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci	r = get_array_entry(info, root, index, new_root);
2058c2ecf20Sopenharmony_ci	if (r)
2068c2ecf20Sopenharmony_ci		return r;
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci	*result = test_bit(b, (unsigned long *) &info->current_bits);
2098c2ecf20Sopenharmony_ci	return 0;
2108c2ecf20Sopenharmony_ci}
2118c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dm_bitset_test_bit);
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_cistatic int cursor_next_array_entry(struct dm_bitset_cursor *c)
2148c2ecf20Sopenharmony_ci{
2158c2ecf20Sopenharmony_ci	int r;
2168c2ecf20Sopenharmony_ci	__le64 *value;
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	r = dm_array_cursor_next(&c->cursor);
2198c2ecf20Sopenharmony_ci	if (r)
2208c2ecf20Sopenharmony_ci		return r;
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci	dm_array_cursor_get_value(&c->cursor, (void **) &value);
2238c2ecf20Sopenharmony_ci	c->array_index++;
2248c2ecf20Sopenharmony_ci	c->bit_index = 0;
2258c2ecf20Sopenharmony_ci	c->current_bits = le64_to_cpu(*value);
2268c2ecf20Sopenharmony_ci	return 0;
2278c2ecf20Sopenharmony_ci}
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ciint dm_bitset_cursor_begin(struct dm_disk_bitset *info,
2308c2ecf20Sopenharmony_ci			   dm_block_t root, uint32_t nr_entries,
2318c2ecf20Sopenharmony_ci			   struct dm_bitset_cursor *c)
2328c2ecf20Sopenharmony_ci{
2338c2ecf20Sopenharmony_ci	int r;
2348c2ecf20Sopenharmony_ci	__le64 *value;
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci	if (!nr_entries)
2378c2ecf20Sopenharmony_ci		return -ENODATA;
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	c->info = info;
2408c2ecf20Sopenharmony_ci	c->entries_remaining = nr_entries;
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci	r = dm_array_cursor_begin(&info->array_info, root, &c->cursor);
2438c2ecf20Sopenharmony_ci	if (r)
2448c2ecf20Sopenharmony_ci		return r;
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci	dm_array_cursor_get_value(&c->cursor, (void **) &value);
2478c2ecf20Sopenharmony_ci	c->array_index = 0;
2488c2ecf20Sopenharmony_ci	c->bit_index = 0;
2498c2ecf20Sopenharmony_ci	c->current_bits = le64_to_cpu(*value);
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	return r;
2528c2ecf20Sopenharmony_ci}
2538c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dm_bitset_cursor_begin);
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_civoid dm_bitset_cursor_end(struct dm_bitset_cursor *c)
2568c2ecf20Sopenharmony_ci{
2578c2ecf20Sopenharmony_ci	return dm_array_cursor_end(&c->cursor);
2588c2ecf20Sopenharmony_ci}
2598c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dm_bitset_cursor_end);
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ciint dm_bitset_cursor_next(struct dm_bitset_cursor *c)
2628c2ecf20Sopenharmony_ci{
2638c2ecf20Sopenharmony_ci	int r = 0;
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	if (!c->entries_remaining)
2668c2ecf20Sopenharmony_ci		return -ENODATA;
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	c->entries_remaining--;
2698c2ecf20Sopenharmony_ci	if (++c->bit_index > 63)
2708c2ecf20Sopenharmony_ci		r = cursor_next_array_entry(c);
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci	return r;
2738c2ecf20Sopenharmony_ci}
2748c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dm_bitset_cursor_next);
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ciint dm_bitset_cursor_skip(struct dm_bitset_cursor *c, uint32_t count)
2778c2ecf20Sopenharmony_ci{
2788c2ecf20Sopenharmony_ci	int r;
2798c2ecf20Sopenharmony_ci	__le64 *value;
2808c2ecf20Sopenharmony_ci	uint32_t nr_array_skip;
2818c2ecf20Sopenharmony_ci	uint32_t remaining_in_word = 64 - c->bit_index;
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	if (c->entries_remaining < count)
2848c2ecf20Sopenharmony_ci		return -ENODATA;
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci	if (count < remaining_in_word) {
2878c2ecf20Sopenharmony_ci		c->bit_index += count;
2888c2ecf20Sopenharmony_ci		c->entries_remaining -= count;
2898c2ecf20Sopenharmony_ci		return 0;
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci	} else {
2928c2ecf20Sopenharmony_ci		c->entries_remaining -= remaining_in_word;
2938c2ecf20Sopenharmony_ci		count -= remaining_in_word;
2948c2ecf20Sopenharmony_ci	}
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	nr_array_skip = (count / 64) + 1;
2978c2ecf20Sopenharmony_ci	r = dm_array_cursor_skip(&c->cursor, nr_array_skip);
2988c2ecf20Sopenharmony_ci	if (r)
2998c2ecf20Sopenharmony_ci		return r;
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci	dm_array_cursor_get_value(&c->cursor, (void **) &value);
3028c2ecf20Sopenharmony_ci	c->entries_remaining -= count;
3038c2ecf20Sopenharmony_ci	c->array_index += nr_array_skip;
3048c2ecf20Sopenharmony_ci	c->bit_index = count & 63;
3058c2ecf20Sopenharmony_ci	c->current_bits = le64_to_cpu(*value);
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	return 0;
3088c2ecf20Sopenharmony_ci}
3098c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dm_bitset_cursor_skip);
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_cibool dm_bitset_cursor_get_value(struct dm_bitset_cursor *c)
3128c2ecf20Sopenharmony_ci{
3138c2ecf20Sopenharmony_ci	return test_bit(c->bit_index, (unsigned long *) &c->current_bits);
3148c2ecf20Sopenharmony_ci}
3158c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dm_bitset_cursor_get_value);
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci/*----------------------------------------------------------------*/
318