[PATCH] more udev-016/extras/multipath

incremental to udev-016/extras/multipath-0.0.16.3,

        * add a GROUP_BY_SERIAL flag. This should be useful for
          controlers that activate their spare paths on simple IO
          submition with a penalty. The StorageWorks HW defaults to
          this mode, even if the MULTIBUS mode is OK.
        * remove unused sg_err.c
        * big restructuring : split devinfo.c from main.c. Export :
                * void basename (char *, char *);
                * int get_serial (int, char *);
                * int get_lun_strings (char *, char *, char *, char *);
                * int get_evpd_wwid(char *, char *);
                * long get_disk_size (char *);
          Now we see clearly what is expected from an external package
          like scsi_id.
        * stop passing struct env as param
This commit is contained in:
christophe.varoqui@free.fr 2004-02-13 00:53:10 -08:00 committed by Greg KH
parent cbb576b91d
commit 09b7985cf6
7 changed files with 313 additions and 1387 deletions

View File

@ -1,4 +1,16 @@
2004-02-04 multipath-016
* add a GROUP_BY_SERIAL flag. This should be useful for
controlers that activate they spare paths on simple IO
submition with a penalty. The StorageWorks HW defaults to
this mode, even if the MULTIBUS mode is OK.
* remove unused sg_err.c
* big restructuring : split devinfo.c from main.c. Export :
* void basename (char *, char *);
* int get_serial (int, char *);
* int get_lun_strings (char *, char *, char *, char *);
* int get_evpd_wwid(char *, char *);
* long get_disk_size (char *);
* stop passing struct env as param
* add devmap_name proggy for udev to name devmaps as per their
internal DM name and not only by their sysfs enum name (dm-*)
The corresponding udev.rules line is :

View File

@ -18,7 +18,7 @@ CFLAGS = -pipe -g -O2 -Wall -Wunused -Wstrict-prototypes -nostdinc \
-I$(klibcdir)/klibc/include -I$(klibcdir)/klibc/include/bits32 \
-I$(GCCINCDIR) -I$(KERNEL_DIR)/include -I$(sysfsdir) -I.
OBJS = main.o
OBJS = devinfo.o main.o
CRT0 = ../../klibc/klibc/crt0.o
LIB = ../../klibc/klibc/libc.a
LIBGCC := $(shell $(CC) -print-libgcc-file-name )
@ -67,4 +67,4 @@ uninstall:
rm $(bindir)/devmap_name
# Code dependencies
main.o: main.c main.h sg_include.h
main.o: main.c main.h sg_include.h devinfo.h

204
extras/multipath/devinfo.c Normal file
View File

