1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) 2012 Red Hat, Inc.
5 * This file is released under the GPL.
9 #include "dm-transaction-manager.h"
11 #include <linux/export.h>
12 #include <linux/device-mapper.h>
14 #define DM_MSG_PREFIX "bitset"
15 #define BITS_PER_ARRAY_ENTRY 64
17 /*----------------------------------------------------------------*/
19 static struct dm_btree_value_type bitset_bvt
= {
21 .size
= sizeof(__le64
),
27 /*----------------------------------------------------------------*/
29 void dm_disk_bitset_init(struct dm_transaction_manager
*tm
,
30 struct dm_disk_bitset
*info
)
32 dm_array_info_init(&info
->array_info
, tm
, &bitset_bvt
);
33 info
->current_index_set
= false;
35 EXPORT_SYMBOL_GPL(dm_disk_bitset_init
);
37 int dm_bitset_empty(struct dm_disk_bitset
*info
, dm_block_t
*root
)
39 return dm_array_empty(&info
->array_info
, root
);
41 EXPORT_SYMBOL_GPL(dm_bitset_empty
);
43 struct packer_context
{
49 static int pack_bits(uint32_t index
, void *value
, void *context
)
52 struct packer_context
*p
= context
;
53 unsigned int bit
, nr
= min(64u, p
->nr_bits
- (index
* 64));
57 for (bit
= 0; bit
< nr
; bit
++) {
58 r
= p
->fn(index
* 64 + bit
, &bv
, p
->context
);
63 set_bit(bit
, (unsigned long *) &word
);
65 clear_bit(bit
, (unsigned long *) &word
);
68 *((__le64
*) value
) = cpu_to_le64(word
);
73 int dm_bitset_new(struct dm_disk_bitset
*info
, dm_block_t
*root
,
74 uint32_t size
, bit_value_fn fn
, void *context
)
76 struct packer_context p
;
82 return dm_array_new(&info
->array_info
, root
, dm_div_up(size
, 64), pack_bits
, &p
);
84 EXPORT_SYMBOL_GPL(dm_bitset_new
);
86 int dm_bitset_resize(struct dm_disk_bitset
*info
, dm_block_t root
,
87 uint32_t old_nr_entries
, uint32_t new_nr_entries
,
88 bool default_value
, dm_block_t
*new_root
)
90 uint32_t old_blocks
= dm_div_up(old_nr_entries
, BITS_PER_ARRAY_ENTRY
);
91 uint32_t new_blocks
= dm_div_up(new_nr_entries
, BITS_PER_ARRAY_ENTRY
);
92 __le64 value
= default_value
? cpu_to_le64(~0) : cpu_to_le64(0);
94 __dm_bless_for_disk(&value
);
95 return dm_array_resize(&info
->array_info
, root
, old_blocks
, new_blocks
,
98 EXPORT_SYMBOL_GPL(dm_bitset_resize
);
100 int dm_bitset_del(struct dm_disk_bitset
*info
, dm_block_t root
)
102 return dm_array_del(&info
->array_info
, root
);
104 EXPORT_SYMBOL_GPL(dm_bitset_del
);
106 int dm_bitset_flush(struct dm_disk_bitset
*info
, dm_block_t root
,
107 dm_block_t
*new_root
)
112 if (!info
->current_index_set
|| !info
->dirty
)
115 value
= cpu_to_le64(info
->current_bits
);
117 __dm_bless_for_disk(&value
);
118 r
= dm_array_set_value(&info
->array_info
, root
, info
->current_index
,
123 info
->current_index_set
= false;
128 EXPORT_SYMBOL_GPL(dm_bitset_flush
);
130 static int read_bits(struct dm_disk_bitset
*info
, dm_block_t root
,
131 uint32_t array_index
)
136 r
= dm_array_get_value(&info
->array_info
, root
, array_index
, &value
);
140 info
->current_bits
= le64_to_cpu(value
);
141 info
->current_index_set
= true;
142 info
->current_index
= array_index
;
148 static int get_array_entry(struct dm_disk_bitset
*info
, dm_block_t root
,
149 uint32_t index
, dm_block_t
*new_root
)
152 unsigned int array_index
= index
/ BITS_PER_ARRAY_ENTRY
;
154 if (info
->current_index_set
) {
155 if (info
->current_index
== array_index
)
158 r
= dm_bitset_flush(info
, root
, new_root
);
163 return read_bits(info
, root
, array_index
);
166 int dm_bitset_set_bit(struct dm_disk_bitset
*info
, dm_block_t root
,
167 uint32_t index
, dm_block_t
*new_root
)
170 unsigned int b
= index
% BITS_PER_ARRAY_ENTRY
;
172 r
= get_array_entry(info
, root
, index
, new_root
);
176 set_bit(b
, (unsigned long *) &info
->current_bits
);
181 EXPORT_SYMBOL_GPL(dm_bitset_set_bit
);
183 int dm_bitset_clear_bit(struct dm_disk_bitset
*info
, dm_block_t root
,
184 uint32_t index
, dm_block_t
*new_root
)
187 unsigned int b
= index
% BITS_PER_ARRAY_ENTRY
;
189 r
= get_array_entry(info
, root
, index
, new_root
);
193 clear_bit(b
, (unsigned long *) &info
->current_bits
);
198 EXPORT_SYMBOL_GPL(dm_bitset_clear_bit
);
200 int dm_bitset_test_bit(struct dm_disk_bitset
*info
, dm_block_t root
,
201 uint32_t index
, dm_block_t
*new_root
, bool *result
)
204 unsigned int b
= index
% BITS_PER_ARRAY_ENTRY
;
206 r
= get_array_entry(info
, root
, index
, new_root
);
210 *result
= test_bit(b
, (unsigned long *) &info
->current_bits
);
213 EXPORT_SYMBOL_GPL(dm_bitset_test_bit
);
215 static int cursor_next_array_entry(struct dm_bitset_cursor
*c
)
220 r
= dm_array_cursor_next(&c
->cursor
);
224 dm_array_cursor_get_value(&c
->cursor
, (void **) &value
);
227 c
->current_bits
= le64_to_cpu(*value
);
231 int dm_bitset_cursor_begin(struct dm_disk_bitset
*info
,
232 dm_block_t root
, uint32_t nr_entries
,
233 struct dm_bitset_cursor
*c
)
242 c
->entries_remaining
= nr_entries
;
244 r
= dm_array_cursor_begin(&info
->array_info
, root
, &c
->cursor
);
248 dm_array_cursor_get_value(&c
->cursor
, (void **) &value
);
251 c
->current_bits
= le64_to_cpu(*value
);
255 EXPORT_SYMBOL_GPL(dm_bitset_cursor_begin
);
257 void dm_bitset_cursor_end(struct dm_bitset_cursor
*c
)
259 return dm_array_cursor_end(&c
->cursor
);
261 EXPORT_SYMBOL_GPL(dm_bitset_cursor_end
);
263 int dm_bitset_cursor_next(struct dm_bitset_cursor
*c
)
267 if (!c
->entries_remaining
)
270 c
->entries_remaining
--;
271 if (++c
->bit_index
> 63)
272 r
= cursor_next_array_entry(c
);
276 EXPORT_SYMBOL_GPL(dm_bitset_cursor_next
);
278 int dm_bitset_cursor_skip(struct dm_bitset_cursor
*c
, uint32_t count
)
282 uint32_t nr_array_skip
;
283 uint32_t remaining_in_word
= 64 - c
->bit_index
;
285 if (c
->entries_remaining
< count
)
288 if (count
< remaining_in_word
) {
289 c
->bit_index
+= count
;
290 c
->entries_remaining
-= count
;
294 c
->entries_remaining
-= remaining_in_word
;
295 count
-= remaining_in_word
;
298 nr_array_skip
= (count
/ 64) + 1;
299 r
= dm_array_cursor_skip(&c
->cursor
, nr_array_skip
);
303 dm_array_cursor_get_value(&c
->cursor
, (void **) &value
);
304 c
->entries_remaining
-= count
;
305 c
->array_index
+= nr_array_skip
;
306 c
->bit_index
= count
& 63;
307 c
->current_bits
= le64_to_cpu(*value
);
311 EXPORT_SYMBOL_GPL(dm_bitset_cursor_skip
);
313 bool dm_bitset_cursor_get_value(struct dm_bitset_cursor
*c
)
315 return test_bit(c
->bit_index
, (unsigned long *) &c
->current_bits
);
317 EXPORT_SYMBOL_GPL(dm_bitset_cursor_get_value
);
319 /*----------------------------------------------------------------*/