xref: /openbmc/linux/drivers/md/persistent-data/dm-bitset.c (revision 9b696229aa7de356675a938c6c8a70b46085ed66)
17a87edfeSJoe Thornber /*
27a87edfeSJoe Thornber  * Copyright (C) 2012 Red Hat, Inc.
37a87edfeSJoe Thornber  *
47a87edfeSJoe Thornber  * This file is released under the GPL.
57a87edfeSJoe Thornber  */
67a87edfeSJoe Thornber 
77a87edfeSJoe Thornber #include "dm-bitset.h"
87a87edfeSJoe Thornber #include "dm-transaction-manager.h"
97a87edfeSJoe Thornber 
107a87edfeSJoe Thornber #include <linux/export.h>
117a87edfeSJoe Thornber #include <linux/device-mapper.h>
127a87edfeSJoe Thornber 
137a87edfeSJoe Thornber #define DM_MSG_PREFIX "bitset"
147a87edfeSJoe Thornber #define BITS_PER_ARRAY_ENTRY 64
157a87edfeSJoe Thornber 
167a87edfeSJoe Thornber /*----------------------------------------------------------------*/
177a87edfeSJoe Thornber 
187a87edfeSJoe Thornber static struct dm_btree_value_type bitset_bvt = {
197a87edfeSJoe Thornber 	.context = NULL,
207a87edfeSJoe Thornber 	.size = sizeof(__le64),
217a87edfeSJoe Thornber 	.inc = NULL,
227a87edfeSJoe Thornber 	.dec = NULL,
237a87edfeSJoe Thornber 	.equal = NULL,
247a87edfeSJoe Thornber };
257a87edfeSJoe Thornber 
267a87edfeSJoe Thornber /*----------------------------------------------------------------*/
277a87edfeSJoe Thornber 
287a87edfeSJoe Thornber void dm_disk_bitset_init(struct dm_transaction_manager *tm,
297a87edfeSJoe Thornber 			 struct dm_disk_bitset *info)
307a87edfeSJoe Thornber {
317a87edfeSJoe Thornber 	dm_array_info_init(&info->array_info, tm, &bitset_bvt);
327a87edfeSJoe Thornber 	info->current_index_set = false;
337a87edfeSJoe Thornber }
347a87edfeSJoe Thornber EXPORT_SYMBOL_GPL(dm_disk_bitset_init);
357a87edfeSJoe Thornber 
367a87edfeSJoe Thornber int dm_bitset_empty(struct dm_disk_bitset *info, dm_block_t *root)
377a87edfeSJoe Thornber {
387a87edfeSJoe Thornber 	return dm_array_empty(&info->array_info, root);
397a87edfeSJoe Thornber }
407a87edfeSJoe Thornber EXPORT_SYMBOL_GPL(dm_bitset_empty);
417a87edfeSJoe Thornber 
422151249eSJoe Thornber struct packer_context {
432151249eSJoe Thornber 	bit_value_fn fn;
442151249eSJoe Thornber 	unsigned nr_bits;
452151249eSJoe Thornber 	void *context;
462151249eSJoe Thornber };
472151249eSJoe Thornber 
482151249eSJoe Thornber static int pack_bits(uint32_t index, void *value, void *context)
492151249eSJoe Thornber {
502151249eSJoe Thornber 	int r;
512151249eSJoe Thornber 	struct packer_context *p = context;
522151249eSJoe Thornber 	unsigned bit, nr = min(64u, p->nr_bits - (index * 64));
532151249eSJoe Thornber 	uint64_t word = 0;
542151249eSJoe Thornber 	bool bv;
552151249eSJoe Thornber 
562151249eSJoe Thornber 	for (bit = 0; bit < nr; bit++) {
572151249eSJoe Thornber 		r = p->fn(index * 64 + bit, &bv, p->context);
582151249eSJoe Thornber 		if (r)
592151249eSJoe Thornber 			return r;
602151249eSJoe Thornber 
612151249eSJoe Thornber 		if (bv)
622151249eSJoe Thornber 			set_bit(bit, (unsigned long *) &word);
632151249eSJoe Thornber 		else
642151249eSJoe Thornber 			clear_bit(bit, (unsigned long *) &word);
652151249eSJoe Thornber 	}
662151249eSJoe Thornber 
672151249eSJoe Thornber 	*((__le64 *) value) = cpu_to_le64(word);
682151249eSJoe Thornber 
692151249eSJoe Thornber 	return 0;
702151249eSJoe Thornber }
712151249eSJoe Thornber 
722151249eSJoe Thornber int dm_bitset_new(struct dm_disk_bitset *info, dm_block_t *root,
732151249eSJoe Thornber 		  uint32_t size, bit_value_fn fn, void *context)
742151249eSJoe Thornber {
752151249eSJoe Thornber 	struct packer_context p;
762151249eSJoe Thornber 	p.fn = fn;
772151249eSJoe Thornber 	p.nr_bits = size;
782151249eSJoe Thornber 	p.context = context;
792151249eSJoe Thornber 
802151249eSJoe Thornber 	return dm_array_new(&info->array_info, root, dm_div_up(size, 64), pack_bits, &p);
812151249eSJoe Thornber }
822151249eSJoe Thornber EXPORT_SYMBOL_GPL(dm_bitset_new);
832151249eSJoe Thornber 
847a87edfeSJoe Thornber int dm_bitset_resize(struct dm_disk_bitset *info, dm_block_t root,
857a87edfeSJoe Thornber 		     uint32_t old_nr_entries, uint32_t new_nr_entries,
867a87edfeSJoe Thornber 		     bool default_value, dm_block_t *new_root)
877a87edfeSJoe Thornber {
887a87edfeSJoe Thornber 	uint32_t old_blocks = dm_div_up(old_nr_entries, BITS_PER_ARRAY_ENTRY);
897a87edfeSJoe Thornber 	uint32_t new_blocks = dm_div_up(new_nr_entries, BITS_PER_ARRAY_ENTRY);
907a87edfeSJoe Thornber 	__le64 value = default_value ? cpu_to_le64(~0) : cpu_to_le64(0);
917a87edfeSJoe Thornber 
927a87edfeSJoe Thornber 	__dm_bless_for_disk(&value);
937a87edfeSJoe Thornber 	return dm_array_resize(&info->array_info, root, old_blocks, new_blocks,
947a87edfeSJoe Thornber 			       &value, new_root);
957a87edfeSJoe Thornber }
967a87edfeSJoe Thornber EXPORT_SYMBOL_GPL(dm_bitset_resize);
977a87edfeSJoe Thornber 
987a87edfeSJoe Thornber int dm_bitset_del(struct dm_disk_bitset *info, dm_block_t root)
997a87edfeSJoe Thornber {
1007a87edfeSJoe Thornber 	return dm_array_del(&info->array_info, root);
1017a87edfeSJoe Thornber }
1027a87edfeSJoe Thornber EXPORT_SYMBOL_GPL(dm_bitset_del);
1037a87edfeSJoe Thornber 
1047a87edfeSJoe Thornber int dm_bitset_flush(struct dm_disk_bitset *info, dm_block_t root,
1057a87edfeSJoe Thornber 		    dm_block_t *new_root)
1067a87edfeSJoe Thornber {
1077a87edfeSJoe Thornber 	int r;
1087a87edfeSJoe Thornber 	__le64 value;
1097a87edfeSJoe Thornber 
110428e4698SJoe Thornber 	if (!info->current_index_set || !info->dirty)
1117a87edfeSJoe Thornber 		return 0;
1127a87edfeSJoe Thornber 
1137a87edfeSJoe Thornber 	value = cpu_to_le64(info->current_bits);
1147a87edfeSJoe Thornber 
1157a87edfeSJoe Thornber 	__dm_bless_for_disk(&value);
1167a87edfeSJoe Thornber 	r = dm_array_set_value(&info->array_info, root, info->current_index,
1177a87edfeSJoe Thornber 			       &value, new_root);
1187a87edfeSJoe Thornber 	if (r)
1197a87edfeSJoe Thornber 		return r;
1207a87edfeSJoe Thornber 
1217a87edfeSJoe Thornber 	info->current_index_set = false;
122428e4698SJoe Thornber 	info->dirty = false;
123428e4698SJoe Thornber 
1247a87edfeSJoe Thornber 	return 0;
1257a87edfeSJoe Thornber }
1267a87edfeSJoe Thornber EXPORT_SYMBOL_GPL(dm_bitset_flush);
1277a87edfeSJoe Thornber 
1287a87edfeSJoe Thornber static int read_bits(struct dm_disk_bitset *info, dm_block_t root,
1297a87edfeSJoe Thornber 		     uint32_t array_index)
1307a87edfeSJoe Thornber {
1317a87edfeSJoe Thornber 	int r;
1327a87edfeSJoe Thornber 	__le64 value;
1337a87edfeSJoe Thornber 
1347a87edfeSJoe Thornber 	r = dm_array_get_value(&info->array_info, root, array_index, &value);
1357a87edfeSJoe Thornber 	if (r)
1367a87edfeSJoe Thornber 		return r;
1377a87edfeSJoe Thornber 
1387a87edfeSJoe Thornber 	info->current_bits = le64_to_cpu(value);
1397a87edfeSJoe Thornber 	info->current_index_set = true;
1407a87edfeSJoe Thornber 	info->current_index = array_index;
141428e4698SJoe Thornber 	info->dirty = false;
142428e4698SJoe Thornber 
1437a87edfeSJoe Thornber 	return 0;
1447a87edfeSJoe Thornber }
1457a87edfeSJoe Thornber 
1467a87edfeSJoe Thornber static int get_array_entry(struct dm_disk_bitset *info, dm_block_t root,
1477a87edfeSJoe Thornber 			   uint32_t index, dm_block_t *new_root)
1487a87edfeSJoe Thornber {
1497a87edfeSJoe Thornber 	int r;
1507a87edfeSJoe Thornber 	unsigned array_index = index / BITS_PER_ARRAY_ENTRY;
1517a87edfeSJoe Thornber 
1527a87edfeSJoe Thornber 	if (info->current_index_set) {
1537a87edfeSJoe Thornber 		if (info->current_index == array_index)
1547a87edfeSJoe Thornber 			return 0;
1557a87edfeSJoe Thornber 
1567a87edfeSJoe Thornber 		r = dm_bitset_flush(info, root, new_root);
1577a87edfeSJoe Thornber 		if (r)
1587a87edfeSJoe Thornber 			return r;
1597a87edfeSJoe Thornber 	}
1607a87edfeSJoe Thornber 
1617a87edfeSJoe Thornber 	return read_bits(info, root, array_index);
1627a87edfeSJoe Thornber }
1637a87edfeSJoe Thornber 
1647a87edfeSJoe Thornber int dm_bitset_set_bit(struct dm_disk_bitset *info, dm_block_t root,
1657a87edfeSJoe Thornber 		      uint32_t index, dm_block_t *new_root)
1667a87edfeSJoe Thornber {
1677a87edfeSJoe Thornber 	int r;
1687a87edfeSJoe Thornber 	unsigned b = index % BITS_PER_ARRAY_ENTRY;
1697a87edfeSJoe Thornber 
1707a87edfeSJoe Thornber 	r = get_array_entry(info, root, index, new_root);
1717a87edfeSJoe Thornber 	if (r)
1727a87edfeSJoe Thornber 		return r;
1737a87edfeSJoe Thornber 
1747a87edfeSJoe Thornber 	set_bit(b, (unsigned long *) &info->current_bits);
175428e4698SJoe Thornber 	info->dirty = true;
176428e4698SJoe Thornber 
1777a87edfeSJoe Thornber 	return 0;
1787a87edfeSJoe Thornber }
1797a87edfeSJoe Thornber EXPORT_SYMBOL_GPL(dm_bitset_set_bit);
1807a87edfeSJoe Thornber 
1817a87edfeSJoe Thornber int dm_bitset_clear_bit(struct dm_disk_bitset *info, dm_block_t root,
1827a87edfeSJoe Thornber 			uint32_t index, dm_block_t *new_root)
1837a87edfeSJoe Thornber {
1847a87edfeSJoe Thornber 	int r;
1857a87edfeSJoe Thornber 	unsigned b = index % BITS_PER_ARRAY_ENTRY;
1867a87edfeSJoe Thornber 
1877a87edfeSJoe Thornber 	r = get_array_entry(info, root, index, new_root);
1887a87edfeSJoe Thornber 	if (r)
1897a87edfeSJoe Thornber 		return r;
1907a87edfeSJoe Thornber 
1917a87edfeSJoe Thornber 	clear_bit(b, (unsigned long *) &info->current_bits);
192428e4698SJoe Thornber 	info->dirty = true;
193428e4698SJoe Thornber 
1947a87edfeSJoe Thornber 	return 0;
1957a87edfeSJoe Thornber }
1967a87edfeSJoe Thornber EXPORT_SYMBOL_GPL(dm_bitset_clear_bit);
1977a87edfeSJoe Thornber 
1987a87edfeSJoe Thornber int dm_bitset_test_bit(struct dm_disk_bitset *info, dm_block_t root,
1997a87edfeSJoe Thornber 		       uint32_t index, dm_block_t *new_root, bool *result)
2007a87edfeSJoe Thornber {
2017a87edfeSJoe Thornber 	int r;
2027a87edfeSJoe Thornber 	unsigned b = index % BITS_PER_ARRAY_ENTRY;
2037a87edfeSJoe Thornber 
2047a87edfeSJoe Thornber 	r = get_array_entry(info, root, index, new_root);
2057a87edfeSJoe Thornber 	if (r)
2067a87edfeSJoe Thornber 		return r;
2077a87edfeSJoe Thornber 
2087a87edfeSJoe Thornber 	*result = test_bit(b, (unsigned long *) &info->current_bits);
2097a87edfeSJoe Thornber 	return 0;
2107a87edfeSJoe Thornber }
2117a87edfeSJoe Thornber EXPORT_SYMBOL_GPL(dm_bitset_test_bit);
2127a87edfeSJoe Thornber 
2136fe28dbfSJoe Thornber static int cursor_next_array_entry(struct dm_bitset_cursor *c)
2146fe28dbfSJoe Thornber {
2156fe28dbfSJoe Thornber 	int r;
2166fe28dbfSJoe Thornber 	__le64 *value;
2176fe28dbfSJoe Thornber 
2186fe28dbfSJoe Thornber 	r = dm_array_cursor_next(&c->cursor);
2196fe28dbfSJoe Thornber 	if (r)
2206fe28dbfSJoe Thornber 		return r;
2216fe28dbfSJoe Thornber 
2226fe28dbfSJoe Thornber 	dm_array_cursor_get_value(&c->cursor, (void **) &value);
2236fe28dbfSJoe Thornber 	c->array_index++;
2246fe28dbfSJoe Thornber 	c->bit_index = 0;
2256fe28dbfSJoe Thornber 	c->current_bits = le64_to_cpu(*value);
2266fe28dbfSJoe Thornber 	return 0;
2276fe28dbfSJoe Thornber }
2286fe28dbfSJoe Thornber 
2296fe28dbfSJoe Thornber int dm_bitset_cursor_begin(struct dm_disk_bitset *info,
2306fe28dbfSJoe Thornber 			   dm_block_t root, uint32_t nr_entries,
2316fe28dbfSJoe Thornber 			   struct dm_bitset_cursor *c)
2326fe28dbfSJoe Thornber {
2336fe28dbfSJoe Thornber 	int r;
2346fe28dbfSJoe Thornber 	__le64 *value;
2356fe28dbfSJoe Thornber 
2366fe28dbfSJoe Thornber 	if (!nr_entries)
2376fe28dbfSJoe Thornber 		return -ENODATA;
2386fe28dbfSJoe Thornber 
2396fe28dbfSJoe Thornber 	c->info = info;
2406fe28dbfSJoe Thornber 	c->entries_remaining = nr_entries;
2416fe28dbfSJoe Thornber 
2426fe28dbfSJoe Thornber 	r = dm_array_cursor_begin(&info->array_info, root, &c->cursor);
2436fe28dbfSJoe Thornber 	if (r)
2446fe28dbfSJoe Thornber 		return r;
2456fe28dbfSJoe Thornber 
2466fe28dbfSJoe Thornber 	dm_array_cursor_get_value(&c->cursor, (void **) &value);
2476fe28dbfSJoe Thornber 	c->array_index = 0;
2486fe28dbfSJoe Thornber 	c->bit_index = 0;
2496fe28dbfSJoe Thornber 	c->current_bits = le64_to_cpu(*value);
2506fe28dbfSJoe Thornber 
2516fe28dbfSJoe Thornber 	return r;
2526fe28dbfSJoe Thornber }
2536fe28dbfSJoe Thornber EXPORT_SYMBOL_GPL(dm_bitset_cursor_begin);
2546fe28dbfSJoe Thornber 
2556fe28dbfSJoe Thornber void dm_bitset_cursor_end(struct dm_bitset_cursor *c)
2566fe28dbfSJoe Thornber {
2576fe28dbfSJoe Thornber 	return dm_array_cursor_end(&c->cursor);
2586fe28dbfSJoe Thornber }
2596fe28dbfSJoe Thornber EXPORT_SYMBOL_GPL(dm_bitset_cursor_end);
2606fe28dbfSJoe Thornber 
2616fe28dbfSJoe Thornber int dm_bitset_cursor_next(struct dm_bitset_cursor *c)
2626fe28dbfSJoe Thornber {
2636fe28dbfSJoe Thornber 	int r = 0;
2646fe28dbfSJoe Thornber 
2656fe28dbfSJoe Thornber 	if (!c->entries_remaining)
2666fe28dbfSJoe Thornber 		return -ENODATA;
2676fe28dbfSJoe Thornber 
2686fe28dbfSJoe Thornber 	c->entries_remaining--;
2696fe28dbfSJoe Thornber 	if (++c->bit_index > 63)
2706fe28dbfSJoe Thornber 		r = cursor_next_array_entry(c);
2716fe28dbfSJoe Thornber 
2726fe28dbfSJoe Thornber 	return r;
2736fe28dbfSJoe Thornber }
2746fe28dbfSJoe Thornber EXPORT_SYMBOL_GPL(dm_bitset_cursor_next);
2756fe28dbfSJoe Thornber 
276*9b696229SJoe Thornber int dm_bitset_cursor_skip(struct dm_bitset_cursor *c, uint32_t count)
277*9b696229SJoe Thornber {
278*9b696229SJoe Thornber 	int r;
279*9b696229SJoe Thornber 	__le64 *value;
280*9b696229SJoe Thornber 	uint32_t nr_array_skip;
281*9b696229SJoe Thornber 	uint32_t remaining_in_word = 64 - c->bit_index;
282*9b696229SJoe Thornber 
283*9b696229SJoe Thornber 	if (c->entries_remaining < count)
284*9b696229SJoe Thornber 		return -ENODATA;
285*9b696229SJoe Thornber 
286*9b696229SJoe Thornber 	if (count < remaining_in_word) {
287*9b696229SJoe Thornber 		c->bit_index += count;
288*9b696229SJoe Thornber 		c->entries_remaining -= count;
289*9b696229SJoe Thornber 		return 0;
290*9b696229SJoe Thornber 
291*9b696229SJoe Thornber 	} else {
292*9b696229SJoe Thornber 		c->entries_remaining -= remaining_in_word;
293*9b696229SJoe Thornber 		count -= remaining_in_word;
294*9b696229SJoe Thornber 	}
295*9b696229SJoe Thornber 
296*9b696229SJoe Thornber 	nr_array_skip = (count / 64) + 1;
297*9b696229SJoe Thornber 	r = dm_array_cursor_skip(&c->cursor, nr_array_skip);
298*9b696229SJoe Thornber 	if (r)
299*9b696229SJoe Thornber 		return r;
300*9b696229SJoe Thornber 
301*9b696229SJoe Thornber 	dm_array_cursor_get_value(&c->cursor, (void **) &value);
302*9b696229SJoe Thornber 	c->entries_remaining -= count;
303*9b696229SJoe Thornber 	c->array_index += nr_array_skip;
304*9b696229SJoe Thornber 	c->bit_index = count & 63;
305*9b696229SJoe Thornber 	c->current_bits = le64_to_cpu(*value);
306*9b696229SJoe Thornber 
307*9b696229SJoe Thornber 	return 0;
308*9b696229SJoe Thornber }
309*9b696229SJoe Thornber EXPORT_SYMBOL_GPL(dm_bitset_cursor_skip);
310*9b696229SJoe Thornber 
3116fe28dbfSJoe Thornber bool dm_bitset_cursor_get_value(struct dm_bitset_cursor *c)
3126fe28dbfSJoe Thornber {
3136fe28dbfSJoe Thornber 	return test_bit(c->bit_index, (unsigned long *) &c->current_bits);
3146fe28dbfSJoe Thornber }
3156fe28dbfSJoe Thornber EXPORT_SYMBOL_GPL(dm_bitset_cursor_get_value);
3166fe28dbfSJoe Thornber 
3177a87edfeSJoe Thornber /*----------------------------------------------------------------*/
318