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