#include "memory.h"
#include "devmapper.h"
#include "sysfs.h"
+#include "config.h"
#include "log_pthread.h"
#include <sys/types.h>
#include <time.h>
+#define FREE_CONST(p) do { free((void*)(unsigned long)p); p = NULL; } while(0)
#define MAX_WAIT 5
#define LOOPS_PER_SEC 5
-#define UUID_PREFIX "mpath-"
-#define UUID_PREFIX_LEN 6
-
static int dm_conf_verbosity;
#ifdef LIBDM_API_DEFERRED
}
static int
-dm_drv_prereq (void)
+dm_drv_prereq (unsigned int *ver)
{
unsigned int minv[3] = {1, 0, 3};
unsigned int version[3] = {0, 0, 0};
condlog(3, "DM multipath kernel driver v%u.%u.%u",
v[0], v[1], v[2]);
- if VERSION_GE(v, minv)
+ if (VERSION_GE(v, minv)) {
+ ver[0] = v[0];
+ ver[1] = v[1];
+ ver[2] = v[2];
return 0;
+ }
condlog(0, "DM multipath kernel driver must be >= v%u.%u.%u",
minv[0], minv[1], minv[2]);
return 1;
}
-int dm_prereq(void)
+static int dm_prereq(unsigned int *v)
{
if (dm_lib_prereq())
return 1;
- return dm_drv_prereq();
+ return dm_drv_prereq(v);
+}
+
+static int libmp_dm_udev_sync = 0;
+
+void libmp_udev_set_sync_support(int on)
+{
+ libmp_dm_udev_sync = !!on;
+}
+
+void libmp_dm_init(void)
+{
+ struct config *conf;
+
+ conf = get_multipath_config();
+ dm_init(conf->verbosity);
+ if (dm_prereq(conf->version))
+ exit(1);
+ put_multipath_config(conf);
+ dm_udev_set_sync_support(libmp_dm_udev_sync);
+}
+
+struct dm_task*
+libmp_dm_task_create(int task)
+{
+ static pthread_once_t dm_initialized = PTHREAD_ONCE_INIT;
+
+ pthread_once(&dm_initialized, libmp_dm_init);
+ return dm_task_create(task);
}
#define do_deferred(x) ((x) == DEFERRED_REMOVE_ON || (x) == DEFERRED_REMOVE_IN_PROGRESS)
uint32_t cookie = 0;
struct dm_task *dmt;
- if (!(dmt = dm_task_create (task)))
+ if (!(dmt = libmp_dm_task_create (task)))
return 0;
if (!dm_task_set_name (dmt, name))
static int
dm_addmap (int task, const char *target, struct multipath *mpp,
- char * params, int ro, int skip_kpartx) {
+ char * params, int ro, uint16_t udev_flags) {
int r = 0;
struct dm_task *dmt;
char *prefixed_uuid = NULL;
uint32_t cookie = 0;
- uint16_t udev_flags = DM_UDEV_DISABLE_LIBRARY_FALLBACK | ((skip_kpartx == SKIP_KPARTX_ON)? MPATH_UDEV_NO_KPARTX_FLAG : 0);
- if (!(dmt = dm_task_create (task)))
+ /* Need to add this here to allow 0 to be passed in udev_flags */
+ udev_flags |= DM_UDEV_DISABLE_LIBRARY_FALLBACK;
+
+ if (!(dmt = libmp_dm_task_create (task)))
return 0;
if (!dm_task_set_name (dmt, mpp->alias))
return r;
}
+static uint16_t build_udev_flags(const struct multipath *mpp, int reload)
+{
+ /* DM_UDEV_DISABLE_LIBRARY_FALLBACK is added in dm_addmap */
+ return (mpp->skip_kpartx == SKIP_KPARTX_ON ?
+ MPATH_UDEV_NO_KPARTX_FLAG : 0) |
+ ((mpp->nr_active == 0 || mpp->ghost_delay_tick > 0)?
+ MPATH_UDEV_NO_PATHS_FLAG : 0) |
+ (reload && !mpp->force_udev_reload ?
+ MPATH_UDEV_RELOAD_FLAG : 0);
+}
+
int dm_addmap_create (struct multipath *mpp, char * params)
{
int ro;
+ uint16_t udev_flags = build_udev_flags(mpp, 0);
for (ro = 0; ro <= 1; ro++) {
int err;
if (dm_addmap(DM_DEVICE_CREATE, TGT_MPATH, mpp, params, ro,
- mpp->skip_kpartx))
+ udev_flags))
return 1;
/*
* DM_DEVICE_CREATE is actually DM_DEV_CREATE + DM_TABLE_LOAD.
int dm_addmap_reload(struct multipath *mpp, char *params, int flush)
{
int r = 0;
- uint16_t udev_flags = (flush ? 0 : MPATH_UDEV_RELOAD_FLAG) |
- ((mpp->skip_kpartx == SKIP_KPARTX_ON)?
- MPATH_UDEV_NO_KPARTX_FLAG : 0) |
- ((mpp->nr_active)? 0 : MPATH_UDEV_NO_PATHS_FLAG);
+ uint16_t udev_flags = build_udev_flags(mpp, 1);
/*
* DM_DEVICE_RELOAD cannot wait on a cookie, as
*/
if (!mpp->force_readonly)
r = dm_addmap(DM_DEVICE_RELOAD, TGT_MPATH, mpp, params,
- ADDMAP_RW, SKIP_KPARTX_OFF);
+ ADDMAP_RW, 0);
if (!r) {
if (!mpp->force_readonly && errno != EROFS)
return 0;
r = dm_addmap(DM_DEVICE_RELOAD, TGT_MPATH, mpp,
- params, ADDMAP_RO, SKIP_KPARTX_OFF);
+ params, ADDMAP_RO, 0);
}
if (r)
r = dm_simplecmd(DM_DEVICE_RESUME, mpp->alias, !flush,
1, udev_flags, 0);
- return r;
+ if (r)
+ return r;
+
+ /* If the resume failed, dm will leave the device suspended, and
+ * drop the new table, so doing a second resume will try using
+ * the original table */
+ if (dm_is_suspended(mpp->alias))
+ dm_simplecmd(DM_DEVICE_RESUME, mpp->alias, !flush, 1,
+ udev_flags, 0);
+ return 0;
}
-int dm_map_present(const char * str)
+static int
+do_get_info(const char *name, struct dm_info *info)
{
- int r = 0;
+ int r = -1;
struct dm_task *dmt;
- struct dm_info info;
- if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
- return 0;
+ if (!(dmt = libmp_dm_task_create(DM_DEVICE_INFO)))
+ return r;
- if (!dm_task_set_name(dmt, str))
+ if (!dm_task_set_name(dmt, name))
goto out;
dm_task_no_open_count(dmt);
if (!dm_task_run(dmt))
goto out;
- if (!dm_task_get_info(dmt, &info))
+ if (!dm_task_get_info(dmt, info))
goto out;
- if (info.exists)
- r = 1;
+ if (!info->exists)
+ goto out;
+
+ r = 0;
out:
dm_task_destroy(dmt);
return r;
}
+int dm_map_present(const char * str)
+{
+ struct dm_info info;
+
+ return (do_get_info(str, &info) == 0);
+}
+
int dm_get_map(const char *name, unsigned long long *size, char *outparams)
{
int r = 1;
char *target_type = NULL;
char *params = NULL;
- if (!(dmt = dm_task_create(DM_DEVICE_TABLE)))
+ if (!(dmt = libmp_dm_task_create(DM_DEVICE_TABLE)))
return 1;
if (!dm_task_set_name(dmt, name))
const char *uuidtmp;
int r = 1;
- dmt = dm_task_create(DM_DEVICE_INFO);
+ dmt = libmp_dm_task_create(DM_DEVICE_INFO);
if (!dmt)
return 1;
return r;
}
-int dm_get_uuid(char *name, char *uuid)
+int dm_get_uuid(const char *name, char *uuid)
{
- char uuidtmp[WWID_SIZE];
-
- if (dm_get_prefixed_uuid(name, uuidtmp))
+ if (dm_get_prefixed_uuid(name, uuid))
return 1;
- if (!strncmp(uuidtmp, UUID_PREFIX, UUID_PREFIX_LEN))
- strcpy(uuid, uuidtmp + UUID_PREFIX_LEN);
- else
- strcpy(uuid, uuidtmp);
-
+ if (!strncmp(uuid, UUID_PREFIX, UUID_PREFIX_LEN))
+ memmove(uuid, uuid + UUID_PREFIX_LEN,
+ strlen(uuid + UUID_PREFIX_LEN) + 1);
return 0;
}
-/*
- * returns:
- * 0 : if both uuids end with same suffix which starts with UUID_PREFIX
- * 1 : otherwise
- */
-int
-dm_compare_uuid(const char* mapname1, const char* mapname2)
+static int
+is_mpath_part(const char *part_name, const char *map_name)
{
- char *p1, *p2;
- char uuid1[WWID_SIZE], uuid2[WWID_SIZE];
+ char *p;
+ char part_uuid[WWID_SIZE], map_uuid[WWID_SIZE];
- if (dm_get_prefixed_uuid(mapname1, uuid1))
- return 1;
+ if (dm_get_prefixed_uuid(part_name, part_uuid))
+ return 0;
- if (dm_get_prefixed_uuid(mapname2, uuid2))
- return 1;
+ if (dm_get_prefixed_uuid(map_name, map_uuid))
+ return 0;
- p1 = strstr(uuid1, UUID_PREFIX);
- p2 = strstr(uuid2, UUID_PREFIX);
- if (p1 && p2 && !strcmp(p1, p2))
+ if (strncmp(part_uuid, "part", 4) != 0)
return 0;
- return 1;
+ p = strstr(part_uuid, UUID_PREFIX);
+ if (p && !strcmp(p, map_uuid))
+ return 1;
+
+ return 0;
}
-int dm_get_status(char *name, char *outstatus)
+int dm_get_status(const char *name, char *outstatus)
{
int r = 1;
struct dm_task *dmt;
char *target_type = NULL;
char *status = NULL;
- if (!(dmt = dm_task_create(DM_DEVICE_STATUS)))
+ if (!(dmt = libmp_dm_task_create(DM_DEVICE_STATUS)))
return 1;
if (!dm_task_set_name(dmt, name))
* returns:
* 1 : match
* 0 : no match
- * -1 : empty map
+ * -1 : empty map, or more than 1 target
*/
int dm_type(const char *name, char *type)
{
char *target_type = NULL;
char *params;
- if (!(dmt = dm_task_create(DM_DEVICE_TABLE)))
+ if (!(dmt = libmp_dm_task_create(DM_DEVICE_TABLE)))
return 0;
if (!dm_task_set_name(dmt, name))
goto out;
/* Fetch 1st target */
- dm_get_next_target(dmt, NULL, &start, &length,
- &target_type, ¶ms);
-
- if (!target_type)
+ if (dm_get_next_target(dmt, NULL, &start, &length,
+ &target_type, ¶ms) != NULL)
+ /* multiple targets */
+ r = -1;
+ else if (!target_type)
r = -1;
else if (!strcmp(target_type, type))
r = 1;
char *params;
const char *uuid;
- if (!(dmt = dm_task_create(DM_DEVICE_TABLE)))
+ if (!(dmt = libmp_dm_task_create(DM_DEVICE_TABLE)))
return 0;
if (!dm_task_set_name(dmt, name))
static int
dm_dev_t (const char * mapname, char * dev_t, int len)
{
- int r = 1;
- struct dm_task *dmt;
struct dm_info info;
- if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
- return 0;
-
- if (!dm_task_set_name(dmt, mapname))
- goto out;
-
- if (!dm_task_run(dmt))
- goto out;
-
- if (!dm_task_get_info(dmt, &info) || !info.exists)
- goto out;
+ if (do_get_info(mapname, &info) != 0)
+ return 1;
if (snprintf(dev_t, len, "%i:%i", info.major, info.minor) > len)
- goto out;
+ return 1;
- r = 0;
-out:
- dm_task_destroy(dmt);
- return r;
+ return 0;
}
int
struct dm_task *dmt;
struct dm_info info;
- if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
+ if (!(dmt = libmp_dm_task_create(DM_DEVICE_INFO)))
return 0;
if (!dm_task_set_name(dmt, mapname))
}
int
-dm_get_major (char * mapname)
-{
- int r = -1;
- struct dm_task *dmt;
- struct dm_info info;
-
- if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
- return 0;
-
- if (!dm_task_set_name(dmt, mapname))
- goto out;
-
- if (!dm_task_run(dmt))
- goto out;
-
- if (!dm_task_get_info(dmt, &info))
- goto out;
-
- if (!info.exists)
- goto out;
-
- r = info.major;
-out:
- dm_task_destroy(dmt);
- return r;
-}
-
-int
-dm_get_minor (char * mapname)
+dm_get_major_minor(const char *name, int *major, int *minor)
{
- int r = -1;
- struct dm_task *dmt;
struct dm_info info;
- if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
- return 0;
-
- if (!dm_task_set_name(dmt, mapname))
- goto out;
-
- if (!dm_task_run(dmt))
- goto out;
-
- if (!dm_task_get_info(dmt, &info))
- goto out;
-
- if (!info.exists)
- goto out;
+ if (do_get_info(name, &info) != 0)
+ return -1;
- r = info.minor;
-out:
- dm_task_destroy(dmt);
- return r;
+ *major = info.major;
+ *minor = info.minor;
+ return 0;
}
static int
if (need_suspend &&
!dm_get_map(mapname, &mapsize, params) &&
strstr(params, "queue_if_no_path")) {
- if (!dm_queue_if_no_path((char *)mapname, 0))
+ if (!dm_queue_if_no_path(mapname, 0))
queue_if_no_path = 1;
else
/* Leave queue_if_no_path alone if unset failed */
} while (retries-- > 0);
if (queue_if_no_path == 1)
- dm_queue_if_no_path((char *)mapname, 1);
+ dm_queue_if_no_path(mapname, 1);
return 1;
}
struct dm_names *names;
unsigned next = 0;
- if (!(dmt = dm_task_create (DM_DEVICE_LIST)))
+ if (!(dmt = libmp_dm_task_create (DM_DEVICE_LIST)))
return 0;
dm_task_no_open_count(dmt);
int r = 1;
struct dm_task *dmt;
- if (!(dmt = dm_task_create(DM_DEVICE_TARGET_MSG)))
+ if (!(dmt = libmp_dm_task_create(DM_DEVICE_TARGET_MSG)))
return 1;
if (!dm_task_set_name(dmt, mapname))
}
int
-dm_fail_path(char * mapname, char * path)
+dm_fail_path(const char * mapname, char * path)
{
char message[32];
}
int
-dm_reinstate_path(char * mapname, char * path)
+dm_reinstate_path(const char * mapname, char * path)
{
char message[32];
}
int
-dm_queue_if_no_path(char *mapname, int enable)
+dm_queue_if_no_path(const char *mapname, int enable)
{
char *message;
}
static int
-dm_groupmsg (char * msg, char * mapname, int index)
+dm_groupmsg (const char * msg, const char * mapname, int index)
{
char message[32];
}
int
-dm_switchgroup(char * mapname, int index)
+dm_switchgroup(const char * mapname, int index)
{
return dm_groupmsg("switch", mapname, index);
}
int
-dm_enablegroup(char * mapname, int index)
+dm_enablegroup(const char * mapname, int index)
{
return dm_groupmsg("enable", mapname, index);
}
int
-dm_disablegroup(char * mapname, int index)
+dm_disablegroup(const char * mapname, int index)
{
return dm_groupmsg("disable", mapname, index);
}
+struct multipath *dm_get_multipath(const char *name)
+{
+ struct multipath *mpp = NULL;
+
+ mpp = alloc_multipath();
+ if (!mpp)
+ return NULL;
+
+ mpp->alias = STRDUP(name);
+
+ if (!mpp->alias)
+ goto out;
+
+ if (dm_get_map(name, &mpp->size, NULL))
+ goto out;
+
+ dm_get_uuid(name, mpp->wwid);
+ dm_get_info(name, &mpp->dmi);
+
+ return mpp;
+out:
+ free_multipath(mpp, KEEP_PATHS);
+ return NULL;
+}
+
int
dm_get_maps (vector mp)
{
if (!mp)
return 1;
- if (!(dmt = dm_task_create(DM_DEVICE_LIST)))
+ if (!(dmt = libmp_dm_task_create(DM_DEVICE_LIST)))
return 1;
dm_task_no_open_count(dmt);
if (!dm_is_mpath(names->name))
goto next;
- mpp = alloc_multipath();
-
+ mpp = dm_get_multipath(names->name);
if (!mpp)
goto out;
- mpp->alias = STRDUP(names->name);
-
- if (!mpp->alias)
- goto out1;
-
- if (dm_get_map(names->name, &mpp->size, NULL))
- goto out1;
-
- dm_get_uuid(names->name, mpp->wwid);
- dm_get_info(names->name, &mpp->dmi);
-
if (!vector_alloc_slot(mp))
- goto out1;
+ goto out;
vector_set_slot(mp, mpp);
mpp = NULL;
r = 0;
goto out;
-out1:
- free_multipath(mpp, KEEP_PATHS);
out:
dm_task_destroy (dmt);
return r;
}
int
-dm_geteventnr (char *name)
+dm_geteventnr (const char *name)
{
- struct dm_task *dmt;
struct dm_info info;
- int event = -1;
- if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
+ if (do_get_info(name, &info) != 0)
return -1;
- if (!dm_task_set_name(dmt, name))
- goto out;
-
- dm_task_no_open_count(dmt);
-
- if (!dm_task_run(dmt))
- goto out;
-
- if (!dm_task_get_info(dmt, &info))
- goto out;
+ return info.event_nr;
+}
- if (info.exists)
- event = info.event_nr;
+int
+dm_is_suspended(const char *name)
+{
+ struct dm_info info;
-out:
- dm_task_destroy(dmt);
+ if (do_get_info(name, &info) != 0)
+ return -1;
- return event;
+ return info.suspended;
}
char *
int r;
int loop = MAX_WAIT * LOOPS_PER_SEC;
- if (!(dmt = dm_task_create(DM_DEVICE_STATUS)))
+ if (!(dmt = libmp_dm_task_create(DM_DEVICE_STATUS)))
return NULL;
if (!dm_task_set_major(dmt, major) ||
map = dm_task_get_name(dmt);
if (map && strlen(map))
- response = STRDUP((char *)dm_task_get_name(dmt));
+ response = STRDUP((const char *)dm_task_get_name(dmt));
dm_task_destroy(dmt);
return response;
unsigned long long size;
char dev_t[32];
int r = 1;
+ char *p;
- if (!(dmt = dm_task_create(DM_DEVICE_LIST)))
+ if (!(dmt = libmp_dm_task_create(DM_DEVICE_LIST)))
return 1;
dm_task_no_open_count(dmt);
do {
if (
/*
- * if devmap target is "linear"
+ * if there is only a single "linear" target
*/
- (dm_type(names->name, TGT_PART) > 0) &&
+ (dm_type(names->name, TGT_PART) == 1) &&
/*
- * and both uuid end with same suffix starting
- * at UUID_PREFIX
+ * and the uuid of the target is a partition of the
+ * uuid of the multipath device
*/
- (!dm_compare_uuid(names->name, mapname)) &&
+ is_mpath_part(names->name, mapname) &&
/*
* and we can fetch the map table from the kernel
/*
* and the table maps over the multipath map
*/
- strstr(params, dev_t)
+ (p = strstr(params, dev_t)) &&
+ !isdigit(*(p + strlen(dev_t)))
) {
if (partmap_func(names->name, data) != 0)
goto out;
}
static int
-dm_get_deferred_remove (char * mapname)
+dm_get_deferred_remove (const char * mapname)
{
- int r = -1;
- struct dm_task *dmt;
struct dm_info info;
- if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
+ if (do_get_info(mapname, &info) != 0)
return -1;
- if (!dm_task_set_name(dmt, mapname))
- goto out;
-
- if (!dm_task_run(dmt))
- goto out;
-
- if (!dm_task_get_info(dmt, &info))
- goto out;
-
- r = info.deferred_remove;
-out:
- dm_task_destroy(dmt);
- return r;
+ return info.deferred_remove;
}
static int
}
int
-dm_get_info (char * mapname, struct dm_info ** dmi)
+dm_get_info (const char * mapname, struct dm_info ** dmi)
{
- int r = 1;
- struct dm_task *dmt = NULL;
-
if (!mapname)
return 1;
if (!*dmi)
return 1;
- if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
- goto out;
-
- if (!dm_task_set_name(dmt, mapname))
- goto out;
-
- dm_task_no_open_count(dmt);
-
- if (!dm_task_run(dmt))
- goto out;
-
- if (!dm_task_get_info(dmt, *dmi))
- goto out;
-
- r = 0;
-out:
- if (r) {
+ if (do_get_info(mapname, *dmi) != 0) {
memset(*dmi, 0, sizeof(struct dm_info));
FREE(*dmi);
*dmi = NULL;
+ return 1;
}
-
- if (dmt)
- dm_task_destroy(dmt);
-
- return r;
+ return 0;
}
struct rename_data {
if (delim)
rd.delim = delim;
- if (isdigit(new[strlen(new)-1]))
- rd.delim = "p";
- else
- rd.delim = "";
+ else {
+ if (isdigit(new[strlen(new)-1]))
+ rd.delim = "p";
+ else
+ rd.delim = "";
+ }
return do_foreach_partmaps(old, rename_partmap, &rd);
}
if (dm_rename_partmaps(old, new, delim))
return r;
- if (!(dmt = dm_task_create(DM_DEVICE_RENAME)))
+ if (!(dmt = libmp_dm_task_create(DM_DEVICE_RENAME)))
return r;
if (!dm_task_set_name(dmt, old))
return r;
}
-void dm_reassign_deps(char *table, char *dep, char *newdep)
+void dm_reassign_deps(char *table, const char *dep, const char *newdep)
{
- char *p, *n;
- char *newtable;
+ char *n;
+ const char *p, *newtable;
newtable = strdup(table);
if (!newtable)
n += strlen(newdep);
p += strlen(dep);
strcat(n, p);
- free(newtable);
+ FREE_CONST(newtable);
}
int dm_reassign_table(const char *name, char *old, char *new)
char *buff;
void *next = NULL;
- if (!(dmt = dm_task_create(DM_DEVICE_TABLE)))
+ if (!(dmt = libmp_dm_task_create(DM_DEVICE_TABLE)))
return 0;
if (!dm_task_set_name(dmt, name))
if (!dm_task_run(dmt))
goto out;
- if (!(reload_dmt = dm_task_create(DM_DEVICE_RELOAD)))
+ if (!(reload_dmt = libmp_dm_task_create(DM_DEVICE_RELOAD)))
goto out;
if (!dm_task_set_name(reload_dmt, name))
goto out_reload;
return 1;
}
- if (!(dmt = dm_task_create(DM_DEVICE_DEPS))) {
+ if (!(dmt = libmp_dm_task_create(DM_DEVICE_DEPS))) {
condlog(3, "%s: couldn't make dm task", mapname);
return 0;
}
return 1;
}
- if (!(dmt = dm_task_create(DM_DEVICE_SET_GEOMETRY)))
+ if (!(dmt = libmp_dm_task_create(DM_DEVICE_SET_GEOMETRY)))
return 0;
if (!dm_task_set_name(dmt, mpp->alias))