Skip to content

Commit 48dc810

Browse files
committed
Merge tag 'for-6.4/dm-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/device-mapper/linux-dm
Pull device mapper updates from Mike Snitzer: - Split dm-bufio's rw_semaphore and rbtree. Offers improvements to dm-bufio's locking to allow increased concurrent IO -- particularly for read access for buffers already in dm-bufio's cache. - Also split dm-bio-prison-v1's spinlock and rbtree with comparable aim at improving concurrent IO (for the DM thinp target). - Both the dm-bufio and dm-bio-prison-v1 scaling of the number of locks and rbtrees used are managed by dm_num_hash_locks(). And the hash function used by both is dm_hash_locks_index(). - Allow DM targets to require DISCARD, WRITE_ZEROES and SECURE_ERASE to be split at the target specified boundary (in terms of max_discard_sectors, max_write_zeroes_sectors and max_secure_erase_sectors respectively). - DM verity error handling fix for check_at_most_once on FEC. - Update DM verity target to emit audit events on verification failure and more. - DM core ->io_hints improvements needed in support of new discard support that is added to the DM "zero" and "error" targets. - Fix missing kmem_cache_destroy() call in initialization error path of both the DM integrity and DM clone targets. - A couple fixes for DM flakey, also add "error_reads" feature. - Fix DM core's resume to not lock FS when the DM map is NULL; otherwise initial table load can race with FS mount that takes superblock's ->s_umount rw_semaphore. - Various small improvements to both DM core and DM targets. * tag 'for-6.4/dm-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/device-mapper/linux-dm: (40 commits) dm: don't lock fs when the map is NULL in process of resume dm flakey: add an "error_reads" option dm flakey: remove trailing space in the table line dm flakey: fix a crash with invalid table line dm ioctl: fix nested locking in table_clear() to remove deadlock concern dm: unexport dm_get_queue_limits() dm: allow targets to require splitting WRITE_ZEROES and SECURE_ERASE dm: add helper macro for simple DM target module init and exit dm raid: remove unused d variable dm: remove unnecessary (void*) conversions dm mirror: add DMERR message if alloc_workqueue fails dm: push error reporting down to dm_register_target() dm integrity: call kmem_cache_destroy() in dm_integrity_init() error path dm clone: call kmem_cache_destroy() in dm_clone_init() error path dm error: add discard support dm zero: add discard support dm table: allow targets without devices to set ->io_hints dm verity: emit audit events on verification failure and more dm verity: fix error handling for check_at_most_once on FEC dm: improve hash_locks sizing and hash function ...
2 parents 9dd6956 + 38d11da commit 48dc810

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+1773
-1080
lines changed

Documentation/admin-guide/device-mapper/dm-flakey.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ Optional feature parameters:
3939
If no feature parameters are present, during the periods of
4040
unreliability, all I/O returns errors.
4141

42+
error_reads:
43+
All read I/O is failed with an error signalled.
44+
Write I/O is handled correctly.
45+
4246
drop_writes:
4347
All write I/O is silently ignored.
4448
Read I/O is handled correctly.

drivers/md/dm-bio-prison-v1.c

Lines changed: 64 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,15 @@
1818

1919
#define MIN_CELLS 1024
2020

