159 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 2001-2002 Sistina Software (UK) Limited.4 * Copyright (C) 2006-2008 Red Hat GmbH5 *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