1
0
mirror of git://sourceware.org/git/lvm2.git synced 2024-12-21 13:34:40 +03:00

Support for v4 interface

This commit is contained in:
Alasdair Kergon 2003-07-01 21:20:58 +00:00
parent 46a68b7dd6
commit d71bfabe39
7 changed files with 556 additions and 101 deletions

View File

@ -10,6 +10,8 @@ Base {
dm_task_get_driver_version; dm_task_get_driver_version;
dm_task_get_info; dm_task_get_info;
dm_task_get_deps; dm_task_get_deps;
dm_task_get_name;
dm_task_get_names;
dm_task_get_uuid; dm_task_get_uuid;
dm_task_set_ro; dm_task_set_ro;
dm_task_set_newname; dm_task_set_newname;
@ -21,6 +23,9 @@ Base {
dm_task_run; dm_task_run;
dm_set_dev_dir; dm_set_dev_dir;
dm_dir; dm_dir;
dm_format_dev;
dm_lib_release;
dm_lib_exit;
local: local:
*; *;
}; };

View File

@ -13,7 +13,10 @@
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include <fcntl.h> #include <fcntl.h>
#include <dirent.h>
#include <errno.h> #include <errno.h>
#include <sys/stat.h>
#include <limits.h>
#include <linux/limits.h> #include <linux/limits.h>
/* /*
@ -31,6 +34,10 @@
static int _dm_version = DM_VERSION_MAJOR; static int _dm_version = DM_VERSION_MAJOR;
static int _log_suppress = 0; static int _log_suppress = 0;
static int _control_fd = -1;
static int _version_checked = 0;
static int _version_ok = 1;
/* /*
* Support both old and new major numbers to ease the transition. * Support both old and new major numbers to ease the transition.
* Clumsy, but only temporary. * Clumsy, but only temporary.
@ -45,18 +52,20 @@ const int _dm_compat = 0;
/* *INDENT-OFF* */ /* *INDENT-OFF* */
static struct cmd_data _cmd_data_v4[] = { static struct cmd_data _cmd_data_v4[] = {
{"create", DM_DEV_CREATE, {4, 0, 0}}, {"create", DM_DEV_CREATE, {4, 0, 0}},
{"reload", DM_DEV_RELOAD, {4, 0, 0}}, {"reload", DM_TABLE_LOAD, {4, 0, 0}},
{"remove", DM_DEV_REMOVE, {4, 0, 0}}, {"remove", DM_DEV_REMOVE, {4, 0, 0}},
{"remove_all", DM_REMOVE_ALL, {4, 0, 0}}, {"remove_all", DM_REMOVE_ALL, {4, 0, 0}},
{"suspend", DM_DEV_SUSPEND, {4, 0, 0}}, {"suspend", DM_DEV_SUSPEND, {4, 0, 0}},
{"resume", DM_DEV_SUSPEND, {4, 0, 0}}, {"resume", DM_DEV_SUSPEND, {4, 0, 0}},
{"info", DM_DEV_STATUS, {4, 0, 0}}, {"info", DM_DEV_STATUS, {4, 0, 0}},
{"deps", DM_DEV_DEPS, {4, 0, 0}}, {"deps", DM_TABLE_DEPS, {4, 0, 0}},
{"rename", DM_DEV_RENAME, {4, 0, 0}}, {"rename", DM_DEV_RENAME, {4, 0, 0}},
{"version", DM_VERSION, {4, 0, 0}}, {"version", DM_VERSION, {4, 0, 0}},
{"status", DM_TARGET_STATUS, {4, 0, 0}}, {"status", DM_TABLE_STATUS, {4, 0, 0}},
{"table", DM_TARGET_STATUS, {4, 0, 0}}, {"table", DM_TABLE_STATUS, {4, 0, 0}},
{"waitevent", DM_TARGET_WAIT, {4, 0, 0}}, {"waitevent", DM_DEV_WAIT, {4, 0, 0}},
{"names", DM_LIST_DEVICES, {4, 0, 0}},
{"clear", DM_TABLE_CLEAR, {4, 0, 0}},
}; };
/* *INDENT-ON* */ /* *INDENT-ON* */
@ -113,6 +122,20 @@ static int _unmarshal_status_v1(struct dm_task *dmt, struct dm_ioctl_v1 *dmi)
return 1; return 1;
} }
static int _dm_format_dev_v1(char *buf, int bufsize, uint32_t dev_major, uint32_t dev_minor)
{
int r;
if (bufsize < 8)
return 0;
r = snprintf(buf, bufsize, "%03x:%03x", dev_major, dev_minor);
if (r < 0 || r > bufsize - 1)
return 0;
return 1;
}
static int _dm_task_get_info_v1(struct dm_task *dmt, struct dm_info *info) static int _dm_task_get_info_v1(struct dm_task *dmt, struct dm_info *info)
{ {
if (!dmt->dmi.v1) if (!dmt->dmi.v1)
@ -131,10 +154,17 @@ static int _dm_task_get_info_v1(struct dm_task *dmt, struct dm_info *info)
info->event_nr = 0; info->event_nr = 0;
info->major = MAJOR(dmt->dmi.v1->dev); info->major = MAJOR(dmt->dmi.v1->dev);
info->minor = MINOR(dmt->dmi.v1->dev); info->minor = MINOR(dmt->dmi.v1->dev);
info->live_table = 1;
info->inactive_table = 0;
return 1; return 1;
} }
static const char *_dm_task_get_name_v1(struct dm_task *dmt)
{
return (dmt->dmi.v1->name);
}
static const char *_dm_task_get_uuid_v1(struct dm_task *dmt) static const char *_dm_task_get_uuid_v1(struct dm_task *dmt)
{ {
return (dmt->dmi.v1->uuid); return (dmt->dmi.v1->uuid);
@ -146,6 +176,12 @@ static struct dm_deps *_dm_task_get_deps_v1(struct dm_task *dmt)
return NULL; return NULL;
} }
static struct dm_names *_dm_task_get_names_v1(struct dm_task *dmt)
{
return (struct dm_names *) (((void *) dmt->dmi.v1) +
dmt->dmi.v1->data_start);
}
static void *_add_target_v1(struct target *t, void *out, void *end) static void *_add_target_v1(struct target *t, void *out, void *end)
{ {
void *out_sp = out; void *out_sp = out;
@ -271,12 +307,86 @@ static struct dm_ioctl_v1 *_flatten_v1(struct dm_task *dmt)
return NULL; return NULL;
} }
static int _dm_names_v1(struct dm_ioctl_v1 *dmi)
{
const char *dev_dir = dm_dir();
int r = 1, len;
const char *name;
struct dirent *dirent;
DIR *d;
struct dm_names *names, *old_names = NULL;
void *end = (void *) dmi + dmi->data_size;
struct stat buf;
char path[PATH_MAX];
if (!(d = opendir(dev_dir))) {
log_error("%s: opendir failed: %s", dev_dir, strerror(errno));
return 0;
}
names = (struct dm_names *) ((void *) dmi + dmi->data_start);
names->dev = 0; /* Flags no data */
while ((dirent = readdir(d))) {
name = dirent->d_name;
if (name[0] == '.' || !strcmp(name, "control"))
continue;
if (old_names)
old_names->next = (uint32_t) ((void *) names -
(void *) old_names);
snprintf(path, sizeof(path), "%s/%s", dev_dir, name);
if (stat(path, &buf)) {
log_error("%s: stat failed: %s", path, strerror(errno));
continue;
}
if (!S_ISBLK(buf.st_mode))
continue;
names->dev = (uint64_t) buf.st_rdev;
names->next = 0;
len = strlen(name);
if (((void *) (names + 1) + len + 1) >= end) {
log_error("Insufficient buffer space for device list");
r = 0;
break;
}
strcpy(names->name, name);
old_names = names;
names = _align((void *) ++names + len + 1, ALIGNMENT);
}
if (closedir(d))
log_error("%s: closedir failed: %s", dev_dir, strerror(errno));
return r;
}
static int _open_control(void)
{
char control[PATH_MAX];
if (_control_fd != -1)
return 1;
snprintf(control, sizeof(control), "%s/control", dm_dir());
if ((_control_fd = open(control, O_RDWR)) < 0) {
log_error("%s: open failed: %s", control, strerror(errno));
log_error("Is device-mapper driver missing from kernel?");
return 0;
}
return 1;
}
static int _dm_task_run_v1(struct dm_task *dmt) static int _dm_task_run_v1(struct dm_task *dmt)
{ {
int fd = -1;
struct dm_ioctl_v1 *dmi; struct dm_ioctl_v1 *dmi;
unsigned int command; unsigned int command;
char control[PATH_MAX];
dmi = _flatten_v1(dmt); dmi = _flatten_v1(dmt);
if (!dmi) { if (!dmi) {
@ -284,13 +394,8 @@ static int _dm_task_run_v1(struct dm_task *dmt)
return 0; return 0;
} }
snprintf(control, sizeof(control), "%s/control", dm_dir()); if (!_open_control())
return 0;
if ((fd = open(control, O_RDWR)) < 0) {
log_error("%s: open failed: %s", control, strerror(errno));
log_error("Is device-mapper driver missing from kernel?");
goto bad;
}
if ((unsigned) dmt->type >= if ((unsigned) dmt->type >=
(sizeof(_cmd_data_v1) / sizeof(*_cmd_data_v1))) { (sizeof(_cmd_data_v1) / sizeof(*_cmd_data_v1))) {
@ -306,7 +411,10 @@ static int _dm_task_run_v1(struct dm_task *dmt)
log_debug("dm %s %s %s %s", _cmd_data_v1[dmt->type].name, dmi->name, log_debug("dm %s %s %s %s", _cmd_data_v1[dmt->type].name, dmi->name,
dmi->uuid, dmt->newname ? dmt->newname : ""); dmi->uuid, dmt->newname ? dmt->newname : "");
if (ioctl(fd, command, dmi) < 0) { if (dmt->type == DM_DEVICE_LIST) {
if (!_dm_names_v1(dmi))
goto bad;
} else if (ioctl(_control_fd, command, dmi) < 0) {
if (_log_suppress) if (_log_suppress)
log_verbose("device-mapper ioctl cmd %d failed: %s", log_verbose("device-mapper ioctl cmd %d failed: %s",
_IOC_NR(command), strerror(errno)); _IOC_NR(command), strerror(errno));
@ -337,13 +445,10 @@ static int _dm_task_run_v1(struct dm_task *dmt)
} }
dmt->dmi.v1 = dmi; dmt->dmi.v1 = dmi;
close(fd);
return 1; return 1;
bad: bad:
free(dmi); free(dmi);
if (fd >= 0)
close(fd);
return 0; return 0;
} }
@ -418,15 +523,13 @@ static int _check_version(char *version, size_t size, int log_suppress)
*/ */
int dm_check_version(void) int dm_check_version(void)
{ {
static int _checked = 0;
static int _ok = 1;
char libversion[64], dmversion[64]; char libversion[64], dmversion[64];
const char *compat = ""; const char *compat = "";
if (_checked) if (_version_checked)
return _ok; return _version_ok;
_checked = 1; _version_checked = 1;
if (_check_version(dmversion, sizeof(dmversion), _dm_compat)) if (_check_version(dmversion, sizeof(dmversion), _dm_compat))
return 1; return 1;
@ -450,7 +553,7 @@ int dm_check_version(void)
libversion, compat, dmversion); libversion, compat, dmversion);
bad: bad:
_ok = 0; _version_ok = 0;
return 0; return 0;
} }
@ -496,6 +599,23 @@ static int _unmarshal_status(struct dm_task *dmt, struct dm_ioctl *dmi)
return 1; return 1;
} }
int dm_format_dev(char *buf, int bufsize, uint32_t dev_major, uint32_t dev_minor)
{
int r;
if (_dm_version == 1)
return _dm_format_dev_v1(buf, bufsize, dev_major, dev_minor);
if (bufsize < 8)
return 0;
r = snprintf(buf, bufsize, "%03u:%03u", dev_major, dev_minor);
if (r < 0 || r > bufsize - 1)
return 0;
return 1;
}
int dm_task_get_info(struct dm_task *dmt, struct dm_info *info) int dm_task_get_info(struct dm_task *dmt, struct dm_info *info)
{ {
if (_dm_version == 1) if (_dm_version == 1)
@ -512,6 +632,9 @@ int dm_task_get_info(struct dm_task *dmt, struct dm_info *info)
info->suspended = dmt->dmi.v4->flags & DM_SUSPEND_FLAG ? 1 : 0; info->suspended = dmt->dmi.v4->flags & DM_SUSPEND_FLAG ? 1 : 0;
info->read_only = dmt->dmi.v4->flags & DM_READONLY_FLAG ? 1 : 0; info->read_only = dmt->dmi.v4->flags & DM_READONLY_FLAG ? 1 : 0;
info->live_table = dmt->dmi.v4->flags & DM_ACTIVE_PRESENT_FLAG ? 1 : 0;
info->inactive_table = dmt->dmi.v4->flags & DM_INACTIVE_PRESENT_FLAG ?
1 : 0;
info->target_count = dmt->dmi.v4->target_count; info->target_count = dmt->dmi.v4->target_count;
info->open_count = dmt->dmi.v4->open_count; info->open_count = dmt->dmi.v4->open_count;
info->event_nr = dmt->dmi.v4->event_nr; info->event_nr = dmt->dmi.v4->event_nr;
@ -521,6 +644,14 @@ int dm_task_get_info(struct dm_task *dmt, struct dm_info *info)
return 1; return 1;
} }
const char *dm_task_get_name(struct dm_task *dmt)
{
if (_dm_version == 1)
return _dm_task_get_name_v1(dmt);
return (dmt->dmi.v4->name);
}
const char *dm_task_get_uuid(struct dm_task *dmt) const char *dm_task_get_uuid(struct dm_task *dmt)
{ {
if (_dm_version == 1) if (_dm_version == 1)
@ -538,6 +669,15 @@ struct dm_deps *dm_task_get_deps(struct dm_task *dmt)
dmt->dmi.v4->data_start); dmt->dmi.v4->data_start);
} }
struct dm_names *dm_task_get_names(struct dm_task *dmt)
{
if (_dm_version == 1)
return _dm_task_get_names_v1(dmt);
return (struct dm_names *) (((void *) dmt->dmi.v4) +
dmt->dmi.v4->data_start);
}
int dm_task_set_ro(struct dm_task *dmt) int dm_task_set_ro(struct dm_task *dmt)
{ {
dmt->read_only = 1; dmt->read_only = 1;
@ -719,30 +859,78 @@ static struct dm_ioctl *_flatten(struct dm_task *dmt)
return NULL; return NULL;
} }
int dm_task_run(struct dm_task *dmt) static int _create_and_load_v4(struct dm_task *dmt)
{ {
int fd = -1; struct dm_task *task;
struct dm_ioctl *dmi; int r;
unsigned int command;
char control[PATH_MAX];
if (_dm_version == 1) /* Use new task struct to create the device */
return _dm_task_run_v1(dmt); if (!(task = dm_task_create(DM_DEVICE_CREATE))) {
log_error("Failed to create device-mapper task struct");
dmi = _flatten(dmt);
if (!dmi) {
log_error("Couldn't create ioctl argument");
return 0; return 0;
} }
snprintf(control, sizeof(control), "%s/control", dm_dir()); /* Copy across relevant fields */
if (dmt->dev_name && !dm_task_set_name(task, dmt->dev_name)) {
if ((fd = open(control, O_RDWR)) < 0) { dm_task_destroy(task);
log_error("%s: open failed: %s", control, strerror(errno)); return 0;
log_error("Is device-mapper driver missing from kernel?");
goto bad;
} }
if (dmt->uuid && !dm_task_set_uuid(task, dmt->uuid)) {
dm_task_destroy(task);
return 0;
}
task->major = dmt->major;
task->minor = dmt->minor;
r = dm_task_run(task);
dm_task_destroy(task);
if (!r)
return r;
/* Next load the table */
if (!(task = dm_task_create(DM_DEVICE_RELOAD))) {
log_error("Failed to create device-mapper task struct");
return 0;
}
/* Copy across relevant fields */
if (dmt->dev_name && !dm_task_set_name(task, dmt->dev_name)) {
dm_task_destroy(task);
return 0;
}
task->read_only = dmt->read_only;
task->head = dmt->head;
task->tail = dmt->tail;
r = dm_task_run(task);
task->head = NULL;
task->tail = NULL;
dm_task_destroy(task);
if (!r)
return r;
/* Use the original structure last so the info will be correct */
dmt->type = DM_DEVICE_RESUME;
dmt->uuid = NULL;
free(dmt->uuid);
r = dm_task_run(dmt);
return r;
}
int dm_task_run(struct dm_task *dmt)
{
struct dm_ioctl *dmi;
unsigned int command;
if (_dm_version == 1)
return _dm_task_run_v1(dmt);
if ((unsigned) dmt->type >= if ((unsigned) dmt->type >=
(sizeof(_cmd_data_v4) / sizeof(*_cmd_data_v4))) { (sizeof(_cmd_data_v4) / sizeof(*_cmd_data_v4))) {
log_error("Internal error: unknown device-mapper task %d", log_error("Internal error: unknown device-mapper task %d",
@ -752,13 +940,26 @@ int dm_task_run(struct dm_task *dmt)
command = _cmd_data_v4[dmt->type].cmd; command = _cmd_data_v4[dmt->type].cmd;
/* Old-style creation had a table supplied */
if (dmt->type == DM_DEVICE_CREATE && dmt->head)
return _create_and_load_v4(dmt);
if (!_open_control())
return 0;
dmi = _flatten(dmt);
if (!dmi) {
log_error("Couldn't create ioctl argument");
return 0;
}
if (dmt->type == DM_DEVICE_TABLE) if (dmt->type == DM_DEVICE_TABLE)
dmi->flags |= DM_STATUS_TABLE_FLAG; dmi->flags |= DM_STATUS_TABLE_FLAG;
dmi->flags |= DM_EXISTS_FLAG; /* FIXME */ dmi->flags |= DM_EXISTS_FLAG; /* FIXME */
log_debug("dm %s %s %s %s", _cmd_data_v4[dmt->type].name, dmi->name, log_debug("dm %s %s %s %s", _cmd_data_v4[dmt->type].name, dmi->name,
dmi->uuid, dmt->newname ? dmt->newname : ""); dmi->uuid, dmt->newname ? dmt->newname : "");
if (ioctl(fd, command, dmi) < 0) { if (ioctl(_control_fd, command, dmi) < 0) {
if (errno == ENXIO && dmt->type == DM_DEVICE_INFO) { if (errno == ENXIO && dmt->type == DM_DEVICE_INFO) {
dmi->flags &= ~DM_EXISTS_FLAG; /* FIXME */ dmi->flags &= ~DM_EXISTS_FLAG; /* FIXME */
goto ignore_error; goto ignore_error;
@ -795,12 +996,28 @@ int dm_task_run(struct dm_task *dmt)
} }
dmt->dmi.v4 = dmi; dmt->dmi.v4 = dmi;
close(fd);
return 1; return 1;
bad: bad:
free(dmi); free(dmi);
if (fd >= 0)
close(fd);
return 0; return 0;
} }
void dm_lib_release(void)
{
if (_control_fd != -1) {
close(_control_fd);
_control_fd = -1;
}
update_devs();
}
void dm_lib_exit(void)
{
if (_control_fd != -1) {
close(_control_fd);
_control_fd = -1;
}
_version_ok = 1;
_version_checked = 0;
}

View File

@ -54,21 +54,55 @@ struct dm_target_deps_v1 {
__kernel_dev_t dev[0]; /* out */ __kernel_dev_t dev[0]; /* out */
}; };
enum {
/* Top level cmds */
DM_VERSION_CMD_V1 = 0,
DM_REMOVE_ALL_CMD_V1,
/* device level cmds */
DM_DEV_CREATE_CMD_V1,
DM_DEV_REMOVE_CMD_V1,
DM_DEV_RELOAD_CMD_V1,
DM_DEV_RENAME_CMD_V1,
DM_DEV_SUSPEND_CMD_V1,
DM_DEV_DEPS_CMD_V1,
DM_DEV_STATUS_CMD_V1,
/* target level cmds */
DM_TARGET_STATUS_CMD_V1,
DM_TARGET_WAIT_CMD_V1,
};
#define DM_VERSION_V1 _IOWR(DM_IOCTL, DM_VERSION_CMD_V1, struct dm_ioctl)
#define DM_REMOVE_ALL_V1 _IOWR(DM_IOCTL, DM_REMOVE_ALL_CMD_V1, struct dm_ioctl)
#define DM_DEV_CREATE_V1 _IOWR(DM_IOCTL, DM_DEV_CREATE_CMD_V1, struct dm_ioctl)
#define DM_DEV_REMOVE_V1 _IOWR(DM_IOCTL, DM_DEV_REMOVE_CMD_V1, struct dm_ioctl)
#define DM_DEV_RELOAD_V1 _IOWR(DM_IOCTL, DM_DEV_RELOAD_CMD_V1, struct dm_ioctl)
#define DM_DEV_SUSPEND_V1 _IOWR(DM_IOCTL, DM_DEV_SUSPEND_CMD_V1, struct dm_ioctl)
#define DM_DEV_RENAME_V1 _IOWR(DM_IOCTL, DM_DEV_RENAME_CMD_V1, struct dm_ioctl)
#define DM_DEV_DEPS_V1 _IOWR(DM_IOCTL, DM_DEV_DEPS_CMD_V1, struct dm_ioctl)
#define DM_DEV_STATUS_V1 _IOWR(DM_IOCTL, DM_DEV_STATUS_CMD_V1, struct dm_ioctl)
#define DM_TARGET_STATUS_V1 _IOWR(DM_IOCTL, DM_TARGET_STATUS_CMD_V1, struct dm_ioctl)
#define DM_TARGET_WAIT_V1 _IOWR(DM_IOCTL, DM_TARGET_WAIT_CMD_V1, struct dm_ioctl)
/* *INDENT-OFF* */ /* *INDENT-OFF* */
static struct cmd_data _cmd_data_v1[] = { static struct cmd_data _cmd_data_v1[] = {
{ "create", DM_DEV_CREATE, {1, 0, 0} }, { "create", DM_DEV_CREATE_V1, {1, 0, 0} },
{ "reload", DM_DEV_RELOAD, {1, 0, 0} }, { "reload", DM_DEV_RELOAD_V1, {1, 0, 0} },
{ "remove", DM_DEV_REMOVE, {1, 0, 0} }, { "remove", DM_DEV_REMOVE_V1, {1, 0, 0} },
{ "remove_all", DM_REMOVE_ALL, {1, 0, 0} }, { "remove_all", DM_REMOVE_ALL_V1, {1, 0, 0} },
{ "suspend", DM_DEV_SUSPEND, {1, 0, 0} }, { "suspend", DM_DEV_SUSPEND_V1, {1, 0, 0} },
{ "resume", DM_DEV_SUSPEND, {1, 0, 0} }, { "resume", DM_DEV_SUSPEND_V1, {1, 0, 0} },
{ "info", DM_DEV_STATUS, {1, 0, 0} }, { "info", DM_DEV_STATUS_V1, {1, 0, 0} },
{ "deps", DM_DEV_DEPS, {1, 0, 0} }, { "deps", DM_DEV_DEPS_V1, {1, 0, 0} },
{ "rename", DM_DEV_RENAME, {1, 0, 0} }, { "rename", DM_DEV_RENAME_V1, {1, 0, 0} },
{ "version", DM_VERSION, {1, 0, 0} }, { "version", DM_VERSION_V1, {1, 0, 0} },
{ "status", DM_TARGET_STATUS, {1, 0, 0} }, { "status", DM_TARGET_STATUS_V1, {1, 0, 0} },
{ "table", DM_TARGET_STATUS, {1, 0, 0} }, { "table", DM_TARGET_STATUS_V1, {1, 0, 0} },
{ "waitevent", DM_TARGET_WAIT, {1, 0, 0} }, { "waitevent", DM_TARGET_WAIT_V1, {1, 0, 0} },
{ "names", 0, {4, 0, 0} }
}; };
/* *INDENT-ON* */ /* *INDENT-ON* */

View File

@ -48,7 +48,11 @@ enum {
DM_DEVICE_STATUS, DM_DEVICE_STATUS,
DM_DEVICE_TABLE, DM_DEVICE_TABLE,
DM_DEVICE_WAITEVENT DM_DEVICE_WAITEVENT,
DM_DEVICE_LIST,
DM_DEVICE_CLEAR
}; };
struct dm_task; struct dm_task;
@ -65,6 +69,8 @@ int dm_task_set_uuid(struct dm_task *dmt, const char *uuid);
struct dm_info { struct dm_info {
int exists; int exists;
int suspended; int suspended;
int live_table;
int inactive_table;
int32_t open_count; int32_t open_count;
uint32_t event_nr; uint32_t event_nr;
uint32_t major; uint32_t major;
@ -80,12 +86,20 @@ struct dm_deps {
uint64_t device[0]; uint64_t device[0];
}; };
struct dm_names {
uint64_t dev;
uint32_t next; /* Offset to next struct from start of this struct */
char name[0];
};
int dm_get_library_version(char *version, size_t size); int dm_get_library_version(char *version, size_t size);
int dm_task_get_driver_version(struct dm_task *dmt, char *version, size_t size); int dm_task_get_driver_version(struct dm_task *dmt, char *version, size_t size);
int dm_task_get_info(struct dm_task *dmt, struct dm_info *dmi); int dm_task_get_info(struct dm_task *dmt, struct dm_info *dmi);
const char *dm_task_get_name(struct dm_task *dmt);
const char *dm_task_get_uuid(struct dm_task *dmt); const char *dm_task_get_uuid(struct dm_task *dmt);
struct dm_deps *dm_task_get_deps(struct dm_task *dmt); struct dm_deps *dm_task_get_deps(struct dm_task *dmt);
struct dm_names *dm_task_get_names(struct dm_task *dmt);
int dm_task_set_ro(struct dm_task *dmt); int dm_task_set_ro(struct dm_task *dmt);
int dm_task_set_newname(struct dm_task *dmt, const char *newname); int dm_task_set_newname(struct dm_task *dmt, const char *newname);
@ -100,6 +114,11 @@ int dm_task_add_target(struct dm_task *dmt,
uint64_t start, uint64_t start,
uint64_t size, const char *ttype, const char *params); uint64_t size, const char *ttype, const char *params);
/*
* Format major/minor numbers correctly for input to driver
*/
int dm_format_dev(char *buf, int bufsize, uint32_t dev_major, uint32_t dev_minor);
/* Use this to retrive target information returned from a STATUS call */ /* Use this to retrive target information returned from a STATUS call */
void *dm_get_next_target(struct dm_task *dmt, void *dm_get_next_target(struct dm_task *dmt,
void *next, uint64_t *start, uint64_t *length, void *next, uint64_t *start, uint64_t *length,
@ -116,4 +135,8 @@ int dm_task_run(struct dm_task *dmt);
int dm_set_dev_dir(const char *dir); int dm_set_dev_dir(const char *dir);
const char *dm_dir(void); const char *dm_dir(void);
/* Release library resources */
void dm_lib_release(void);
void dm_lib_exit(void);
#endif /* LIB_DEVICE_MAPPER_H */ #endif /* LIB_DEVICE_MAPPER_H */

View File

@ -6,6 +6,7 @@
#include "libdm-targets.h" #include "libdm-targets.h"
#include "libdm-common.h" #include "libdm-common.h"
#include "list.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@ -183,7 +184,7 @@ int dm_task_add_target(struct dm_task *dmt, uint64_t start, uint64_t size,
return 1; return 1;
} }
int add_dev_node(const char *dev_name, uint32_t major, uint32_t minor) static int _add_dev_node(const char *dev_name, uint32_t major, uint32_t minor)
{ {
char path[PATH_MAX]; char path[PATH_MAX];
struct stat info; struct stat info;
@ -216,7 +217,7 @@ int add_dev_node(const char *dev_name, uint32_t major, uint32_t minor)
return 1; return 1;
} }
int rename_dev_node(const char *old_name, const char *new_name) static int _rename_dev_node(const char *old_name, const char *new_name)
{ {
char oldpath[PATH_MAX]; char oldpath[PATH_MAX];
char newpath[PATH_MAX]; char newpath[PATH_MAX];
@ -252,7 +253,7 @@ int rename_dev_node(const char *old_name, const char *new_name)
return 1; return 1;
} }
int rm_dev_node(const char *dev_name) static int _rm_dev_node(const char *dev_name)
{ {
char path[PATH_MAX]; char path[PATH_MAX];
struct stat info; struct stat info;
@ -270,6 +271,105 @@ int rm_dev_node(const char *dev_name)
return 1; return 1;
} }
typedef enum {
NODE_ADD,
NODE_DEL,
NODE_RENAME
} node_op_t;
static int _do_node_op(node_op_t type, const char *dev_name, uint32_t major,
uint32_t minor, const char *old_name)
{
switch (type) {
case NODE_ADD:
return _add_dev_node(dev_name, major, minor);
case NODE_DEL:
return _rm_dev_node(dev_name);
case NODE_RENAME:
return _rename_dev_node(old_name, dev_name);
}
return 1;
}
static LIST_INIT(_node_ops);
struct node_op_parms {
struct list list;
node_op_t type;
char *dev_name;
uint32_t major;
uint32_t minor;
char *old_name;
char names[0];
};
static void _store_str(char **pos, char **ptr, const char *str)
{
strcpy(*pos, str);
*ptr = *pos;
*pos += strlen(*ptr) + 1;
}
static int _stack_node_op(node_op_t type, const char *dev_name, uint32_t major,
uint32_t minor, const char *old_name)
{
struct node_op_parms *nop;
size_t len = strlen(dev_name) + strlen(old_name) + 2;
char *pos;
if (!(nop = malloc(sizeof(*nop) + len))) {
log_error("Insufficient memory to stack mknod operation");
return 0;
}
pos = nop->names;
nop->type = type;
nop->major = major;
nop->minor = minor;
_store_str(&pos, &nop->dev_name, dev_name);
_store_str(&pos, &nop->old_name, old_name);
list_add(&_node_ops, &nop->list);
return 1;
}
static void _pop_node_ops(void)
{
struct list *noph, *nopht;
struct node_op_parms *nop;
list_iterate_safe(noph, nopht, &_node_ops) {
nop = list_item(noph, struct node_op_parms);
_do_node_op(nop->type, nop->dev_name, nop->major, nop->minor,
nop->old_name);
list_del(&nop->list);
free(nop);
}
}
int add_dev_node(const char *dev_name, uint32_t major, uint32_t minor)
{
return _stack_node_op(NODE_ADD, dev_name, major, minor, "");
}
int rename_dev_node(const char *old_name, const char *new_name)
{
return _stack_node_op(NODE_RENAME, new_name, 0, 0, old_name);
}
int rm_dev_node(const char *dev_name)
{
return _stack_node_op(NODE_DEL, dev_name, 0, 0, "");
}
void update_devs(void)
{
_pop_node_ops();
}
int dm_set_dev_dir(const char *dir) int dm_set_dev_dir(const char *dir)
{ {
snprintf(_dm_dir, sizeof(_dm_dir), "%s%s", dir, DM_DIR); snprintf(_dm_dir, sizeof(_dm_dir), "%s%s", dir, DM_DIR);

View File

@ -31,6 +31,7 @@ struct target *create_target(uint64_t start,
int add_dev_node(const char *dev_name, uint32_t minor, uint32_t major); int add_dev_node(const char *dev_name, uint32_t minor, uint32_t major);
int rm_dev_node(const char *dev_name); int rm_dev_node(const char *dev_name);
int rename_dev_node(const char *old_name, const char *new_name); int rename_dev_node(const char *old_name, const char *new_name);
void update_devs(void);
#define DM_LIB_VERSION @DM_LIB_VERSION@ #define DM_LIB_VERSION @DM_LIB_VERSION@

View File

@ -84,6 +84,47 @@ static int _parse_file(struct dm_task *dmt, const char *file)
return r; return r;
} }
static void _display_info(struct dm_task *dmt)
{
struct dm_info info;
const char *uuid;
if (!dm_task_get_info(dmt, &info))
return;
if (!info.exists) {
printf("Device does not exist.\n");
return;
}
printf("Name: %s\n", dm_task_get_name(dmt));
printf("State: %s%s\n",
info.suspended ? "SUSPENDED" : "ACTIVE",
info.read_only ? " (READ-ONLY)" : "");
if (!info.live_table && !info.inactive_table)
printf("Tables present: None\n");
else
printf("Tables present: %s%s%s\n",
info.live_table ? "LIVE" : "",
info.live_table && info.inactive_table ? " & " : "",
info.inactive_table ? "INACTIVE" : "");
if (info.open_count != -1)
printf("Open count: %d\n", info.open_count);
printf("Event number: %" PRIu32 "\n", info.event_nr);
printf("Major, minor: %d, %d\n", info.major, info.minor);
if (info.target_count != -1)
printf("Number of targets: %d\n", info.target_count);
if ((uuid = dm_task_get_uuid(dmt)) && *uuid)
printf("UUID: %s\n", uuid);
}
static int _load(int task, const char *name, const char *file, const char *uuid) static int _load(int task, const char *name, const char *file, const char *uuid)
{ {
int r = 0; int r = 0;
@ -98,7 +139,7 @@ static int _load(int task, const char *name, const char *file, const char *uuid)
if (uuid && !dm_task_set_uuid(dmt, uuid)) if (uuid && !dm_task_set_uuid(dmt, uuid))
goto out; goto out;
if (!_parse_file(dmt, file)) if (file && !_parse_file(dmt, file))
goto out; goto out;
if (_switches[READ_ONLY] && !dm_task_set_ro(dmt)) if (_switches[READ_ONLY] && !dm_task_set_ro(dmt))
@ -115,6 +156,8 @@ static int _load(int task, const char *name, const char *file, const char *uuid)
r = 1; r = 1;
_display_info(dmt);
out: out:
dm_task_destroy(dmt); dm_task_destroy(dmt);
@ -123,7 +166,11 @@ static int _load(int task, const char *name, const char *file, const char *uuid)
static int _create(int argc, char **argv) static int _create(int argc, char **argv)
{ {
return _load(DM_DEVICE_CREATE, argv[1], argv[2], argv[3]); if (argc == 1)
return _load(DM_DEVICE_CREATE, argv[1], NULL, NULL);
return _load(DM_DEVICE_CREATE, argv[1], argv[2],
(argc == 3) ? argv[3] : NULL);
} }
static int _reload(int argc, char **argv) static int _reload(int argc, char **argv)
@ -185,7 +232,7 @@ static int _version(int argc, char **argv)
return r; return r;
} }
static int _simple(int task, const char *name) static int _simple(int task, const char *name, int display)
{ {
int r = 0; int r = 0;
@ -200,6 +247,9 @@ static int _simple(int task, const char *name)
r = dm_task_run(dmt); r = dm_task_run(dmt);
if (r && display)
_display_info(dmt);
out: out:
dm_task_destroy(dmt); dm_task_destroy(dmt);
return r; return r;
@ -207,27 +257,32 @@ static int _simple(int task, const char *name)
static int _remove_all(int argc, char **argv) static int _remove_all(int argc, char **argv)
{ {
return _simple(DM_DEVICE_REMOVE_ALL, ""); return _simple(DM_DEVICE_REMOVE_ALL, "", 0);
} }
static int _remove(int argc, char **argv) static int _remove(int argc, char **argv)
{ {
return _simple(DM_DEVICE_REMOVE, argv[1]); return _simple(DM_DEVICE_REMOVE, argv[1], 0);
} }
static int _suspend(int argc, char **argv) static int _suspend(int argc, char **argv)
{ {
return _simple(DM_DEVICE_SUSPEND, argv[1]); return _simple(DM_DEVICE_SUSPEND, argv[1], 1);
} }
static int _resume(int argc, char **argv) static int _resume(int argc, char **argv)
{ {
return _simple(DM_DEVICE_RESUME, argv[1]); return _simple(DM_DEVICE_RESUME, argv[1], 1);
}
static int _clear(int argc, char **argv)
{
return _simple(DM_DEVICE_CLEAR, argv[1], 1);
} }
static int _wait(int argc, char **argv) static int _wait(int argc, char **argv)
{ {
return _simple(DM_DEVICE_WAITEVENT, argv[1]); return _simple(DM_DEVICE_WAITEVENT, argv[1], 2);
} }
static int _status(int argc, char **argv) static int _status(int argc, char **argv)
@ -254,6 +309,11 @@ static int _status(int argc, char **argv)
if (!dm_task_run(dmt)) if (!dm_task_run(dmt))
goto out; goto out;
if (cmd == DM_DEVICE_STATUS) {
_display_info(dmt);
printf("\n");
}
/* Fetch targets and print 'em */ /* Fetch targets and print 'em */
do { do {
next = dm_get_next_target(dmt, next, &start, &length, next = dm_get_next_target(dmt, next, &start, &length,
@ -275,11 +335,9 @@ static int _status(int argc, char **argv)
static int _info(int argc, char **argv) static int _info(int argc, char **argv)
{ {
int r = 0; int r = 0;
const char *uuid;
/* remove <dev_name> */ /* remove <dev_name> */
struct dm_task *dmt; struct dm_task *dmt;
struct dm_info info;
if (!(dmt = dm_task_create(DM_DEVICE_INFO))) if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
return 0; return 0;
@ -290,33 +348,7 @@ static int _info(int argc, char **argv)
if (!dm_task_run(dmt)) if (!dm_task_run(dmt))
goto out; goto out;
if (!dm_task_get_info(dmt, &info)) _display_info(dmt);
goto out;
if (!info.exists) {
printf("Device does not exist.\n");
r = 1;
goto out;
}
printf("Name: %s\n", argv[1]);
printf("State: %s%s\n",
info.suspended ? "SUSPENDED" : "ACTIVE",
info.read_only ? " (READ-ONLY)" : "");
if (info.open_count != -1)
printf("Open count: %d\n", info.open_count);
printf("Event number: %" PRIu32 "\n", info.event_nr);
printf("Major, minor: %d, %d\n", info.major, info.minor);
if (info.target_count != -1)
printf("Number of targets: %d\n", info.target_count);
if ((uuid = dm_task_get_uuid(dmt)) && *uuid)
printf("UUID: %s\n", uuid);
r = 1; r = 1;
out: out:
@ -355,6 +387,8 @@ static int _deps(int argc, char **argv)
goto out; goto out;
} }
_display_info(dmt);
printf("%d dependencies\t:", deps->count); printf("%d dependencies\t:", deps->count);
for (i = 0; i < deps->count; i++) for (i = 0; i < deps->count; i++)
@ -370,6 +404,41 @@ static int _deps(int argc, char **argv)
return r; return r;
} }
static int _ls(int argc, char **argv)
{
int r = 0;
struct dm_names *names;
unsigned next = 0;
struct dm_task *dmt;
if (!(dmt = dm_task_create(DM_DEVICE_LIST)))
return 0;
if (!dm_task_run(dmt))
goto out;
if (!(names = dm_task_get_names(dmt)))
goto out;
r = 1;
if (!names->dev) {
printf("No devices found\n");
goto out;
}
do {
names = (void *) names + next;
printf("%s\t(%d, %d)\n", names->name,
(int) MAJOR(names->dev), (int) MINOR(names->dev));
next = names->next;
} while (next);
out:
dm_task_destroy(dmt);
return r;
}
/* /*
* dispatch table * dispatch table
*/ */
@ -384,15 +453,18 @@ struct command {
}; };
static struct command _commands[] = { static struct command _commands[] = {
{"create", "<dev_name> <table_file> [<uuid>]", 2, 3, _create}, {"create", "<dev_name> <table_file> [<uuid>]", 1, 3, _create},
{"remove", "<dev_name>", 1, 1, _remove}, {"remove", "<dev_name>", 1, 1, _remove},
{"remove_all", "", 0, 0, _remove_all}, {"remove_all", "", 0, 0, _remove_all},
{"suspend", "<dev_name>", 1, 1, _suspend}, {"suspend", "<dev_name>", 1, 1, _suspend},
{"resume", "<dev_name>", 1, 1, _resume}, {"resume", "<dev_name>", 1, 1, _resume},
{"load", "<dev_name> <table_file>", 2, 2, _reload},
{"clear", "<dev_name>", 1, 1, _clear},
{"reload", "<dev_name> <table_file>", 2, 2, _reload}, {"reload", "<dev_name> <table_file>", 2, 2, _reload},
{"rename", "<dev_name> <new_name>", 2, 2, _rename},
{"ls", "", 0, 0, _ls},
{"info", "<dev_name>", 1, 1, _info}, {"info", "<dev_name>", 1, 1, _info},
{"deps", "<dev_name>", 1, 1, _deps}, {"deps", "<dev_name>", 1, 1, _deps},
{"rename", "<dev_name> <new_name>", 2, 2, _rename},
{"status", "<dev_name>", 1, 1, _status}, {"status", "<dev_name>", 1, 1, _status},
{"table", "<dev_name>", 1, 1, _status}, {"table", "<dev_name>", 1, 1, _status},
{"wait", "<dev_name>", 1, 1, _wait}, {"wait", "<dev_name>", 1, 1, _wait},
@ -494,5 +566,8 @@ int main(int argc, char **argv)
exit(1); exit(1);
} }
dm_lib_release();
dm_lib_exit();
return 0; return 0;
} }