21-
struct dm_bio_prison {
21+
struct prison_region {
2222
spinlock_t lock;
23-
struct rb_root cells;
23+
struct rb_root cell;
24+
} ____cacheline_aligned_in_smp;
25+
26+
struct dm_bio_prison {
2427
mempool_t cell_pool;
28+
unsigned int num_locks;
29+
struct prison_region regions[];
2530
};
2631

2732
static struct kmem_cache *_cell_cache;
@@ -34,22 +39,27 @@ static struct kmem_cache *_cell_cache;
3439
*/
3540
struct dm_bio_prison *dm_bio_prison_create(void)
3641
{
37-
struct dm_bio_prison *prison = kzalloc(sizeof(*prison), GFP_KERNEL);
3842
int ret;
43+
unsigned int i, num_locks;
44+
struct dm_bio_prison *prison;
3945

46+
num_locks = dm_num_hash_locks();
47+
prison = kzalloc(struct_size(prison, regions, num_locks), GFP_KERNEL);
4048
if (!prison)
4149
return NULL;
50+
prison->num_locks = num_locks;
4251

43-
spin_lock_init(&prison->lock);
52+
for (i = 0; i < prison->num_locks; i++) {
53+
spin_lock_init(&prison->regions[i].lock);
54+
prison->regions[i].cell = RB_ROOT;
55+
}
4456

4557
ret = mempool_init_slab_pool(&prison->cell_pool, MIN_CELLS, _cell_cache);
4658
if (ret) {
4759
kfree(prison);
4860
return NULL;
4961
}
5062

51-
prison->cells = RB_ROOT;
52-
5363
return prison;
5464
}
5565
EXPORT_SYMBOL_GPL(dm_bio_prison_create);
@@ -107,14 +117,32 @@ static int cmp_keys(struct dm_cell_key *lhs,
107117
return 0;
108118
}
109119

110-
static int __bio_detain(struct dm_bio_prison *prison,
120+
static inline unsigned int lock_nr(struct dm_cell_key *key, unsigned int num_locks)
121+
{
122+
return dm_hash_locks_index((key->block_begin >> BIO_PRISON_MAX_RANGE_SHIFT),
123+
num_locks);
124+
}
125+
126+
bool dm_cell_key_has_valid_range(struct dm_cell_key *key)
127+
{
128+
if (WARN_ON_ONCE(key->block_end - key->block_begin > BIO_PRISON_MAX_RANGE))
129+
return false;
130+
if (WARN_ON_ONCE((key->block_begin >> BIO_PRISON_MAX_RANGE_SHIFT) !=
131+
(key->block_end - 1) >> BIO_PRISON_MAX_RANGE_SHIFT))
132+
return false;
133+
134+
return true;
135+
}
136+
EXPORT_SYMBOL(dm_cell_key_has_valid_range);
137+
138+
static int __bio_detain(struct rb_root *root,
111139
struct dm_cell_key *key,
112140
struct bio *inmate,
113141
struct dm_bio_prison_cell *cell_prealloc,
114142
struct dm_bio_prison_cell **cell_result)
115143
{
116144
int r;
117-
struct rb_node **new = &prison->cells.rb_node, *parent = NULL;
145+
struct rb_node **new = &root->rb_node, *parent = NULL;
118146

119147
while (*new) {
120148
struct dm_bio_prison_cell *cell =
@@ -139,7 +167,7 @@ static int __bio_detain(struct dm_bio_prison *prison,
139167
*cell_result = cell_prealloc;
140168

141169
rb_link_node(&cell_prealloc->node, parent, new);
142-
rb_insert_color(&cell_prealloc->node, &prison->cells);
170+
rb_insert_color(&cell_prealloc->node, root);
143171

144172
return 0;
145173
}
@@ -151,10 +179,11 @@ static int bio_detain(struct dm_bio_prison *prison,
151179
struct dm_bio_prison_cell **cell_result)
152180
{
153181
int r;
182+
unsigned l = lock_nr(key, prison->num_locks);
154183

155-
spin_lock_irq(&prison->lock);
156-
r = __bio_detain(prison, key, inmate, cell_prealloc, cell_result);
157-
spin_unlock_irq(&prison->lock);
184+
spin_lock_irq(&prison->regions[l].lock);
185+
r = __bio_detain(&prison->regions[l].cell, key, inmate, cell_prealloc, cell_result);
186+
spin_unlock_irq(&prison->regions[l].lock);
158187

159188
return r;
160189
}
@@ -181,11 +210,11 @@ EXPORT_SYMBOL_GPL(dm_get_cell);
181210
/*
182211
* @inmates must have been initialised prior to this call
183212
*/
184-
static void __cell_release(struct dm_bio_prison *prison,
213+
static void __cell_release(struct rb_root *root,
185214
struct dm_bio_prison_cell *cell,
186215
struct bio_list *inmates)
187216
{
188-
rb_erase(&cell->node, &prison->cells);
217+
rb_erase(&cell->node, root);
189218

190219
if (inmates) {
191220
if (cell->holder)
@@ -198,32 +227,35 @@ void dm_cell_release(struct dm_bio_prison *prison,
198227
struct dm_bio_prison_cell *cell,
199228
struct bio_list *bios)
200229
{
201-
spin_lock_irq(&prison->lock);
202-
__cell_release(prison, cell, bios);
203-
spin_unlock_irq(&prison->lock);
230+
unsigned l = lock_nr(&cell->key, prison->num_locks);
231+
232+
spin_lock_irq(&prison->regions[l].lock);
233+
__cell_release(&prison->regions[l].cell, cell, bios);
234+
spin_unlock_irq(&prison->regions[l].lock);
204235
}
205236
EXPORT_SYMBOL_GPL(dm_cell_release);
206237

207238
/*
208239
* Sometimes we don't want the holder, just the additional bios.
209240
*/
210-
static void __cell_release_no_holder(struct dm_bio_prison *prison,
241+
static void __cell_release_no_holder(struct rb_root *root,
211242
struct dm_bio_prison_cell *cell,
212243
struct bio_list *inmates)
213244
{
214-
rb_erase(&cell->node, &prison->cells);
245+
rb_erase(&cell->node, root);
215246
bio_list_merge(inmates, &cell->bios);
216247
}
217248

218249
void dm_cell_release_no_holder(struct dm_bio_prison *prison,
219250
struct dm_bio_prison_cell *cell,
220251
struct bio_list *inmates)
221252
{
253+
unsigned l = lock_nr(&cell->key, prison->num_locks);
222254
unsigned long flags;
223255

224-
spin_lock_irqsave(&prison->lock, flags);
225-
__cell_release_no_holder(prison, cell, inmates);
226-
spin_unlock_irqrestore(&prison->lock, flags);
256+
spin_lock_irqsave(&prison->regions[l].lock, flags);
257+
__cell_release_no_holder(&prison->regions[l].cell, cell, inmates);
258+
spin_unlock_irqrestore(&prison->regions[l].lock, flags);
227259
}
228260
EXPORT_SYMBOL_GPL(dm_cell_release_no_holder);
229261

@@ -248,18 +280,19 @@ void dm_cell_visit_release(struct dm_bio_prison *prison,
248280
void *context,
249281
struct dm_bio_prison_cell *cell)
250282
{
251-
spin_lock_irq(&prison->lock);
283+
unsigned l = lock_nr(&cell->key, prison->num_locks);
284+
spin_lock_irq(&prison->regions[l].lock);
252285
visit_fn(context, cell);
253-
rb_erase(&cell->node, &prison->cells);
254-
spin_unlock_irq(&prison->lock);
286+
rb_erase(&cell->node, &prison->regions[l].cell);
287+
spin_unlock_irq(&prison->regions[l].lock);
255288
}
256289
EXPORT_SYMBOL_GPL(dm_cell_visit_release);
257290

258-
static int __promote_or_release(struct dm_bio_prison *prison,
291+
static int __promote_or_release(struct rb_root *root,
259292
struct dm_bio_prison_cell *cell)
260293
{
261294
if (bio_list_empty(&cell->bios)) {
262-
rb_erase(&cell->node, &prison->cells);
295+
rb_erase(&cell->node, root);
263296
return 1;
264297
}
265298

@@ -271,10 +304,11 @@ int dm_cell_promote_or_release(struct dm_bio_prison *prison,
271304
struct dm_bio_prison_cell *cell)
272305
{
273306
int r;
307+
unsigned l = lock_nr(&cell->key, prison->num_locks);
274308

275-
spin_lock_irq(&prison->lock);
276-
r = __promote_or_release(prison, cell);
277-
spin_unlock_irq(&prison->lock);
309+
spin_lock_irq(&prison->regions[l].lock);
310+
r = __promote_or_release(&prison->regions[l].cell, cell);
311+
spin_unlock_irq(&prison->regions[l].lock);
278312

279313
return r;
280314
}

drivers/md/dm-bio-prison-v1.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,16 @@ struct dm_cell_key {
3434
dm_block_t block_begin, block_end;
3535
};
3636

37+
/*
38+
* The range of a key (block_end - block_begin) must not
39+
* exceed BIO_PRISON_MAX_RANGE. Also the range must not
40+
* cross a similarly sized boundary.
41+
*
42+
* Must be a power of 2.
43+
*/
44+
#define BIO_PRISON_MAX_RANGE 1024
45+
#define BIO_PRISON_MAX_RANGE_SHIFT 10
46+
3747
/*
3848
* Treat this as opaque, only in header so callers can manage allocation
3949
* themselves.
@@ -73,6 +83,11 @@ int dm_get_cell(struct dm_bio_prison *prison,
7383
struct dm_bio_prison_cell *cell_prealloc,
7484
struct dm_bio_prison_cell **cell_result);
7585

86+
/*
87+
* Returns false if key is beyond BIO_PRISON_MAX_RANGE or spans a boundary.
88+
*/
89+
bool dm_cell_key_has_valid_range(struct dm_cell_key *key);
90+
7691
/*
7792
* An atomic op that combines retrieving or creating a cell, and adding a
7893
* bio to it.

0 commit comments

Comments
 (0)