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 
427a87edfeSJoe Thornber int dm_bitset_resize(struct dm_disk_bitset *info, dm_block_t root,
437a87edfeSJoe Thornber 		     uint32_t old_nr_entries, uint32_t new_nr_entries,
447a87edfeSJoe Thornber 		     bool default_value, dm_block_t *new_root)
457a87edfeSJoe Thornber {
467a87edfeSJoe Thornber 	uint32_t old_blocks = dm_div_up(old_nr_entries, BITS_PER_ARRAY_ENTRY);
477a87edfeSJoe Thornber 	uint32_t new_blocks = dm_div_up(new_nr_entries, BITS_PER_ARRAY_ENTRY);
487a87edfeSJoe Thornber 	__le64 value = default_value ? cpu_to_le64(~0) : cpu_to_le64(0);
497a87edfeSJoe Thornber 
507a87edfeSJoe Thornber 	__dm_bless_for_disk(&value);
517a87edfeSJoe Thornber 	return dm_array_resize(&info->array_info, root, old_blocks, new_blocks,
527a87edfeSJoe Thornber 			       &value, new_root);
537a87edfeSJoe Thornber }
547a87edfeSJoe Thornber EXPORT_SYMBOL_GPL(dm_bitset_resize);
557a87edfeSJoe Thornber 
567a87edfeSJoe Thornber int dm_bitset_del(struct dm_disk_bitset *info, dm_block_t root)
577a87edfeSJoe Thornber {
587a87edfeSJoe Thornber 	return dm_array_del(&info->array_info, root);
597a87edfeSJoe Thornber }
607a87edfeSJoe Thornber EXPORT_SYMBOL_GPL(dm_bitset_del);
617a87edfeSJoe Thornber 
627a87edfeSJoe Thornber int dm_bitset_flush(struct dm_disk_bitset *info, dm_block_t root,
637a87edfeSJoe Thornber 		    dm_block_t *new_root)
647a87edfeSJoe Thornber {
657a87edfeSJoe Thornber 	int r;
667a87edfeSJoe Thornber 	__le64 value;
677a87edfeSJoe Thornber 
68428e4698SJoe Thornber 	if (!info->current_index_set || !info->dirty)
697a87edfeSJoe Thornber 		return 0;
707a87edfeSJoe Thornber 
717a87edfeSJoe Thornber 	value = cpu_to_le64(info->current_bits);
727a87edfeSJoe Thornber 
737a87edfeSJoe Thornber 	__dm_bless_for_disk(&value);
747a87edfeSJoe Thornber 	r = dm_array_set_value(&info->array_info, root, info->current_index,
757a87edfeSJoe Thornber 			       &value, new_root);
767a87edfeSJoe Thornber 	if (r)
777a87edfeSJoe Thornber 		return r;
787a87edfeSJoe Thornber 
797a87edfeSJoe Thornber 	info->current_index_set = false;
80428e4698SJoe Thornber 	info->dirty = false;
81428e4698SJoe Thornber 
827a87edfeSJoe Thornber 	return 0;
837a87edfeSJoe Thornber }
847a87edfeSJoe Thornber EXPORT_SYMBOL_GPL(dm_bitset_flush);
857a87edfeSJoe Thornber 
867a87edfeSJoe Thornber static int read_bits(struct dm_disk_bitset *info, dm_block_t root,
877a87edfeSJoe Thornber 		     uint32_t array_index)
887a87edfeSJoe Thornber {
897a87edfeSJoe Thornber 	int r;
907a87edfeSJoe Thornber 	__le64 value;
917a87edfeSJoe Thornber 
927a87edfeSJoe Thornber 	r = dm_array_get_value(&info->array_info, root, array_index, &value);
937a87edfeSJoe Thornber 	if (r)
947a87edfeSJoe Thornber 		return r;
957a87edfeSJoe Thornber 
967a87edfeSJoe Thornber 	info->current_bits = le64_to_cpu(value);
977a87edfeSJoe Thornber 	info->current_index_set = true;
987a87edfeSJoe Thornber 	info->current_index = array_index;
99428e4698SJoe Thornber 	info->dirty = false;
100428e4698SJoe Thornber 
1017a87edfeSJoe Thornber 	return 0;
1027a87edfeSJoe Thornber }
1037a87edfeSJoe Thornber 
1047a87edfeSJoe Thornber static int get_array_entry(struct dm_disk_bitset *info, dm_block_t root,
1057a87edfeSJoe Thornber 			   uint32_t index, dm_block_t *new_root)
1067a87edfeSJoe Thornber {
1077a87edfeSJoe Thornber 	int r;
1087a87edfeSJoe Thornber 	unsigned array_index = index / BITS_PER_ARRAY_ENTRY;
1097a87edfeSJoe Thornber 
1107a87edfeSJoe Thornber 	if (info->current_index_set) {
1117a87edfeSJoe Thornber 		if (info->current_index == array_index)
1127a87edfeSJoe Thornber 			return 0;
1137a87edfeSJoe Thornber 
1147a87edfeSJoe Thornber 		r = dm_bitset_flush(info, root, new_root);
1157a87edfeSJoe Thornber 		if (r)
1167a87edfeSJoe Thornber 			return r;
1177a87edfeSJoe Thornber 	}
1187a87edfeSJoe Thornber 
1197a87edfeSJoe Thornber 	return read_bits(info, root, array_index);
1207a87edfeSJoe Thornber }
1217a87edfeSJoe Thornber 
1227a87edfeSJoe Thornber int dm_bitset_set_bit(struct dm_disk_bitset *info, dm_block_t root,
1237a87edfeSJoe Thornber 		      uint32_t index, dm_block_t *new_root)
1247a87edfeSJoe Thornber {
1257a87edfeSJoe Thornber 	int r;
1267a87edfeSJoe Thornber 	unsigned b = index % BITS_PER_ARRAY_ENTRY;
1277a87edfeSJoe Thornber 
1287a87edfeSJoe Thornber 	r = get_array_entry(info, root, index, new_root);
1297a87edfeSJoe Thornber 	if (r)
1307a87edfeSJoe Thornber 		return r;
1317a87edfeSJoe Thornber 
1327a87edfeSJoe Thornber 	set_bit(b, (unsigned long *) &info->current_bits);
133428e4698SJoe Thornber 	info->dirty = true;
134428e4698SJoe Thornber 
1357a87edfeSJoe Thornber 	return 0;
1367a87edfeSJoe Thornber }
1377a87edfeSJoe Thornber EXPORT_SYMBOL_GPL(dm_bitset_set_bit);
1387a87edfeSJoe Thornber 
1397a87edfeSJoe Thornber int dm_bitset_clear_bit(struct dm_disk_bitset *info, dm_block_t root,
1407a87edfeSJoe Thornber 			uint32_t index, dm_block_t *new_root)
1417a87edfeSJoe Thornber {
1427a87edfeSJoe Thornber 	int r;
1437a87edfeSJoe Thornber 	unsigned b = index % BITS_PER_ARRAY_ENTRY;
1447a87edfeSJoe Thornber 
1457a87edfeSJoe Thornber 	r = get_array_entry(info, root, index, new_root);
1467a87edfeSJoe Thornber 	if (r)
1477a87edfeSJoe Thornber 		return r;
1487a87edfeSJoe Thornber 
1497a87edfeSJoe Thornber 	clear_bit(b, (unsigned long *) &info->current_bits);
150428e4698SJoe Thornber 	info->dirty = true;
151428e4698SJoe Thornber 
1527a87edfeSJoe Thornber 	return 0;
1537a87edfeSJoe Thornber }
1547a87edfeSJoe Thornber EXPORT_SYMBOL_GPL(dm_bitset_clear_bit);
1557a87edfeSJoe Thornber 
1567a87edfeSJoe Thornber int dm_bitset_test_bit(struct dm_disk_bitset *info, dm_block_t root,
1577a87edfeSJoe Thornber 		       uint32_t index, dm_block_t *new_root, bool *result)
1587a87edfeSJoe Thornber {
1597a87edfeSJoe Thornber 	int r;
1607a87edfeSJoe Thornber 	unsigned b = index % BITS_PER_ARRAY_ENTRY;
1617a87edfeSJoe Thornber 
1627a87edfeSJoe Thornber 	r = get_array_entry(info, root, index, new_root);
1637a87edfeSJoe Thornber 	if (r)
1647a87edfeSJoe Thornber 		return r;
1657a87edfeSJoe Thornber 
1667a87edfeSJoe Thornber 	*result = test_bit(b, (unsigned long *) &info->current_bits);
1677a87edfeSJoe Thornber 	return 0;
1687a87edfeSJoe Thornber }
1697a87edfeSJoe Thornber EXPORT_SYMBOL_GPL(dm_bitset_test_bit);
1707a87edfeSJoe Thornber 
1717a87edfeSJoe Thornber /*----------------------------------------------------------------*/
172