13bd94003SHeinz Mauelshagen /* SPDX-License-Identifier: GPL-2.0-only */ 2742c8fdcSJoe Thornber /* 3742c8fdcSJoe Thornber * Copyright (C) 2011-2017 Red Hat, Inc. 4742c8fdcSJoe Thornber * 5742c8fdcSJoe Thornber * This file is released under the GPL. 6742c8fdcSJoe Thornber */ 7742c8fdcSJoe Thornber 8742c8fdcSJoe Thornber #ifndef DM_BIO_PRISON_H 9742c8fdcSJoe Thornber #define DM_BIO_PRISON_H 10742c8fdcSJoe Thornber 11742c8fdcSJoe Thornber #include "persistent-data/dm-block-manager.h" /* FIXME: for dm_block_t */ 12742c8fdcSJoe Thornber #include "dm-thin-metadata.h" /* FIXME: for dm_thin_id */ 13742c8fdcSJoe Thornber 14742c8fdcSJoe Thornber #include <linux/bio.h> 15742c8fdcSJoe Thornber #include <linux/rbtree.h> 16742c8fdcSJoe Thornber 17742c8fdcSJoe Thornber /*----------------------------------------------------------------*/ 18742c8fdcSJoe Thornber 19742c8fdcSJoe Thornber /* 20742c8fdcSJoe Thornber * Sometimes we can't deal with a bio straight away. We put them in prison 21742c8fdcSJoe Thornber * where they can't cause any mischief. Bios are put in a cell identified 22742c8fdcSJoe Thornber * by a key, multiple bios can be in the same cell. When the cell is 23742c8fdcSJoe Thornber * subsequently unlocked the bios become available. 24742c8fdcSJoe Thornber */ 25742c8fdcSJoe Thornber struct dm_bio_prison; 26742c8fdcSJoe Thornber 27742c8fdcSJoe Thornber /* 28742c8fdcSJoe Thornber * Keys define a range of blocks within either a virtual or physical 29742c8fdcSJoe Thornber * device. 30742c8fdcSJoe Thornber */ 31742c8fdcSJoe Thornber struct dm_cell_key { 32742c8fdcSJoe Thornber int virtual; 33742c8fdcSJoe Thornber dm_thin_id dev; 34742c8fdcSJoe Thornber dm_block_t block_begin, block_end; 35742c8fdcSJoe Thornber }; 36742c8fdcSJoe Thornber 37742c8fdcSJoe Thornber /* 38e2dd8acaSJoe Thornber * The range of a key (block_end - block_begin) must not 39e2dd8acaSJoe Thornber * exceed BIO_PRISON_MAX_RANGE. Also the range must not 40e2dd8acaSJoe Thornber * cross a similarly sized boundary. 41e2dd8acaSJoe Thornber * 42e2dd8acaSJoe Thornber * Must be a power of 2. 43e2dd8acaSJoe Thornber */ 44e2dd8acaSJoe Thornber #define BIO_PRISON_MAX_RANGE 1024 45e2dd8acaSJoe Thornber #define BIO_PRISON_MAX_RANGE_SHIFT 10 46e2dd8acaSJoe Thornber 47e2dd8acaSJoe Thornber /* 48742c8fdcSJoe Thornber * Treat this as opaque, only in header so callers can manage allocation 49742c8fdcSJoe Thornber * themselves. 50742c8fdcSJoe Thornber */ 51742c8fdcSJoe Thornber struct dm_bio_prison_cell { 52742c8fdcSJoe Thornber struct list_head user_list; /* for client use */ 53742c8fdcSJoe Thornber struct rb_node node; 54742c8fdcSJoe Thornber 55742c8fdcSJoe Thornber struct dm_cell_key key; 56742c8fdcSJoe Thornber struct bio *holder; 57742c8fdcSJoe Thornber struct bio_list bios; 58742c8fdcSJoe Thornber }; 59742c8fdcSJoe Thornber 60742c8fdcSJoe Thornber struct dm_bio_prison *dm_bio_prison_create(void); 61742c8fdcSJoe Thornber void dm_bio_prison_destroy(struct dm_bio_prison *prison); 62742c8fdcSJoe Thornber 63742c8fdcSJoe Thornber /* 64742c8fdcSJoe Thornber * These two functions just wrap a mempool. This is a transitory step: 65742c8fdcSJoe Thornber * Eventually all bio prison clients should manage their own cell memory. 66742c8fdcSJoe Thornber * 67742c8fdcSJoe Thornber * Like mempool_alloc(), dm_bio_prison_alloc_cell() can only fail if called 68742c8fdcSJoe Thornber * in interrupt context or passed GFP_NOWAIT. 69742c8fdcSJoe Thornber */ 70742c8fdcSJoe Thornber struct dm_bio_prison_cell *dm_bio_prison_alloc_cell(struct dm_bio_prison *prison, 71742c8fdcSJoe Thornber gfp_t gfp); 72742c8fdcSJoe Thornber void dm_bio_prison_free_cell(struct dm_bio_prison *prison, 73742c8fdcSJoe Thornber struct dm_bio_prison_cell *cell); 74742c8fdcSJoe Thornber 75742c8fdcSJoe Thornber /* 76742c8fdcSJoe Thornber * Creates, or retrieves a cell that overlaps the given key. 77742c8fdcSJoe Thornber * 78742c8fdcSJoe Thornber * Returns 1 if pre-existing cell returned, zero if new cell created using 79742c8fdcSJoe Thornber * @cell_prealloc. 80742c8fdcSJoe Thornber */ 81742c8fdcSJoe Thornber int dm_get_cell(struct dm_bio_prison *prison, 82742c8fdcSJoe Thornber struct dm_cell_key *key, 83742c8fdcSJoe Thornber struct dm_bio_prison_cell *cell_prealloc, 84742c8fdcSJoe Thornber struct dm_bio_prison_cell **cell_result); 85742c8fdcSJoe Thornber 86742c8fdcSJoe Thornber /* 87*3f8d3f54SMike Snitzer * Returns false if key is beyond BIO_PRISON_MAX_RANGE or spans a boundary. 88*3f8d3f54SMike Snitzer */ 89*3f8d3f54SMike Snitzer bool dm_cell_key_has_valid_range(struct dm_cell_key *key); 90*3f8d3f54SMike Snitzer 91*3f8d3f54SMike Snitzer /* 92742c8fdcSJoe Thornber * An atomic op that combines retrieving or creating a cell, and adding a 93742c8fdcSJoe Thornber * bio to it. 94742c8fdcSJoe Thornber * 95742c8fdcSJoe Thornber * Returns 1 if the cell was already held, 0 if @inmate is the new holder. 96742c8fdcSJoe Thornber */ 97742c8fdcSJoe Thornber int dm_bio_detain(struct dm_bio_prison *prison, 98742c8fdcSJoe Thornber struct dm_cell_key *key, 99742c8fdcSJoe Thornber struct bio *inmate, 100742c8fdcSJoe Thornber struct dm_bio_prison_cell *cell_prealloc, 101742c8fdcSJoe Thornber struct dm_bio_prison_cell **cell_result); 102742c8fdcSJoe Thornber 103742c8fdcSJoe Thornber void dm_cell_release(struct dm_bio_prison *prison, 104742c8fdcSJoe Thornber struct dm_bio_prison_cell *cell, 105742c8fdcSJoe Thornber struct bio_list *bios); 106742c8fdcSJoe Thornber void dm_cell_release_no_holder(struct dm_bio_prison *prison, 107742c8fdcSJoe Thornber struct dm_bio_prison_cell *cell, 108742c8fdcSJoe Thornber struct bio_list *inmates); 109742c8fdcSJoe Thornber void dm_cell_error(struct dm_bio_prison *prison, 1104e4cbee9SChristoph Hellwig struct dm_bio_prison_cell *cell, blk_status_t error); 111742c8fdcSJoe Thornber 112742c8fdcSJoe Thornber /* 113742c8fdcSJoe Thornber * Visits the cell and then releases. Guarantees no new inmates are 114742c8fdcSJoe Thornber * inserted between the visit and release. 115742c8fdcSJoe Thornber */ 116742c8fdcSJoe Thornber void dm_cell_visit_release(struct dm_bio_prison *prison, 117742c8fdcSJoe Thornber void (*visit_fn)(void *, struct dm_bio_prison_cell *), 118742c8fdcSJoe Thornber void *context, struct dm_bio_prison_cell *cell); 119742c8fdcSJoe Thornber 120742c8fdcSJoe Thornber /* 121742c8fdcSJoe Thornber * Rather than always releasing the prisoners in a cell, the client may 122742c8fdcSJoe Thornber * want to promote one of them to be the new holder. There is a race here 123742c8fdcSJoe Thornber * though between releasing an empty cell, and other threads adding new 124742c8fdcSJoe Thornber * inmates. So this function makes the decision with its lock held. 125742c8fdcSJoe Thornber * 126742c8fdcSJoe Thornber * This function can have two outcomes: 127742c8fdcSJoe Thornber * i) An inmate is promoted to be the holder of the cell (return value of 0). 128742c8fdcSJoe Thornber * ii) The cell has no inmate for promotion and is released (return value of 1). 129742c8fdcSJoe Thornber */ 130742c8fdcSJoe Thornber int dm_cell_promote_or_release(struct dm_bio_prison *prison, 131742c8fdcSJoe Thornber struct dm_bio_prison_cell *cell); 132742c8fdcSJoe Thornber 133742c8fdcSJoe Thornber /*----------------------------------------------------------------*/ 134742c8fdcSJoe Thornber 135742c8fdcSJoe Thornber /* 136742c8fdcSJoe Thornber * We use the deferred set to keep track of pending reads to shared blocks. 137742c8fdcSJoe Thornber * We do this to ensure the new mapping caused by a write isn't performed 138742c8fdcSJoe Thornber * until these prior reads have completed. Otherwise the insertion of the 139742c8fdcSJoe Thornber * new mapping could free the old block that the read bios are mapped to. 140742c8fdcSJoe Thornber */ 141742c8fdcSJoe Thornber 142742c8fdcSJoe Thornber struct dm_deferred_set; 143742c8fdcSJoe Thornber struct dm_deferred_entry; 144742c8fdcSJoe Thornber 145742c8fdcSJoe Thornber struct dm_deferred_set *dm_deferred_set_create(void); 146742c8fdcSJoe Thornber void dm_deferred_set_destroy(struct dm_deferred_set *ds); 147742c8fdcSJoe Thornber 148742c8fdcSJoe Thornber struct dm_deferred_entry *dm_deferred_entry_inc(struct dm_deferred_set *ds); 149742c8fdcSJoe Thornber void dm_deferred_entry_dec(struct dm_deferred_entry *entry, struct list_head *head); 150742c8fdcSJoe Thornber int dm_deferred_set_add_work(struct dm_deferred_set *ds, struct list_head *work); 151742c8fdcSJoe Thornber 152742c8fdcSJoe Thornber /*----------------------------------------------------------------*/ 153742c8fdcSJoe Thornber 154742c8fdcSJoe Thornber #endif 155