Commit | Line | Data |
---|---|---|
3bd94003 | 1 | /* SPDX-License-Identifier: GPL-2.0-only */ |
4f81a417 | 2 | /* |
742c8fdc | 3 | * Copyright (C) 2011-2017 Red Hat, Inc. |
4f81a417 MS |
4 | * |
5 | * This file is released under the GPL. | |
6 | */ | |
7 | ||
8 | #ifndef DM_BIO_PRISON_H | |
9 | #define DM_BIO_PRISON_H | |
10 | ||
11 | #include "persistent-data/dm-block-manager.h" /* FIXME: for dm_block_t */ | |
12 | #include "dm-thin-metadata.h" /* FIXME: for dm_thin_id */ | |
13 | ||
4f81a417 | 14 | #include <linux/bio.h> |
a195db2d | 15 | #include <linux/rbtree.h> |
4f81a417 MS |
16 | |
17 | /*----------------------------------------------------------------*/ | |
18 | ||
19 | /* | |
20 | * Sometimes we can't deal with a bio straight away. We put them in prison | |
21 | * where they can't cause any mischief. Bios are put in a cell identified | |
22 | * by a key, multiple bios can be in the same cell. When the cell is | |
23 | * subsequently unlocked the bios become available. | |
24 | */ | |
25 | struct dm_bio_prison; | |
4f81a417 | 26 | |
5f274d88 JT |
27 | /* |
28 | * Keys define a range of blocks within either a virtual or physical | |
29 | * device. | |
30 | */ | |
4f81a417 MS |
31 | struct dm_cell_key { |
32 | int virtual; | |
33 | dm_thin_id dev; | |
5f274d88 | 34 | dm_block_t block_begin, block_end; |
4f81a417 MS |
35 | }; |
36 | ||
e2dd8aca JT |
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 | ||
025b9685 JT |
47 | /* |
48 | * Treat this as opaque, only in header so callers can manage allocation | |
49 | * themselves. | |
50 | */ | |
51 | struct dm_bio_prison_cell { | |
a374bb21 | 52 | struct list_head user_list; /* for client use */ |
a195db2d JT |
53 | struct rb_node node; |
54 | ||
025b9685 JT |
55 | struct dm_cell_key key; |
56 | struct bio *holder; | |
57 | struct bio_list bios; | |
58 | }; | |
59 | ||
a195db2d | 60 | struct dm_bio_prison *dm_bio_prison_create(void); |
4f81a417 MS |
61 | void dm_bio_prison_destroy(struct dm_bio_prison *prison); |
62 | ||
63 | /* | |
6beca5eb JT |
64 | * These two functions just wrap a mempool. This is a transitory step: |
65 | * Eventually all bio prison clients should manage their own cell memory. | |
4f81a417 | 66 | * |
6beca5eb JT |
67 | * Like mempool_alloc(), dm_bio_prison_alloc_cell() can only fail if called |
68 | * in interrupt context or passed GFP_NOWAIT. | |
4f81a417 | 69 | */ |
6beca5eb JT |
70 | struct dm_bio_prison_cell *dm_bio_prison_alloc_cell(struct dm_bio_prison *prison, |
71 | gfp_t gfp); | |
72 | void dm_bio_prison_free_cell(struct dm_bio_prison *prison, | |
73 | struct dm_bio_prison_cell *cell); | |
4f81a417 | 74 | |
c6b4fcba | 75 | /* |
5f274d88 | 76 | * Creates, or retrieves a cell that overlaps the given key. |
c6b4fcba JT |
77 | * |
78 | * Returns 1 if pre-existing cell returned, zero if new cell created using | |
79 | * @cell_prealloc. | |
80 | */ | |
81 | int dm_get_cell(struct dm_bio_prison *prison, | |
82 | struct dm_cell_key *key, | |
83 | struct dm_bio_prison_cell *cell_prealloc, | |
84 | struct dm_bio_prison_cell **cell_result); | |
85 | ||
3f8d3f54 MS |
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 | ||
6beca5eb | 91 | /* |
5f274d88 JT |
92 | * An atomic op that combines retrieving or creating a cell, and adding a |
93 | * bio to it. | |
6beca5eb JT |
94 | * |
95 | * Returns 1 if the cell was already held, 0 if @inmate is the new holder. | |
96 | */ | |
97 | int dm_bio_detain(struct dm_bio_prison *prison, | |
98 | struct dm_cell_key *key, | |
99 | struct bio *inmate, | |
100 | struct dm_bio_prison_cell *cell_prealloc, | |
101 | struct dm_bio_prison_cell **cell_result); | |
102 | ||
103 | void dm_cell_release(struct dm_bio_prison *prison, | |
104 | struct dm_bio_prison_cell *cell, | |
105 | struct bio_list *bios); | |
106 | void dm_cell_release_no_holder(struct dm_bio_prison *prison, | |
107 | struct dm_bio_prison_cell *cell, | |
108 | struct bio_list *inmates); | |
109 | void dm_cell_error(struct dm_bio_prison *prison, | |
4e4cbee9 | 110 | struct dm_bio_prison_cell *cell, blk_status_t error); |
4f81a417 | 111 | |
2d759a46 JT |
112 | /* |
113 | * Visits the cell and then releases. Guarantees no new inmates are | |
114 | * inserted between the visit and release. | |
115 | */ | |
116 | void dm_cell_visit_release(struct dm_bio_prison *prison, | |
117 | void (*visit_fn)(void *, struct dm_bio_prison_cell *), | |
118 | void *context, struct dm_bio_prison_cell *cell); | |
119 | ||
3cdf93f9 JT |
120 | /* |
121 | * Rather than always releasing the prisoners in a cell, the client may | |
122 | * want to promote one of them to be the new holder. There is a race here | |
123 | * though between releasing an empty cell, and other threads adding new | |
124 | * inmates. So this function makes the decision with its lock held. | |
125 | * | |
126 | * This function can have two outcomes: | |
127 | * i) An inmate is promoted to be the holder of the cell (return value of 0). | |
128 | * ii) The cell has no inmate for promotion and is released (return value of 1). | |
129 | */ | |
130 | int dm_cell_promote_or_release(struct dm_bio_prison *prison, | |
131 | struct dm_bio_prison_cell *cell); | |
132 | ||
4f81a417 MS |
133 | /*----------------------------------------------------------------*/ |
134 | ||
135 | /* | |
136 | * We use the deferred set to keep track of pending reads to shared blocks. | |
137 | * We do this to ensure the new mapping caused by a write isn't performed | |
138 | * until these prior reads have completed. Otherwise the insertion of the | |
139 | * new mapping could free the old block that the read bios are mapped to. | |
140 | */ | |
141 | ||
142 | struct dm_deferred_set; | |
143 | struct dm_deferred_entry; | |
144 | ||
145 | struct dm_deferred_set *dm_deferred_set_create(void); | |
146 | void dm_deferred_set_destroy(struct dm_deferred_set *ds); | |
147 | ||
148 | struct dm_deferred_entry *dm_deferred_entry_inc(struct dm_deferred_set *ds); | |
149 | void dm_deferred_entry_dec(struct dm_deferred_entry *entry, struct list_head *head); | |
150 | int dm_deferred_set_add_work(struct dm_deferred_set *ds, struct list_head *work); | |
151 | ||
152 | /*----------------------------------------------------------------*/ | |
153 | ||
154 | #endif |