--- libmultipath/defaults.h | 3 - libmultipath/file.c | 89 +++++++++++++++++++++++++++++++++++++++++- libmultipath/file.h | 3 + libmultipath/wwids.c | 7 ++- multipath/main.c | 36 +++++++++++++++- multipath/multipath.rules | 26 +++++++++--- multipathd/main.c | 4 + multipathd/multipathd.service | 2 multipathd/pidfile.c | 3 + 9 files changed, 160 insertions(+), 13 deletions(-) Index: multipath-tools-130222/libmultipath/defaults.h =================================================================== --- multipath-tools-130222.orig/libmultipath/defaults.h +++ multipath-tools-130222/libmultipath/defaults.h @@ -24,7 +24,8 @@ #define MAX_CHECKINT(a) (a << 2) #define MAX_DEV_LOSS_TMO 0x7FFFFFFF -#define DEFAULT_PIDFILE "/var/run/multipathd.pid" +#define DEFAULT_PIDFILE "/var/run/multipathd/multipathd.pid" +#define DEFAULT_TIMESTAMP_FILE "/var/run/multipathd/timestamp" #define DEFAULT_SOCKET "/org/kernel/linux/storage/multipathd" #define DEFAULT_CONFIGFILE "/etc/multipath.conf" #define DEFAULT_BINDINGS_FILE "/etc/multipath/bindings" Index: multipath-tools-130222/libmultipath/file.c =================================================================== --- multipath-tools-130222.orig/libmultipath/file.c +++ multipath-tools-130222/libmultipath/file.c @@ -12,10 +12,12 @@ #include #include #include +#include #include "file.h" #include "debug.h" #include "uxsock.h" +#include "defaults.h" /* @@ -36,8 +38,8 @@ * See the file COPYING included with this distribution for more details. */ -static int -ensure_directories_exist(char *str, mode_t dir_mode) +int +ensure_directories_exist(const char *str, mode_t dir_mode) { char *pathname; char *end; @@ -178,3 +180,86 @@ fail: close(fd); return -1; } + +/* If you can't get the timestamp, return equal to just keep using the + * existing value. + */ +int timestamp_equal(long int chk_timestamp) +{ + char buf[4096]; + FILE *file; + long int file_timestamp; + int ret = 1; + + if ((file = fopen(DEFAULT_TIMESTAMP_FILE, "r")) == NULL) { + if (errno != ENOENT) + condlog(2, "Cannot open timestamp file [%s]: %s", + DEFAULT_TIMESTAMP_FILE, strerror(errno)); + goto out; + } + errno = 0; + if (fgets(buf, sizeof(buf), file) == NULL) { + if (errno) + condlog(2, "Cannot read from timestamp file: %s", + strerror(errno)); + goto out; + } + if (sscanf(buf, "DM_MULTIPATH_TIMESTAMP=%ld", &file_timestamp) != 1) { + if (errno) + condlog(0, "Cannot get timestamp: %s", strerror(errno)); + else + condlog(0, "invalid timestamp file [%s]: %s", + DEFAULT_TIMESTAMP_FILE, strerror(errno)); + goto out; + } + if (file_timestamp != chk_timestamp) { + condlog(3, "timestamp has changed"); + ret = 0; + } + else + condlog(3, "timestamp has not changed"); +out: + if (file) + fclose(file); + return ret; +} + +int update_timestamp(int create) +{ + char buf[44]; + time_t timestamp; + int fd; + int flags = O_WRONLY; + if (create) + flags |= O_CREAT; + if((fd = open(DEFAULT_TIMESTAMP_FILE, flags, + (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) < 0) { + if (errno == ENOENT) + return 0; + condlog(0, "Cannot open timestamp file [%s]: %s", + DEFAULT_TIMESTAMP_FILE, strerror(errno)); + return 1; + } + if (ftruncate(fd, 0) < 0) { + condlog(0, "Cannot truncate timestamp file [%s]: %s", + DEFAULT_TIMESTAMP_FILE, strerror(errno)); + goto fail; + } + if (time(×tamp) == -1) { + condlog(0, "Cannot get current time: %s", strerror(errno)); + goto fail; + } + memset(buf, 0, sizeof(buf)); + snprintf(buf, sizeof(buf)-1, "DM_MULTIPATH_TIMESTAMP=%ld\n", + timestamp); + if (write(fd, buf, strlen(buf)) != strlen(buf)) { + condlog(0, "Cannot write out timestamp to %s: %s", + DEFAULT_TIMESTAMP_FILE, strerror(errno)); + goto fail; + } + close(fd); + return 0; +fail: + close(fd); + return 1; +} Index: multipath-tools-130222/libmultipath/file.h =================================================================== --- multipath-tools-130222.orig/libmultipath/file.h +++ multipath-tools-130222/libmultipath/file.h @@ -7,5 +7,8 @@ #define FILE_TIMEOUT 30 int open_file(char *file, int *can_write, char *header); +int ensure_directories_exist(const char *str, mode_t dir_mode); +int update_timestamp(int create); +int timestamp_equal(long int chk_timestamp); #endif /* _FILE_H */ Index: multipath-tools-130222/multipathd/pidfile.c =================================================================== --- multipath-tools-130222.orig/multipathd/pidfile.c +++ multipath-tools-130222/multipathd/pidfile.c @@ -9,6 +9,7 @@ #include /* for fcntl() */ #include +#include #include "pidfile.h" @@ -18,6 +19,8 @@ int pidfile_create(const char *pidFile, struct flock lock; int fd, value; + if (ensure_directories_exist(pidFile, 0700)) + return 1; if((fd = open(pidFile, O_WRONLY | O_CREAT, (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) < 0) { condlog(0, "Cannot open pidfile [%s], error was [%s]", Index: multipath-tools-130222/libmultipath/wwids.c =================================================================== --- multipath-tools-130222.orig/libmultipath/wwids.c +++ multipath-tools-130222/libmultipath/wwids.c @@ -125,6 +125,7 @@ replace_wwids(vector mp) goto out_file; } ret = 0; + update_timestamp(0); out_file: close(fd); out: @@ -209,6 +210,8 @@ remove_wwid(char *wwid) { goto out_file; } ret = do_remove_wwid(fd, str); + if (!ret) + update_timestamp(0); out_file: close(fd); @@ -294,8 +297,10 @@ remember_wwid(char *wwid) condlog(3, "failed writing wwid %s to wwids file", wwid); return -1; } - if (ret == 1) + if (ret == 1) { condlog(3, "wrote wwid %s to wwids file", wwid); + update_timestamp(0); + } else condlog(4, "wwid %s already in wwids file", wwid); return 0; Index: multipath-tools-130222/multipath/multipath.rules =================================================================== --- multipath-tools-130222.orig/multipath/multipath.rules +++ multipath-tools-130222/multipath/multipath.rules @@ -4,18 +4,34 @@ SUBSYSTEM!="block", GOTO="end_mpath" IMPORT{cmdline}="nompath" ENV{nompath}=="?*", GOTO="end_mpath" +ENV{DEVTYPE}=="partition", GOTO="end_mpath" ENV{MPATH_SBIN_PATH}="/sbin" TEST!="$env{MPATH_SBIN_PATH}/multipath", ENV{MPATH_SBIN_PATH}="/usr/sbin" +TEST!="/etc/multipath.conf", GOTO="check_kpartx" -ACTION=="add", ENV{DEVTYPE}!="partition", \ - ENV{DM_MULTIPATH_DEVICE_PATH}!="1", \ - TEST=="/etc/multipath.conf", \ +ACTION=="add", ENV{DM_MULTIPATH_DEVICE_PATH}!="1", \ PROGRAM=="$env{MPATH_SBIN_PATH}/multipath -c $tempnode", \ - ENV{DM_MULTIPATH_DEVICE_PATH}="1" ENV{ID_FS_TYPE}="mpath_member" + ENV{DM_MULTIPATH_DEVICE_PATH}="1", ENV{ID_FS_TYPE}="mpath_member" -ENV{DM_MULTIPATH_DEVICE_PATH}=="1", ENV{DEVTYPE}!="partition", \ +ENV{DM_MULTIPATH_DEVICE_PATH}=="1", \ RUN+="/sbin/partx -d --nr 1-1024 $env{DEVNAME}" +ACTION!="change", GOTO="update_timestamp" +IMPORT{db}="DM_MULTIPATH_TIMESTAMP" +IMPORT{db}="DM_MULTIPATH_DEVICE_PATH" +# Check if the device is part of a multipath device. the -T option just keeps +# the old result if the timestamp hasn't changed. +PROGRAM=="$env{MPATH_SBIN_PATH}/multipath -T $env{DM_MULTIPATH_TIMESTAMP}:$env{DM_MULTIPATH_DEVICE_PATH} -c $env{DEVNAME}", \ + ENV{DM_MULTIPATH_DEVICE_PATH}="1", ENV{ID_FS_TYPE}="mpath_member", \ + GOTO="update_timestamp" + +# If the device isn't part of a multipath device, clear this +ENV{DM_MULTIPATH_DEVICE_PATH}="" + +LABEL="update_timestamp" +IMPORT{file}="/run/multipathd/timestamp" + +LABEL="check_kpartx" KERNEL!="dm-*", GOTO="end_mpath" ENV{DM_UUID}=="mpath-?*|part[0-9]*-mpath-?*", OPTIONS+="link_priority=10" ACTION!="change", GOTO="end_mpath" Index: multipath-tools-130222/multipathd/main.c =================================================================== --- multipath-tools-130222.orig/multipathd/main.c +++ multipath-tools-130222/multipathd/main.c @@ -54,6 +54,7 @@ #include #include #include +#include #include "main.h" #include "pidfile.h" @@ -1417,6 +1418,7 @@ reconfigure (struct vectors * vecs) free_config(old); retval = 0; } + update_timestamp(0); return retval; } @@ -1709,6 +1711,7 @@ child (void * param) /* Startup complete, create logfile */ pid_rc = pidfile_create(DEFAULT_PIDFILE, daemon_pid); + update_timestamp(1); /* Ignore errors, we can live without */ running_state = DAEMON_RUNNING; @@ -1758,6 +1761,7 @@ child (void * param) if (!pid_rc) { condlog(3, "unlink pidfile"); unlink(DEFAULT_PIDFILE); + unlink(DEFAULT_TIMESTAMP_FILE); } condlog(2, "--------shut down-------"); Index: multipath-tools-130222/multipathd/multipathd.service =================================================================== --- multipath-tools-130222.orig/multipathd/multipathd.service +++ multipath-tools-130222/multipathd/multipathd.service @@ -9,7 +9,7 @@ Conflicts=shutdown.target [Service] Type=forking -PIDFile=/var/run/multipathd.pid +PIDFile=/var/run/multipathd/multipathd.pid ExecStartPre=/sbin/modprobe dm-multipath ExecStart=/sbin/multipathd ExecReload=/sbin/multipathd reconfigure Index: multipath-tools-130222/multipath/main.c =================================================================== --- multipath-tools-130222.orig/multipath/main.c +++ multipath-tools-130222/multipath/main.c @@ -55,6 +55,7 @@ #include #include #include +#include #include "dev_t.h" int logsink; @@ -84,7 +85,7 @@ usage (char * progname) { fprintf (stderr, VERSION_STRING); fprintf (stderr, "Usage:\n"); - fprintf (stderr, " %s [-c|-w|-W] [-d] [-r] [-v lvl] [-p pol] [-b fil] [-q] [dev]\n", progname); + fprintf (stderr, " %s [-c|-w|-W] [-d] [-T tm:val] [-r] [-v lvl] [-p pol] [-b fil] [-q] [dev]\n", progname); fprintf (stderr, " %s -l|-ll|-f [-v lvl] [-b fil] [dev]\n", progname); fprintf (stderr, " %s -F [-v lvl]\n", progname); fprintf (stderr, " %s -t\n", progname); @@ -98,6 +99,9 @@ usage (char * progname) " -f flush a multipath device map\n" \ " -F flush all multipath device maps\n" \ " -c check if a device should be a path in a multipath device\n" \ + " -T tm:val\n" \ + " check if tm matches the multipathd timestamp. If so val is\n" \ + " whether or not the device is a path in a multipath device\n" \ " -q allow queue_if_no_path when multipathd is not running\n"\ " -d dry run, do not create or update devmaps\n" \ " -t dump internal hardware table\n" \ @@ -441,7 +445,31 @@ main (int argc, char *argv[]) extern char *optarg; extern int optind; int r = 1; - + long int timestamp = -1; + int valid = -1; + while ((arg = getopt(argc, argv, ":dchl::FfM:v:p:b:BrtT:qwW")) != EOF ) { + switch(arg) { + case 'T': + if (optarg[0] == ':') + sscanf(optarg, ":%d", &valid); + else + sscanf(optarg, "%ld:%d", ×tamp, &valid); + if (timestamp_equal(timestamp)) + return (valid != 1); + break; + case ':': + fprintf(stderr, "Missing option argument\n"); + usage(argv[0]); + exit(1); + case '?': + fprintf(stderr, "Unknown switch: %s\n", optarg); + usage(argv[0]); + exit(1); + default: + break; + } + } + optind = 1; if (getuid() != 0) { fprintf(stderr, "need to be root\n"); exit(1); @@ -455,7 +483,7 @@ main (int argc, char *argv[]) if (dm_prereq()) exit(1); - while ((arg = getopt(argc, argv, ":dchl::FfM:v:p:b:BrtqwW")) != EOF ) { + while ((arg = getopt(argc, argv, ":dchl::FfM:v:p:b:BrtT:qwW")) != EOF ) { switch(arg) { case 1: printf("optarg : %s\n",optarg); break; @@ -517,6 +545,8 @@ main (int argc, char *argv[]) case 't': r = dump_config(); goto out; + case 'T': + break; case 'h': usage(argv[0]); exit(0);