162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2011-2017 Red Hat, Inc. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * This file is released under the GPL. 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#ifndef DM_BIO_PRISON_H 962306a36Sopenharmony_ci#define DM_BIO_PRISON_H 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include "persistent-data/dm-block-manager.h" /* FIXME: for dm_block_t */ 1262306a36Sopenharmony_ci#include "dm-thin-metadata.h" /* FIXME: for dm_thin_id */ 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include <linux/bio.h> 1562306a36Sopenharmony_ci#include <linux/rbtree.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci/*----------------------------------------------------------------*/ 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci/* 2062306a36Sopenharmony_ci * Sometimes we can't deal with a bio straight away. We put them in prison 2162306a36Sopenharmony_ci * where they can't cause any mischief. Bios are put in a cell identified 2262306a36Sopenharmony_ci * by a key, multiple bios can be in the same cell. When the cell is 2362306a36Sopenharmony_ci * subsequently unlocked the bios become available. 2462306a36Sopenharmony_ci */ 2562306a36Sopenharmony_cistruct dm_bio_prison; 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci/* 2862306a36Sopenharmony_ci * Keys define a range of blocks within either a virtual or physical 2962306a36Sopenharmony_ci * device. 3062306a36Sopenharmony_ci */ 3162306a36Sopenharmony_cistruct dm_cell_key { 3262306a36Sopenharmony_ci int virtual; 3362306a36Sopenharmony_ci dm_thin_id dev; 3462306a36Sopenharmony_ci dm_block_t block_begin, block_end; 3562306a36Sopenharmony_ci}; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci/* 3862306a36Sopenharmony_ci * The range of a key (block_end - block_begin) must not 3962306a36Sopenharmony_ci * exceed BIO_PRISON_MAX_RANGE. Also the range must not 4062306a36Sopenharmony_ci * cross a similarly sized boundary. 4162306a36Sopenharmony_ci * 4262306a36Sopenharmony_ci * Must be a power of 2. 4362306a36Sopenharmony_ci */ 4462306a36Sopenharmony_ci#define BIO_PRISON_MAX_RANGE 1024 4562306a36Sopenharmony_ci#define BIO_PRISON_MAX_RANGE_SHIFT 10 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci/* 4862306a36Sopenharmony_ci * Treat this as opaque, only in header so callers can manage allocation 4962306a36Sopenharmony_ci * themselves. 5062306a36Sopenharmony_ci */ 5162306a36Sopenharmony_cistruct dm_bio_prison_cell { 5262306a36Sopenharmony_ci struct list_head user_list; /* for client use */ 5362306a36Sopenharmony_ci struct rb_node node; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci struct dm_cell_key key; 5662306a36Sopenharmony_ci struct bio *holder; 5762306a36Sopenharmony_ci struct bio_list bios; 5862306a36Sopenharmony_ci}; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_cistruct dm_bio_prison *dm_bio_prison_create(void); 6162306a36Sopenharmony_civoid dm_bio_prison_destroy(struct dm_bio_prison *prison); 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci/* 6462306a36Sopenharmony_ci * These two functions just wrap a mempool. This is a transitory step: 6562306a36Sopenharmony_ci * Eventually all bio prison clients should manage their own cell memory. 6662306a36Sopenharmony_ci * 6762306a36Sopenharmony_ci * Like mempool_alloc(), dm_bio_prison_alloc_cell() can only fail if called 6862306a36Sopenharmony_ci * in interrupt context or passed GFP_NOWAIT. 6962306a36Sopenharmony_ci */ 7062306a36Sopenharmony_cistruct dm_bio_prison_cell *dm_bio_prison_alloc_cell(struct dm_bio_prison *prison, 7162306a36Sopenharmony_ci gfp_t gfp); 7262306a36Sopenharmony_civoid dm_bio_prison_free_cell(struct dm_bio_prison *prison, 7362306a36Sopenharmony_ci struct dm_bio_prison_cell *cell); 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci/* 7662306a36Sopenharmony_ci * Creates, or retrieves a cell that overlaps the given key. 7762306a36Sopenharmony_ci * 7862306a36Sopenharmony_ci * Returns 1 if pre-existing cell returned, zero if new cell created using 7962306a36Sopenharmony_ci * @cell_prealloc. 8062306a36Sopenharmony_ci */ 8162306a36Sopenharmony_ciint dm_get_cell(struct dm_bio_prison *prison, 8262306a36Sopenharmony_ci struct dm_cell_key *key, 8362306a36Sopenharmony_ci struct dm_bio_prison_cell *cell_prealloc, 8462306a36Sopenharmony_ci struct dm_bio_prison_cell **cell_result); 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci/* 8762306a36Sopenharmony_ci * Returns false if key is beyond BIO_PRISON_MAX_RANGE or spans a boundary. 8862306a36Sopenharmony_ci */ 8962306a36Sopenharmony_cibool dm_cell_key_has_valid_range(struct dm_cell_key *key); 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci/* 9262306a36Sopenharmony_ci * An atomic op that combines retrieving or creating a cell, and adding a 9362306a36Sopenharmony_ci * bio to it. 9462306a36Sopenharmony_ci * 9562306a36Sopenharmony_ci * Returns 1 if the cell was already held, 0 if @inmate is the new holder. 9662306a36Sopenharmony_ci */ 9762306a36Sopenharmony_ciint dm_bio_detain(struct dm_bio_prison *prison, 9862306a36Sopenharmony_ci struct dm_cell_key *key, 9962306a36Sopenharmony_ci struct bio *inmate, 10062306a36Sopenharmony_ci struct dm_bio_prison_cell *cell_prealloc, 10162306a36Sopenharmony_ci struct dm_bio_prison_cell **cell_result); 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_civoid dm_cell_release(struct dm_bio_prison *prison, 10462306a36Sopenharmony_ci struct dm_bio_prison_cell *cell, 10562306a36Sopenharmony_ci struct bio_list *bios); 10662306a36Sopenharmony_civoid dm_cell_release_no_holder(struct dm_bio_prison *prison, 10762306a36Sopenharmony_ci struct dm_bio_prison_cell *cell, 10862306a36Sopenharmony_ci struct bio_list *inmates); 10962306a36Sopenharmony_civoid dm_cell_error(struct dm_bio_prison *prison, 11062306a36Sopenharmony_ci struct dm_bio_prison_cell *cell, blk_status_t error); 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci/* 11362306a36Sopenharmony_ci * Visits the cell and then releases. Guarantees no new inmates are 11462306a36Sopenharmony_ci * inserted between the visit and release. 11562306a36Sopenharmony_ci */ 11662306a36Sopenharmony_civoid dm_cell_visit_release(struct dm_bio_prison *prison, 11762306a36Sopenharmony_ci void (*visit_fn)(void *, struct dm_bio_prison_cell *), 11862306a36Sopenharmony_ci void *context, struct dm_bio_prison_cell *cell); 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci/* 12162306a36Sopenharmony_ci * Rather than always releasing the prisoners in a cell, the client may 12262306a36Sopenharmony_ci * want to promote one of them to be the new holder. There is a race here 12362306a36Sopenharmony_ci * though between releasing an empty cell, and other threads adding new 12462306a36Sopenharmony_ci * inmates. So this function makes the decision with its lock held. 12562306a36Sopenharmony_ci * 12662306a36Sopenharmony_ci * This function can have two outcomes: 12762306a36Sopenharmony_ci * i) An inmate is promoted to be the holder of the cell (return value of 0). 12862306a36Sopenharmony_ci * ii) The cell has no inmate for promotion and is released (return value of 1). 12962306a36Sopenharmony_ci */ 13062306a36Sopenharmony_ciint dm_cell_promote_or_release(struct dm_bio_prison *prison, 13162306a36Sopenharmony_ci struct dm_bio_prison_cell *cell); 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci/*----------------------------------------------------------------*/ 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci/* 13662306a36Sopenharmony_ci * We use the deferred set to keep track of pending reads to shared blocks. 13762306a36Sopenharmony_ci * We do this to ensure the new mapping caused by a write isn't performed 13862306a36Sopenharmony_ci * until these prior reads have completed. Otherwise the insertion of the 13962306a36Sopenharmony_ci * new mapping could free the old block that the read bios are mapped to. 14062306a36Sopenharmony_ci */ 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_cistruct dm_deferred_set; 14362306a36Sopenharmony_cistruct dm_deferred_entry; 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_cistruct dm_deferred_set *dm_deferred_set_create(void); 14662306a36Sopenharmony_civoid dm_deferred_set_destroy(struct dm_deferred_set *ds); 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_cistruct dm_deferred_entry *dm_deferred_entry_inc(struct dm_deferred_set *ds); 14962306a36Sopenharmony_civoid dm_deferred_entry_dec(struct dm_deferred_entry *entry, struct list_head *head); 15062306a36Sopenharmony_ciint dm_deferred_set_add_work(struct dm_deferred_set *ds, struct list_head *work); 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci/*----------------------------------------------------------------*/ 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci#endif 155