Search
j0ke.net Open Build Service
>
Projects
>
GFS
>
multipath-tools
> multipath-tools-git-sp2-update
Sign Up
|
Log In
Username
Password
Cancel
Overview
Repositories
Revisions
Requests
Users
Advanced
Attributes
Meta
File multipath-tools-git-sp2-update of Package multipath-tools
From 3b3d4906e5e98b9c7cb8dcbb5bb495f04b0a2f27 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke <hare@suse.de> Date: Fri, 9 Nov 2007 14:05:29 +0100 Subject: [PATCH] Backport git fixes Various fixes from git which have been accumulated. Signed-off-by: Hannes Reinecke <hare@suse.de> --- Makefile | 2 +- kpartx/Makefile | 2 +- kpartx/devmapper.c | 9 +++- kpartx/devmapper.h | 4 +- kpartx/gpt.c | 35 ++++++++++------ kpartx/kpartx.c | 15 ++++--- kpartx/kpartx.h | 6 ++- libcheckers/checkers.c | 31 +++++++++++++- libcheckers/checkers.h | 17 ++++++- libcheckers/directio.c | 37 +++++++++++----- libcheckers/emc_clariion.c | 2 +- libcheckers/libsg.c | 7 +++- libcheckers/rdac.c | 4 +- libcheckers/readsector0.c | 2 +- libmultipath/alias.c | 38 ++++++++++++----- libmultipath/blacklist.c | 6 +++ libmultipath/devmapper.c | 1 + libmultipath/discovery.c | 82 +++++++++++++++++------------------- libmultipath/hwtable.c | 8 ++-- libmultipath/uevent.c | 99 +++++++++++++++++++++++++++++--------------- multipathd/cli_handlers.c | 10 ++++- multipathd/main.c | 16 ++++++- 22 files changed, 289 insertions(+), 144 deletions(-) diff --git a/Makefile b/Makefile index aacede3..ee554e7 100644 --- a/Makefile +++ b/Makefile @@ -20,7 +20,7 @@ endif export KRNLSRC export KRNLOBJ -BUILDDIRS = $(shell find . -mindepth 2 -name Makefile -exec dirname {} \; | grep -v ^lib) +BUILDDIRS = $(shell find . -mindepth 2 -name Makefile -exec dirname {} \; | grep -vE '^lib|/\.') ifeq ($(MULTIPATH_VERSION),) VERSION = $(shell basename ${PWD} | cut -d'-' -f3) diff --git a/kpartx/Makefile b/kpartx/Makefile index 1fa547e..d979cc5 100644 --- a/kpartx/Makefile +++ b/kpartx/Makefile @@ -6,7 +6,7 @@ BUILD=glibc include ../Makefile.inc -CFLAGS += -I. -D_LARGEFILE64_SOURCE +CFLAGS += -I. -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 ifeq ($(strip $(BUILD)),klibc) OBJS = bsd.o dos.o kpartx.o solaris.o unixware.o gpt.o crc32.o \ diff --git a/kpartx/devmapper.c b/kpartx/devmapper.c index 4b228ed..213a2f1 100644 --- a/kpartx/devmapper.c +++ b/kpartx/devmapper.c @@ -4,10 +4,12 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <stdint.h> #include <libdevmapper.h> #include <ctype.h> #include <linux/kdev_t.h> #include <errno.h> +#include "devmapper.h" #define UUID_PREFIX "part%d-" #define MAX_PREFIX_LEN 8 @@ -72,10 +74,10 @@ dm_simplecmd (int task, const char *name) { extern int dm_addmap (int task, const char *name, const char *target, - const char *params, unsigned long size, const char *uuid, int part) { + const char *params, uint64_t size, const char *uuid, int part) { int r = 0; struct dm_task *dmt; - char *prefixed_uuid; + char *prefixed_uuid = NULL; if (!(dmt = dm_task_create (task))) return 0; @@ -200,7 +202,8 @@ char * dm_mapuuid(int major, int minor) { struct dm_task *dmt; - char *tmp, *uuid = NULL; + const char *tmp; + char *uuid = NULL; if (!(dmt = dm_task_create(DM_DEVICE_INFO))) return NULL; diff --git a/kpartx/devmapper.h b/kpartx/devmapper.h index e20e456..2465998 100644 --- a/kpartx/devmapper.h +++ b/kpartx/devmapper.h @@ -1,7 +1,7 @@ int dm_prereq (char *, int, int, int); int dm_simplecmd (int, const char *); -int dm_addmap (int, const char *, const char *, const char *, unsigned long, - char *, int); +int dm_addmap (int, const char *, const char *, const char *, uint64_t, + const char *, int); int dm_map_present (char *); char * dm_mapname(int major, int minor); dev_t dm_get_first_dep(char *devname); diff --git a/kpartx/gpt.c b/kpartx/gpt.c index dc846ca..047a829 100644 --- a/kpartx/gpt.c +++ b/kpartx/gpt.c @@ -36,6 +36,7 @@ #include <errno.h> #include <endian.h> #include <byteswap.h> +#include <linux/fs.h> #include "crc32.h" #if BYTE_ORDER == LITTLE_ENDIAN @@ -50,10 +51,18 @@ # define __cpu_to_le32(x) bswap_32(x) #endif +#ifndef BLKGETLASTSECT #define BLKGETLASTSECT _IO(0x12,108) /* get last sector of block device */ +#endif +#ifndef BLKGETSIZE #define BLKGETSIZE _IO(0x12,96) /* return device size */ +#endif +#ifndef BLKSSZGET #define BLKSSZGET _IO(0x12,104) /* get block device sector size */ +#endif +#ifndef BLKGETSIZE64 #define BLKGETSIZE64 _IOR(0x12,114,sizeof(uint64_t)) /* return device size in bytes (u64 *arg) */ +#endif struct blkdev_ioctl_param { unsigned int block; @@ -143,20 +152,14 @@ get_sector_size(int filedes) static uint64_t _get_num_sectors(int filedes) { - unsigned long sectors=0; int rc; -#if 0 - uint64_t bytes=0; + uint64_t bytes=0; - rc = ioctl(filedes, BLKGETSIZE64, &bytes); + rc = ioctl(filedes, BLKGETSIZE64, &bytes); if (!rc) return bytes / get_sector_size(filedes); -#endif - rc = ioctl(filedes, BLKGETSIZE, §ors); - if (rc) - return 0; - - return sectors; + + return 0; } /************************************************************ @@ -193,7 +196,7 @@ last_lba(int filedes) sectors = 1; } - return sectors - 1; + return sectors ? sectors - 1 : 0; } @@ -220,17 +223,22 @@ read_lba(int fd, uint64_t lba, void *buffer, size_t bytes) { int sector_size = get_sector_size(fd); off_t offset = lba * sector_size; + uint64_t lastlba; ssize_t bytesread; lseek(fd, offset, SEEK_SET); bytesread = read(fd, buffer, bytes); + lastlba = last_lba(fd); + if (!lastlba) + return bytesread; + /* Kludge. This is necessary to read/write the last block of an odd-sized disk, until Linux 2.5.x kernel fixes. This is only used by gpt.c, and only to read one sector, so we don't have to be fancy. */ - if (!bytesread && !(last_lba(fd) & 1) && lba == last_lba(fd)) { + if (!bytesread && !(lastlba & 1) && lba == lastlba) { bytesread = read_lastoddsector(fd, lba, buffer, bytes); } return bytesread; @@ -505,7 +513,8 @@ find_valid_gpt(int fd, gpt_header ** gpt, gpt_entry ** ptes) if (!gpt || !ptes) return 0; - lastlba = last_lba(fd); + if (!(lastlba = last_lba(fd))) + return 0; good_pgpt = is_gpt_valid(fd, GPT_PRIMARY_PARTITION_TABLE_LBA, &pgpt, &pptes); if (good_pgpt) { diff --git a/kpartx/kpartx.c b/kpartx/kpartx.c index b406b95..7703f06 100644 --- a/kpartx/kpartx.c +++ b/kpartx/kpartx.c @@ -25,6 +25,7 @@ #include <stdlib.h> #include <string.h> #include <unistd.h> +#include <stdint.h> #include <sys/stat.h> #include <sys/types.h> #include <ctype.h> @@ -372,10 +373,10 @@ main(int argc, char **argv){ if (slices[j].size == 0) continue; - printf("%s%s%d : 0 %lu %s %lu\n", + printf("%s%s%d : 0 %" PRIu64 " %s %" PRIu64 "\n", mapname, delim, j+1, - (unsigned long) slices[j].size, device, - (unsigned long) slices[j].start); + slices[j].size, device, + slices[j].start); } break; @@ -415,14 +416,14 @@ main(int argc, char **argv){ continue; if (safe_sprintf(partname, "%s%s%d", - mapname, delim, j+1)) { + mapname, delim, j+1)) { fprintf(stderr, "partname too small\n"); exit(1); } strip_slash(partname); - if (safe_sprintf(params, "%s %lu", device, - (unsigned long)slices[j].start)) { + if (safe_sprintf(params, "%s %" PRIu64, device, + slices[j].start)) { fprintf(stderr, "params too small\n"); exit(1); } @@ -438,7 +439,7 @@ main(int argc, char **argv){ partname); if (verbose) - printf("add map %s : 0 %lu %s %s\n", + printf("add map %s : 0 %" PRIu64 " %s %s\n", partname, slices[j].size, DM_TARGET, params); } diff --git a/kpartx/kpartx.h b/kpartx/kpartx.h index 6a715de..42e7f38 100644 --- a/kpartx/kpartx.h +++ b/kpartx/kpartx.h @@ -1,6 +1,8 @@ #ifndef _KPARTX_H #define _KPARTX_H +#include <stdint.h> + /* * For each partition type there is a routine that takes * a block device and a range, and returns the list of @@ -20,8 +22,8 @@ * units: 512 byte sectors */ struct slice { - unsigned long start; - unsigned long size; + uint64_t start; + uint64_t size; }; typedef int (ptreader)(int fd, struct slice all, struct slice *sp, int ns); diff --git a/libcheckers/checkers.c b/libcheckers/checkers.c index a49ad59..f07d537 100644 --- a/libcheckers/checkers.c +++ b/libcheckers/checkers.c @@ -13,6 +13,7 @@ static struct checker checkers[] = { { .fd = 0, + .sync = 1, .name = DIRECTIO, .message = "", .context = NULL, @@ -22,6 +23,7 @@ static struct checker checkers[] = { }, { .fd = 0, + .sync = 1, .name = TUR, .message = "", .context = NULL, @@ -31,6 +33,7 @@ static struct checker checkers[] = { }, { .fd = 0, + .sync = 1, .name = HP_SW, .message = "", .context = NULL, @@ -40,6 +43,7 @@ static struct checker checkers[] = { }, { .fd = 0, + .sync = 1, .name = EMC_CLARIION, .message = "", .context = NULL, @@ -49,6 +53,7 @@ static struct checker checkers[] = { }, { .fd = 0, + .sync = 1, .name = RDAC, .message = "", .context = NULL, @@ -58,6 +63,7 @@ static struct checker checkers[] = { }, { .fd = 0, + .sync = 1, .name = READSECTOR0, .message = "", .context = NULL, @@ -65,7 +71,7 @@ static struct checker checkers[] = { .init = readsector0_init, .free = readsector0_free }, - {0, "", "", NULL, NULL, NULL, NULL}, + {0, 1, 0, "", "", NULL, NULL, NULL, NULL}, }; void checker_set_fd (struct checker * c, int fd) @@ -73,6 +79,26 @@ void checker_set_fd (struct checker * c, int fd) c->fd = fd; } +void checker_set_sync (struct checker * c) +{ + c->sync = 1; +} + +void checker_set_async (struct checker * c) +{ + c->sync = 0; +} + +void checker_enable (struct checker * c) +{ + c->disable = 0; +} + +void checker_disable (struct checker * c) +{ + c->disable = 1; +} + struct checker * checker_lookup (char * name) { struct checker * c = &checkers[0]; @@ -102,6 +128,8 @@ int checker_check (struct checker * c) { int r; + if (c->disable) + return PATH_UNCHECKED; if (c->fd <= 0) { MSG(c, "no usable fd"); return PATH_WILD; @@ -134,6 +162,7 @@ struct checker * checker_default (void) void checker_get (struct checker * dst, struct checker * src) { dst->fd = src->fd; + dst->sync = src->sync; strncpy(dst->name, src->name, CHECKER_NAME_LEN); strncpy(dst->message, src->message, CHECKER_MSG_LEN); dst->check = src->check; diff --git a/libcheckers/checkers.h b/libcheckers/checkers.h index d4dad9c..3ce643b 100644 --- a/libcheckers/checkers.h +++ b/libcheckers/checkers.h @@ -40,6 +40,9 @@ * The path needs an initialization command to be sent to it in order for * I/Os to succeed. * + * PATH_PENDING: + * - Use: All async checkers + * - Description: Indicates a check IO is in flight. */ #define PATH_WILD -1 #define PATH_UNCHECKED 0 @@ -47,6 +50,7 @@ #define PATH_UP 2 #define PATH_SHAKY 3 #define PATH_GHOST 4 +#define PATH_PENDING 5 #define DIRECTIO "directio" #define TUR "tur" @@ -55,7 +59,7 @@ #define EMC_CLARIION "emc_clariion" #define READSECTOR0 "readsector0" -#define DEFAULT_CHECKER READSECTOR0 +#define DEFAULT_CHECKER DIRECTIO /* * Overloaded storage response time can be very long. @@ -70,7 +74,8 @@ * Provision a long timeout. Longer than any real-world application would cope * with. */ -#define DEF_TIMEOUT 300000 +#define DEF_TIMEOUT 300000 +#define ASYNC_TIMEOUT_SEC 30 /* * strings lengths @@ -81,6 +86,8 @@ struct checker { int fd; + int sync; + int disable; char name[CHECKER_NAME_LEN]; char message[CHECKER_MSG_LEN]; /* comm with callers */ void * context; /* store for persistent data */ @@ -95,8 +102,12 @@ struct checker { int checker_init (struct checker *, void **); void checker_put (struct checker *); -void checker_reset (struct checker * c); +void checker_reset (struct checker *); +void checker_set_sync (struct checker *); +void checker_set_async (struct checker *); void checker_set_fd (struct checker *, int); +void checker_enable (struct checker *); +void checker_disable (struct checker *); struct checker * checker_lookup (char *); int checker_check (struct checker *); int checker_selected (struct checker *); diff --git a/libcheckers/directio.c b/libcheckers/directio.c index 2251515..7421437 100644 --- a/libcheckers/directio.c +++ b/libcheckers/directio.c @@ -22,6 +22,9 @@ #define MSG_DIRECTIO_UNKNOWN "directio checker is not available" #define MSG_DIRECTIO_UP "directio checker reports path is up" #define MSG_DIRECTIO_DOWN "directio checker reports path is down" +#define MSG_DIRECTIO_PENDING "directio checker is waiting on aio" + +#define LOG(prio, fmt, args...) condlog(prio, "directio: " fmt, ##args) struct directio_context { int running; @@ -115,38 +118,47 @@ void directio_free (struct checker * c) } static int -check_state(int fd, struct directio_context *ct) +check_state(int fd, struct directio_context *ct, int sync) { - struct timespec timeout = { .tv_sec = 2 }; + struct timespec timeout = { .tv_nsec = 5 }; struct io_event event; struct stat sb; int rc = PATH_UNCHECKED; long r; if (fstat(fd, &sb) == 0) { - condlog(4, "directio: called for %x", (unsigned) sb.st_rdev); + LOG(4, "called for %x", (unsigned) sb.st_rdev); + } + if (sync) { + LOG(4, "called in synchronous mode"); + timeout.tv_sec = ASYNC_TIMEOUT_SEC; + timeout.tv_nsec = 0; } if (!ct->running) { struct iocb *ios[1] = { &ct->io }; - condlog(3, "directio: starting new request"); + LOG(3, "starting new request"); memset(&ct->io, 0, sizeof(struct iocb)); io_prep_pread(&ct->io, fd, ct->ptr, ct->blksize, 0); if (syscall(__NR_io_submit, ct->ioctx, 1, ios) != 1) { - condlog(3, "directio: io_submit error %i", errno); + LOG(3, "io_submit error %i", errno); return PATH_UNCHECKED; } } - ct->running = 1; + ct->running++; r = syscall(__NR_io_getevents, ct->ioctx, 1L, 1L, &event, &timeout); + LOG(3, "async io getevents returns %li (errno=%s)", r, strerror(errno)); + if (r < 1L) { - condlog(3, "directio: timeout r=%li errno=%i", r, errno); - rc = PATH_DOWN; + if (ct->running > ASYNC_TIMEOUT_SEC || sync) { + LOG(3, "abort check on timeout"); + rc = PATH_DOWN; + } else + rc = PATH_PENDING; } else { - condlog(3, "directio: io finished %lu/%lu", event.res, - event.res2); + LOG(3, "io finished %lu/%lu", event.res, event.res2); ct->running = 0; rc = (event.res == ct->blksize) ? PATH_UP : PATH_DOWN; } @@ -162,7 +174,7 @@ int directio (struct checker * c) if (!ct) return PATH_UNCHECKED; - ret = check_state(c->fd, ct); + ret = check_state(c->fd, ct, c->sync); switch (ret) { @@ -175,6 +187,9 @@ int directio (struct checker * c) case PATH_UP: MSG(c, MSG_DIRECTIO_UP); break; + case PATH_PENDING: + MSG(c, MSG_DIRECTIO_PENDING); + break; default: break; } diff --git a/libcheckers/emc_clariion.c b/libcheckers/emc_clariion.c index d801b42..6c7167e 100644 --- a/libcheckers/emc_clariion.c +++ b/libcheckers/emc_clariion.c @@ -176,7 +176,7 @@ int emc_clariion(struct checker * c) * Issue read on active path to determine if inactive snapshot. */ if (sense_buffer[4] == 2) {/* if active path */ - unsigned char buf[512]; + unsigned char buf[4096]; ret = sg_read(c->fd, &buf[0], sbb = &sb[0]); if (ret == PATH_DOWN) { diff --git a/libcheckers/libsg.c b/libcheckers/libsg.c index f426aaf..9171b10 100644 --- a/libcheckers/libsg.c +++ b/libcheckers/libsg.c @@ -4,6 +4,7 @@ #include <string.h> #include <sys/ioctl.h> #include <errno.h> +#include <sys/stat.h> #include "checkers.h" #include "libsg.h" @@ -25,8 +26,12 @@ sg_read (int sg_fd, unsigned char * buff, unsigned char * senseBuff) int res; int rd_opcode[] = {0x8, 0x28, 0xa8, 0x88}; int sz_ind; + struct stat filestatus; int retry_count = 3; - + + if (fstat(sg_fd, &filestatus) != 0) + return PATH_DOWN; + bs = (filestatus.st_blksize > 4096)? 4096: filestatus.st_blksize; memset(rdCmd, 0, cdbsz); sz_ind = 1; rdCmd[0] = rd_opcode[sz_ind]; diff --git a/libcheckers/rdac.c b/libcheckers/rdac.c index 76a2498..3e4f886 100644 --- a/libcheckers/rdac.c +++ b/libcheckers/rdac.c @@ -18,7 +18,7 @@ #define INQUIRY_CMDLEN 6 #define INQUIRY_CMD 0x12 #define SENSE_BUFF_LEN 32 -#define DEF_TIMEOUT 60000 +#define RDAC_DEF_TIMEOUT 60000 #define SCSI_CHECK_CONDITION 0x2 #define SCSI_COMMAND_TERMINATED 0x22 #define SG_ERR_DRIVER_SENSE 0x08 @@ -61,7 +61,7 @@ do_inq(int sg_fd, unsigned int pg_op, void *resp, int mx_resp_len) io_hdr.dxferp = resp; io_hdr.cmdp = inqCmdBlk; io_hdr.sbp = sense_b; - io_hdr.timeout = DEF_TIMEOUT; + io_hdr.timeout = RDAC_DEF_TIMEOUT; if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) return 1; diff --git a/libcheckers/readsector0.c b/libcheckers/readsector0.c index 3cddfa8..bef0eb6 100644 --- a/libcheckers/readsector0.c +++ b/libcheckers/readsector0.c @@ -26,7 +26,7 @@ void readsector0_free (struct checker * c) extern int readsector0 (struct checker * c) { - unsigned char buf[512]; + unsigned char buf[4096]; unsigned char sbuf[SENSE_BUFF_LEN]; int ret; diff --git a/libmultipath/alias.c b/libmultipath/alias.c index 86cae9b..ca434fe 100644 --- a/libmultipath/alias.c +++ b/libmultipath/alias.c @@ -120,21 +120,34 @@ lock_bindings_file(int fd) static int -open_bindings_file(char *file) +open_bindings_file(char *file, int *can_write) { int fd; struct stat s; if (ensure_directories_exist(file, 0700)) return -1; + *can_write = 1; fd = open(file, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); if (fd < 0) { - condlog(0, "Cannot open bindings file [%s] : %s", file, - strerror(errno)); - return -1; + if (errno == EROFS) { + *can_write = 0; + condlog(3, "Cannot open bindings file [%s] read/write. " + " trying readonly", file); + fd = open(file, O_RDONLY); + if (fd < 0) { + condlog(0, "Cannot open bindings file [%s] " + "readonly : %s", file, strerror(errno)); + return -1; + } + } + else { + condlog(0, "Cannot open bindings file [%s] : %s", file, + strerror(errno)); + return -1; + } } - - if (lock_bindings_file(fd) < 0) + if (*can_write && lock_bindings_file(fd) < 0) goto fail; memset(&s, 0, sizeof(s)); @@ -143,6 +156,8 @@ open_bindings_file(char *file) goto fail; } if (s.st_size == 0) { + if (*can_write == 0) + goto fail; /* If bindings file is empty, write the header */ size_t len = strlen(BINDINGS_FILE_HEADER); if (write_all(fd, BINDINGS_FILE_HEADER, len) != len) { @@ -196,7 +211,7 @@ lookup_binding(FILE *f, char *map_wwid, char **map_alias) } if (strcmp(wwid, map_wwid) == 0){ condlog(3, "Found matching wwid [%s] in bindings file." - "\nSetting alias to %s", wwid, alias); + " Setting alias to %s", wwid, alias); *map_alias = strdup(alias); if (*map_alias == NULL) condlog(0, "Cannot copy alias from bindings " @@ -297,13 +312,14 @@ get_user_friendly_alias(char *wwid, char *file) char *alias; int fd, scan_fd, id; FILE *f; + int can_write; if (!wwid || *wwid == '\0') { condlog(3, "Cannot find binding for empty WWID"); return NULL; } - fd = open_bindings_file(file); + fd = open_bindings_file(file, &can_write); if (fd < 0) return NULL; @@ -332,7 +348,7 @@ get_user_friendly_alias(char *wwid, char *file) return NULL; } - if (!alias) + if (!alias && can_write) alias = allocate_binding(fd, wwid, id); fclose(f); @@ -345,7 +361,7 @@ char * get_user_friendly_wwid(char *alias, char *file) { char *wwid; - int fd, scan_fd, id; + int fd, scan_fd, id, unused; FILE *f; if (!alias || *alias == '\0') { @@ -353,7 +369,7 @@ get_user_friendly_wwid(char *alias, char *file) return NULL; } - fd = open_bindings_file(file); + fd = open_bindings_file(file, &unused); if (fd < 0) return NULL; diff --git a/libmultipath/blacklist.c b/libmultipath/blacklist.c index 44987f6..5a7c1ec 100644 --- a/libmultipath/blacklist.c +++ b/libmultipath/blacklist.c @@ -121,6 +121,12 @@ setup_default_blist (struct config * conf) if (store_ble(conf->blist_devnode, str, ORIGIN_DEFAULT)) return 1; + str = STRDUP("^dcssblk[0-9]*"); + if (!str) + return 1; + if (store_ble(conf->blist_devnode, str, ORIGIN_DEFAULT)) + return 1; + vector_foreach_slot (conf->hwtable, hwe, i) { if (hwe->bl_product) { if (alloc_ble_device(conf->blist_device)) diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c index b0be110..b04a30f 100644 --- a/libmultipath/devmapper.c +++ b/libmultipath/devmapper.c @@ -6,6 +6,7 @@ */ #include <stdio.h> #include <stdlib.h> +#include <stdarg.h> #include <string.h> #include <libdevmapper.h> #include <ctype.h> diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c index 10141f5..74311a8 100644 --- a/libmultipath/discovery.c +++ b/libmultipath/discovery.c @@ -234,60 +234,54 @@ opennode (char * dev, int mode) extern int devt2devname (char *devname, char *devt) { - struct dlist * ls; - char attr_path[FILE_NAME_SIZE]; + FILE *fd; + unsigned int tmpmaj, tmpmin, major, minor; + char dev[FILE_NAME_SIZE]; char block_path[FILE_NAME_SIZE]; - struct sysfs_attribute * attr = NULL; - struct sysfs_class * class; - struct sysfs_class_device * dev; + struct stat statbuf; - if(safe_sprintf(block_path, "%s/block", sysfs_path)) { - condlog(0, "block_path too small"); + if (sscanf(devt, "%u:%u", &major, &minor) != 2) { + condlog(0, "Invalid device number %s", devt); return 1; } - if (!(class = sysfs_open_class("block"))) - return 1; - if (!(ls = sysfs_get_class_devices(class))) - goto err; - - dlist_for_each_data(ls, dev, struct sysfs_class_device) { - if(safe_sprintf(attr_path, "%s/%s/dev", - block_path, dev->name)) { - condlog(0, "attr_path too small"); - goto err; + if ((fd = fopen("/proc/partitions", "r")) < 0) { + condlog(0, "Cannot open /proc/partitions"); + return 1; + } + + while (!feof(fd)) { + int r = fscanf(fd,"%u %u %*d %s",&tmpmaj, &tmpmin, dev); + if (!r) { + fscanf(fd,"%*s\n"); + continue; } - if (!(attr = sysfs_open_attribute(attr_path))) - goto err; - - if (sysfs_read_attribute(attr)) - goto err1; - - /* discard newline */ - if (attr->len > 1) attr->len--; - - if (strlen(devt) == attr->len && - strncmp(attr->value, devt, attr->len) == 0) { - if(safe_sprintf(attr_path, "%s/%s", - block_path, dev->name)) { - condlog(0, "attr_path too small"); - goto err1; - } - sysfs_get_name_from_path(attr_path, devname, - FILE_NAME_SIZE); - sysfs_close_attribute(attr); - sysfs_close_class(class); - return 0; + if (r != 3) + continue; + if ((major == tmpmaj) && (minor == tmpmin)) { + sprintf(block_path, "/sys/block/%s", dev); + break; } } -err1: - sysfs_close_attribute(attr); -err: - sysfs_close_class(class); - return 1; + fclose(fd); + + if (strncmp(block_path,"/sys/block", 10)) + return 1; + + if (stat(block_path, &statbuf) < 0) { + condlog(0, "No sysfs entry for %s\n", block_path); + return 1; + } + + if (S_ISDIR(statbuf.st_mode) == 0) { + condlog(0, "sysfs entry %s is not a directory\n", block_path); + return 1; + } + strncpy(devname, dev, FILE_NAME_SIZE); + return 0; } -static int +int do_inq(int sg_fd, int cmddt, int evpd, unsigned int pg_op, void *resp, int mx_resp_len, int noisy) { diff --git a/libmultipath/hwtable.c b/libmultipath/hwtable.c index e67d3a5..924299c 100644 --- a/libmultipath/hwtable.c +++ b/libmultipath/hwtable.c @@ -479,14 +479,14 @@ static struct hwentry default_hw[] = { /* * Pillar Data controller family * - * Maintainer : Christophe Varoqui - * Mail : christophe.varoqui@free.fr + * Maintainer : Srinivasan Ramani + * Mail : sramani@pillardata.com */ { .vendor = "Pillar", - .product = "Axiom 500", + .product = "Axiom.*", .getuid = DEFAULT_GETUID, - .getprio = "mpath_prio_alua %d", + .getprio = "mpath_prio_alua %n", .features = DEFAULT_FEATURES, .hwhandler = DEFAULT_HWHANDLER, .selector = DEFAULT_SELECTOR, diff --git a/libmultipath/uevent.c b/libmultipath/uevent.c index 6482698..a4028d8 100644 --- a/libmultipath/uevent.c +++ b/libmultipath/uevent.c @@ -26,12 +26,14 @@ #include <unistd.h> #include <stdio.h> #include <stdlib.h> +#include <stddef.h> #include <string.h> #include <fcntl.h> #include <time.h> #include <sys/socket.h> #include <sys/user.h> -#include <asm/types.h> +#include <sys/un.h> +#include <linux/types.h> #include <linux/netlink.h> #include <pthread.h> #include <sys/mman.h> @@ -105,6 +107,8 @@ int uevent_listen(int (*uev_trigger)(struct uevent *, void * trigger_data), { int sock; struct sockaddr_nl snl; + struct sockaddr_un sun; + socklen_t addrlen; int retval; int rcvbufsz = 128*1024; int rcvsz = 0; @@ -131,43 +135,72 @@ int uevent_listen(int (*uev_trigger)(struct uevent *, void * trigger_data), pthread_attr_setstacksize(&attr, 64 * 1024); pthread_create(&uevq_thr, &attr, uevq_thread, NULL); - memset(&snl, 0x00, sizeof(struct sockaddr_nl)); - snl.nl_family = AF_NETLINK; - snl.nl_pid = getpid(); - snl.nl_groups = 0xffffffff; - - sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT); - if (sock == -1) { - condlog(0, "error getting socket, exit"); - return 1; - } - /* - * try to avoid dropping uevents, even so, this is not a guarantee, - * but it does help to change the netlink uevent socket's - * receive buffer threshold from the default value of 106,496 to - * the maximum value of 262,142. + * First check whether we have a udev socket */ - retval = setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &rcvbufsz, - sizeof(rcvbufsz)); + memset(&sun, 0x00, sizeof(struct sockaddr_un)); + sun.sun_family = AF_LOCAL; + strcpy(&sun.sun_path[1], "/org/kernel/dm/multipath_event"); + addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(sun.sun_path+1) + 1; + + sock = socket(AF_LOCAL, SOCK_DGRAM, 0); + if (sock >= 0) { + const int feature_on = 1; + + condlog(3, "reading events from udev socket."); + + /* the bind takes care of ensuring only one copy running */ + retval = bind(sock, (struct sockaddr *) &sun, addrlen); + if (retval < 0) { + condlog(0, "bind failed, exit"); + goto exit; + } - if (retval < 0) { - condlog(0, "error setting receive buffer size for socket, exit"); - exit(1); - } - retval = getsockopt(sock, SOL_SOCKET, SO_RCVBUF, &rcvsz, prcvszsz); + /* enable receiving of the sender credentials */ + setsockopt(sock, SOL_SOCKET, SO_PASSCRED, + &feature_on, sizeof(feature_on)); + + } else { + /* Fallback to read kernel netlink events */ + memset(&snl, 0x00, sizeof(struct sockaddr_nl)); + snl.nl_family = AF_NETLINK; + snl.nl_pid = getpid(); + snl.nl_groups = 0xffffffff; + + sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT); + if (sock == -1) { + condlog(0, "error getting socket, exit"); + return 1; + } - if (retval < 0) { - condlog(0, "error setting receive buffer size for socket, exit"); - exit(1); - } - condlog(3, "receive buffer size for socket is %u.", rcvsz); + condlog(3, "reading events from kernel."); - retval = bind(sock, (struct sockaddr *) &snl, - sizeof(struct sockaddr_nl)); - if (retval < 0) { - condlog(0, "bind failed, exit"); - goto exit; + /* + * try to avoid dropping uevents, even so, this is not a guarantee, + * but it does help to change the netlink uevent socket's + * receive buffer threshold from the default value of 106,496 to + * the maximum value of 262,142. + */ + retval = setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &rcvbufsz, + sizeof(rcvbufsz)); + + if (retval < 0) { + condlog(0, "error setting receive buffer size for socket, exit"); + exit(1); + } + retval = getsockopt(sock, SOL_SOCKET, SO_RCVBUF, &rcvsz, prcvszsz); + if (retval < 0) { + condlog(0, "error setting receive buffer size for socket, exit"); + exit(1); + } + condlog(3, "receive buffer size for socket is %u.", rcvsz); + + retval = bind(sock, (struct sockaddr *) &snl, + sizeof(struct sockaddr_nl)); + if (retval < 0) { + condlog(0, "bind failed, exit"); + goto exit; + } } while (1) { diff --git a/multipathd/cli_handlers.c b/multipathd/cli_handlers.c index 9cd5902..b01a60a 100644 --- a/multipathd/cli_handlers.c +++ b/multipathd/cli_handlers.c @@ -416,6 +416,7 @@ cli_reinstate(void * v, char ** reply, int * len, void * data) condlog(2, "%s: reinstate path %s (operator)", pp->mpp->alias, pp->dev_t); + checker_enable(&pp->checker); return dm_reinstate_path(pp->mpp->alias, pp->dev_t); } @@ -425,6 +426,7 @@ cli_fail(void * v, char ** reply, int * len, void * data) struct vectors * vecs = (struct vectors *)data; char * param = get_keyparam(v, PATH); struct path * pp; + int r; pp = find_path_by_dev(vecs->pathvec, param); @@ -437,7 +439,13 @@ cli_fail(void * v, char ** reply, int * len, void * data) condlog(2, "%s: fail path %s (operator)", pp->mpp->alias, pp->dev_t); - return dm_fail_path(pp->mpp->alias, pp->dev_t); + r = dm_fail_path(pp->mpp->alias, pp->dev_t); + /* + * Suspend path checking to avoid auto-reinstating the path + */ + if (!r) + checker_disable(&pp->checker); + return r; } int diff --git a/multipathd/main.c b/multipathd/main.c index 586a200..4c99ce6 100644 --- a/multipathd/main.c +++ b/multipathd/main.c @@ -900,11 +900,16 @@ checkerloop (void *ap) pathinfo(pp, conf->hwtable, DI_SYSFS); select_checker(pp); } - if (!checker_selected(&pp->checker)) { condlog(0, "%s: checker is not set", pp->dev); continue; } + /* + * Set checker in async mode. + * Honored only by checker implementing the said mode. + */ + checker_set_async(&pp->checker); + newstate = checker_check(&pp->checker); if (newstate < 0) { @@ -912,7 +917,14 @@ checkerloop (void *ap) pathinfo(pp, conf->hwtable, 0); continue; } - + /* + * Async IO in flight. Keep the previous path state + * and reschedule as soon as possible + */ + if (newstate == PATH_PENDING) { + pp->tick = 1; + continue; + } if (newstate != pp->state) { int oldstate = pp->state; pp->state = newstate; -- 1.5.0.4.GIT