@ -0,0 +1,204 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <libsysfs.h>
#include "devinfo.h"
#include "sg_include.h"
#define FILE_NAME_SIZE 255
void
basename(char * str1, char * str2)
{
char *p = str1 + (strlen(str1) - 1);
while (*--p != '/')
continue;
strcpy(str2, ++p);
}
static int
do_inq(int sg_fd, int cmddt, int evpd, unsigned int pg_op,
void *resp, int mx_resp_len, int noisy)
{
unsigned char inqCmdBlk[INQUIRY_CMDLEN] =
{ INQUIRY_CMD, 0, 0, 0, 0, 0 };
unsigned char sense_b[SENSE_BUFF_LEN];
struct sg_io_hdr io_hdr;
if (cmddt)
inqCmdBlk[1] |= 2;
if (evpd)
inqCmdBlk[1] |= 1;
inqCmdBlk[2] = (unsigned char) pg_op;
inqCmdBlk[4] = (unsigned char) mx_resp_len;
memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
io_hdr.interface_id = 'S';
io_hdr.cmd_len = sizeof (inqCmdBlk);
io_hdr.mx_sb_len = sizeof (sense_b);
io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
io_hdr.dxfer_len = mx_resp_len;
io_hdr.dxferp = resp;
io_hdr.cmdp = inqCmdBlk;
io_hdr.sbp = sense_b;
io_hdr.timeout = DEF_TIMEOUT;
if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
perror("SG_IO (inquiry) error");
return -1;
}
/* treat SG_ERR here to get rid of sg_err.[ch] */
io_hdr.status &= 0x7e;
if ((0 == io_hdr.status) && (0 == io_hdr.host_status) &&
(0 == io_hdr.driver_status))
return 0;
if ((SCSI_CHECK_CONDITION == io_hdr.status) ||
(SCSI_COMMAND_TERMINATED == io_hdr.status) ||
(SG_ERR_DRIVER_SENSE == (0xf & io_hdr.driver_status))) {
if (io_hdr.sbp && (io_hdr.sb_len_wr > 2)) {
int sense_key;
unsigned char * sense_buffer = io_hdr.sbp;
if (sense_buffer[0] & 0x2)
sense_key = sense_buffer[1] & 0xf;
else
sense_key = sense_buffer[2] & 0xf;
if(RECOVERED_ERROR == sense_key)
return 0;
}
}
return -1;
}
int
get_serial (char * str, char * devname)
{
int fd;
int len;
char buff[MX_ALLOC_LEN + 1];
if ((fd = open(devname, O_RDONLY)) < 0)
return 0;
if (0 == do_inq(fd, 0, 1, 0x80, buff, MX_ALLOC_LEN, 0)) {
len = buff[3];
if (len > 0) {
memcpy(str, buff + 4, len);
buff[len] = '\0';
}
close(fd);
return 1;
}
close(fd);
return 0;
}
int
get_lun_strings(char * vendor_id, char * product_id, char * rev, char * devname)
{
int fd;
char buff[36];
char attr_path[FILE_NAME_SIZE];
char sysfs_path[FILE_NAME_SIZE];
char basedev[FILE_NAME_SIZE];
if (0 == sysfs_get_mnt_path(sysfs_path, FILE_NAME_SIZE)) {
/* sysfs style */
basename(devname, basedev);
sprintf(attr_path, "%s/block/%s/device/vendor",
sysfs_path, basedev);
if (0 > sysfs_read_attribute_value(attr_path,
vendor_id, 8)) return 0;
sprintf(attr_path, "%s/block/%s/device/model",
sysfs_path, basedev);
if (0 > sysfs_read_attribute_value(attr_path,
product_id, 16)) return 0;
sprintf(attr_path, "%s/block/%s/device/rev",
sysfs_path, basedev);
if (0 > sysfs_read_attribute_value(attr_path,
rev, 4)) return 0;
} else {
/* ioctl style */
if ((fd = open(devname, O_RDONLY)) < 0)
return 0;
if (0 != do_inq(fd, 0, 0, 0, buff, 36, 1))
return 0;
memcpy(vendor_id, &buff[8], 8);
memcpy(product_id, &buff[16], 16);
memcpy(rev, &buff[32], 4);
close(fd);
return 1;
}
return 0;
}
static void
sprint_wwid(char * buff, const char * str)
{
int i;
const char *p;
char *cursor;
unsigned char c;
p = str;
cursor = buff;
for (i = 0; i <= WWID_SIZE / 2 - 1; i++) {
c = *p++;
sprintf(cursor, "%.2x", (int) (unsigned char) c);
cursor += 2;
}
buff[WWID_SIZE - 1] = '\0';
}
/* get EVPD page 0x83 off 8 */
/* tested ok with StorageWorks */
int
get_evpd_wwid(char * devname, char * wwid)
{
int fd;
char buff[64];
if ((fd = open(devname, O_RDONLY)) < 0)
return 0;
if (0 == do_inq(fd, 0, 1, 0x83, buff, sizeof (buff), 1)) {
sprint_wwid(wwid, &buff[8]);
close(fd);
return 1; /* success */
}
close(fd);
return 0; /* not good */
}
long
get_disk_size (char * devname) {
long size;
int fd;
char attr_path[FILE_NAME_SIZE];
char sysfs_path[FILE_NAME_SIZE];
char buff[FILE_NAME_SIZE];
char basedev[FILE_NAME_SIZE];
if (0 == sysfs_get_mnt_path(sysfs_path, FILE_NAME_SIZE)) {
basename(devname, basedev);
sprintf(attr_path, "%s/block/%s/size",
sysfs_path, basedev);
if (0 > sysfs_read_attribute_value(attr_path, buff,
FILE_NAME_SIZE * sizeof(char)))
return -1;
size = atoi(buff);
return size;
} else {
if ((fd = open(devname, O_RDONLY)) < 0)
return -1;
if(!ioctl(fd, BLKGETSIZE, &size))
return size;
}
return -1;
}

