1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2001-2002 Sistina Software (UK) Limited. 4 * Copyright (C) 2006-2008 Red Hat GmbH 5 * 6 * This file is released under the GPL. 7 */ 8 9 #include "dm-exception-store.h" 10 11 #include <linux/mm.h> 12 #include <linux/pagemap.h> 13 #include <linux/vmalloc.h> 14 #include <linux/export.h> 15 #include <linux/slab.h> 16 #include <linux/dm-io.h> 17 18 #define DM_MSG_PREFIX "transient snapshot" 19 20 /* 21 *--------------------------------------------------------------- 22 * Implementation of the store for non-persistent snapshots. 23 *--------------------------------------------------------------- 24 */ 25 struct transient_c { 26 sector_t next_free; 27 }; 28 29 static void transient_dtr(struct dm_exception_store *store) 30 { 31 kfree(store->context); 32 } 33 34 static int transient_read_metadata(struct dm_exception_store *store, 35 int (*callback)(void *callback_context, 36 chunk_t old, chunk_t new), 37 void *callback_context) 38 { 39 return 0; 40 } 41 42 static int transient_prepare_exception(struct dm_exception_store *store, 43 struct dm_exception *e) 44 { 45 struct transient_c *tc = store->context; 46 sector_t size = get_dev_size(dm_snap_cow(store->snap)->bdev); 47 48 if (size < (tc->next_free + store->chunk_size)) 49 return -1; 50 51 e->new_chunk = sector_to_chunk(store, tc->next_free); 52 tc->next_free += store->chunk_size; 53 54 return 0; 55 } 56 57 static void transient_commit_exception(struct dm_exception_store *store, 58 struct dm_exception *e, int valid, 59 void (*callback)(void *, int success), 60 void *callback_context) 61 { 62 /* Just succeed */ 63 callback(callback_context, valid); 64 } 65 66 static void transient_usage(struct dm_exception_store *store, 67 sector_t *total_sectors, 68 sector_t *sectors_allocated, 69 sector_t *metadata_sectors) 70 { 71 *sectors_allocated = ((struct transient_c *) store->context)->next_free; 72 *total_sectors = get_dev_size(dm_snap_cow(store->snap)->bdev); 73 *metadata_sectors = 0; 74 } 75 76 static int transient_ctr(struct dm_exception_store *store, char *options) 77 { 78 struct transient_c *tc; 79 80 tc = kmalloc(sizeof(struct transient_c), GFP_KERNEL); 81 if (!tc) 82 return -ENOMEM; 83 84 tc->next_free = 0; 85 store->context = tc; 86 87 return 0; 88 } 89 90 static unsigned int transient_status(struct dm_exception_store *store, 91 status_type_t status, char *result, 92 unsigned int maxlen) 93 { 94 unsigned int sz = 0; 95 96 switch (status) { 97 case STATUSTYPE_INFO: 98 break; 99 case STATUSTYPE_TABLE: 100 DMEMIT(" N %llu", (unsigned long long)store->chunk_size); 101 break; 102 case STATUSTYPE_IMA: 103 *result = '\0'; 104 break; 105 } 106 107 return sz; 108 } 109 110 static struct dm_exception_store_type _transient_type = { 111 .name = "transient", 112 .module = THIS_MODULE, 113 .ctr = transient_ctr, 114 .dtr = transient_dtr, 115 .read_metadata = transient_read_metadata, 116 .prepare_exception = transient_prepare_exception, 117 .commit_exception = transient_commit_exception, 118 .usage = transient_usage, 119 .status = transient_status, 120 }; 121 122 static struct dm_exception_store_type _transient_compat_type = { 123 .name = "N", 124 .module = THIS_MODULE, 125 .ctr = transient_ctr, 126 .dtr = transient_dtr, 127 .read_metadata = transient_read_metadata, 128 .prepare_exception = transient_prepare_exception, 129 .commit_exception = transient_commit_exception, 130 .usage = transient_usage, 131 .status = transient_status, 132 }; 133 134 int dm_transient_snapshot_init(void) 135 { 136 int r; 137 138 r = dm_exception_store_type_register(&_transient_type); 139 if (r) { 140 DMWARN("Unable to register transient exception store type"); 141 return r; 142 } 143 144 r = dm_exception_store_type_register(&_transient_compat_type); 145 if (r) { 146 DMWARN("Unable to register old-style transient exception store type"); 147 dm_exception_store_type_unregister(&_transient_type); 148 return r; 149 } 150 151 return r; 152 } 153 154 void dm_transient_snapshot_exit(void) 155 { 156 dm_exception_store_type_unregister(&_transient_type); 157 dm_exception_store_type_unregister(&_transient_compat_type); 158 } 159