#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: dm_target_snapshot.c,v 1.38 2020/01/21 16:27:53 tkusumi Exp $");
#include <sys/types.h>
#include <sys/param.h>
#include <sys/buf.h>
#include <sys/kmem.h>
#include "dm.h"
int dm_target_snapshot_init(dm_table_entry_t *, int, char **);
char *dm_target_snapshot_table(void *);
int dm_target_snapshot_strategy(dm_table_entry_t *, struct buf *);
int dm_target_snapshot_sync(dm_table_entry_t *);
int dm_target_snapshot_destroy(dm_table_entry_t *);
int dm_target_snapshot_orig_init(dm_table_entry_t *, int, char **);
char *dm_target_snapshot_orig_table(void *);
int dm_target_snapshot_orig_strategy(dm_table_entry_t *, struct buf *);
int dm_target_snapshot_orig_sync(dm_table_entry_t *);
int dm_target_snapshot_orig_destroy(dm_table_entry_t *);
typedef struct target_snapshot_config {
dm_pdev_t *tsc_snap_dev;
dm_pdev_t *tsc_cow_dev;
uint64_t tsc_chunk_size;
uint32_t tsc_persistent_dev;
} dm_target_snapshot_config_t;
typedef struct target_snapshot_origin_config {
dm_pdev_t *tsoc_real_dev;
} dm_target_snapshot_origin_config_t;
#ifdef DM_TARGET_MODULE
#include <sys/kernel.h>
#include <sys/module.h>
MODULE(MODULE_CLASS_MISC, dm_target_snapshot, "dm");
static int
dm_target_snapshot_modcmd(modcmd_t cmd, void *arg)
{
dm_target_t *dmt, *dmt1;
int r;
switch (cmd) {
case MODULE_CMD_INIT:
if (((dmt = dm_target_lookup("snapshot")) != NULL)) {
dm_target_unbusy(dmt);
return EEXIST;
}
if (((dmt = dm_target_lookup("snapshot-origin")) != NULL)) {
dm_target_unbusy(dmt);
return EEXIST;
}
dmt = dm_target_alloc("snapshot");
dmt1 = dm_target_alloc("snapshot-origin");
dmt->version[0] = 1;
dmt->version[1] = 0;
dmt->version[2] = 5;
dmt->init = &dm_target_snapshot_init;
dmt->table = &dm_target_snapshot_table;
dmt->strategy = &dm_target_snapshot_strategy;
dmt->sync = &dm_target_snapshot_sync;
dmt->destroy = &dm_target_snapshot_destroy;
r = dm_target_insert(dmt);
dmt1->version[0] = 1;
dmt1->version[1] = 0;
dmt1->version[2] = 5;
dmt1->init = &dm_target_snapshot_orig_init;
dmt1->table = &dm_target_snapshot_orig_table;
dmt1->strategy = &dm_target_snapshot_orig_strategy;
dmt1->sync = &dm_target_snapshot_orig_sync;
dmt1->destroy = &dm_target_snapshot_orig_destroy;
r = dm_target_insert(dmt1);
break;
case MODULE_CMD_FINI:
if ((r = dm_target_rem("snapshot")) == 0)
r = dm_target_rem("snapshot-origin");
break;
case MODULE_CMD_STAT:
return ENOTTY;
default:
return ENOTTY;
}
return r;
}
#endif
int
dm_target_snapshot_init(dm_table_entry_t *table_en, int argc, char **argv)
{
dm_target_snapshot_config_t *tsc;
dm_pdev_t *dmp_snap, *dmp_cow;
dmp_cow = NULL;
printf("Snapshot target init function called!!\n");
printf("Snapshotted device: %s, cow device %s,\n\t persistent flag: %s, "
"chunk size: %s\n", argv[0], argv[1], argv[2], argv[3]);
if ((dmp_snap = dm_pdev_insert(argv[0])) == NULL)
return ENOENT;
tsc = kmem_alloc(sizeof(*tsc), KM_SLEEP);
tsc->tsc_persistent_dev = 0;
if (strcmp(argv[2], "p") == 0) {
tsc->tsc_persistent_dev = 1;
if ((dmp_cow = dm_pdev_insert(argv[1])) == NULL) {
kmem_free(tsc, sizeof(*tsc));
return ENOENT;
}
}
tsc->tsc_chunk_size = atoi64(argv[3]);
tsc->tsc_snap_dev = dmp_snap;
tsc->tsc_cow_dev = dmp_cow;
dm_table_add_deps(table_en, dmp_snap);
dm_table_add_deps(table_en, dmp_cow);
table_en->target_config = tsc;
return 0;
}
char *
dm_target_snapshot_table(void *target_config)
{
dm_target_snapshot_config_t *tsc;
uint32_t i;
uint32_t count;
size_t prm_len, cow_len;
char *params;
tsc = target_config;
prm_len = 0;
cow_len = 0;
count = 0;
printf("Snapshot target table function called\n");
for (i = tsc->tsc_chunk_size; i != 0; i /= 10)
count++;
if (tsc->tsc_persistent_dev)
cow_len = strlen(tsc->tsc_cow_dev->name);
prm_len = strlen(tsc->tsc_snap_dev->name) + cow_len + count + 5;
params = kmem_alloc(prm_len, KM_SLEEP);
printf("%s %s %s %" PRIu64 "\n", tsc->tsc_snap_dev->name,
tsc->tsc_cow_dev->name, tsc->tsc_persistent_dev ? "p" : "n",
tsc->tsc_chunk_size);
snprintf(params, prm_len, "%s %s %s %" PRIu64, tsc->tsc_snap_dev->name,
tsc->tsc_persistent_dev ? tsc->tsc_cow_dev->name : "",
tsc->tsc_persistent_dev ? "p" : "n",
tsc->tsc_chunk_size);
return params;
}
int
dm_target_snapshot_strategy(dm_table_entry_t *table_en, struct buf *bp)
{
bp->b_error = EIO;
bp->b_resid = 0;
biodone(bp);
return 0;
}
int
dm_target_snapshot_sync(dm_table_entry_t *table_en)
{
return 0;
}
int
dm_target_snapshot_destroy(dm_table_entry_t *table_en)
{
if (table_en->target_config == NULL)
goto out;
printf("Snapshot target destroy function called\n");
dm_target_snapshot_config_t *tsc = table_en->target_config;
dm_pdev_decr(tsc->tsc_snap_dev);
if (tsc->tsc_persistent_dev)
dm_pdev_decr(tsc->tsc_cow_dev);
kmem_free(tsc, sizeof(*tsc));
out:
dm_target_unbusy(table_en->target);
return 0;
}
#if 0
int
dm_target_snapshot_upcall(dm_table_entry_t *table_en, struct buf *bp)
{
printf("dm_target_snapshot_upcall called\n");
printf("upcall buf flags %s %s\n",
(bp->b_flags & B_WRITE) ? "B_WRITE" : "",
(bp->b_flags & B_READ) ? "B_READ" : "");
return 0;
}
#endif
int
dm_target_snapshot_orig_init(dm_table_entry_t *table_en, int argc, char **argv)
{
dm_target_snapshot_origin_config_t *tsoc;
dm_pdev_t *dmp_real;
printf("Snapshot origin target init function called!!\n");
printf("Parent device: %s\n", argv[0]);
if ((dmp_real = dm_pdev_insert(argv[0])) == NULL)
return ENOENT;
tsoc = kmem_alloc(sizeof(dm_target_snapshot_origin_config_t), KM_SLEEP);
tsoc->tsoc_real_dev = dmp_real;
dm_table_add_deps(table_en, dmp_real);
table_en->target_config = tsoc;
return 0;
}
char *
dm_target_snapshot_orig_table(void *target_config)
{
dm_target_snapshot_origin_config_t *tsoc;
size_t prm_len;
char *params;
tsoc = target_config;
prm_len = 0;
printf("Snapshot origin target table function called\n");
prm_len = strlen(tsoc->tsoc_real_dev->name) + 1;
printf("real_dev name %s\n", tsoc->tsoc_real_dev->name);
params = kmem_alloc(prm_len, KM_SLEEP);
printf("%s\n", tsoc->tsoc_real_dev->name);
snprintf(params, prm_len, "%s", tsoc->tsoc_real_dev->name);
return params;
}
int
dm_target_snapshot_orig_strategy(dm_table_entry_t *table_en, struct buf *bp)
{
bp->b_error = EIO;
bp->b_resid = 0;
biodone(bp);
return 0;
}
int
dm_target_snapshot_orig_sync(dm_table_entry_t *table_en)
{
int cmd;
dm_target_snapshot_origin_config_t *tsoc;
tsoc = table_en->target_config;
cmd = 1;
return VOP_IOCTL(tsoc->tsoc_real_dev->pdev_vnode, DIOCCACHESYNC,
&cmd, FREAD|FWRITE, kauth_cred_get());
}
int
dm_target_snapshot_orig_destroy(dm_table_entry_t *table_en)
{
if (table_en->target_config == NULL)
goto out;
dm_target_snapshot_origin_config_t *tsoc = table_en->target_config;
dm_pdev_decr(tsoc->tsoc_real_dev);
kmem_free(tsoc, sizeof(*tsoc));
out:
dm_target_unbusy(table_en->target);
return 0;
}
#if 0
int
dm_target_snapshot_orig_upcall(dm_table_entry_t *table_en, struct buf *bp)
{
return 0;
}
#endif