18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (C) 2011 Red Hat, Inc. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * This file is released under the GPL. 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci#include "dm-block-manager.h" 78c2ecf20Sopenharmony_ci#include "dm-persistent-data-internal.h" 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/dm-bufio.h> 108c2ecf20Sopenharmony_ci#include <linux/crc32c.h> 118c2ecf20Sopenharmony_ci#include <linux/module.h> 128c2ecf20Sopenharmony_ci#include <linux/slab.h> 138c2ecf20Sopenharmony_ci#include <linux/rwsem.h> 148c2ecf20Sopenharmony_ci#include <linux/device-mapper.h> 158c2ecf20Sopenharmony_ci#include <linux/stacktrace.h> 168c2ecf20Sopenharmony_ci#include <linux/sched/task.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#define DM_MSG_PREFIX "block manager" 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci/*----------------------------------------------------------------*/ 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#ifdef CONFIG_DM_DEBUG_BLOCK_MANAGER_LOCKING 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci/* 258c2ecf20Sopenharmony_ci * This is a read/write semaphore with a couple of differences. 268c2ecf20Sopenharmony_ci * 278c2ecf20Sopenharmony_ci * i) There is a restriction on the number of concurrent read locks that 288c2ecf20Sopenharmony_ci * may be held at once. This is just an implementation detail. 298c2ecf20Sopenharmony_ci * 308c2ecf20Sopenharmony_ci * ii) Recursive locking attempts are detected and return EINVAL. A stack 318c2ecf20Sopenharmony_ci * trace is also emitted for the previous lock acquisition. 328c2ecf20Sopenharmony_ci * 338c2ecf20Sopenharmony_ci * iii) Priority is given to write locks. 348c2ecf20Sopenharmony_ci */ 358c2ecf20Sopenharmony_ci#define MAX_HOLDERS 4 368c2ecf20Sopenharmony_ci#define MAX_STACK 10 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_cistruct stack_store { 398c2ecf20Sopenharmony_ci unsigned int nr_entries; 408c2ecf20Sopenharmony_ci unsigned long entries[MAX_STACK]; 418c2ecf20Sopenharmony_ci}; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistruct block_lock { 448c2ecf20Sopenharmony_ci spinlock_t lock; 458c2ecf20Sopenharmony_ci __s32 count; 468c2ecf20Sopenharmony_ci struct list_head waiters; 478c2ecf20Sopenharmony_ci struct task_struct *holders[MAX_HOLDERS]; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci#ifdef CONFIG_DM_DEBUG_BLOCK_STACK_TRACING 508c2ecf20Sopenharmony_ci struct stack_store traces[MAX_HOLDERS]; 518c2ecf20Sopenharmony_ci#endif 528c2ecf20Sopenharmony_ci}; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_cistruct waiter { 558c2ecf20Sopenharmony_ci struct list_head list; 568c2ecf20Sopenharmony_ci struct task_struct *task; 578c2ecf20Sopenharmony_ci int wants_write; 588c2ecf20Sopenharmony_ci}; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_cistatic unsigned __find_holder(struct block_lock *lock, 618c2ecf20Sopenharmony_ci struct task_struct *task) 628c2ecf20Sopenharmony_ci{ 638c2ecf20Sopenharmony_ci unsigned i; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci for (i = 0; i < MAX_HOLDERS; i++) 668c2ecf20Sopenharmony_ci if (lock->holders[i] == task) 678c2ecf20Sopenharmony_ci break; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci BUG_ON(i == MAX_HOLDERS); 708c2ecf20Sopenharmony_ci return i; 718c2ecf20Sopenharmony_ci} 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci/* call this *after* you increment lock->count */ 748c2ecf20Sopenharmony_cistatic void __add_holder(struct block_lock *lock, struct task_struct *task) 758c2ecf20Sopenharmony_ci{ 768c2ecf20Sopenharmony_ci unsigned h = __find_holder(lock, NULL); 778c2ecf20Sopenharmony_ci#ifdef CONFIG_DM_DEBUG_BLOCK_STACK_TRACING 788c2ecf20Sopenharmony_ci struct stack_store *t; 798c2ecf20Sopenharmony_ci#endif 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci get_task_struct(task); 828c2ecf20Sopenharmony_ci lock->holders[h] = task; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci#ifdef CONFIG_DM_DEBUG_BLOCK_STACK_TRACING 858c2ecf20Sopenharmony_ci t = lock->traces + h; 868c2ecf20Sopenharmony_ci t->nr_entries = stack_trace_save(t->entries, MAX_STACK, 2); 878c2ecf20Sopenharmony_ci#endif 888c2ecf20Sopenharmony_ci} 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci/* call this *before* you decrement lock->count */ 918c2ecf20Sopenharmony_cistatic void __del_holder(struct block_lock *lock, struct task_struct *task) 928c2ecf20Sopenharmony_ci{ 938c2ecf20Sopenharmony_ci unsigned h = __find_holder(lock, task); 948c2ecf20Sopenharmony_ci lock->holders[h] = NULL; 958c2ecf20Sopenharmony_ci put_task_struct(task); 968c2ecf20Sopenharmony_ci} 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_cistatic int __check_holder(struct block_lock *lock) 998c2ecf20Sopenharmony_ci{ 1008c2ecf20Sopenharmony_ci unsigned i; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci for (i = 0; i < MAX_HOLDERS; i++) { 1038c2ecf20Sopenharmony_ci if (lock->holders[i] == current) { 1048c2ecf20Sopenharmony_ci DMERR("recursive lock detected in metadata"); 1058c2ecf20Sopenharmony_ci#ifdef CONFIG_DM_DEBUG_BLOCK_STACK_TRACING 1068c2ecf20Sopenharmony_ci DMERR("previously held here:"); 1078c2ecf20Sopenharmony_ci stack_trace_print(lock->traces[i].entries, 1088c2ecf20Sopenharmony_ci lock->traces[i].nr_entries, 4); 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci DMERR("subsequent acquisition attempted here:"); 1118c2ecf20Sopenharmony_ci dump_stack(); 1128c2ecf20Sopenharmony_ci#endif 1138c2ecf20Sopenharmony_ci return -EINVAL; 1148c2ecf20Sopenharmony_ci } 1158c2ecf20Sopenharmony_ci } 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci return 0; 1188c2ecf20Sopenharmony_ci} 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_cistatic void __wait(struct waiter *w) 1218c2ecf20Sopenharmony_ci{ 1228c2ecf20Sopenharmony_ci for (;;) { 1238c2ecf20Sopenharmony_ci set_current_state(TASK_UNINTERRUPTIBLE); 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci if (!w->task) 1268c2ecf20Sopenharmony_ci break; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci schedule(); 1298c2ecf20Sopenharmony_ci } 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci set_current_state(TASK_RUNNING); 1328c2ecf20Sopenharmony_ci} 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_cistatic void __wake_waiter(struct waiter *w) 1358c2ecf20Sopenharmony_ci{ 1368c2ecf20Sopenharmony_ci struct task_struct *task; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci list_del(&w->list); 1398c2ecf20Sopenharmony_ci task = w->task; 1408c2ecf20Sopenharmony_ci smp_mb(); 1418c2ecf20Sopenharmony_ci w->task = NULL; 1428c2ecf20Sopenharmony_ci wake_up_process(task); 1438c2ecf20Sopenharmony_ci} 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci/* 1468c2ecf20Sopenharmony_ci * We either wake a few readers or a single writer. 1478c2ecf20Sopenharmony_ci */ 1488c2ecf20Sopenharmony_cistatic void __wake_many(struct block_lock *lock) 1498c2ecf20Sopenharmony_ci{ 1508c2ecf20Sopenharmony_ci struct waiter *w, *tmp; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci BUG_ON(lock->count < 0); 1538c2ecf20Sopenharmony_ci list_for_each_entry_safe(w, tmp, &lock->waiters, list) { 1548c2ecf20Sopenharmony_ci if (lock->count >= MAX_HOLDERS) 1558c2ecf20Sopenharmony_ci return; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci if (w->wants_write) { 1588c2ecf20Sopenharmony_ci if (lock->count > 0) 1598c2ecf20Sopenharmony_ci return; /* still read locked */ 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci lock->count = -1; 1628c2ecf20Sopenharmony_ci __add_holder(lock, w->task); 1638c2ecf20Sopenharmony_ci __wake_waiter(w); 1648c2ecf20Sopenharmony_ci return; 1658c2ecf20Sopenharmony_ci } 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci lock->count++; 1688c2ecf20Sopenharmony_ci __add_holder(lock, w->task); 1698c2ecf20Sopenharmony_ci __wake_waiter(w); 1708c2ecf20Sopenharmony_ci } 1718c2ecf20Sopenharmony_ci} 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_cistatic void bl_init(struct block_lock *lock) 1748c2ecf20Sopenharmony_ci{ 1758c2ecf20Sopenharmony_ci int i; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci spin_lock_init(&lock->lock); 1788c2ecf20Sopenharmony_ci lock->count = 0; 1798c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&lock->waiters); 1808c2ecf20Sopenharmony_ci for (i = 0; i < MAX_HOLDERS; i++) 1818c2ecf20Sopenharmony_ci lock->holders[i] = NULL; 1828c2ecf20Sopenharmony_ci} 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_cistatic int __available_for_read(struct block_lock *lock) 1858c2ecf20Sopenharmony_ci{ 1868c2ecf20Sopenharmony_ci return lock->count >= 0 && 1878c2ecf20Sopenharmony_ci lock->count < MAX_HOLDERS && 1888c2ecf20Sopenharmony_ci list_empty(&lock->waiters); 1898c2ecf20Sopenharmony_ci} 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_cistatic int bl_down_read(struct block_lock *lock) 1928c2ecf20Sopenharmony_ci{ 1938c2ecf20Sopenharmony_ci int r; 1948c2ecf20Sopenharmony_ci struct waiter w; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci spin_lock(&lock->lock); 1978c2ecf20Sopenharmony_ci r = __check_holder(lock); 1988c2ecf20Sopenharmony_ci if (r) { 1998c2ecf20Sopenharmony_ci spin_unlock(&lock->lock); 2008c2ecf20Sopenharmony_ci return r; 2018c2ecf20Sopenharmony_ci } 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci if (__available_for_read(lock)) { 2048c2ecf20Sopenharmony_ci lock->count++; 2058c2ecf20Sopenharmony_ci __add_holder(lock, current); 2068c2ecf20Sopenharmony_ci spin_unlock(&lock->lock); 2078c2ecf20Sopenharmony_ci return 0; 2088c2ecf20Sopenharmony_ci } 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci get_task_struct(current); 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci w.task = current; 2138c2ecf20Sopenharmony_ci w.wants_write = 0; 2148c2ecf20Sopenharmony_ci list_add_tail(&w.list, &lock->waiters); 2158c2ecf20Sopenharmony_ci spin_unlock(&lock->lock); 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci __wait(&w); 2188c2ecf20Sopenharmony_ci put_task_struct(current); 2198c2ecf20Sopenharmony_ci return 0; 2208c2ecf20Sopenharmony_ci} 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_cistatic int bl_down_read_nonblock(struct block_lock *lock) 2238c2ecf20Sopenharmony_ci{ 2248c2ecf20Sopenharmony_ci int r; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci spin_lock(&lock->lock); 2278c2ecf20Sopenharmony_ci r = __check_holder(lock); 2288c2ecf20Sopenharmony_ci if (r) 2298c2ecf20Sopenharmony_ci goto out; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci if (__available_for_read(lock)) { 2328c2ecf20Sopenharmony_ci lock->count++; 2338c2ecf20Sopenharmony_ci __add_holder(lock, current); 2348c2ecf20Sopenharmony_ci r = 0; 2358c2ecf20Sopenharmony_ci } else 2368c2ecf20Sopenharmony_ci r = -EWOULDBLOCK; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ciout: 2398c2ecf20Sopenharmony_ci spin_unlock(&lock->lock); 2408c2ecf20Sopenharmony_ci return r; 2418c2ecf20Sopenharmony_ci} 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_cistatic void bl_up_read(struct block_lock *lock) 2448c2ecf20Sopenharmony_ci{ 2458c2ecf20Sopenharmony_ci spin_lock(&lock->lock); 2468c2ecf20Sopenharmony_ci BUG_ON(lock->count <= 0); 2478c2ecf20Sopenharmony_ci __del_holder(lock, current); 2488c2ecf20Sopenharmony_ci --lock->count; 2498c2ecf20Sopenharmony_ci if (!list_empty(&lock->waiters)) 2508c2ecf20Sopenharmony_ci __wake_many(lock); 2518c2ecf20Sopenharmony_ci spin_unlock(&lock->lock); 2528c2ecf20Sopenharmony_ci} 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_cistatic int bl_down_write(struct block_lock *lock) 2558c2ecf20Sopenharmony_ci{ 2568c2ecf20Sopenharmony_ci int r; 2578c2ecf20Sopenharmony_ci struct waiter w; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci spin_lock(&lock->lock); 2608c2ecf20Sopenharmony_ci r = __check_holder(lock); 2618c2ecf20Sopenharmony_ci if (r) { 2628c2ecf20Sopenharmony_ci spin_unlock(&lock->lock); 2638c2ecf20Sopenharmony_ci return r; 2648c2ecf20Sopenharmony_ci } 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci if (lock->count == 0 && list_empty(&lock->waiters)) { 2678c2ecf20Sopenharmony_ci lock->count = -1; 2688c2ecf20Sopenharmony_ci __add_holder(lock, current); 2698c2ecf20Sopenharmony_ci spin_unlock(&lock->lock); 2708c2ecf20Sopenharmony_ci return 0; 2718c2ecf20Sopenharmony_ci } 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci get_task_struct(current); 2748c2ecf20Sopenharmony_ci w.task = current; 2758c2ecf20Sopenharmony_ci w.wants_write = 1; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci /* 2788c2ecf20Sopenharmony_ci * Writers given priority. We know there's only one mutator in the 2798c2ecf20Sopenharmony_ci * system, so ignoring the ordering reversal. 2808c2ecf20Sopenharmony_ci */ 2818c2ecf20Sopenharmony_ci list_add(&w.list, &lock->waiters); 2828c2ecf20Sopenharmony_ci spin_unlock(&lock->lock); 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci __wait(&w); 2858c2ecf20Sopenharmony_ci put_task_struct(current); 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci return 0; 2888c2ecf20Sopenharmony_ci} 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_cistatic void bl_up_write(struct block_lock *lock) 2918c2ecf20Sopenharmony_ci{ 2928c2ecf20Sopenharmony_ci spin_lock(&lock->lock); 2938c2ecf20Sopenharmony_ci __del_holder(lock, current); 2948c2ecf20Sopenharmony_ci lock->count = 0; 2958c2ecf20Sopenharmony_ci if (!list_empty(&lock->waiters)) 2968c2ecf20Sopenharmony_ci __wake_many(lock); 2978c2ecf20Sopenharmony_ci spin_unlock(&lock->lock); 2988c2ecf20Sopenharmony_ci} 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_cistatic void report_recursive_bug(dm_block_t b, int r) 3018c2ecf20Sopenharmony_ci{ 3028c2ecf20Sopenharmony_ci if (r == -EINVAL) 3038c2ecf20Sopenharmony_ci DMERR("recursive acquisition of block %llu requested.", 3048c2ecf20Sopenharmony_ci (unsigned long long) b); 3058c2ecf20Sopenharmony_ci} 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci#else /* !CONFIG_DM_DEBUG_BLOCK_MANAGER_LOCKING */ 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci#define bl_init(x) do { } while (0) 3108c2ecf20Sopenharmony_ci#define bl_down_read(x) 0 3118c2ecf20Sopenharmony_ci#define bl_down_read_nonblock(x) 0 3128c2ecf20Sopenharmony_ci#define bl_up_read(x) do { } while (0) 3138c2ecf20Sopenharmony_ci#define bl_down_write(x) 0 3148c2ecf20Sopenharmony_ci#define bl_up_write(x) do { } while (0) 3158c2ecf20Sopenharmony_ci#define report_recursive_bug(x, y) do { } while (0) 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci#endif /* CONFIG_DM_DEBUG_BLOCK_MANAGER_LOCKING */ 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci/*----------------------------------------------------------------*/ 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci/* 3228c2ecf20Sopenharmony_ci * Block manager is currently implemented using dm-bufio. struct 3238c2ecf20Sopenharmony_ci * dm_block_manager and struct dm_block map directly onto a couple of 3248c2ecf20Sopenharmony_ci * structs in the bufio interface. I want to retain the freedom to move 3258c2ecf20Sopenharmony_ci * away from bufio in the future. So these structs are just cast within 3268c2ecf20Sopenharmony_ci * this .c file, rather than making it through to the public interface. 3278c2ecf20Sopenharmony_ci */ 3288c2ecf20Sopenharmony_cistatic struct dm_buffer *to_buffer(struct dm_block *b) 3298c2ecf20Sopenharmony_ci{ 3308c2ecf20Sopenharmony_ci return (struct dm_buffer *) b; 3318c2ecf20Sopenharmony_ci} 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_cidm_block_t dm_block_location(struct dm_block *b) 3348c2ecf20Sopenharmony_ci{ 3358c2ecf20Sopenharmony_ci return dm_bufio_get_block_number(to_buffer(b)); 3368c2ecf20Sopenharmony_ci} 3378c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dm_block_location); 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_civoid *dm_block_data(struct dm_block *b) 3408c2ecf20Sopenharmony_ci{ 3418c2ecf20Sopenharmony_ci return dm_bufio_get_block_data(to_buffer(b)); 3428c2ecf20Sopenharmony_ci} 3438c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dm_block_data); 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_cistruct buffer_aux { 3468c2ecf20Sopenharmony_ci struct dm_block_validator *validator; 3478c2ecf20Sopenharmony_ci int write_locked; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci#ifdef CONFIG_DM_DEBUG_BLOCK_MANAGER_LOCKING 3508c2ecf20Sopenharmony_ci struct block_lock lock; 3518c2ecf20Sopenharmony_ci#endif 3528c2ecf20Sopenharmony_ci}; 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_cistatic void dm_block_manager_alloc_callback(struct dm_buffer *buf) 3558c2ecf20Sopenharmony_ci{ 3568c2ecf20Sopenharmony_ci struct buffer_aux *aux = dm_bufio_get_aux_data(buf); 3578c2ecf20Sopenharmony_ci aux->validator = NULL; 3588c2ecf20Sopenharmony_ci bl_init(&aux->lock); 3598c2ecf20Sopenharmony_ci} 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_cistatic void dm_block_manager_write_callback(struct dm_buffer *buf) 3628c2ecf20Sopenharmony_ci{ 3638c2ecf20Sopenharmony_ci struct buffer_aux *aux = dm_bufio_get_aux_data(buf); 3648c2ecf20Sopenharmony_ci if (aux->validator) { 3658c2ecf20Sopenharmony_ci aux->validator->prepare_for_write(aux->validator, (struct dm_block *) buf, 3668c2ecf20Sopenharmony_ci dm_bufio_get_block_size(dm_bufio_get_client(buf))); 3678c2ecf20Sopenharmony_ci } 3688c2ecf20Sopenharmony_ci} 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci/*---------------------------------------------------------------- 3718c2ecf20Sopenharmony_ci * Public interface 3728c2ecf20Sopenharmony_ci *--------------------------------------------------------------*/ 3738c2ecf20Sopenharmony_cistruct dm_block_manager { 3748c2ecf20Sopenharmony_ci struct dm_bufio_client *bufio; 3758c2ecf20Sopenharmony_ci bool read_only:1; 3768c2ecf20Sopenharmony_ci}; 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_cistruct dm_block_manager *dm_block_manager_create(struct block_device *bdev, 3798c2ecf20Sopenharmony_ci unsigned block_size, 3808c2ecf20Sopenharmony_ci unsigned max_held_per_thread) 3818c2ecf20Sopenharmony_ci{ 3828c2ecf20Sopenharmony_ci int r; 3838c2ecf20Sopenharmony_ci struct dm_block_manager *bm; 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci bm = kmalloc(sizeof(*bm), GFP_KERNEL); 3868c2ecf20Sopenharmony_ci if (!bm) { 3878c2ecf20Sopenharmony_ci r = -ENOMEM; 3888c2ecf20Sopenharmony_ci goto bad; 3898c2ecf20Sopenharmony_ci } 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci bm->bufio = dm_bufio_client_create(bdev, block_size, max_held_per_thread, 3928c2ecf20Sopenharmony_ci sizeof(struct buffer_aux), 3938c2ecf20Sopenharmony_ci dm_block_manager_alloc_callback, 3948c2ecf20Sopenharmony_ci dm_block_manager_write_callback); 3958c2ecf20Sopenharmony_ci if (IS_ERR(bm->bufio)) { 3968c2ecf20Sopenharmony_ci r = PTR_ERR(bm->bufio); 3978c2ecf20Sopenharmony_ci kfree(bm); 3988c2ecf20Sopenharmony_ci goto bad; 3998c2ecf20Sopenharmony_ci } 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci bm->read_only = false; 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci return bm; 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_cibad: 4068c2ecf20Sopenharmony_ci return ERR_PTR(r); 4078c2ecf20Sopenharmony_ci} 4088c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dm_block_manager_create); 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_civoid dm_block_manager_destroy(struct dm_block_manager *bm) 4118c2ecf20Sopenharmony_ci{ 4128c2ecf20Sopenharmony_ci dm_bufio_client_destroy(bm->bufio); 4138c2ecf20Sopenharmony_ci kfree(bm); 4148c2ecf20Sopenharmony_ci} 4158c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dm_block_manager_destroy); 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ciunsigned dm_bm_block_size(struct dm_block_manager *bm) 4188c2ecf20Sopenharmony_ci{ 4198c2ecf20Sopenharmony_ci return dm_bufio_get_block_size(bm->bufio); 4208c2ecf20Sopenharmony_ci} 4218c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dm_bm_block_size); 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_cidm_block_t dm_bm_nr_blocks(struct dm_block_manager *bm) 4248c2ecf20Sopenharmony_ci{ 4258c2ecf20Sopenharmony_ci return dm_bufio_get_device_size(bm->bufio); 4268c2ecf20Sopenharmony_ci} 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_cistatic int dm_bm_validate_buffer(struct dm_block_manager *bm, 4298c2ecf20Sopenharmony_ci struct dm_buffer *buf, 4308c2ecf20Sopenharmony_ci struct buffer_aux *aux, 4318c2ecf20Sopenharmony_ci struct dm_block_validator *v) 4328c2ecf20Sopenharmony_ci{ 4338c2ecf20Sopenharmony_ci if (unlikely(!aux->validator)) { 4348c2ecf20Sopenharmony_ci int r; 4358c2ecf20Sopenharmony_ci if (!v) 4368c2ecf20Sopenharmony_ci return 0; 4378c2ecf20Sopenharmony_ci r = v->check(v, (struct dm_block *) buf, dm_bufio_get_block_size(bm->bufio)); 4388c2ecf20Sopenharmony_ci if (unlikely(r)) { 4398c2ecf20Sopenharmony_ci DMERR_LIMIT("%s validator check failed for block %llu", v->name, 4408c2ecf20Sopenharmony_ci (unsigned long long) dm_bufio_get_block_number(buf)); 4418c2ecf20Sopenharmony_ci return r; 4428c2ecf20Sopenharmony_ci } 4438c2ecf20Sopenharmony_ci aux->validator = v; 4448c2ecf20Sopenharmony_ci } else { 4458c2ecf20Sopenharmony_ci if (unlikely(aux->validator != v)) { 4468c2ecf20Sopenharmony_ci DMERR_LIMIT("validator mismatch (old=%s vs new=%s) for block %llu", 4478c2ecf20Sopenharmony_ci aux->validator->name, v ? v->name : "NULL", 4488c2ecf20Sopenharmony_ci (unsigned long long) dm_bufio_get_block_number(buf)); 4498c2ecf20Sopenharmony_ci return -EINVAL; 4508c2ecf20Sopenharmony_ci } 4518c2ecf20Sopenharmony_ci } 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci return 0; 4548c2ecf20Sopenharmony_ci} 4558c2ecf20Sopenharmony_ciint dm_bm_read_lock(struct dm_block_manager *bm, dm_block_t b, 4568c2ecf20Sopenharmony_ci struct dm_block_validator *v, 4578c2ecf20Sopenharmony_ci struct dm_block **result) 4588c2ecf20Sopenharmony_ci{ 4598c2ecf20Sopenharmony_ci struct buffer_aux *aux; 4608c2ecf20Sopenharmony_ci void *p; 4618c2ecf20Sopenharmony_ci int r; 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci p = dm_bufio_read(bm->bufio, b, (struct dm_buffer **) result); 4648c2ecf20Sopenharmony_ci if (IS_ERR(p)) 4658c2ecf20Sopenharmony_ci return PTR_ERR(p); 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci aux = dm_bufio_get_aux_data(to_buffer(*result)); 4688c2ecf20Sopenharmony_ci r = bl_down_read(&aux->lock); 4698c2ecf20Sopenharmony_ci if (unlikely(r)) { 4708c2ecf20Sopenharmony_ci dm_bufio_release(to_buffer(*result)); 4718c2ecf20Sopenharmony_ci report_recursive_bug(b, r); 4728c2ecf20Sopenharmony_ci return r; 4738c2ecf20Sopenharmony_ci } 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci aux->write_locked = 0; 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci r = dm_bm_validate_buffer(bm, to_buffer(*result), aux, v); 4788c2ecf20Sopenharmony_ci if (unlikely(r)) { 4798c2ecf20Sopenharmony_ci bl_up_read(&aux->lock); 4808c2ecf20Sopenharmony_ci dm_bufio_release(to_buffer(*result)); 4818c2ecf20Sopenharmony_ci return r; 4828c2ecf20Sopenharmony_ci } 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci return 0; 4858c2ecf20Sopenharmony_ci} 4868c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dm_bm_read_lock); 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ciint dm_bm_write_lock(struct dm_block_manager *bm, 4898c2ecf20Sopenharmony_ci dm_block_t b, struct dm_block_validator *v, 4908c2ecf20Sopenharmony_ci struct dm_block **result) 4918c2ecf20Sopenharmony_ci{ 4928c2ecf20Sopenharmony_ci struct buffer_aux *aux; 4938c2ecf20Sopenharmony_ci void *p; 4948c2ecf20Sopenharmony_ci int r; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci if (dm_bm_is_read_only(bm)) 4978c2ecf20Sopenharmony_ci return -EPERM; 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci p = dm_bufio_read(bm->bufio, b, (struct dm_buffer **) result); 5008c2ecf20Sopenharmony_ci if (IS_ERR(p)) 5018c2ecf20Sopenharmony_ci return PTR_ERR(p); 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci aux = dm_bufio_get_aux_data(to_buffer(*result)); 5048c2ecf20Sopenharmony_ci r = bl_down_write(&aux->lock); 5058c2ecf20Sopenharmony_ci if (r) { 5068c2ecf20Sopenharmony_ci dm_bufio_release(to_buffer(*result)); 5078c2ecf20Sopenharmony_ci report_recursive_bug(b, r); 5088c2ecf20Sopenharmony_ci return r; 5098c2ecf20Sopenharmony_ci } 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci aux->write_locked = 1; 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci r = dm_bm_validate_buffer(bm, to_buffer(*result), aux, v); 5148c2ecf20Sopenharmony_ci if (unlikely(r)) { 5158c2ecf20Sopenharmony_ci bl_up_write(&aux->lock); 5168c2ecf20Sopenharmony_ci dm_bufio_release(to_buffer(*result)); 5178c2ecf20Sopenharmony_ci return r; 5188c2ecf20Sopenharmony_ci } 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci return 0; 5218c2ecf20Sopenharmony_ci} 5228c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dm_bm_write_lock); 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ciint dm_bm_read_try_lock(struct dm_block_manager *bm, 5258c2ecf20Sopenharmony_ci dm_block_t b, struct dm_block_validator *v, 5268c2ecf20Sopenharmony_ci struct dm_block **result) 5278c2ecf20Sopenharmony_ci{ 5288c2ecf20Sopenharmony_ci struct buffer_aux *aux; 5298c2ecf20Sopenharmony_ci void *p; 5308c2ecf20Sopenharmony_ci int r; 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci p = dm_bufio_get(bm->bufio, b, (struct dm_buffer **) result); 5338c2ecf20Sopenharmony_ci if (IS_ERR(p)) 5348c2ecf20Sopenharmony_ci return PTR_ERR(p); 5358c2ecf20Sopenharmony_ci if (unlikely(!p)) 5368c2ecf20Sopenharmony_ci return -EWOULDBLOCK; 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci aux = dm_bufio_get_aux_data(to_buffer(*result)); 5398c2ecf20Sopenharmony_ci r = bl_down_read_nonblock(&aux->lock); 5408c2ecf20Sopenharmony_ci if (r < 0) { 5418c2ecf20Sopenharmony_ci dm_bufio_release(to_buffer(*result)); 5428c2ecf20Sopenharmony_ci report_recursive_bug(b, r); 5438c2ecf20Sopenharmony_ci return r; 5448c2ecf20Sopenharmony_ci } 5458c2ecf20Sopenharmony_ci aux->write_locked = 0; 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci r = dm_bm_validate_buffer(bm, to_buffer(*result), aux, v); 5488c2ecf20Sopenharmony_ci if (unlikely(r)) { 5498c2ecf20Sopenharmony_ci bl_up_read(&aux->lock); 5508c2ecf20Sopenharmony_ci dm_bufio_release(to_buffer(*result)); 5518c2ecf20Sopenharmony_ci return r; 5528c2ecf20Sopenharmony_ci } 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci return 0; 5558c2ecf20Sopenharmony_ci} 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ciint dm_bm_write_lock_zero(struct dm_block_manager *bm, 5588c2ecf20Sopenharmony_ci dm_block_t b, struct dm_block_validator *v, 5598c2ecf20Sopenharmony_ci struct dm_block **result) 5608c2ecf20Sopenharmony_ci{ 5618c2ecf20Sopenharmony_ci int r; 5628c2ecf20Sopenharmony_ci struct buffer_aux *aux; 5638c2ecf20Sopenharmony_ci void *p; 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci if (dm_bm_is_read_only(bm)) 5668c2ecf20Sopenharmony_ci return -EPERM; 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci p = dm_bufio_new(bm->bufio, b, (struct dm_buffer **) result); 5698c2ecf20Sopenharmony_ci if (IS_ERR(p)) 5708c2ecf20Sopenharmony_ci return PTR_ERR(p); 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci memset(p, 0, dm_bm_block_size(bm)); 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci aux = dm_bufio_get_aux_data(to_buffer(*result)); 5758c2ecf20Sopenharmony_ci r = bl_down_write(&aux->lock); 5768c2ecf20Sopenharmony_ci if (r) { 5778c2ecf20Sopenharmony_ci dm_bufio_release(to_buffer(*result)); 5788c2ecf20Sopenharmony_ci return r; 5798c2ecf20Sopenharmony_ci } 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci aux->write_locked = 1; 5828c2ecf20Sopenharmony_ci aux->validator = v; 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci return 0; 5858c2ecf20Sopenharmony_ci} 5868c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dm_bm_write_lock_zero); 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_civoid dm_bm_unlock(struct dm_block *b) 5898c2ecf20Sopenharmony_ci{ 5908c2ecf20Sopenharmony_ci struct buffer_aux *aux; 5918c2ecf20Sopenharmony_ci aux = dm_bufio_get_aux_data(to_buffer(b)); 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci if (aux->write_locked) { 5948c2ecf20Sopenharmony_ci dm_bufio_mark_buffer_dirty(to_buffer(b)); 5958c2ecf20Sopenharmony_ci bl_up_write(&aux->lock); 5968c2ecf20Sopenharmony_ci } else 5978c2ecf20Sopenharmony_ci bl_up_read(&aux->lock); 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci dm_bufio_release(to_buffer(b)); 6008c2ecf20Sopenharmony_ci} 6018c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dm_bm_unlock); 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ciint dm_bm_flush(struct dm_block_manager *bm) 6048c2ecf20Sopenharmony_ci{ 6058c2ecf20Sopenharmony_ci if (dm_bm_is_read_only(bm)) 6068c2ecf20Sopenharmony_ci return -EPERM; 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci return dm_bufio_write_dirty_buffers(bm->bufio); 6098c2ecf20Sopenharmony_ci} 6108c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dm_bm_flush); 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_civoid dm_bm_prefetch(struct dm_block_manager *bm, dm_block_t b) 6138c2ecf20Sopenharmony_ci{ 6148c2ecf20Sopenharmony_ci dm_bufio_prefetch(bm->bufio, b, 1); 6158c2ecf20Sopenharmony_ci} 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_cibool dm_bm_is_read_only(struct dm_block_manager *bm) 6188c2ecf20Sopenharmony_ci{ 6198c2ecf20Sopenharmony_ci return (bm ? bm->read_only : true); 6208c2ecf20Sopenharmony_ci} 6218c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dm_bm_is_read_only); 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_civoid dm_bm_set_read_only(struct dm_block_manager *bm) 6248c2ecf20Sopenharmony_ci{ 6258c2ecf20Sopenharmony_ci if (bm) 6268c2ecf20Sopenharmony_ci bm->read_only = true; 6278c2ecf20Sopenharmony_ci} 6288c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dm_bm_set_read_only); 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_civoid dm_bm_set_read_write(struct dm_block_manager *bm) 6318c2ecf20Sopenharmony_ci{ 6328c2ecf20Sopenharmony_ci if (bm) 6338c2ecf20Sopenharmony_ci bm->read_only = false; 6348c2ecf20Sopenharmony_ci} 6358c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dm_bm_set_read_write); 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ciu32 dm_bm_checksum(const void *data, size_t len, u32 init_xor) 6388c2ecf20Sopenharmony_ci{ 6398c2ecf20Sopenharmony_ci return crc32c(~(u32) 0, data, len) ^ init_xor; 6408c2ecf20Sopenharmony_ci} 6418c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dm_bm_checksum); 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci/*----------------------------------------------------------------*/ 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 6468c2ecf20Sopenharmony_ciMODULE_AUTHOR("Joe Thornber <dm-devel@redhat.com>"); 6478c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Immutable metadata library for dm"); 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci/*----------------------------------------------------------------*/ 650