From 058a0044cb2ab7cac6f7c3e2e17b16e00b5e57fa Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Thu, 19 Apr 2012 11:09:02 +0200 Subject: [PATCH] Use struct udev_device instead of sysdev Remove hand-crafted sysdev and use struct udev_device instead. Signed-off-by: Hannes Reinecke --- libmultipath/discovery.c | 279 ++++++++++++++++++++++++--------------------- libmultipath/discovery.h | 6 +- libmultipath/propsel.c | 2 +- libmultipath/structs.c | 6 + libmultipath/structs.h | 8 +- libmultipath/structs_vec.c | 10 +- libmultipath/sysfs.c | 200 -------------------------------- libmultipath/sysfs.h | 3 +- libmultipath/uevent.c | 4 +- libmultipath/uevent.h | 1 + libmultipath/util.c | 10 ++ libmultipath/util.h | 1 + multipath/main.c | 1 - multipathd/Makefile | 2 +- multipathd/cli_handlers.c | 11 +- multipathd/main.c | 9 +- 16 files changed, 196 insertions(+), 357 deletions(-) diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c index fd0f827..f45602a 100644 --- a/libmultipath/discovery.c +++ b/libmultipath/discovery.c @@ -30,9 +30,15 @@ #include "defaults.h" struct path * -store_pathinfo (vector pathvec, vector hwtable, char * devname, int flag) +store_pathinfo (vector pathvec, vector hwtable, struct udev_device *udevice, + int flag) { struct path * pp; + const char * devname; + + devname = udev_device_get_sysname(udevice); + if (!devname) + return NULL; pp = alloc_path(); @@ -43,6 +49,7 @@ store_pathinfo (vector pathvec, vector hwtable, char * devname, int flag) condlog(0, "pp->dev too small"); goto out; } + pp->udev = udev_device_ref(udevice); if (pathinfo(pp, hwtable, flag)) goto out; @@ -73,7 +80,7 @@ path_discover (vector pathvec, struct config * conf, pp = find_path_by_dev(pathvec, (char *)devname); if (!pp) { pp = store_pathinfo(pathvec, conf->hwtable, - (char *)devname, flag); + udevice, flag); return (pp ? 0 : 1); } return pathinfo(pp, conf->hwtable, flag); @@ -114,24 +121,27 @@ path_discovery (vector pathvec, struct config * conf, int flag) return r; } -#define declare_sysfs_get_str(fname) \ -extern int \ -sysfs_get_##fname (const char * devpath, char * buff, size_t len) \ -{ \ - int size; \ - \ - size = sysfs_attr_get_value(devpath, #fname, buff, len); \ - if (!size) { \ +#define declare_sysfs_get_str(fname) \ +extern int \ +sysfs_get_##fname (struct udev_device * udev, char * buff, size_t len) \ +{ \ + const char * attr; \ + const char * devname; \ + \ + devname = udev_device_get_sysname(udev); \ + \ + attr = udev_device_get_sysattr_value(udev, #fname); \ + if (!attr) { \ condlog(3, "%s: attribute %s not found in sysfs", \ - devpath, #fname); \ + devname, #fname); \ return 1; \ } \ - if (size == len) { \ + if (strlen(attr) > len) { \ condlog(3, "%s: overflow in attribute %s", \ - devpath, #fname); \ + devname, #fname); \ return 2; \ } \ - strchop(buff); \ + strlcpy(buff, attr, len); \ return 0; \ } @@ -144,22 +154,27 @@ declare_sysfs_get_str(state); declare_sysfs_get_str(dev); int -sysfs_get_timeout(const char *devpath, unsigned int *timeout) +sysfs_get_timeout(struct path *pp, unsigned int *timeout) { - char attr_path[SYSFS_PATH_SIZE], attr[NAME_SIZE]; - size_t len; + const char *attr = NULL; + const char *subsys; + struct udev_device *parent; int r; unsigned int t; - if (!devpath) - return 1; - - if (safe_sprintf(attr_path, "%s/device", devpath)) + if (!pp->udev) return 1; - len = sysfs_attr_get_value(attr_path, "timeout", attr, NAME_SIZE); - if (!len) { - condlog(3, "%s: No timeout value in sysfs", devpath); + parent = pp->udev; + while (parent) { + subsys = udev_device_get_subsystem(parent); + attr = udev_device_get_sysattr_value(parent, "timeout"); + if (subsys && attr) + break; + parent = udev_device_get_parent(parent); + } + if (!attr) { + condlog(3, "%s: No timeout value in sysfs", pp->dev); return 1; } @@ -167,7 +182,7 @@ sysfs_get_timeout(const char *devpath, unsigned int *timeout) if (r != 1) { condlog(3, "%s: Cannot parse timeout attribute '%s'", - devpath, attr); + pp->dev, attr); return 1; } @@ -177,15 +192,17 @@ sysfs_get_timeout(const char *devpath, unsigned int *timeout) } int -sysfs_get_size (const char * devpath, unsigned long long * size) +sysfs_get_size (struct path *pp, unsigned long long * size) { - char attr[NAME_SIZE]; - size_t len; + const char * attr; int r; - len = sysfs_attr_get_value(devpath, "size", attr, NAME_SIZE); - if (!len) { - condlog(3, "%s: No size attribute in sysfs", devpath); + if (!pp->udev) + return 1; + + attr = udev_device_get_sysattr_value(pp->udev, "size"); + if (!attr) { + condlog(3, "%s: No size attribute in sysfs", pp->dev); return 1; } @@ -193,7 +210,7 @@ sysfs_get_size (const char * devpath, unsigned long long * size) if (r != 1) { condlog(3, "%s: Cannot parse size attribute '%s'", - devpath, attr); + pp->dev, attr); return 1; } @@ -201,41 +218,56 @@ sysfs_get_size (const char * devpath, unsigned long long * size) } int -sysfs_get_tgt_nodename (const char * devpath, char * node, - unsigned int host, unsigned int channel, - unsigned int target) +sysfs_get_tgt_nodename (struct path *pp, char * node) { - unsigned int checkhost, session; + const char * targetid; + struct udev_device *parent; char attr_path[SYSFS_PATH_SIZE]; size_t len; + parent = pp->udev; + while (parent) { + targetid = udev_device_get_sysname(parent); + if (!strncmp(targetid , "target", 6)) + break; + parent = udev_device_get_parent(parent); + } + /* 'target' needs to exist */ + if (!parent || !targetid) + return 1; + /* Check if it's FibreChannel */ if (safe_sprintf(attr_path, - "/class/fc_transport/target%i:%i:%i", - host, channel, target)) { + "/class/fc_transport/%s", targetid)) { condlog(0, "attr_path too small"); return 1; } - len = sysfs_attr_get_value(attr_path, "node_name", node, NODE_NAME_SIZE); + len = sysfs_attr_get_value(attr_path, "node_name", + node, NODE_NAME_SIZE); if (len) return 0; - if (sscanf(devpath, "/devices/platform/host%u/session%u/", - &checkhost, &session) != 2) - return 1; - if (checkhost != host) - return 1; - if (safe_sprintf(attr_path, "/devices/platform/host%u/session%u/iscsi_session/session%u", host, session, session)) { - condlog(0, "attr_path too small"); - return 1; + /* Check for iSCSI */ + parent = pp->udev; + while (parent) { + targetid = udev_device_get_sysname(parent); + if (!strncmp(targetid , "session", 6)) + break; + parent = udev_device_get_parent(parent); + } + if (parent) { + if (safe_sprintf(attr_path, "/class/iscsi_session/%s", + targetid)) { + condlog(0, "attr_path too small"); + return 1; + } + len = sysfs_attr_get_value(attr_path, "targetname", node, + NODE_NAME_SIZE); + if (len) + return 0; } - len = sysfs_attr_get_value(attr_path, "targetname", node, - NODE_NAME_SIZE); - if (!len) - return 1; - - return 0; + return 1; } static int @@ -535,9 +567,28 @@ get_geometry(struct path *pp) } static int -scsi_sysfs_pathinfo (struct path * pp, const char * parent) +scsi_sysfs_pathinfo (struct path * pp) { - char attr_path[FILE_NAME_SIZE]; + struct udev_device *parent; + const char *attr_path = NULL; + + parent = pp->udev; + while (parent) { + if (!strncmp(udev_device_get_subsystem(parent), "scsi", 4)) { + attr_path = udev_device_get_sysname(parent); + if (!attr_path) + break; + if (sscanf(attr_path, "%i:%i:%i:%i", + &pp->sg_id.host_no, + &pp->sg_id.channel, + &pp->sg_id.scsi_id, + &pp->sg_id.lun) == 4) + break; + } + parent = udev_device_get_parent(parent); + } + if (!attr_path || pp->sg_id.host_no == -1) + return 1; if (sysfs_get_vendor(parent, pp->vendor_id, SCSI_VENDOR_SIZE)) return 1; @@ -562,13 +613,6 @@ scsi_sysfs_pathinfo (struct path * pp, const char * parent) /* * host / bus / target / lun */ - basenamecpy(parent, attr_path, FILE_NAME_SIZE); - - sscanf(attr_path, "%i:%i:%i:%i", - &pp->sg_id.host_no, - &pp->sg_id.channel, - &pp->sg_id.scsi_id, - &pp->sg_id.lun); condlog(3, "%s: h:b:t:l = %i:%i:%i:%i", pp->dev, pp->sg_id.host_no, @@ -579,10 +623,7 @@ scsi_sysfs_pathinfo (struct path * pp, const char * parent) /* * target node name */ - if(!sysfs_get_tgt_nodename(parent, pp->tgt_node_name, - pp->sg_id.host_no, - pp->sg_id.channel, - pp->sg_id.scsi_id)) { + if(!sysfs_get_tgt_nodename(pp, pp->tgt_node_name)) { condlog(3, "%s: tgt_node_name = %s", pp->dev, pp->tgt_node_name); } @@ -591,10 +632,20 @@ scsi_sysfs_pathinfo (struct path * pp, const char * parent) } static int -ccw_sysfs_pathinfo (struct path * pp, const char * parent) +ccw_sysfs_pathinfo (struct path * pp) { - char attr_path[FILE_NAME_SIZE]; - char attr_buff[FILE_NAME_SIZE]; + struct udev_device *parent; + char attr_buff[NAME_SIZE]; + const char *attr_path; + + parent = pp->udev; + while (parent) { + if (!strncmp(udev_device_get_subsystem(parent), "ccw", 3)) + break; + parent = udev_device_get_parent(parent); + } + if (!parent) + return 1; sprintf(pp->vendor_id, "IBM"); @@ -621,7 +672,7 @@ ccw_sysfs_pathinfo (struct path * pp, const char * parent) /* * host / bus / target / lun */ - basenamecpy(parent, attr_path, FILE_NAME_SIZE); + attr_path = udev_device_get_sysname(parent); pp->sg_id.lun = 0; sscanf(attr_path, "%i.%i.%x", &pp->sg_id.host_no, @@ -638,14 +689,17 @@ ccw_sysfs_pathinfo (struct path * pp, const char * parent) } static int -cciss_sysfs_pathinfo (struct path * pp, const char * devpath) +cciss_sysfs_pathinfo (struct path * pp) { - char attr_path[FILE_NAME_SIZE]; + const char * attr_path; /* * host / bus / target / lun */ - basenamecpy(devpath, attr_path, FILE_NAME_SIZE); + attr_path = udev_device_get_devpath(pp->udev); + if (!attr_path) + return 1; + pp->sg_id.lun = 0; pp->sg_id.channel = 0; sscanf(attr_path, "cciss!c%id%i", @@ -661,20 +715,20 @@ cciss_sysfs_pathinfo (struct path * pp, const char * devpath) } static int -common_sysfs_pathinfo (struct path * pp, const char * devpath) +common_sysfs_pathinfo (struct path * pp) { - size_t len; - - len = sysfs_attr_get_value(devpath, "dev", - pp->dev_t, BLK_DEV_SIZE); - if (!len) { + if (!pp->udev) { + condlog(4, "%s: udev not initialised", pp->dev); + return 1; + } + if (sysfs_get_dev(pp->udev, pp->dev_t, BLK_DEV_SIZE)) { condlog(3, "%s: no 'dev' attribute in sysfs", pp->dev); return 1; } condlog(3, "%s: dev_t = %s", pp->dev, pp->dev_t); - if (sysfs_get_size(devpath, &pp->size)) + if (sysfs_get_size(pp, &pp->size)) return 1; condlog(3, "%s: size = %llu", pp->dev, pp->size); @@ -682,45 +736,28 @@ common_sysfs_pathinfo (struct path * pp, const char * devpath) return 0; } -struct sysfs_device *sysfs_device_from_path(struct path *pp) -{ - char sysdev[FILE_NAME_SIZE]; - - if (pp->sysdev && sysfs_device_verify(pp->sysdev)) - return pp->sysdev; - - strlcpy(sysdev,"/block/", FILE_NAME_SIZE); - strlcat(sysdev,pp->dev, FILE_NAME_SIZE); - - return sysfs_device_get(sysdev); -} - int path_offline (struct path * pp) { - struct sysfs_device * parent; + struct udev_device * parent; char buff[SCSI_STATE_SIZE]; if (pp->bus != SYSFS_BUS_SCSI) return PATH_UP; - pp->sysdev = sysfs_device_from_path(pp); - if (!pp->sysdev) { - condlog(1, "%s: failed to get sysfs information", pp->dev); - return PATH_WILD; + parent = pp->udev; + while (parent) { + if (!strncmp(udev_device_get_subsystem(parent), "scsi", 4)) + break; + parent = udev_device_get_parent(parent); } - parent = sysfs_device_get_parent(pp->sysdev); - if (!parent) - parent = pp->sysdev; - if (parent && !strncmp(parent->kernel, "block",5)) - parent = sysfs_device_get_parent(parent); if (!parent) { - condlog(1, "%s: failed to get parent", pp->dev); + condlog(1, "%s: failed to get sysfs information", pp->dev); return PATH_WILD; } - if (sysfs_get_state(parent->devpath, buff, SCSI_STATE_SIZE)) + if (sysfs_get_state(parent, buff, SCSI_STATE_SIZE)) return PATH_WILD; condlog(3, "%s: path state = %s", pp->dev, buff); @@ -741,26 +778,8 @@ path_offline (struct path * pp) extern int sysfs_pathinfo(struct path * pp) { - struct sysfs_device *parent; - - pp->sysdev = sysfs_device_from_path(pp); - if (!pp->sysdev) { - condlog(1, "%s: failed to get sysfs information", pp->dev); + if (common_sysfs_pathinfo(pp)) return 1; - } - - if (common_sysfs_pathinfo(pp, pp->sysdev->devpath)) - return 1; - - parent = sysfs_device_get_parent(pp->sysdev); - if (!parent) - parent = pp->sysdev; - if (parent && !strncmp(parent->kernel, "block",5)) - parent = sysfs_device_get_parent(parent); - if (!parent) { - condlog(1, "%s: failed to get parent", pp->dev); - return 1; - } pp->bus = SYSFS_BUS_UNDEF; if (!strncmp(pp->dev,"cciss",5)) @@ -773,13 +792,13 @@ sysfs_pathinfo(struct path * pp) if (pp->bus == SYSFS_BUS_UNDEF) return 0; else if (pp->bus == SYSFS_BUS_SCSI) { - if (scsi_sysfs_pathinfo(pp, parent->devpath)) + if (scsi_sysfs_pathinfo(pp)) return 1; } else if (pp->bus == SYSFS_BUS_CCW) { - if (ccw_sysfs_pathinfo(pp, parent->devpath)) + if (ccw_sysfs_pathinfo(pp)) return 1; } else if (pp->bus == SYSFS_BUS_CCISS) { - if (cciss_sysfs_pathinfo(pp, pp->sysdev->devpath)) + if (cciss_sysfs_pathinfo(pp)) return 1; } return 0; @@ -829,7 +848,7 @@ get_state (struct path * pp, int daemon) condlog(3, "%s: get_state", pp->dev); if (!checker_selected(c)) { - if (daemon || pp->sysdev == NULL) { + if (daemon) { if (pathinfo(pp, conf->hwtable, DI_SYSFS) != 0) { condlog(3, "%s: couldn't get sysfs pathinfo", pp->dev); @@ -850,8 +869,8 @@ get_state (struct path * pp, int daemon) checker_clear_message(c); if (daemon) checker_set_async(c); - if (!conf->checker_timeout && pp->sysdev) - sysfs_get_timeout(pp->sysdev->devpath, &(c->timeout)); + if (!conf->checker_timeout) + sysfs_get_timeout(pp, &(c->timeout)); state = checker_check(c); condlog(3, "%s: state = %s", pp->dev, checker_state_name(state)); if (state == PATH_DOWN && strlen(checker_message(c))) diff --git a/libmultipath/discovery.h b/libmultipath/discovery.h index c071026..17108c7 100644 --- a/libmultipath/discovery.h +++ b/libmultipath/discovery.h @@ -26,7 +26,7 @@ struct config; -int sysfs_get_dev (const char * dev, char * buff, size_t len); +int sysfs_get_dev (struct udev_device *udev, char * buff, size_t len); int path_discovery (vector pathvec, struct config * conf, int flag); int do_tur (char *); @@ -34,9 +34,9 @@ int path_offline (struct path *); int get_state (struct path * pp, int daemon); int pathinfo (struct path *, vector hwtable, int mask); struct path * store_pathinfo (vector pathvec, vector hwtable, - char * devname, int flag); + struct udev_device *udevice, int flag); int sysfs_set_scsi_tmo (struct multipath *mpp); -int sysfs_get_timeout(const char * devpath, unsigned int *timeout); +int sysfs_get_timeout(struct path *pp, unsigned int *timeout); /* * discovery bitmask diff --git a/libmultipath/propsel.c b/libmultipath/propsel.c index 50b0e8a..f38af86 100644 --- a/libmultipath/propsel.c +++ b/libmultipath/propsel.c @@ -335,7 +335,7 @@ out: condlog(3, "%s: checker timeout = %u ms (config file default)", pp->dev, c->timeout); } - else if (pp->sysdev && sysfs_get_timeout(pp->sysdev->devpath, &c->timeout) == 0) + else if (pp->udev && sysfs_get_timeout(pp, &c->timeout) == 0) condlog(3, "%s: checker timeout = %u ms (sysfs setting)", pp->dev, c->timeout); else { diff --git a/libmultipath/structs.c b/libmultipath/structs.c index 280d2eb..3c0fe90 100644 --- a/libmultipath/structs.c +++ b/libmultipath/structs.c @@ -5,6 +5,7 @@ #include #include #include +#include #include "checkers.h" #include "memory.h" @@ -47,6 +48,11 @@ free_path (struct path * pp) if (pp->fd >= 0) close(pp->fd); + if (pp->udev) { + udev_device_unref(pp->udev); + pp->udev = NULL; + } + FREE(pp); } diff --git a/libmultipath/structs.h b/libmultipath/structs.h index 010be5d..16aa0ff 100644 --- a/libmultipath/structs.h +++ b/libmultipath/structs.h @@ -115,12 +115,6 @@ struct scsi_dev { int host_no; }; -struct sysfs_device { - struct sysfs_device *parent; /* parent device */ - char devpath[PATH_SIZE]; - char kernel[NAME_SIZE]; /* device instance name */ -}; - # ifndef HDIO_GETGEO # define HDIO_GETGEO 0x0301 /* get device geometry */ @@ -134,7 +128,7 @@ struct hd_geometry { struct path { char dev[FILE_NAME_SIZE]; char dev_t[BLK_DEV_SIZE]; - struct sysfs_device *sysdev; + struct udev_device *udev; struct scsi_idlun scsi_id; struct sg_id sg_id; struct hd_geometry geom; diff --git a/libmultipath/structs_vec.c b/libmultipath/structs_vec.c index bbbe888..b7dd7c4 100644 --- a/libmultipath/structs_vec.c +++ b/libmultipath/structs_vec.c @@ -445,16 +445,14 @@ verify_paths(struct multipath * mpp, struct vectors * vecs, vector rpvec) /* * see if path is in sysfs */ - if (!pp->sysdev || sysfs_get_dev(pp->sysdev->devpath, - pp->dev_t, BLK_DEV_SIZE)) { + if (!pp->udev || sysfs_get_dev(pp->udev, pp->dev_t, + BLK_DEV_SIZE)) { if (pp->state != PATH_DOWN) { condlog(1, "%s: removing valid path %s in state %d", - mpp->alias, - pp->sysdev?pp->sysdev->devpath:pp->dev_t, pp->state); + mpp->alias, pp->dev, pp->state); } else { condlog(3, "%s: failed to access path %s", - mpp->alias, - pp->sysdev ? pp->sysdev->devpath : pp->dev_t); + mpp->alias, pp->dev); } count++; vector_del_slot(mpp->paths, i); diff --git a/libmultipath/sysfs.c b/libmultipath/sysfs.c index 13af8a1..5cd365a 100644 --- a/libmultipath/sysfs.c +++ b/libmultipath/sysfs.c @@ -39,14 +39,6 @@ char sysfs_path[PATH_SIZE]; -/* list of sysfs devices */ -static LIST_HEAD(sysfs_dev_list); -struct sysfs_dev { - struct list_head node; - struct sysfs_device dev; - int refcount; -}; - int sysfs_init(char *path, size_t len) { if (path) { @@ -56,43 +48,9 @@ int sysfs_init(char *path, size_t len) strlcpy(sysfs_path, "/sys", sizeof(sysfs_path)); dbg("sysfs_path='%s'", sysfs_path); - INIT_LIST_HEAD(&sysfs_dev_list); return 0; } -void sysfs_cleanup(void) -{ - struct sysfs_dev *sysdev_loop; - struct sysfs_dev *sysdev_temp; - - list_for_each_entry_safe(sysdev_loop, sysdev_temp, &sysfs_dev_list, node) { - list_del(&sysdev_loop->node); - free(sysdev_loop); - } -} - -void sysfs_device_set_values(struct sysfs_device *dev, const char *devpath) -{ - char *pos; - - strlcpy(dev->devpath, devpath, sizeof(dev->devpath)); - - /* set kernel name */ - pos = strrchr(dev->devpath, '/'); - if (pos == NULL) - return; - strlcpy(dev->kernel, &pos[1], sizeof(dev->kernel)); - dbg("kernel='%s'", dev->kernel); - - /* some devices have '!' in their name, change that to '/' */ - pos = dev->kernel; - while (pos[0] != '\0') { - if (pos[0] == '!') - pos[0] = '/'; - pos++; - } -} - int sysfs_resolve_link(char *devpath, size_t size) { char link_path[PATH_SIZE]; @@ -125,164 +83,6 @@ int sysfs_resolve_link(char *devpath, size_t size) return 0; } -/* - * Caution: this routine is called extremely often. - * Should be as efficient as possible. - */ -struct sysfs_device *sysfs_device_get(const char *devpath) -{ - char path[PATH_SIZE]; - char devpath_real[PATH_SIZE]; - struct sysfs_device *dev = NULL; - struct sysfs_dev *sysdev_loop, *sysdev; - struct stat statbuf; - - dbg("open '%s'", devpath); - strlcpy(devpath_real, devpath, sizeof(devpath_real)); - remove_trailing_chars(devpath_real, '/'); - if (devpath[0] == '\0' ) - return NULL; - - /* if we got a link, resolve it to the real device */ - strlcpy(path, sysfs_path, sizeof(path)); - strlcat(path, devpath_real, sizeof(path)); - if (lstat(path, &statbuf) != 0) { - /* if stat fails look in the cache */ - dbg("stat '%s' failed: %s", path, strerror(errno)); - list_for_each_entry(sysdev_loop, &sysfs_dev_list, node) { - if (strcmp(sysdev_loop->dev.devpath, devpath_real) == 0) { - dbg("found vanished dev in cache '%s'", - sysdev_loop->dev.devpath); - sysdev_loop->refcount++; - return &sysdev_loop->dev; - } - } - return NULL; - } - - if (S_ISLNK(statbuf.st_mode)) { - if (sysfs_resolve_link(devpath_real, sizeof(devpath_real)) != 0) - return NULL; - } - - list_for_each_entry(sysdev_loop, &sysfs_dev_list, node) { - if (strcmp(sysdev_loop->dev.devpath, devpath_real) == 0) { - dbg("found dev in cache '%s'", sysdev_loop->dev.devpath); - dev = &sysdev_loop->dev; - sysdev_loop->refcount++; - } - } - - if(!dev) { - /* it is a new device */ - dbg("new device '%s'", devpath_real); - sysdev = malloc(sizeof(struct sysfs_dev)); - if (sysdev == NULL) - return NULL; - memset(sysdev, 0x00, sizeof(struct sysfs_dev)); - sysdev->refcount = 1; - list_add(&sysdev->node, &sysfs_dev_list); - dev = &sysdev->dev; - } - - sysfs_device_set_values(dev, devpath_real); - - return dev; -} - -struct sysfs_device *sysfs_device_get_parent(struct sysfs_device *dev) -{ - char parent_devpath[PATH_SIZE]; - char *pos; - - dbg("open '%s'", dev->devpath); - - /* look if we already know the parent */ - if (dev->parent != NULL) - return dev->parent; - - strlcpy(parent_devpath, dev->devpath, sizeof(parent_devpath)); - dbg("'%s'", parent_devpath); - - /* strip last element */ - pos = strrchr(parent_devpath, '/'); - if (pos == NULL || pos == parent_devpath) - return NULL; - pos[0] = '\0'; - - if (strncmp(parent_devpath, "/class", 6) == 0) { - pos = strrchr(parent_devpath, '/'); - if (pos == &parent_devpath[6] || pos == parent_devpath) { - dbg("/class top level, look for device link"); - goto device_link; - } - } - if (strcmp(parent_devpath, "/block") == 0) { - dbg("/block top level, look for device link"); - goto device_link; - } - - /* are we at the top level? */ - pos = strrchr(parent_devpath, '/'); - if (pos == NULL || pos == parent_devpath) - return NULL; - - /* get parent and remember it */ - dev->parent = sysfs_device_get(parent_devpath); - return dev->parent; - -device_link: - strlcpy(parent_devpath, dev->devpath, sizeof(parent_devpath)); - strlcat(parent_devpath, "/device", sizeof(parent_devpath)); - if (sysfs_resolve_link(parent_devpath, sizeof(parent_devpath)) != 0) - return NULL; - - /* get parent and remember it */ - dev->parent = sysfs_device_get(parent_devpath); - return dev->parent; -} - -struct sysfs_device *sysfs_device_verify(struct sysfs_device *dev) -{ - char path[PATH_SIZE]; - struct stat statbuf; - - if (!dev->devpath) - return NULL; - strlcpy(path, sysfs_path, sizeof(path)); - strlcat(path, dev->devpath, sizeof(path)); - if (stat(dev->devpath, &statbuf) == 0 && - S_ISDIR(statbuf.st_mode)) - return dev; - - return NULL; -} - -void sysfs_device_put(struct sysfs_device *dev) -{ - struct sysfs_dev *sysdev_loop; - - list_for_each_entry(sysdev_loop, &sysfs_dev_list, node) { - if (&sysdev_loop->dev == dev) { - sysdev_loop->refcount--; - if (!sysdev_loop->refcount) { - dbg("removed dev '%s' from cache", - sysdev_loop->dev.devpath); - list_del(&sysdev_loop->node); - free(sysdev_loop); - } else { - dbg("dev '%s' still in cache, refcount %d", - sysdev_loop->dev.devpath, - sysdev_loop->refcount); - } - return; - } - } - dbg("dev '%s' not found in cache", dev->devpath); - - return; -} - size_t sysfs_attr_get_value(const char *devpath, const char *attr_name, char *attr_value, int attr_len) { diff --git a/libmultipath/sysfs.h b/libmultipath/sysfs.h index 22a4c5b..b5a3f21 100644 --- a/libmultipath/sysfs.h +++ b/libmultipath/sysfs.h @@ -13,7 +13,6 @@ int sysfs_init(char *path, size_t len); void sysfs_cleanup(void); -void sysfs_device_set_values(struct sysfs_device *dev, const char *devpath); struct sysfs_device *sysfs_device_get(const char *devpath); struct sysfs_device *sysfs_device_get_parent(struct sysfs_device *dev); void sysfs_device_put(struct sysfs_device *dev); @@ -23,6 +22,6 @@ size_t sysfs_attr_get_value(const char *devpath, const char *attr_name, ssize_t sysfs_attr_set_value(const char *devpath, const char *attr_name, const char *value, int value_len); int sysfs_resolve_link(char *path, size_t size); -int sysfs_get_size(const char * devpath, unsigned long long * size); +int sysfs_get_size(struct path *pp, unsigned long long * size); int sysfs_check_holders(char * check_devt, char * new_devt); #endif diff --git a/libmultipath/uevent.c b/libmultipath/uevent.c index 4e31d4f..a29a43c 100644 --- a/libmultipath/uevent.c +++ b/libmultipath/uevent.c @@ -117,6 +117,8 @@ service_uevq(struct list_head *tmpq) if (my_uev_trigger && my_uev_trigger(uev, my_trigger_data)) condlog(0, "uevent trigger error"); + if (uev->udev) + udev_device_unref(uev->udev); FREE(uev); } } @@ -472,7 +474,7 @@ int uevent_listen(void) if (i == HOTPLUG_NUM_ENVP - 1) break; } - udev_device_unref(dev); + uev->udev = dev; uev->envp[i] = NULL; condlog(3, "uevent '%s' from '%s'", uev->action, uev->devpath); diff --git a/libmultipath/uevent.h b/libmultipath/uevent.h index 46596fd..64f00b7 100644 --- a/libmultipath/uevent.h +++ b/libmultipath/uevent.h @@ -15,6 +15,7 @@ struct uevent { struct list_head node; + struct udev_device *udev; char buffer[HOTPLUG_BUFFER_SIZE + OBJECT_SIZE]; char *devpath; char *action; diff --git a/libmultipath/util.c b/libmultipath/util.c index f6ee09c..70735e6 100644 --- a/libmultipath/util.c +++ b/libmultipath/util.c @@ -234,3 +234,13 @@ skip_proc: basenamecpy((const char *)block_path, devname, devname_len); return 0; } + +dev_t parse_devt(const char *dev_t) +{ + int maj, min; + + if (sscanf(dev_t,"%d:%d", &maj, &min) != 2) + return 0; + + return makedev(maj, min); +} diff --git a/libmultipath/util.h b/libmultipath/util.h index cb4ce1b..44184a1 100644 --- a/libmultipath/util.h +++ b/libmultipath/util.h @@ -9,6 +9,7 @@ size_t strlcpy(char *dst, const char *src, size_t size); size_t strlcat(char *dst, const char *src, size_t size); void remove_trailing_chars(char *path, char c); int devt2devname (char *, int, char *); +dev_t parse_devt(const char *dev_t); #define safe_sprintf(var, format, args...) \ snprintf(var, sizeof(var), format, ##args) >= sizeof(var) diff --git a/multipath/main.c b/multipath/main.c index 2078fe3..9be52b5 100644 --- a/multipath/main.c +++ b/multipath/main.c @@ -539,7 +539,6 @@ main (int argc, char *argv[]) out: udev_wait(conf->cookie); - sysfs_cleanup(); dm_lib_release(); dm_lib_exit(); diff --git a/multipathd/Makefile b/multipathd/Makefile index 1d4ea14..9553251 100644 --- a/multipathd/Makefile +++ b/multipathd/Makefile @@ -6,7 +6,7 @@ include ../Makefile.inc # basic flags setting # CFLAGS += -I$(multipathdir) -I$(mpathpersistdir) -LDFLAGS += -lpthread -ldevmapper -lreadline -lncurses -ldl \ +LDFLAGS += -lpthread -ldevmapper -lreadline -lncurses -ludev -ldl \ -L$(multipathdir) -lmultipath -L$(mpathpersistdir) -lmpathpersist # diff --git a/multipathd/cli_handlers.c b/multipathd/cli_handlers.c index 5cf5f4b..39b89bf 100644 --- a/multipathd/cli_handlers.c +++ b/multipathd/cli_handlers.c @@ -16,6 +16,8 @@ #include #include #include +#include +#include #include "main.h" #include "cli.h" @@ -426,10 +428,15 @@ cli_add_path (void * v, char ** reply, int * len, void * data) if (pp->mpp) return 0; } else { + struct udev_device *udevice; + + udevice = udev_device_new_from_devnum(conf->udev, 'b', + parse_devt(pp->dev_t)); pp = store_pathinfo(vecs->pathvec, conf->hwtable, - param, DI_ALL); + udevice, DI_ALL); if (!pp) { condlog(0, "%s: failed to store path info", param); + udev_device_unref(udevice); return 1; } } @@ -596,7 +603,7 @@ cli_resize(void *v, char **reply, int *len, void *data) pgp = VECTOR_SLOT(mpp->pg, 0); pp = VECTOR_SLOT(pgp->paths, 0); - if (!pp->sysdev || sysfs_get_size(pp->sysdev->devpath, &size)) { + if (!pp->udev || sysfs_get_size(pp, &size)) { condlog(0, "%s: couldn't get size for sysfs. cannot resize", mapname); return 1; diff --git a/multipathd/main.c b/multipathd/main.c index e87375c..b54f6c6 100644 --- a/multipathd/main.c +++ b/multipathd/main.c @@ -16,6 +16,7 @@ #include #include #include +#include #include /* @@ -390,13 +391,17 @@ uev_add_path (struct uevent *uev, struct vectors * vecs) if (pp->mpp) return 0; } else { + struct udev_device *udevice; + /* * get path vital state */ + udevice = udev_device_ref(uev->udev); if (!(pp = store_pathinfo(vecs->pathvec, conf->hwtable, - uev->kernel, DI_ALL))) { + udevice, DI_ALL))) { condlog(0, "%s: failed to store path info", uev->kernel); + udev_device_unref(udevice); return 1; } pp->checkint = conf->checkint; @@ -1671,8 +1676,6 @@ child (void * param) pthread_cancel(uxlsnr_thr); pthread_cancel(uevq_thr); - sysfs_cleanup(); - lock(vecs->lock); free_pathvec(vecs->pathvec, FREE_PATHS); vecs->pathvec = NULL; -- 2.7.4