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 */ 25struct transient_c { 26 sector_t next_free; 27}; 28 29static void transient_dtr(struct dm_exception_store *store) 30{ 31 kfree(store->context); 32} 33 34static 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 42static 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 57static 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 66static 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 76static 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 90static 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 110static 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 122static 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 134int 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 154void 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