View File

@ -0,0 +1,19 @@
#define INQUIRY_CMDLEN 6
#define INQUIRY_CMD 0x12
#define SENSE_BUFF_LEN 32
#define DEF_TIMEOUT 60000
#define RECOVERED_ERROR 0x01
#define MX_ALLOC_LEN 255
#define WWID_SIZE 33
#define BLKGETSIZE _IO(0x12,96)
/* exerpt from "sg_err.h" */
#define SCSI_CHECK_CONDITION 0x2
#define SCSI_COMMAND_TERMINATED 0x22
#define SG_ERR_DRIVER_SENSE 0x08
void basename (char *, char *);
int get_serial (char *, char *);
int get_lun_strings (char *, char *, char *, char *);
int get_evpd_wwid(char *, char *);
long get_disk_size (char *);

View File

@ -28,150 +28,7 @@
#include <libsysfs.h>
#include "libdevmapper/libdevmapper.h"
#include "main.h"
static int
do_inq(int sg_fd, int cmddt, int evpd, unsigned int pg_op,
void *resp, int mx_resp_len, int noisy)
{
unsigned char inqCmdBlk[INQUIRY_CMDLEN] =
{ INQUIRY_CMD, 0, 0, 0, 0, 0 };
unsigned char sense_b[SENSE_BUFF_LEN];
struct sg_io_hdr io_hdr;
if (cmddt)
inqCmdBlk[1] |= 2;
if (evpd)
inqCmdBlk[1] |= 1;
inqCmdBlk[2] = (unsigned char) pg_op;
inqCmdBlk[4] = (unsigned char) mx_resp_len;
memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
io_hdr.interface_id = 'S';
io_hdr.cmd_len = sizeof (inqCmdBlk);
io_hdr.mx_sb_len = sizeof (sense_b);
io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
io_hdr.dxfer_len = mx_resp_len;
io_hdr.dxferp = resp;
io_hdr.cmdp = inqCmdBlk;
io_hdr.sbp = sense_b;
io_hdr.timeout = DEF_TIMEOUT;
if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
perror("SG_IO (inquiry) error");
return -1;
}
/* treat SG_ERR here to get rid of sg_err.[ch] */
io_hdr.status &= 0x7e;
if ((0 == io_hdr.status) && (0 == io_hdr.host_status) &&
(0 == io_hdr.driver_status))
return 0;
if ((SCSI_CHECK_CONDITION == io_hdr.status) ||
(SCSI_COMMAND_TERMINATED == io_hdr.status) ||
(SG_ERR_DRIVER_SENSE == (0xf & io_hdr.driver_status))) {
if (io_hdr.sbp && (io_hdr.sb_len_wr > 2)) {
int sense_key;
unsigned char * sense_buffer = io_hdr.sbp;
if (sense_buffer[0] & 0x2)
sense_key = sense_buffer[1] & 0xf;
else
sense_key = sense_buffer[2] & 0xf;
if(RECOVERED_ERROR == sense_key)
return 0;
}
}
return -1;
}
static void
sprint_wwid(char * buff, const char * str)
{
int i;
const char *p;
char *cursor;
unsigned char c;
p = str;
cursor = buff;
for (i = 0; i <= WWID_SIZE / 2 - 1; i++) {
c = *p++;
sprintf(cursor, "%.2x", (int) (unsigned char) c);
cursor += 2;
}
buff[WWID_SIZE - 1] = '\0';
}
static void
basename(char * str1, char * str2)
{
char *p = str1 + (strlen(str1) - 1);
while (*--p != '/')
continue;
strcpy(str2, ++p);
}
static int
get_lun_strings(struct env * conf, struct path * mypath)
{
int fd;
char buff[36];
char attr_path[FILE_NAME_SIZE];
char basedev[FILE_NAME_SIZE];
if(conf->with_sysfs) {
/* sysfs style */
basename(mypath->sg_dev, basedev);
sprintf(attr_path, "%s/block/%s/device/vendor",
conf->sysfs_path, basedev);
if (0 > sysfs_read_attribute_value(attr_path,
mypath->vendor_id, 8)) return 0;
sprintf(attr_path, "%s/block/%s/device/model",
conf->sysfs_path, basedev);
if (0 > sysfs_read_attribute_value(attr_path,
mypath->product_id, 16)) return 0;
sprintf(attr_path, "%s/block/%s/device/rev",
conf->sysfs_path, basedev);
if (0 > sysfs_read_attribute_value(attr_path,
mypath->rev, 4)) return 0;
} else {
/* ioctl style */
if ((fd = open(mypath->sg_dev, O_RDONLY)) < 0)
return 0;
if (0 != do_inq(fd, 0, 0, 0, buff, 36, 1))
return 0;
memcpy(mypath->vendor_id, &buff[8], 8);
memcpy(mypath->product_id, &buff[16], 16);
memcpy(mypath->rev, &buff[32], 4);
close(fd);
return 1;
}
return 0;
}
/* hardware vendor specifics : add support for new models below */
/* this one get EVPD page 0x83 off 8 */
/* tested ok with StorageWorks */
static int
get_evpd_wwid(struct path * mypath)
{
int fd;
char buff[64];
if ((fd = open(mypath->sg_dev, O_RDONLY)) < 0)
return 0;
if (0 == do_inq(fd, 0, 1, 0x83, buff, sizeof (buff), 1)) {
sprint_wwid(mypath->wwid, &buff[8]);
close(fd);
return 1; /* success */
}
close(fd);
return 0; /* not good */
}
#include "devinfo.h"
/* White list switch */
static int
@ -182,13 +39,13 @@ get_unique_id(struct path * mypath)
char * vendor;
char * product;
int iopolicy;
int (*getuid) (struct path *);
int (*getuid) (char *, char *);
} wlist[] = {
{"COMPAQ ", "HSV110 (C)COMPAQ", MULTIBUS, &get_evpd_wwid},
{"COMPAQ ", "MSA1000 ", MULTIBUS, &get_evpd_wwid},
{"COMPAQ ", "MSA1000 VOLUME ", MULTIBUS, &get_evpd_wwid},
{"DEC ", "HSG80 ", MULTIBUS, &get_evpd_wwid},
{"HP ", "HSV100 ", MULTIBUS, &get_evpd_wwid},
{"COMPAQ ", "HSV110 (C)COMPAQ", GROUP_BY_SERIAL, &get_evpd_wwid},
{"COMPAQ ", "MSA1000 ", GROUP_BY_SERIAL, &get_evpd_wwid},
{"COMPAQ ", "MSA1000 VOLUME ", GROUP_BY_SERIAL, &get_evpd_wwid},
{"DEC ", "HSG80 ", GROUP_BY_SERIAL, &get_evpd_wwid},
{"HP ", "HSV100 ", GROUP_BY_SERIAL, &get_evpd_wwid},
{"HP ", "A6189A ", MULTIBUS, &get_evpd_wwid},
{"HP ", "OPEN- ", MULTIBUS, &get_evpd_wwid},
{"DDN ", "SAN DataDirector", MULTIBUS, &get_evpd_wwid},
@ -208,7 +65,7 @@ get_unique_id(struct path * mypath)
if (strncmp(mypath->vendor_id, wlist[i].vendor, 8) == 0 &&
strncmp(mypath->product_id, wlist[i].product, 16) == 0) {
mypath->iopolicy = wlist[i].iopolicy;
if (!wlist[i].getuid(mypath))
if (!wlist[i].getuid(mypath->sg_dev, mypath->wwid))
return 0;
}
}
@ -269,7 +126,11 @@ get_all_paths_sysfs(struct env * conf, struct path * all_paths)
basename(conf->hotplugdev, buff);
sprintf(curpath.sg_dev, "/dev/%s", buff);
get_lun_strings(conf, &curpath);
get_lun_strings(curpath.vendor_id,
curpath.product_id,
curpath.rev,
curpath.sg_dev);
get_serial(curpath.serial, curpath.sg_dev);
if (!get_unique_id(&curpath))
return 0;
strcpy(refwwid, curpath.wwid);
@ -301,7 +162,11 @@ get_all_paths_sysfs(struct env * conf, struct path * all_paths)
basename(devp->path, buff);
sprintf(curpath.sg_dev, "/dev/%s", buff);
get_lun_strings(conf, &curpath);
get_lun_strings(curpath.vendor_id,
curpath.product_id,
curpath.rev,
curpath.sg_dev);
get_serial(curpath.serial, curpath.sg_dev);
if(!get_unique_id(&curpath)) {
memset(&curpath, 0, sizeof(path));
continue;
@ -349,7 +214,11 @@ get_all_paths_nosysfs(struct env * conf, struct path * all_paths,
strncat(file_name, buff, FILE_NAME_SIZE);
strcpy(all_paths[k].sg_dev, file_name);
get_lun_strings(conf, &all_paths[k]);
get_lun_strings(all_paths[k].vendor_id,
all_paths[k].product_id,
all_paths[k].rev,
all_paths[k].sg_dev);
get_serial(all_paths[k].serial, all_paths[k].sg_dev);
if (!get_unique_id(&all_paths[k]))
continue;
@ -484,32 +353,6 @@ print_all_mp(struct path * all_paths, struct multipath * mp, int nmp)
}
}
static long
get_disk_size (struct env * conf, char * dev) {
long size;
int fd;
char attr_path[FILE_NAME_SIZE];
char buff[FILE_NAME_SIZE];
char basedev[FILE_NAME_SIZE];
if(conf->with_sysfs) {
basename(dev, basedev);
sprintf(attr_path, "%s/block/%s/size",
conf->sysfs_path, basedev);
if (0 > sysfs_read_attribute_value(attr_path, buff,
FILE_NAME_SIZE * sizeof(char)))
return -1;
size = atoi(buff);
return size;
} else {
if ((fd = open(dev, O_RDONLY)) < 0)
return -1;
if(!ioctl(fd, BLKGETSIZE, &size))
return size;
}
return -1;
}
static int
coalesce_paths(struct env * conf, struct multipath * mp,
struct path * all_paths)
@ -528,7 +371,7 @@ coalesce_paths(struct env * conf, struct multipath * mp,
if (memcmp(empty_buff, all_paths[k].wwid, WWID_SIZE) == 0)
continue;
/* 2. mp with this uid already instanciated */
/* 2. if mp with this uid already instanciated */
for (i = 0; i <= nmp; i++) {
if (0 == strcmp(mp[i].wwid, all_paths[k].wwid))
already_done = 1;
@ -545,7 +388,7 @@ coalesce_paths(struct env * conf, struct multipath * mp,
PINDEX(nmp,np) = k;
if (mp[nmp].size == 0)
mp[nmp].size = get_disk_size(conf, all_paths[k].dev);
mp[nmp].size = get_disk_size(all_paths[k].dev);
for (i = k + 1; i < conf->max_devs; i++) {
if (0 == strcmp(all_paths[k].wwid, all_paths[i].wwid)) {
@ -558,6 +401,49 @@ coalesce_paths(struct env * conf, struct multipath * mp,
return nmp;
}
static void
group_by_serial(struct multipath * mp, struct path * all_paths, char * str) {
int path_count, pg_count = 0;
int i, k;
int * bitmap;
char path_buff[FILE_NAME_SIZE];
char pg_buff[FILE_NAME_SIZE];
char * path_buff_p = &path_buff[0];
char * pg_buff_p = &pg_buff[0];
/* init the bitmap */
bitmap = malloc((mp->npaths + 1) * sizeof(int));
memset(bitmap, 0, (mp->npaths + 1) * sizeof(int));
for (i = 0; i <= mp->npaths; i++) {
if (bitmap[i])
continue;
/* here, we really got a new pg */
pg_count++;
path_count = 1;
memset(&path_buff, 0, FILE_NAME_SIZE * sizeof(char));
path_buff_p = &path_buff[0];
path_buff_p += sprintf(path_buff_p, " %s", all_paths[mp->pindex[i]].dev);
bitmap[i] = 1;
for (k = i + 1; k <= mp->npaths; k++) {
if (bitmap[k])
continue;
if (0 == strcmp(all_paths[mp->pindex[i]].serial,
all_paths[mp->pindex[k]].serial)) {
path_buff_p += sprintf(path_buff_p, " %s", all_paths[mp->pindex[k]].dev);
bitmap[k] = 1;
path_count++;
}
}
pg_buff_p += sprintf(pg_buff_p, " 1 round-robin %i 0%s",
path_count, path_buff);
}
sprintf(str, " %i%s", pg_count, pg_buff);
}
static int
dm_simplecmd(int task, const char *name) {
int r = 0;
@ -651,6 +537,11 @@ setup_map(struct env * conf, struct path * all_paths,
}
}
if (all_paths[PINDEX(index,0)].iopolicy == GROUP_BY_SERIAL &&
!conf->forcedfailover ) {
group_by_serial(&mp[index], all_paths, params_p);
}
if (mp[index].size < 0)
return 0;

View File

@ -28,29 +28,25 @@
#define SG_ERR_DRIVER_SENSE 0x08
/* exerpt from "scsi.h" */
#define RECOVERED_ERROR 0x01
#define SCSI_IOCTL_GET_IDLUN 0x5382
#define SCSI_IOCTL_GET_BUS_NUMBER 0x5386
/* global defs */
#define WWID_SIZE 33
#define SERIAL_SIZE 14
#define MAX_DEVS 128
#define MAX_MP MAX_DEVS / 2
#define MAX_MP_PATHS MAX_DEVS / 4
#define FILE_NAME_SIZE 256
#define INQUIRY_CMDLEN 6
#define INQUIRY_CMD 0x12
#define SENSE_BUFF_LEN 32
#define DEF_TIMEOUT 60000
#define EBUFF_SZ 256
#define TUR_CMD_LEN 6
#define MX_ALLOC_LEN 255
#define BLKGETSIZE _IO(0x12,96)
#define DM_TARGET "multipath"
/* Storage controlers cpabilities */
#define FAILOVER 0
#define MULTIBUS 1
#define GROUP_BY_SERIAL 2
#define PINDEX(x,y) mp[(x)].pindex[(y)]
@ -88,6 +84,7 @@ struct path {
char vendor_id[8];
char product_id[16];
char rev[4];
char serial[SERIAL_SIZE];
int iopolicy;
};

File diff suppressed because it is too large Load Diff