Replace by an Unix socket communication with the daemon.
The daemon has its pathvec always up-to-date, thanks to its
event-driven model.
As a side-effect, people who care about early userspace have now
2 options :
1) No daemon in early userspace, and disable hotplug-triggered multipath.
/sbin/multipath is ran once.
2) Start the daemon in early userspace, let multipath be hotplug-triggered
Comments welcome on dm-devel. It's not too late to revert the thing :/
-#include <stdio.h>
#include <unistd.h>
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <string.h>
-#include <time.h>
+#include "memory.h"
#include "vector.h"
#include "structs.h"
#include "debug.h"
#include "cache.h"
+#include "uxsock.h"
static void
revoke_cache_info(struct path * pp)
{
+ pp->checker_context = NULL;
pp->fd = 0;
}
-static int
-lock_fd (int fd, int flag)
-{
- struct flock fl;
-
- fl.l_type = flag;
- fl.l_whence = 0;
- fl.l_start = 0;
- fl.l_len = 0;
-
- alarm(MAX_WAIT);
-
- if (fcntl(fd, F_SETLKW, &fl) == -1) {
- condlog(0, "can't take a write lease on cache file\n");
- return 1;
- }
- alarm(0);
- return 0;
-}
-
int
cache_load (vector pathvec)
{
+ char *reply;
+ size_t len;
int fd;
- int r = 1;
- off_t record_len;
- struct path record;
struct path * pp;
+ int r = 1;
+ char * p;
- fd = open(CACHE_FILE, O_RDONLY);
+ fd = ux_socket_connect(SOCKET_NAME);
- if (fd < 0)
+ if (fd == -1) {
+ condlog(0, "ux_socket_connect error");
return 1;
+ }
- if (lock_fd(fd, F_RDLCK))
- goto out;
-
- record_len = sizeof(struct path);
+ send_packet(fd, "dump pathvec", 13);
+ recv_packet(fd, &reply, &len);
- while (read(fd, &record, record_len)) {
+ for (p = reply; p < (reply + len); p += sizeof(struct path)) {
pp = alloc_path();
if (!pp)
goto out;
}
vector_set_slot(pathvec, pp);
- memcpy(pp, &record, record_len);
+ memcpy(pp, (void *)p, sizeof(struct path));
revoke_cache_info(pp);
}
- r = 0;
- lock_fd(fd, F_UNLCK);
-out:
- close(fd);
- return r;
-}
-int
-cache_dump (vector pathvec)
-{
- int i;
- int fd;
- int r = 1;
- off_t record_len;
- struct path * pp;
-
- fd = open(CACHE_TMPFILE, O_RDWR|O_CREAT, 0600);
-
- if (fd < 0)
- return 1;
-
- if (lock_fd(fd, F_WRLCK))
- goto out;
-
- ftruncate(fd, 0);
- record_len = sizeof(struct path);
-
- vector_foreach_slot (pathvec, pp, i) {
- if (write(fd, pp, record_len) < record_len)
- goto out1;
- }
- rename(CACHE_TMPFILE, CACHE_FILE);
r = 0;
-out1:
- lock_fd(fd, F_UNLCK);
out:
+ FREE(reply);
close(fd);
return r;
}
-
-int
-cache_cold (int expire)
-{
- time_t t;
- struct stat s;
-
- if (time(&t) < 0)
- return 1;
-
- if(stat(CACHE_FILE, &s))
- return 1;
-
- if ((t - s.st_mtime) < expire)
- return 0;
-
- return 1;
-}
-#define CACHE_FILE "/var/cache/multipath/.multipath.cache"
-#define CACHE_TMPFILE "/var/cache/multipath/.multipath.cache.tmp"
-#define CACHE_EXPIRE 5
-#define MAX_WAIT 5
-
int cache_load (vector pathvec);
-int cache_dump (vector pathvec);
-int cache_cold (int expire);
printf("%-7s ", pp->dev_t);
if (conf->list > 1) {
- len = pstate_snprintf(&buff, MAX_PSTATE_LEN, pp->state);
+ len = pstate_snprintf(&buff[0], MAX_PSTATE_LEN, pp->state);
if (len) {
printf("[%s", buff);
if (conf->dev && blacklist(conf->blist, conf->dev))
goto out;
- if (!cache_cold(CACHE_EXPIRE)) {
- condlog(3, "load path identifiers cache");
- cache_load(pathvec);
+ condlog(3, "load path identifiers cache");
+ cache_load(pathvec);
+
+ if (conf->verbosity > 2) {
+ fprintf(stdout, "#\n# all paths in cache :\n#\n");
+ print_all_paths(pathvec);
}
/*
if (get_dm_mpvec(curmp, pathvec, refwwid))
goto out;
- cache_dump(pathvec);
filter_pathvec(pathvec, refwwid);
if (conf->list)
}
int
-add_handler (int fp, char * (*fn)(void *, void *))
+add_handler (int fp, int (*fn)(void *, char **, int *, void *))
{
struct handler * h;
r += add_key(keys, "path", PATH, 1);
r += add_key(keys, "map", MAP, 1);
r += add_key(keys, "group", GROUP, 1);
+ r += add_key(keys, "dump", DUMP, 0);
+ r += add_key(keys, "pathvec", PATHVEC, 0);
if (r) {
free_keys(keys);
struct key * kw = NULL;
vector_foreach_slot (keys, kw, i)
- if (!strncmp(kw->str, str, strlen(kw->str)))
+ if (strlen(str) == strlen(kw->str) &&
+ !strcmp(kw->str, str))
return kw;
return NULL;
return reply;
}
-char *
-parse_cmd (char * cmd, void * data)
+int
+parse_cmd (char * cmd, char ** reply, int * len, void * data)
{
- char * reply;
+ int r;
struct handler * h;
vector cmdvec = get_cmdvec(cmd);
- if (!cmdvec)
- return genhelp_handler();
+ if (!cmdvec) {
+ *reply = genhelp_handler();
+ *len = strlen(*reply);
+ return 0;
+ }
h = find_handler(fingerprint(cmdvec));
- if (!h)
- return genhelp_handler();
+ if (!h) {
+ *reply = genhelp_handler();
+ *len = strlen(*reply);
+ return 0;
+ }
/*
* execute handler
*/
- reply = h->fn(cmdvec, data);
+ r = h->fn(cmdvec, reply, len, data);
free_keys(cmdvec);
- return reply;
+ return r;
}
char *
#define PATH (1 << 6)
#define MAP (1 << 7)
#define GROUP (1 << 8)
+#define DUMP (1 << 9)
+#define PATHVEC (1 << 10)
#define MAX_REPLY_LEN 1000
struct handler {
int fingerprint;
- char * (*fn)(void *, void *);
+ int (*fn)(void *, char **, int *, void *);
};
vector keys;
vector handlers;
int alloc_handlers (void);
-int add_handler (int fp, char * (*fn)(void *, void *));
-char * parse_cmd (char * cmd, void *);
+int add_handler (int fp, int (*fn)(void *, char **, int *, void *));
+int parse_cmd (char * cmd, char ** reply, int * len, void *);
int load_keys (void);
char * get_keyparam (vector v, int code);
void free_keys (vector vec);
#include "main.h"
#include "cli.h"
-char *
-list_paths (void * v, void * data)
+int
+cli_list_paths (void * v, char ** reply, int * len, void * data)
{
struct paths * allpaths = (struct paths *)data;
- return show_paths(allpaths);
+ return show_paths(reply, len, allpaths);
}
-char *
-list_maps (void * v, void * data)
+int
+cli_list_maps (void * v, char ** reply, int * len, void * data)
{
struct paths * allpaths = (struct paths *)data;
- return show_maps(allpaths);
+ return show_maps(reply, len, allpaths);
}
-char *
-add_path (void * v, void * data)
+int
+cli_add_path (void * v, char ** reply, int * len, void * data)
{
struct paths * allpaths = (struct paths *)data;
char * param = get_keyparam(v, PATH);
- if (uev_add_path(param, allpaths))
- return NULL;
-
- return STRDUP("ok");
+ return uev_add_path(param, allpaths);
}
-char *
-del_path (void * v, void * data)
+int
+cli_del_path (void * v, char ** reply, int * len, void * data)
{
struct paths * allpaths = (struct paths *)data;
char * param = get_keyparam(v, PATH);
- if (uev_remove_path(param, allpaths))
- return NULL;
-
- return STRDUP("ok");
+ return uev_remove_path(param, allpaths);
}
-char *
-add_map (void * v, void * data)
+int
+cli_add_map (void * v, char ** reply, int * len, void * data)
{
struct paths * allpaths = (struct paths *)data;
char * param = get_keyparam(v, MAP);
- if (uev_add_map(param, allpaths))
- return NULL;
-
- return STRDUP("ok");
+ return uev_add_map(param, allpaths);
}
-char *
-del_map (void * v, void * data)
+int
+cli_del_map (void * v, char ** reply, int * len, void * data)
{
struct paths * allpaths = (struct paths *)data;
char * param = get_keyparam(v, MAP);
- if (uev_remove_map(param, allpaths))
- return NULL;
-
- return STRDUP("ok");
+ return uev_remove_map(param, allpaths);
}
-char *
-switch_group(void * v, void * data)
+int
+cli_switch_group(void * v, char ** reply, int * len, void * data)
{
char * mapname = get_keyparam(v, MAP);
int groupnum = atoi(get_keyparam(v, GROUP));
- dm_switchgroup(mapname, groupnum);
+ return dm_switchgroup(mapname, groupnum);
+}
- return STRDUP("ok");
+int
+cli_dump_pathvec(void * v, char ** reply, int * len, void * data)
+{
+ struct paths * allpaths = (struct paths *)data;
+
+ return dump_pathvec(reply, len, allpaths);
}
-char * list_paths (void * v, void * data);
-char * list_maps (void * v, void * data);
-char * add_path (void * v, void * data);
-char * del_path (void * v, void * data);
-char * add_map (void * v, void * data);
-char * del_map (void * v, void * data);
-char * switch_group (void * v, void * data);
+int cli_list_paths (void * v, char ** reply, int * len, void * data);
+int cli_list_maps (void * v, char ** reply, int * len, void * data);
+int cli_add_path (void * v, char ** reply, int * len, void * data);
+int cli_del_path (void * v, char ** reply, int * len, void * data);
+int cli_add_map (void * v, char ** reply, int * len, void * data);
+int cli_del_map (void * v, char ** reply, int * len, void * data);
+int cli_switch_group(void * v, char ** reply, int * len, void * data);
+int cli_dump_pathvec(void * v, char ** reply, int * len, void * data);
return 0;
}
-char *
-show_paths (struct paths * allpaths)
+int
+show_paths (char ** r, int * len, struct paths * allpaths)
{
int i, j, k;
struct path * pp;
reply = MALLOC(MAX_REPLY_LEN);
if (!reply)
- return NULL;
+ return 1;
c = reply;
c += sprintf(c, "\n");
if (MAX_REPLY_LEN - MAX_PSTATE_LEN < 0) {
FREE(reply);
- return NULL;
+ return 1;
}
j = pstate_snprintf(c, MAX_PSTATE_LEN, pp->state);
c += sprintf(c, "\n");
}
- reply[MAX_REPLY_LEN - 1] = 0;
- return reply;
+ *r = reply;
+ *len = (int)(c - reply);
+ return 0;
}
-char *
-show_maps (struct paths * allpaths)
+int
+show_maps (char ** r, int *len, struct paths * allpaths)
{
int i, j, k;
struct multipath * mpp;
reply = MALLOC(MAX_REPLY_LEN);
if (!reply)
- return NULL;
+ return 1;
c = reply;
c += sprintf(c, "\n");
c += sprintf(c, "\n");
}
- reply[MAX_REPLY_LEN - 1] = 0;
- return reply;
+ *r = reply;
+ *len = (int)(c - reply);
+ return 0;
}
-char *
-uxsock_trigger (char * str, void * trigger_data)
+int
+dump_pathvec (char ** r, int * len, struct paths * allpaths)
{
- struct paths * allpaths;
- char * reply = NULL;
+ int i;
+ struct path * pp;
+ char * reply;
+ char * p;
+
+ *len = VECTOR_SIZE(allpaths->pathvec) * sizeof(struct path);
+ reply = (char *)MALLOC(*len);
+ *r = reply;
+
+ if (!reply)
+ return 1;
+ p = reply;
+
+ vector_foreach_slot (allpaths->pathvec, pp, i) {
+ memcpy((void *)p, pp, sizeof(struct path));
+ p += sizeof(struct path);
+ }
+
+ return 0;
+}
+
+int
+uxsock_trigger (char * str, char ** reply, int * len, void * trigger_data)
+{
+ struct paths * allpaths;
+ int r;
+
+ *reply = NULL;
+ *len = 0;
allpaths = (struct paths *)trigger_data;
pthread_cleanup_push(cleanup_lock, allpaths->lock);
lock(allpaths->lock);
- reply = parse_cmd(str, allpaths);
-
- if (!reply)
- reply = STRDUP("fail\n");
+ r = parse_cmd(str, reply, len, allpaths);
- else if (strlen(reply) == 0)
- reply = STRDUP("ok\n");
+ if (r) {
+ *reply = STRDUP("fail\n");
+ *len = strlen(*reply) + 1;
+ r = 1;
+ }
+ else if (*len == 0) {
+ *reply = STRDUP("ok\n");
+ *len = strlen(*reply) + 1;
+ r = 0;
+ }
pthread_cleanup_pop(1);
- return reply;
+ return r;
}
int
if (alloc_handlers())
return NULL;
- add_handler(LIST+PATHS, list_paths);
- add_handler(LIST+MAPS, list_maps);
- add_handler(ADD+PATH, add_path);
- add_handler(DEL+PATH, del_path);
- add_handler(ADD+MAP, add_map);
- add_handler(DEL+MAP, del_map);
- add_handler(SWITCH+MAP+GROUP, switch_group);
+ add_handler(LIST+PATHS, cli_list_paths);
+ add_handler(LIST+MAPS, cli_list_maps);
+ add_handler(ADD+PATH, cli_add_path);
+ add_handler(DEL+PATH, cli_del_path);
+ add_handler(ADD+MAP, cli_add_map);
+ add_handler(DEL+MAP, cli_del_map);
+ add_handler(SWITCH+MAP+GROUP, cli_switch_group);
+ add_handler(DUMP+PATHVEC, cli_dump_pathvec);
uxsock_listen(&uxsock_trigger, ap);
vector mpvec;
};
-char * show_paths (struct paths *);
-char * show_maps (struct paths *);
+int show_paths (char **, int *, struct paths *);
+int show_maps (char **, int *, struct paths *);
+int dump_pathvec (char **, int *, struct paths * allpaths);
int uev_add_path (char *, struct paths *);
int uev_remove_path (char *, struct paths *);
int uev_add_map (char *, struct paths *);
/*
* entry point
*/
-void * uxsock_listen(char * (*uxsock_trigger)(char *, void * trigger_data),
+void * uxsock_listen(int (*uxsock_trigger)(char *, char **, int *, void *),
void * trigger_data)
{
int ux_sock;
size_t len;
+ int rlen;
char *inbuf;
char *reply;
dead_client(c);
} else {
inbuf[len - 1] = 0;
- condlog(4, "Got request [s]", inbuf);
- reply = uxsock_trigger(inbuf,
+ condlog(4, "Got request [%s]", inbuf);
+ uxsock_trigger(inbuf, &reply, &rlen,
trigger_data);
if (reply) {
if (send_packet(c->fd, reply,
- strlen(reply) + 1) != 0) {
+ rlen) != 0) {
dead_client(c);
}
FREE(reply);
+ reply = NULL;
}
FREE(inbuf);
}
struct pollfd *polls;
void free_polls(void);
-void * uxsock_listen(char * (*uxsock_trigger)
- (char *, void * trigger_data),
+void * uxsock_listen(int (*uxsock_trigger)
+ (char *, char **, int *, void *),
void * trigger_data);