Skip to content

Commit b2dbff1

Browse files
committed
sbitmap: flush deferred clears for resize and shallow gets
We're missing a deferred clear off the shallow get, which can cause a hang. Additionally, when we resize the sbitmap, we should also flush deferred clears for good measure. Ensure we have full coverage on batch clears, even for paths where we would not be doing deferred clear. This makes it less error prone for future additions. Reported-by: Bart Van Assche <bvanassche@acm.org> Tested-by: Ming Lei <ming.lei@redhat.com> Signed-off-by: Jens Axboe <axboe@kernel.dk>
1 parent 2c4d535 commit b2dbff1

File tree

1 file changed

+51
-43
lines changed

1 file changed

+51
-43
lines changed

lib/sbitmap.c

Lines changed: 51 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,47 @@
2020
#include <linux/sbitmap.h>
2121
#include <linux/seq_file.h>
2222

23+
/*
24+
* See if we have deferred clears that we can batch move
25+
*/
26+
static inline bool sbitmap_deferred_clear(struct sbitmap *sb, int index)
27+
{
28+
unsigned long mask, val;
29+
unsigned long __maybe_unused flags;
30+
bool ret = false;
31+
32+
/* Silence bogus lockdep warning */
33+
#if defined(CONFIG_LOCKDEP)
34+
local_irq_save(flags);
35+
#endif
36+
spin_lock(&sb->map[index].swap_lock);
37+
38+
if (!sb->map[index].cleared)
39+
goto out_unlock;
40+
41+
/*
42+
* First get a stable cleared mask, setting the old mask to 0.
43+
*/
44+
do {
45+
mask = sb->map[index].cleared;
46+
} while (cmpxchg(&sb->map[index].cleared, mask, 0) != mask);
47+
48+
/*
49+
* Now clear the masked bits in our free word
50+
*/
51+
do {
52+
val = sb->map[index].word;
53+
} while (cmpxchg(&sb->map[index].word, val, val & ~mask) != val);
54+
55+
ret = true;
56+
out_unlock:
57+
spin_unlock(&sb->map[index].swap_lock);
58+
#if defined(CONFIG_LOCKDEP)
59+
local_irq_restore(flags);
60+
#endif
61+
return ret;
62+
}
63+
2364
int sbitmap_init_node(struct sbitmap *sb, unsigned int depth, int shift,
2465
gfp_t flags, int node)
2566
{
@@ -70,6 +111,9 @@ void sbitmap_resize(struct sbitmap *sb, unsigned int depth)
70111
unsigned int bits_per_word = 1U << sb->shift;
71112
unsigned int i;
72113

114+
for (i = 0; i < sb->map_nr; i++)
115+
sbitmap_deferred_clear(sb, i);
116+
73117
sb->depth = depth;
74118
sb->map_nr = DIV_ROUND_UP(sb->depth, bits_per_word);
75119

@@ -112,47 +156,6 @@ static int __sbitmap_get_word(unsigned long *word, unsigned long depth,
112156
return nr;
113157
}
114158

115-
/*
116-
* See if we have deferred clears that we can batch move
117-
*/
118-
static inline bool sbitmap_deferred_clear(struct sbitmap *sb, int index)
119-
{
120-
unsigned long mask, val;
121-
unsigned long __maybe_unused flags;
122-
bool ret = false;
123-
124-
/* Silence bogus lockdep warning */
125-
#if defined(CONFIG_LOCKDEP)
126-
local_irq_save(flags);
127-
#endif
128-
spin_lock(&sb->map[index].swap_lock);
129-
130-
if (!sb->map[index].cleared)
131-
goto out_unlock;
132-
133-
/*
134-
* First get a stable cleared mask, setting the old mask to 0.
135-
*/
136-
do {
137-
mask = sb->map[index].cleared;
138-
} while (cmpxchg(&sb->map[index].cleared, mask, 0) != mask);
139-
140-
/*
141-
* Now clear the masked bits in our free word
142-
*/
143-
do {
144-
val = sb->map[index].word;
145-
} while (cmpxchg(&sb->map[index].word, val, val & ~mask) != val);
146-
147-
ret = true;
148-
out_unlock:
149-
spin_unlock(&sb->map[index].swap_lock);
150-
#if defined(CONFIG_LOCKDEP)
151-
local_irq_restore(flags);
152-
#endif
153-
return ret;
154-
}
155-
156159
static int sbitmap_find_bit_in_index(struct sbitmap *sb, int index,
157160
unsigned int alloc_hint, bool round_robin)
158161
{
@@ -215,6 +218,7 @@ int sbitmap_get_shallow(struct sbitmap *sb, unsigned int alloc_hint,
215218
index = SB_NR_TO_INDEX(sb, alloc_hint);
216219

217220
for (i = 0; i < sb->map_nr; i++) {
221+
again:
218222
nr = __sbitmap_get_word(&sb->map[index].word,
219223
min(sb->map[index].depth, shallow_depth),
220224
SB_NR_TO_BIT(sb, alloc_hint), true);
@@ -223,6 +227,9 @@ int sbitmap_get_shallow(struct sbitmap *sb, unsigned int alloc_hint,
223227
break;
224228
}
225229

230+
if (sbitmap_deferred_clear(sb, index))
231+
goto again;
232+
226233
/* Jump to next index. */
227234
index++;
228235
alloc_hint = index << sb->shift;
@@ -242,7 +249,7 @@ bool sbitmap_any_bit_set(const struct sbitmap *sb)
242249
unsigned int i;
243250

244251
for (i = 0; i < sb->map_nr; i++) {
245-
if (sb->map[i].word)
252+
if (sb->map[i].word & ~sb->map[i].cleared)
246253
return true;
247254
}
248255
return false;
@@ -255,9 +262,10 @@ bool sbitmap_any_bit_clear(const struct sbitmap *sb)
255262

256263
for (i = 0; i < sb->map_nr; i++) {
257264
const struct sbitmap_word *word = &sb->map[i];
265+
unsigned long mask = word->word & ~word->cleared;
258266
unsigned long ret;
259267

260-
ret = find_first_zero_bit(&word->word, word->depth);
268+
ret = find_first_zero_bit(&mask, word->depth);
261269
if (ret < word->depth)
262270
return true;
263271
}

0 commit comments

Comments
 (0)