conf->multipath_dir = set_default(DEFAULT_MULTIPATHDIR);
conf->flush_on_last_del = 0;
conf->attribute_flags = 0;
+ conf->reassign_maps = DEFAULT_REASSIGN_MAPS;
/*
* preload default hwtable
gid_t gid;
mode_t mode;
uint32_t cookie;
+ int reassign_maps;
char * dev;
char * sysfs_dir;
#define DEFAULT_PGTIMEOUT -PGTIMEOUT_NONE
#define DEFAULT_USER_FRIENDLY_NAMES 0
#define DEFAULT_VERBOSITY 2
+#define DEFAULT_REASSIGN_MAPS 1
#define DEFAULT_CHECKINT 5
#define MAX_CHECKINT(a) (a << 2)
#include "memory.h"
#include "devmapper.h"
#include "config.h"
+#include "sysfs.h"
#include "log_pthread.h"
#include <sys/types.h>
return r;
}
+void dm_reassign_deps(char *table, char *dep, char *newdep)
+{
+ char *p, *n;
+ char newtable[PARAMS_SIZE];
+
+ strcpy(newtable, table);
+ p = strstr(newtable, dep);
+ n = table + (p - newtable);
+ strcpy(n, newdep);
+ n += strlen(newdep);
+ p += strlen(dep);
+ strcat(n, p);
+}
+
+int dm_reassign_table(const char *name, char *old, char *new)
+{
+ int r, modified = 0;
+ uint64_t start, length;
+ struct dm_task *dmt, *reload_dmt;
+ char *target, *params = NULL;
+ char buff[PARAMS_SIZE];
+ void *next = NULL;
+
+ if (!(dmt = dm_task_create(DM_DEVICE_TABLE)))
+ return 0;
+
+ if (!dm_task_set_name(dmt, name))
+ goto out;
+
+ dm_task_no_open_count(dmt);
+
+ if (!dm_task_run(dmt))
+ goto out;
+ if (!(reload_dmt = dm_task_create(DM_DEVICE_RELOAD)))
+ goto out;
+ if (!dm_task_set_name(reload_dmt, name))
+ goto out_reload;
+
+ do {
+ next = dm_get_next_target(dmt, next, &start, &length,
+ &target, ¶ms);
+ memset(buff, 0, PARAMS_SIZE);
+ strcpy(buff, params);
+ if (strcmp(target, TGT_MPATH) && strstr(params, old)) {
+ condlog(3, "%s: replace target %s %s",
+ name, target, buff);
+ dm_reassign_deps(buff, old, new);
+ condlog(3, "%s: with target %s %s",
+ name, target, buff);
+ modified++;
+ }
+ dm_task_add_target(reload_dmt, start, length, target, buff);
+ } while (next);
+
+ if (modified) {
+ dm_task_no_open_count(reload_dmt);
+
+ if (!dm_task_run(reload_dmt)) {
+ condlog(3, "%s: failed to reassign targets", name);
+ goto out_reload;
+ }
+ dm_simplecmd_noflush(DM_DEVICE_RESUME, name);
+ }
+ r = 1;
+
+out_reload:
+ dm_task_destroy(reload_dmt);
+out:
+ dm_task_destroy(dmt);
+ return r;
+}
+
+
+/*
+ * Reassign existing device-mapper table(s) to not use
+ * the block devices but point to the multipathed
+ * device instead
+ */
+int dm_reassign(const char *mapname)
+{
+ struct dm_deps *deps;
+ struct dm_task *dmt;
+ struct dm_info info;
+ char dev_t[32], dm_dep[32];
+ int r = 0, i;
+
+ if (dm_dev_t(mapname, &dev_t[0], 32)) {
+ condlog(3, "%s: failed to get device number\n", mapname);
+ return 1;
+ }
+
+ if (!(dmt = dm_task_create(DM_DEVICE_DEPS)))
+ return 0;
+
+ 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, &info))
+ goto out;
+
+ if (!(deps = dm_task_get_deps(dmt)))
+ goto out;
+
+ if (!info.exists)
+ goto out;
+
+ for (i = 0; i < deps->count; i++) {
+ sprintf(dm_dep, "%d:%d",
+ major(deps->device[i]),
+ minor(deps->device[i]));
+ sysfs_check_holders(dm_dep, dev_t);
+ }
+
+ dm_task_destroy (dmt);
+
+ r = 1;
+out:
+ return r;
+}
+
int dm_setgeometry(struct multipath *mpp)
{
struct dm_task *dmt;
int dm_get_info (char * mapname, struct dm_info ** dmi);
int dm_rename (char * old, char * new);
char * dm_get_name(char * uuid);
+int dm_reassign(const char * mapname);
+int dm_reassign_table(const char *name, char *old, char *new);
int dm_setgeometry(struct multipath *mpp);
void udev_wait(unsigned int c);
void udev_set_sync_support(int c);
return 0;
}
+static int
+reassign_maps_handler(vector strvec)
+{
+ char * buff;
+
+ buff = set_value(strvec);
+ if (!strcmp(buff, "yes"))
+ conf->reassign_maps = 1;
+ else if (!strcmp(buff, "no"))
+ conf->reassign_maps = 0;
+ else
+ return 1;
+
+ return 0;
+}
+
static int
udev_dir_handler(vector strvec)
{
return snprintf(buff, len, "%i", conf->max_checkint);
}
+static int
+snprint_reassign_maps (char * buff, int len, void * data)
+{
+ if (conf->reassign_maps == DEFAULT_REASSIGN_MAPS)
+ return 0;
+ return snprintf(buff, len, "%s",
+ conf->reassign_maps?"yes":"no");
+}
+
static int
snprint_def_udev_dir (char * buff, int len, void * data)
{
install_keyword("verbosity", &verbosity_handler, &snprint_def_verbosity);
install_keyword("polling_interval", &polling_interval_handler, &snprint_def_polling_interval);
install_keyword("max_polling_interval", &max_polling_interval_handler, &snprint_def_max_polling_interval);
+ install_keyword("reassign_maps", &reassign_maps_handler, &snprint_reassign_maps);
install_keyword("udev_dir", &udev_dir_handler, &snprint_def_udev_dir);
install_keyword("multipath_dir", &multipath_dir_handler, &snprint_def_multipath_dir);
install_keyword("path_selector", &def_selector_handler, &snprint_def_selector);
#include <errno.h>
#include <sys/stat.h>
#include <string.h>
+#include <dirent.h>
#include "checkers.h"
#include "vector.h"
#include "list.h"
#include "util.h"
#include "debug.h"
+#include "devmapper.h"
char sysfs_path[PATH_SIZE];
return size;
}
+
+int sysfs_check_holders(char * check_devt, char * new_devt)
+{
+ unsigned int major, new_minor, table_minor;
+ char path[PATH_SIZE], check_dev[PATH_SIZE];
+ char * table_name;
+ DIR *dirfd;
+ struct dirent *holder;
+
+ if (sscanf(new_devt,"%d:%d", &major, &new_minor) != 2) {
+ condlog(1, "invalid device number %s", new_devt);
+ return 0;
+ }
+
+ if (devt2devname(check_dev, PATH_SIZE, check_devt))
+ return 0;
+
+ condlog(3, "%s: checking holder", check_dev);
+
+ snprintf(path, PATH_SIZE, "/sys/block/%s/holders", check_dev);
+ dirfd = opendir(path);
+ if (dirfd == NULL) {
+ condlog(3, "%s: failed to open directory %s (%d)",
+ check_dev, path, errno);
+ return 0;
+ }
+ while ((holder = readdir(dirfd)) != NULL) {
+ if ((strcmp(holder->d_name,".") == 0) ||
+ (strcmp(holder->d_name,"..") == 0))
+ continue;
+
+ if (sscanf(holder->d_name, "dm-%d", &table_minor) != 1) {
+ condlog(3, "%s: %s is not a dm-device",
+ check_dev, holder->d_name);
+ continue;
+ }
+ if (table_minor == new_minor) {
+ condlog(3, "%s: holder already correct", check_dev);
+ continue;
+ }
+ table_name = dm_mapname(major, table_minor);
+
+ condlog(3, "%s: reassign table %s old %s new %s", check_dev,
+ table_name, check_devt, new_devt);
+
+ dm_reassign_table(table_name, check_devt, new_devt);
+ FREE(table_name);
+ }
+ closedir(dirfd);
+
+ return 0;
+}
const char *value, int value_len);
int sysfs_resolve_link(char *path, size_t size);
int sysfs_get_size (struct sysfs_device * dev, unsigned long long * size);
+int sysfs_check_holders(char * check_devt, char * new_devt);
#endif
levels are between 0 and 6; default is
.I 2
.TP
+.B reassign_maps
+enable reassigning of device-mapper maps. With this option multipathd
+will remap existing device-mapper maps to always point to multipath
+device, not the underlying block devices. Possible values are
+\fIyes\fR and \fIno\fR. Default is
+.I yes
+.TP
.B path_selector
The default path selector algorithm to use; they are offered by the
kernel multipath target. There are three selector algorithms.
r += add_key(keys, "reinstate", REINSTATE, 0);
r += add_key(keys, "fail", FAIL, 0);
r += add_key(keys, "resize", RESIZE, 0);
+ r += add_key(keys, "reset", RESET, 0);
r += add_key(keys, "disablequeueing", DISABLEQ, 0);
r += add_key(keys, "restorequeueing", RESTOREQ, 0);
r += add_key(keys, "paths", PATHS, 0);
add_handler(SUSPEND+MAP, NULL);
add_handler(RESUME+MAP, NULL);
add_handler(RESIZE+MAP, NULL);
+ add_handler(RESET+MAP, NULL);
add_handler(DISABLEQ+MAP, NULL);
add_handler(RESTOREQ+MAP, NULL);
add_handler(DISABLEQ+MAPS, NULL);
__REINSTATE,
__FAIL,
__RESIZE,
+ __RESET,
__DISABLEQ,
__RESTOREQ,
__PATHS,
#define REINSTATE (1 << __REINSTATE)
#define FAIL (1 << __FAIL)
#define RESIZE (1 << __RESIZE)
+#define RESET (1 << __RESET)
#define DISABLEQ (1 << __DISABLEQ)
#define RESTOREQ (1 << __RESTOREQ)
#define PATHS (1 << __PATHS)
#include "main.h"
#include "cli.h"
+#include "uevent.h"
#define REALLOC_REPLY(r, a, m) \
do { \
return dm_reinstate_path(pp->mpp->alias, pp->dev_t);
}
+int
+cli_reassign (void * v, char ** reply, int * len, void * data)
+{
+ char * param = get_keyparam(v, MAP);
+
+ condlog(3, "%s: reset devices (operator)", param);
+
+ dm_reassign(param);
+ return 0;
+}
+
int
cli_fail(void * v, char ** reply, int * len, void * data)
{
int cli_fail(void * v, char ** reply, int * len, void * data);
int cli_quit(void * v, char ** reply, int * len, void * data);
int cli_shutdown(void * v, char ** reply, int * len, void * data);
+int cli_reassign (void * v, char ** reply, int * len, void * data);
dm_lib_release();
condlog(2, "%s devmap removed", ompp->alias);
}
+ } else if (conf->reassign_maps) {
+ condlog(3, "%s: Reassign existing device-mapper"
+ " devices", ompp->alias);
+ dm_reassign(ompp->alias);
}
}
return 0;
* if we create a multipath mapped device as a result
* of uev_add_path
*/
- condlog(0, "%s: devmap already registered", dev);
+ if (conf->reassign_maps) {
+ condlog(3, "%s: Reassign existing device-mapper devices",
+ alias);
+ dm_reassign(alias);
+ }
+ FREE(alias);
return 0;
}
set_handler_callback(SUSPEND+MAP, cli_suspend);
set_handler_callback(RESUME+MAP, cli_resume);
set_handler_callback(RESIZE+MAP, cli_resize);
+ set_handler_callback(RESET+MAP, cli_reassign);
set_handler_callback(REINSTATE+PATH, cli_reinstate);
set_handler_callback(FAIL+PATH, cli_fail);
set_handler_callback(DISABLEQ+MAP, cli_disable_queueing);