1 /* SPDX-License-Identifier: GPL-2.0-only */ 2 /* 3 * Copyright (C) 2011 Red Hat, Inc. 4 * 5 * This file is released under the GPL. 6 */ 7 8 #ifndef _LINUX_DM_TRANSACTION_MANAGER_H 9 #define _LINUX_DM_TRANSACTION_MANAGER_H 10 11 #include "dm-block-manager.h" 12 13 struct dm_transaction_manager; 14 struct dm_space_map; 15 16 /*----------------------------------------------------------------*/ 17 18 /* 19 * This manages the scope of a transaction. It also enforces immutability 20 * of the on-disk data structures by limiting access to writeable blocks. 21 * 22 * Clients should not fiddle with the block manager directly. 23 */ 24 25 void dm_tm_destroy(struct dm_transaction_manager *tm); 26 27 /* 28 * The non-blocking version of a transaction manager is intended for use in 29 * fast path code that needs to do lookups e.g. a dm mapping function. 30 * You create the non-blocking variant from a normal tm. The interface is 31 * the same, except that most functions will just return -EWOULDBLOCK. 32 * Methods that return void yet may block should not be called on a clone 33 * viz. dm_tm_inc, dm_tm_dec. Call dm_tm_destroy() as you would with a normal 34 * tm when you've finished with it. You may not destroy the original prior 35 * to clones. 36 */ 37 struct dm_transaction_manager *dm_tm_create_non_blocking_clone(struct dm_transaction_manager *real); 38 39 /* 40 * We use a 2-phase commit here. 41 * 42 * i) Make all changes for the transaction *except* for the superblock. 43 * Then call dm_tm_pre_commit() to flush them to disk. 44 * 45 * ii) Lock your superblock. Update. Then call dm_tm_commit() which will 46 * unlock the superblock and flush it. No other blocks should be updated 47 * during this period. Care should be taken to never unlock a partially 48 * updated superblock; perform any operations that could fail *before* you 49 * take the superblock lock. 50 */ 51 int dm_tm_pre_commit(struct dm_transaction_manager *tm); 52 int dm_tm_commit(struct dm_transaction_manager *tm, struct dm_block *superblock); 53 54 /* 55 * These methods are the only way to get hold of a writeable block. 56 */ 57 58 /* 59 * dm_tm_new_block() is pretty self-explanatory. Make sure you do actually 60 * write to the whole of @data before you unlock, otherwise you could get 61 * a data leak. (The other option is for tm_new_block() to zero new blocks 62 * before handing them out, which will be redundant in most, if not all, 63 * cases). 64 * Zeroes the new block and returns with write lock held. 65 */ 66 int dm_tm_new_block(struct dm_transaction_manager *tm, 67 struct dm_block_validator *v, 68 struct dm_block **result); 69 70 /* 71 * dm_tm_shadow_block() allocates a new block and copies the data from @orig 72 * to it. It then decrements the reference count on original block. Use 73 * this to update the contents of a block in a data structure, don't 74 * confuse this with a clone - you shouldn't access the orig block after 75 * this operation. Because the tm knows the scope of the transaction it 76 * can optimise requests for a shadow of a shadow to a no-op. Don't forget 77 * to unlock when you've finished with the shadow. 78 * 79 * The @inc_children flag is used to tell the caller whether it needs to 80 * adjust reference counts for children. (Data in the block may refer to 81 * other blocks.) 82 * 83 * Shadowing implicitly drops a reference on @orig so you must not have 84 * it locked when you call this. 85 */ 86 int dm_tm_shadow_block(struct dm_transaction_manager *tm, dm_block_t orig, 87 struct dm_block_validator *v, 88 struct dm_block **result, int *inc_children); 89 90 /* 91 * Read access. You can lock any block you want. If there's a write lock 92 * on it outstanding then it'll block. 93 */ 94 int dm_tm_read_lock(struct dm_transaction_manager *tm, dm_block_t b, 95 struct dm_block_validator *v, 96 struct dm_block **result); 97 98 void dm_tm_unlock(struct dm_transaction_manager *tm, struct dm_block *b); 99 100 /* 101 * Functions for altering the reference count of a block directly. 102 */ 103 void dm_tm_inc(struct dm_transaction_manager *tm, dm_block_t b); 104 void dm_tm_inc_range(struct dm_transaction_manager *tm, dm_block_t b, dm_block_t e); 105 void dm_tm_dec(struct dm_transaction_manager *tm, dm_block_t b); 106 void dm_tm_dec_range(struct dm_transaction_manager *tm, dm_block_t b, dm_block_t e); 107 108 /* 109 * Builds up runs of adjacent blocks, and then calls the given fn 110 * (typically dm_tm_inc/dec). Very useful when you have to perform 111 * the same tm operation on all values in a btree leaf. 112 */ 113 typedef void (*dm_tm_run_fn)(struct dm_transaction_manager *, dm_block_t, dm_block_t); 114 void dm_tm_with_runs(struct dm_transaction_manager *tm, 115 const __le64 *value_le, unsigned int count, dm_tm_run_fn fn); 116 117 int dm_tm_ref(struct dm_transaction_manager *tm, dm_block_t b, uint32_t *result); 118 119 /* 120 * Finds out if a given block is shared (ie. has a reference count higher 121 * than one). 122 */ 123 int dm_tm_block_is_shared(struct dm_transaction_manager *tm, dm_block_t b, 124 int *result); 125 126 struct dm_block_manager *dm_tm_get_bm(struct dm_transaction_manager *tm); 127 128 /* 129 * If you're using a non-blocking clone the tm will build up a list of 130 * requested blocks that weren't in core. This call will request those 131 * blocks to be prefetched. 132 */ 133 void dm_tm_issue_prefetches(struct dm_transaction_manager *tm); 134 135 /* 136 * A little utility that ties the knot by producing a transaction manager 137 * that has a space map managed by the transaction manager... 138 * 139 * Returns a tm that has an open transaction to write the new disk sm. 140 * Caller should store the new sm root and commit. 141 * 142 * The superblock location is passed so the metadata space map knows it 143 * shouldn't be used. 144 */ 145 int dm_tm_create_with_sm(struct dm_block_manager *bm, dm_block_t sb_location, 146 struct dm_transaction_manager **tm, 147 struct dm_space_map **sm); 148 149 int dm_tm_open_with_sm(struct dm_block_manager *bm, dm_block_t sb_location, 150 void *sm_root, size_t root_len, 151 struct dm_transaction_manager **tm, 152 struct dm_space_map **sm); 153 154 #endif /* _LINUX_DM_TRANSACTION_MANAGER_H */ 155