162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2012 Red Hat, Inc. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * This file is released under the GPL. 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include "dm.h" 962306a36Sopenharmony_ci#include "dm-bio-prison-v1.h" 1062306a36Sopenharmony_ci#include "dm-bio-prison-v2.h" 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <linux/spinlock.h> 1362306a36Sopenharmony_ci#include <linux/mempool.h> 1462306a36Sopenharmony_ci#include <linux/module.h> 1562306a36Sopenharmony_ci#include <linux/slab.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci/*----------------------------------------------------------------*/ 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#define MIN_CELLS 1024 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_cistruct prison_region { 2262306a36Sopenharmony_ci spinlock_t lock; 2362306a36Sopenharmony_ci struct rb_root cell; 2462306a36Sopenharmony_ci} ____cacheline_aligned_in_smp; 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_cistruct dm_bio_prison { 2762306a36Sopenharmony_ci mempool_t cell_pool; 2862306a36Sopenharmony_ci unsigned int num_locks; 2962306a36Sopenharmony_ci struct prison_region regions[]; 3062306a36Sopenharmony_ci}; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_cistatic struct kmem_cache *_cell_cache; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci/*----------------------------------------------------------------*/ 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci/* 3762306a36Sopenharmony_ci * @nr_cells should be the number of cells you want in use _concurrently_. 3862306a36Sopenharmony_ci * Don't confuse it with the number of distinct keys. 3962306a36Sopenharmony_ci */ 4062306a36Sopenharmony_cistruct dm_bio_prison *dm_bio_prison_create(void) 4162306a36Sopenharmony_ci{ 4262306a36Sopenharmony_ci int ret; 4362306a36Sopenharmony_ci unsigned int i, num_locks; 4462306a36Sopenharmony_ci struct dm_bio_prison *prison; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci num_locks = dm_num_hash_locks(); 4762306a36Sopenharmony_ci prison = kzalloc(struct_size(prison, regions, num_locks), GFP_KERNEL); 4862306a36Sopenharmony_ci if (!prison) 4962306a36Sopenharmony_ci return NULL; 5062306a36Sopenharmony_ci prison->num_locks = num_locks; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci for (i = 0; i < prison->num_locks; i++) { 5362306a36Sopenharmony_ci spin_lock_init(&prison->regions[i].lock); 5462306a36Sopenharmony_ci prison->regions[i].cell = RB_ROOT; 5562306a36Sopenharmony_ci } 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci ret = mempool_init_slab_pool(&prison->cell_pool, MIN_CELLS, _cell_cache); 5862306a36Sopenharmony_ci if (ret) { 5962306a36Sopenharmony_ci kfree(prison); 6062306a36Sopenharmony_ci return NULL; 6162306a36Sopenharmony_ci } 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci return prison; 6462306a36Sopenharmony_ci} 6562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dm_bio_prison_create); 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_civoid dm_bio_prison_destroy(struct dm_bio_prison *prison) 6862306a36Sopenharmony_ci{ 6962306a36Sopenharmony_ci mempool_exit(&prison->cell_pool); 7062306a36Sopenharmony_ci kfree(prison); 7162306a36Sopenharmony_ci} 7262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dm_bio_prison_destroy); 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_cistruct dm_bio_prison_cell *dm_bio_prison_alloc_cell(struct dm_bio_prison *prison, gfp_t gfp) 7562306a36Sopenharmony_ci{ 7662306a36Sopenharmony_ci return mempool_alloc(&prison->cell_pool, gfp); 7762306a36Sopenharmony_ci} 7862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dm_bio_prison_alloc_cell); 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_civoid dm_bio_prison_free_cell(struct dm_bio_prison *prison, 8162306a36Sopenharmony_ci struct dm_bio_prison_cell *cell) 8262306a36Sopenharmony_ci{ 8362306a36Sopenharmony_ci mempool_free(cell, &prison->cell_pool); 8462306a36Sopenharmony_ci} 8562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dm_bio_prison_free_cell); 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_cistatic void __setup_new_cell(struct dm_cell_key *key, 8862306a36Sopenharmony_ci struct bio *holder, 8962306a36Sopenharmony_ci struct dm_bio_prison_cell *cell) 9062306a36Sopenharmony_ci{ 9162306a36Sopenharmony_ci memcpy(&cell->key, key, sizeof(cell->key)); 9262306a36Sopenharmony_ci cell->holder = holder; 9362306a36Sopenharmony_ci bio_list_init(&cell->bios); 9462306a36Sopenharmony_ci} 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_cistatic int cmp_keys(struct dm_cell_key *lhs, 9762306a36Sopenharmony_ci struct dm_cell_key *rhs) 9862306a36Sopenharmony_ci{ 9962306a36Sopenharmony_ci if (lhs->virtual < rhs->virtual) 10062306a36Sopenharmony_ci return -1; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci if (lhs->virtual > rhs->virtual) 10362306a36Sopenharmony_ci return 1; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci if (lhs->dev < rhs->dev) 10662306a36Sopenharmony_ci return -1; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci if (lhs->dev > rhs->dev) 10962306a36Sopenharmony_ci return 1; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci if (lhs->block_end <= rhs->block_begin) 11262306a36Sopenharmony_ci return -1; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci if (lhs->block_begin >= rhs->block_end) 11562306a36Sopenharmony_ci return 1; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci return 0; 11862306a36Sopenharmony_ci} 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_cistatic inline unsigned int lock_nr(struct dm_cell_key *key, unsigned int num_locks) 12162306a36Sopenharmony_ci{ 12262306a36Sopenharmony_ci return dm_hash_locks_index((key->block_begin >> BIO_PRISON_MAX_RANGE_SHIFT), 12362306a36Sopenharmony_ci num_locks); 12462306a36Sopenharmony_ci} 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_cibool dm_cell_key_has_valid_range(struct dm_cell_key *key) 12762306a36Sopenharmony_ci{ 12862306a36Sopenharmony_ci if (WARN_ON_ONCE(key->block_end - key->block_begin > BIO_PRISON_MAX_RANGE)) 12962306a36Sopenharmony_ci return false; 13062306a36Sopenharmony_ci if (WARN_ON_ONCE((key->block_begin >> BIO_PRISON_MAX_RANGE_SHIFT) != 13162306a36Sopenharmony_ci (key->block_end - 1) >> BIO_PRISON_MAX_RANGE_SHIFT)) 13262306a36Sopenharmony_ci return false; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci return true; 13562306a36Sopenharmony_ci} 13662306a36Sopenharmony_ciEXPORT_SYMBOL(dm_cell_key_has_valid_range); 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_cistatic int __bio_detain(struct rb_root *root, 13962306a36Sopenharmony_ci struct dm_cell_key *key, 14062306a36Sopenharmony_ci struct bio *inmate, 14162306a36Sopenharmony_ci struct dm_bio_prison_cell *cell_prealloc, 14262306a36Sopenharmony_ci struct dm_bio_prison_cell **cell_result) 14362306a36Sopenharmony_ci{ 14462306a36Sopenharmony_ci int r; 14562306a36Sopenharmony_ci struct rb_node **new = &root->rb_node, *parent = NULL; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci while (*new) { 14862306a36Sopenharmony_ci struct dm_bio_prison_cell *cell = 14962306a36Sopenharmony_ci rb_entry(*new, struct dm_bio_prison_cell, node); 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci r = cmp_keys(key, &cell->key); 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci parent = *new; 15462306a36Sopenharmony_ci if (r < 0) 15562306a36Sopenharmony_ci new = &((*new)->rb_left); 15662306a36Sopenharmony_ci else if (r > 0) 15762306a36Sopenharmony_ci new = &((*new)->rb_right); 15862306a36Sopenharmony_ci else { 15962306a36Sopenharmony_ci if (inmate) 16062306a36Sopenharmony_ci bio_list_add(&cell->bios, inmate); 16162306a36Sopenharmony_ci *cell_result = cell; 16262306a36Sopenharmony_ci return 1; 16362306a36Sopenharmony_ci } 16462306a36Sopenharmony_ci } 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci __setup_new_cell(key, inmate, cell_prealloc); 16762306a36Sopenharmony_ci *cell_result = cell_prealloc; 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci rb_link_node(&cell_prealloc->node, parent, new); 17062306a36Sopenharmony_ci rb_insert_color(&cell_prealloc->node, root); 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci return 0; 17362306a36Sopenharmony_ci} 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_cistatic int bio_detain(struct dm_bio_prison *prison, 17662306a36Sopenharmony_ci struct dm_cell_key *key, 17762306a36Sopenharmony_ci struct bio *inmate, 17862306a36Sopenharmony_ci struct dm_bio_prison_cell *cell_prealloc, 17962306a36Sopenharmony_ci struct dm_bio_prison_cell **cell_result) 18062306a36Sopenharmony_ci{ 18162306a36Sopenharmony_ci int r; 18262306a36Sopenharmony_ci unsigned l = lock_nr(key, prison->num_locks); 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci spin_lock_irq(&prison->regions[l].lock); 18562306a36Sopenharmony_ci r = __bio_detain(&prison->regions[l].cell, key, inmate, cell_prealloc, cell_result); 18662306a36Sopenharmony_ci spin_unlock_irq(&prison->regions[l].lock); 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci return r; 18962306a36Sopenharmony_ci} 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ciint dm_bio_detain(struct dm_bio_prison *prison, 19262306a36Sopenharmony_ci struct dm_cell_key *key, 19362306a36Sopenharmony_ci struct bio *inmate, 19462306a36Sopenharmony_ci struct dm_bio_prison_cell *cell_prealloc, 19562306a36Sopenharmony_ci struct dm_bio_prison_cell **cell_result) 19662306a36Sopenharmony_ci{ 19762306a36Sopenharmony_ci return bio_detain(prison, key, inmate, cell_prealloc, cell_result); 19862306a36Sopenharmony_ci} 19962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dm_bio_detain); 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ciint dm_get_cell(struct dm_bio_prison *prison, 20262306a36Sopenharmony_ci struct dm_cell_key *key, 20362306a36Sopenharmony_ci struct dm_bio_prison_cell *cell_prealloc, 20462306a36Sopenharmony_ci struct dm_bio_prison_cell **cell_result) 20562306a36Sopenharmony_ci{ 20662306a36Sopenharmony_ci return bio_detain(prison, key, NULL, cell_prealloc, cell_result); 20762306a36Sopenharmony_ci} 20862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dm_get_cell); 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci/* 21162306a36Sopenharmony_ci * @inmates must have been initialised prior to this call 21262306a36Sopenharmony_ci */ 21362306a36Sopenharmony_cistatic void __cell_release(struct rb_root *root, 21462306a36Sopenharmony_ci struct dm_bio_prison_cell *cell, 21562306a36Sopenharmony_ci struct bio_list *inmates) 21662306a36Sopenharmony_ci{ 21762306a36Sopenharmony_ci rb_erase(&cell->node, root); 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci if (inmates) { 22062306a36Sopenharmony_ci if (cell->holder) 22162306a36Sopenharmony_ci bio_list_add(inmates, cell->holder); 22262306a36Sopenharmony_ci bio_list_merge(inmates, &cell->bios); 22362306a36Sopenharmony_ci } 22462306a36Sopenharmony_ci} 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_civoid dm_cell_release(struct dm_bio_prison *prison, 22762306a36Sopenharmony_ci struct dm_bio_prison_cell *cell, 22862306a36Sopenharmony_ci struct bio_list *bios) 22962306a36Sopenharmony_ci{ 23062306a36Sopenharmony_ci unsigned l = lock_nr(&cell->key, prison->num_locks); 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci spin_lock_irq(&prison->regions[l].lock); 23362306a36Sopenharmony_ci __cell_release(&prison->regions[l].cell, cell, bios); 23462306a36Sopenharmony_ci spin_unlock_irq(&prison->regions[l].lock); 23562306a36Sopenharmony_ci} 23662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dm_cell_release); 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci/* 23962306a36Sopenharmony_ci * Sometimes we don't want the holder, just the additional bios. 24062306a36Sopenharmony_ci */ 24162306a36Sopenharmony_cistatic void __cell_release_no_holder(struct rb_root *root, 24262306a36Sopenharmony_ci struct dm_bio_prison_cell *cell, 24362306a36Sopenharmony_ci struct bio_list *inmates) 24462306a36Sopenharmony_ci{ 24562306a36Sopenharmony_ci rb_erase(&cell->node, root); 24662306a36Sopenharmony_ci bio_list_merge(inmates, &cell->bios); 24762306a36Sopenharmony_ci} 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_civoid dm_cell_release_no_holder(struct dm_bio_prison *prison, 25062306a36Sopenharmony_ci struct dm_bio_prison_cell *cell, 25162306a36Sopenharmony_ci struct bio_list *inmates) 25262306a36Sopenharmony_ci{ 25362306a36Sopenharmony_ci unsigned l = lock_nr(&cell->key, prison->num_locks); 25462306a36Sopenharmony_ci unsigned long flags; 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci spin_lock_irqsave(&prison->regions[l].lock, flags); 25762306a36Sopenharmony_ci __cell_release_no_holder(&prison->regions[l].cell, cell, inmates); 25862306a36Sopenharmony_ci spin_unlock_irqrestore(&prison->regions[l].lock, flags); 25962306a36Sopenharmony_ci} 26062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dm_cell_release_no_holder); 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_civoid dm_cell_error(struct dm_bio_prison *prison, 26362306a36Sopenharmony_ci struct dm_bio_prison_cell *cell, blk_status_t error) 26462306a36Sopenharmony_ci{ 26562306a36Sopenharmony_ci struct bio_list bios; 26662306a36Sopenharmony_ci struct bio *bio; 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci bio_list_init(&bios); 26962306a36Sopenharmony_ci dm_cell_release(prison, cell, &bios); 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci while ((bio = bio_list_pop(&bios))) { 27262306a36Sopenharmony_ci bio->bi_status = error; 27362306a36Sopenharmony_ci bio_endio(bio); 27462306a36Sopenharmony_ci } 27562306a36Sopenharmony_ci} 27662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dm_cell_error); 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_civoid dm_cell_visit_release(struct dm_bio_prison *prison, 27962306a36Sopenharmony_ci void (*visit_fn)(void *, struct dm_bio_prison_cell *), 28062306a36Sopenharmony_ci void *context, 28162306a36Sopenharmony_ci struct dm_bio_prison_cell *cell) 28262306a36Sopenharmony_ci{ 28362306a36Sopenharmony_ci unsigned l = lock_nr(&cell->key, prison->num_locks); 28462306a36Sopenharmony_ci spin_lock_irq(&prison->regions[l].lock); 28562306a36Sopenharmony_ci visit_fn(context, cell); 28662306a36Sopenharmony_ci rb_erase(&cell->node, &prison->regions[l].cell); 28762306a36Sopenharmony_ci spin_unlock_irq(&prison->regions[l].lock); 28862306a36Sopenharmony_ci} 28962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dm_cell_visit_release); 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_cistatic int __promote_or_release(struct rb_root *root, 29262306a36Sopenharmony_ci struct dm_bio_prison_cell *cell) 29362306a36Sopenharmony_ci{ 29462306a36Sopenharmony_ci if (bio_list_empty(&cell->bios)) { 29562306a36Sopenharmony_ci rb_erase(&cell->node, root); 29662306a36Sopenharmony_ci return 1; 29762306a36Sopenharmony_ci } 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci cell->holder = bio_list_pop(&cell->bios); 30062306a36Sopenharmony_ci return 0; 30162306a36Sopenharmony_ci} 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ciint dm_cell_promote_or_release(struct dm_bio_prison *prison, 30462306a36Sopenharmony_ci struct dm_bio_prison_cell *cell) 30562306a36Sopenharmony_ci{ 30662306a36Sopenharmony_ci int r; 30762306a36Sopenharmony_ci unsigned l = lock_nr(&cell->key, prison->num_locks); 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci spin_lock_irq(&prison->regions[l].lock); 31062306a36Sopenharmony_ci r = __promote_or_release(&prison->regions[l].cell, cell); 31162306a36Sopenharmony_ci spin_unlock_irq(&prison->regions[l].lock); 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci return r; 31462306a36Sopenharmony_ci} 31562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dm_cell_promote_or_release); 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci/*----------------------------------------------------------------*/ 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci#define DEFERRED_SET_SIZE 64 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_cistruct dm_deferred_entry { 32262306a36Sopenharmony_ci struct dm_deferred_set *ds; 32362306a36Sopenharmony_ci unsigned int count; 32462306a36Sopenharmony_ci struct list_head work_items; 32562306a36Sopenharmony_ci}; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_cistruct dm_deferred_set { 32862306a36Sopenharmony_ci spinlock_t lock; 32962306a36Sopenharmony_ci unsigned int current_entry; 33062306a36Sopenharmony_ci unsigned int sweeper; 33162306a36Sopenharmony_ci struct dm_deferred_entry entries[DEFERRED_SET_SIZE]; 33262306a36Sopenharmony_ci}; 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_cistruct dm_deferred_set *dm_deferred_set_create(void) 33562306a36Sopenharmony_ci{ 33662306a36Sopenharmony_ci int i; 33762306a36Sopenharmony_ci struct dm_deferred_set *ds; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci ds = kmalloc(sizeof(*ds), GFP_KERNEL); 34062306a36Sopenharmony_ci if (!ds) 34162306a36Sopenharmony_ci return NULL; 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci spin_lock_init(&ds->lock); 34462306a36Sopenharmony_ci ds->current_entry = 0; 34562306a36Sopenharmony_ci ds->sweeper = 0; 34662306a36Sopenharmony_ci for (i = 0; i < DEFERRED_SET_SIZE; i++) { 34762306a36Sopenharmony_ci ds->entries[i].ds = ds; 34862306a36Sopenharmony_ci ds->entries[i].count = 0; 34962306a36Sopenharmony_ci INIT_LIST_HEAD(&ds->entries[i].work_items); 35062306a36Sopenharmony_ci } 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci return ds; 35362306a36Sopenharmony_ci} 35462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dm_deferred_set_create); 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_civoid dm_deferred_set_destroy(struct dm_deferred_set *ds) 35762306a36Sopenharmony_ci{ 35862306a36Sopenharmony_ci kfree(ds); 35962306a36Sopenharmony_ci} 36062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dm_deferred_set_destroy); 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_cistruct dm_deferred_entry *dm_deferred_entry_inc(struct dm_deferred_set *ds) 36362306a36Sopenharmony_ci{ 36462306a36Sopenharmony_ci unsigned long flags; 36562306a36Sopenharmony_ci struct dm_deferred_entry *entry; 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci spin_lock_irqsave(&ds->lock, flags); 36862306a36Sopenharmony_ci entry = ds->entries + ds->current_entry; 36962306a36Sopenharmony_ci entry->count++; 37062306a36Sopenharmony_ci spin_unlock_irqrestore(&ds->lock, flags); 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci return entry; 37362306a36Sopenharmony_ci} 37462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dm_deferred_entry_inc); 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_cistatic unsigned int ds_next(unsigned int index) 37762306a36Sopenharmony_ci{ 37862306a36Sopenharmony_ci return (index + 1) % DEFERRED_SET_SIZE; 37962306a36Sopenharmony_ci} 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_cistatic void __sweep(struct dm_deferred_set *ds, struct list_head *head) 38262306a36Sopenharmony_ci{ 38362306a36Sopenharmony_ci while ((ds->sweeper != ds->current_entry) && 38462306a36Sopenharmony_ci !ds->entries[ds->sweeper].count) { 38562306a36Sopenharmony_ci list_splice_init(&ds->entries[ds->sweeper].work_items, head); 38662306a36Sopenharmony_ci ds->sweeper = ds_next(ds->sweeper); 38762306a36Sopenharmony_ci } 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci if ((ds->sweeper == ds->current_entry) && !ds->entries[ds->sweeper].count) 39062306a36Sopenharmony_ci list_splice_init(&ds->entries[ds->sweeper].work_items, head); 39162306a36Sopenharmony_ci} 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_civoid dm_deferred_entry_dec(struct dm_deferred_entry *entry, struct list_head *head) 39462306a36Sopenharmony_ci{ 39562306a36Sopenharmony_ci unsigned long flags; 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci spin_lock_irqsave(&entry->ds->lock, flags); 39862306a36Sopenharmony_ci BUG_ON(!entry->count); 39962306a36Sopenharmony_ci --entry->count; 40062306a36Sopenharmony_ci __sweep(entry->ds, head); 40162306a36Sopenharmony_ci spin_unlock_irqrestore(&entry->ds->lock, flags); 40262306a36Sopenharmony_ci} 40362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dm_deferred_entry_dec); 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci/* 40662306a36Sopenharmony_ci * Returns 1 if deferred or 0 if no pending items to delay job. 40762306a36Sopenharmony_ci */ 40862306a36Sopenharmony_ciint dm_deferred_set_add_work(struct dm_deferred_set *ds, struct list_head *work) 40962306a36Sopenharmony_ci{ 41062306a36Sopenharmony_ci int r = 1; 41162306a36Sopenharmony_ci unsigned int next_entry; 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci spin_lock_irq(&ds->lock); 41462306a36Sopenharmony_ci if ((ds->sweeper == ds->current_entry) && 41562306a36Sopenharmony_ci !ds->entries[ds->current_entry].count) 41662306a36Sopenharmony_ci r = 0; 41762306a36Sopenharmony_ci else { 41862306a36Sopenharmony_ci list_add(work, &ds->entries[ds->current_entry].work_items); 41962306a36Sopenharmony_ci next_entry = ds_next(ds->current_entry); 42062306a36Sopenharmony_ci if (!ds->entries[next_entry].count) 42162306a36Sopenharmony_ci ds->current_entry = next_entry; 42262306a36Sopenharmony_ci } 42362306a36Sopenharmony_ci spin_unlock_irq(&ds->lock); 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci return r; 42662306a36Sopenharmony_ci} 42762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dm_deferred_set_add_work); 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci/*----------------------------------------------------------------*/ 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_cistatic int __init dm_bio_prison_init_v1(void) 43262306a36Sopenharmony_ci{ 43362306a36Sopenharmony_ci _cell_cache = KMEM_CACHE(dm_bio_prison_cell, 0); 43462306a36Sopenharmony_ci if (!_cell_cache) 43562306a36Sopenharmony_ci return -ENOMEM; 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci return 0; 43862306a36Sopenharmony_ci} 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_cistatic void dm_bio_prison_exit_v1(void) 44162306a36Sopenharmony_ci{ 44262306a36Sopenharmony_ci kmem_cache_destroy(_cell_cache); 44362306a36Sopenharmony_ci _cell_cache = NULL; 44462306a36Sopenharmony_ci} 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_cistatic int (*_inits[])(void) __initdata = { 44762306a36Sopenharmony_ci dm_bio_prison_init_v1, 44862306a36Sopenharmony_ci dm_bio_prison_init_v2, 44962306a36Sopenharmony_ci}; 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_cistatic void (*_exits[])(void) = { 45262306a36Sopenharmony_ci dm_bio_prison_exit_v1, 45362306a36Sopenharmony_ci dm_bio_prison_exit_v2, 45462306a36Sopenharmony_ci}; 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_cistatic int __init dm_bio_prison_init(void) 45762306a36Sopenharmony_ci{ 45862306a36Sopenharmony_ci const int count = ARRAY_SIZE(_inits); 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci int r, i; 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci for (i = 0; i < count; i++) { 46362306a36Sopenharmony_ci r = _inits[i](); 46462306a36Sopenharmony_ci if (r) 46562306a36Sopenharmony_ci goto bad; 46662306a36Sopenharmony_ci } 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci return 0; 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_cibad: 47162306a36Sopenharmony_ci while (i--) 47262306a36Sopenharmony_ci _exits[i](); 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci return r; 47562306a36Sopenharmony_ci} 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_cistatic void __exit dm_bio_prison_exit(void) 47862306a36Sopenharmony_ci{ 47962306a36Sopenharmony_ci int i = ARRAY_SIZE(_exits); 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci while (i--) 48262306a36Sopenharmony_ci _exits[i](); 48362306a36Sopenharmony_ci} 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci/* 48662306a36Sopenharmony_ci * module hooks 48762306a36Sopenharmony_ci */ 48862306a36Sopenharmony_cimodule_init(dm_bio_prison_init); 48962306a36Sopenharmony_cimodule_exit(dm_bio_prison_exit); 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ciMODULE_DESCRIPTION(DM_NAME " bio prison"); 49262306a36Sopenharmony_ciMODULE_AUTHOR("Joe Thornber <dm-devel@redhat.com>"); 49362306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 494