exit(1);
}
+/*
+ ***************************************************************************
+ * Extract WWWN identifiers from filename, as read from /dev/disk/by-id.
+ *
+ * Sample valid names read from /dev/disk/by-id:
+ * wwn-0x5000cca369f193ac
+ * wwn-0x5000cca369f193ac-part12
+ * wwn-0x600605b00a2bdf00242b28c10dcb1999
+ * wwn-0x600605b00a2bdf00242b28c10dcb1999-part2
+ *
+ * WWN ids like these ones are ignored:
+ * wwn-0x5438850077615869953x
+ * wwn-0x5438850077615869953x-part1
+ *
+ * IN:
+ * @name Filename read from /dev/disk/by-id.
+ *
+ * OUT:
+ * @wwn WWN identifier (8 or 16 hex characters).
+ * @part-nr Partition number if applicable.
+ *
+ * RETURNS:
+ * 0 on success, -1 otherwise.
+ ***************************************************************************
+*/
+int extract_wwnid(char *name, unsigned long long *wwn, unsigned int *part_nr)
+{
+ char id[17];
+ char *s;
+ int wwnlen;
+
+ *wwn = *(wwn + 1) = 0ULL;
+ *part_nr = 0;
+
+ /* Check name */
+ if (((wwnlen = strlen(name)) < 22) || (strncmp(name, "wwn-0x", 6)))
+ return -1;
+
+ /* Is there a partition number? */
+ if ((s = strstr(name, "-part")) != NULL) {
+ /* Yes: Get partition number */
+ if (sscanf(s + 5, "%u", part_nr) == 0)
+ return -1;
+ wwnlen = s - name - 6;
+ }
+ else {
+ wwnlen -= 6; /* Don't count "wwn-0x" */
+ }
+
+ /* Check WWN length */
+ if ((wwnlen != 16) && (wwnlen != 32))
+ return -1;
+
+ /* Extract first 8 hex chars of WWN */
+ strncpy(id, name + 6, 16);
+ id[16] = '\0';
+ if (sscanf(id, "%llx", wwn) == 0)
+ return -1;
+
+ if (strlen(name) < 38)
+ /* This is a short (8 hex chars) WWN id */
+ return 0;
+
+ /* Extract second part of WWN */
+ if (sscanf(name + 22, "%llx", wwn + 1) == 0)
+ return -1;
+
+ return 0;
+}
+
+/*
+ ***************************************************************************
+ * Get WWWN identifiers from a pretty filename using links present in
+ * /dev/disk/by-id directory.
+ *
+ * IN:
+ * @pretty Pretty name (e.g. sda, sdb3...).
+ *
+ * OUT:
+ * @wwn WWN identifier (8 or 16 hex characters).
+ * @part-nr Partition number if applicable.
+ *
+ * RETURNS:
+ * 0 on success, -1 otherwise.
+ ***************************************************************************
+*/
+int get_wwnid_from_pretty(char *pretty, unsigned long long *wwn, unsigned int *part_nr)
+{
+ DIR *dir;
+ struct dirent *drd;
+ ssize_t r;
+ char link[PATH_MAX], target[PATH_MAX], wwn_name[FILENAME_MAX];
+ char *name;
+ int rc = -1;
+
+ /* Open /dev/disk/by-id directory */
+ if ((dir = opendir(DEV_DISK_BY_ID)) == NULL)
+ return -1;
+
+ /* Get current id */
+ while ((drd = readdir(dir)) != NULL) {
+
+ if (strncmp(drd->d_name, "wwn-0x", 6))
+ continue;
+
+ /* Get absolute path for current persistent name */
+ snprintf(link, PATH_MAX, "%s/%s", DEV_DISK_BY_ID, drd->d_name);
+
+ /* Persistent name is usually a symlink: Read it... */
+ r = readlink(link, target, PATH_MAX);
+ if ((r <= 0) || (r >= PATH_MAX))
+ continue;
+
+ target[r] = '\0';
+
+ /* ... and get device pretty name it points at */
+ name = basename(target);
+ if (!name || (name[0] == '\0'))
+ continue;
+
+ if (!strncmp(name, pretty, FILENAME_MAX)) {
+ /* We have found pretty name for current persistent one */
+ strncpy(wwn_name, drd->d_name, FILENAME_MAX);
+ wwn_name[FILENAME_MAX - 1] = '\0';
+
+ /* Try to extract WWN */
+ if (!extract_wwnid(wwn_name, wwn, part_nr)) {
+ /* WWN successfully extracted */
+ rc = 0;
+ break;
+ }
+ }
+ }
+
+ /* Close directory */
+ closedir(dir);
+
+ return rc;
+}
+
#ifndef SOURCE_SADC
/*
***************************************************************************
* i != k because we are ignoring "." and ".." entries.
*/
for (i = 0; i < n; i++) {
- /* Ignore "." and "..". */
+ /* Ignore "." and ".." */
if (!strcmp(".", namelist[i]->d_name) ||
!strcmp("..", namelist[i]->d_name))
continue;
#define DEVICES PRE "/proc/devices"
#define SYSFS_USBDEV PRE "/sys/bus/usb/devices"
#define DEV_DISK_BY PRE "/dev/disk/by"
+#define DEV_DISK_BY_ID PRE "/dev/disk/by-id"
#define SYSFS_IDVENDOR "idVendor"
#define SYSFS_IDPRODUCT "idProduct"
#define SYSFS_BMAXPOWER "bMaxPower"
(char *, int);
void sysstat_panic
(const char *, int);
+int extract_wwnid
+ (char *, unsigned long long *, unsigned int *);
+int get_wwnid_from_pretty
+ (char *, unsigned long long *, unsigned int *);
#ifndef SOURCE_SADC
int count_bits
}
/* Get device name */
- dev_name = get_sa_devname(sdc->major, sdc->minor, flags);
+ dev_name = get_sa_devname(sdc->major, sdc->minor,
+ sdc->wwn, sdc->part_nr, flags);
if (a->item_list != NULL) {
/* A list of devices has been entered on the command line */
}
/* Get device name */
- dev_name = get_sa_devname(sdc->major, sdc->minor, flags);
+ dev_name = get_sa_devname(sdc->major, sdc->minor,
+ sdc->wwn, sdc->part_nr, flags);
if (a->item_list != NULL) {
/* A list of devices has been entered on the command line */
continue;
/* Get device name */
- dev_name = get_sa_devname(sdc->major, sdc->minor, flags);
+ dev_name = get_sa_devname(sdc->major, sdc->minor, sdc->wwn, sdc->part_nr, flags);
if (a->item_list != NULL) {
/* A list of devices has been entered on the command line */
sdc = (struct stats_disk *) ((char *) a->buf[curr] + i * a->msize);
/* Get device name */
- dev_name = get_sa_devname(sdc->major, sdc->minor, flags);
+ dev_name = get_sa_devname(sdc->major, sdc->minor,
+ sdc->wwn, sdc->part_nr, flags);
if (a->item_list != NULL) {
/* A list of devices has been entered on the command line */
char line[1024];
char dev_name[MAX_NAME_LEN];
struct stats_disk *st_disk_i;
- unsigned int major, minor, rd_ticks, wr_ticks, dc_ticks, tot_ticks, rq_ticks;
+ unsigned int major, minor, rd_ticks, wr_ticks, dc_ticks, tot_ticks, rq_ticks, part_nr;
unsigned long rd_ios, wr_ios, dc_ios, rd_sec, wr_sec, dc_sec;
+ unsigned long long wwn[2];
__nr_t dsk_read = 0;
if ((fp = fopen(DISKSTATS, "r")) == NULL)
st_disk_i->dc_ticks = dc_ticks;
st_disk_i->tot_ticks = tot_ticks;
st_disk_i->rq_ticks = rq_ticks;
+
+ if (get_wwnid_from_pretty(dev_name, wwn, &part_nr) < 0) {
+ st_disk_i->wwn[0] = 0ULL;
+ }
+ else {
+ st_disk_i->wwn[0] = wwn[0];
+ st_disk_i->wwn[1] = wwn[1];
+ st_disk_i->part_nr = part_nr;
+ }
}
}
}
/* Structure for block devices statistics */
struct stats_disk {
unsigned long long nr_ios;
+ unsigned long long wwn[2];
unsigned long rd_sect __attribute__ ((aligned (8)));
unsigned long wr_sect __attribute__ ((aligned (8)));
unsigned long dc_sect __attribute__ ((aligned (8)));
unsigned int major;
unsigned int minor;
unsigned int dc_ticks;
+ unsigned int part_nr;
};
#define STATS_DISK_SIZE (sizeof(struct stats_disk))
-#define STATS_DISK_ULL 1
+#define STATS_DISK_ULL 3
#define STATS_DISK_UL 3
-#define STATS_DISK_U 7
+#define STATS_DISK_U 8
/* Structure for network interfaces statistics */
struct stats_net_dev {
}
/* Get device name */
- dev_name = get_sa_devname(sdc->major, sdc->minor, flags);
+ dev_name = get_sa_devname(sdc->major, sdc->minor,
+ sdc->wwn, sdc->part_nr, flags);
if (a->item_list != NULL) {
/* A list of devices has been entered on the command line */
*/
#define S_F_SINCE_BOOT 0x00000001
-#define S_F_SA_ROTAT 0x00000002
+#define S_F_SA_ROTAT 0x00000002 /* Only used by sadc */
+#define S_F_DEV_SID 0x00000002 /* Only used by sar/sadf */
#define S_F_DEV_PRETTY 0x00000004
#define S_F_FORCE_FILE 0x00000008
#define S_F_INTERVAL_SET 0x00000010
#define WANT_SINCE_BOOT(m) (((m) & S_F_SINCE_BOOT) == S_F_SINCE_BOOT)
#define WANT_SA_ROTAT(m) (((m) & S_F_SA_ROTAT) == S_F_SA_ROTAT)
+#define USE_STABLE_ID(m) (((m) & S_F_DEV_SID) == S_F_DEV_SID)
#define USE_PRETTY_OPTION(m) (((m) & S_F_DEV_PRETTY) == S_F_DEV_PRETTY)
#define FORCE_FILE(m) (((m) & S_F_FORCE_FILE) == S_F_FORCE_FILE)
#define INTERVAL_SET(m) (((m) & S_F_INTERVAL_SET) == S_F_INTERVAL_SET)
/* Keywords */
#define K_A_NULL "A_NULL"
-#define K_XALL "XALL"
-#define K_SUM "SUM"
+#define K_CPU "CPU"
#define K_DEV "DEV"
#define K_EDEV "EDEV"
-#define K_NFS "NFS"
-#define K_NFSD "NFSD"
-#define K_SOCK "SOCK"
-#define K_IP "IP"
-#define K_EIP "EIP"
-#define K_ICMP "ICMP"
#define K_EICMP "EICMP"
-#define K_TCP "TCP"
-#define K_ETCP "ETCP"
-#define K_UDP "UDP"
-#define K_SOCK6 "SOCK6"
-#define K_IP6 "IP6"
-#define K_EIP6 "EIP6"
-#define K_ICMP6 "ICMP6"
#define K_EICMP6 "EICMP6"
-#define K_UDP6 "UDP6"
-#define K_CPU "CPU"
+#define K_EIP "EIP"
+#define K_EIP6 "EIP6"
+#define K_ETCP "ETCP"
#define K_FAN "FAN"
-#define K_TEMP "TEMP"
-#define K_IN "IN"
+#define K_FC "FC"
#define K_FREQ "FREQ"
+#define K_ICMP "ICMP"
+#define K_ICMP6 "ICMP6"
+#define K_IN "IN"
+#define K_IP "IP"
+#define K_IP6 "IP6"
#define K_MOUNT "MOUNT"
-#define K_FC "FC"
+#define K_NFS "NFS"
+#define K_NFSD "NFSD"
+#define K_SID "SID"
+#define K_SOCK "SOCK"
+#define K_SOCK6 "SOCK6"
#define K_SOFT "SOFT"
+#define K_SUM "SUM"
+#define K_TCP "TCP"
+#define K_TEMP "TEMP"
+#define K_UDP "UDP"
+#define K_UDP6 "UDP6"
+#define K_XALL "XALL"
#define K_INT "INT"
#define K_DISK "DISK"
char *get_devname
(unsigned int, unsigned int, int);
char *get_sa_devname
- (unsigned int, unsigned int, unsigned int);
+ (unsigned int, unsigned int, unsigned long long [], unsigned int, unsigned int);
void get_file_timestamp_struct
(unsigned int, struct tm *, struct file_header *);
unsigned long long get_global_cpu_statistics
return 1;
}
(*opt)++;
+ if (!strcmp(argv[*opt], K_SID)) {
+ *flags |= S_F_DEV_SID + S_F_DEV_PRETTY;
+ return 0;
+ }
+
if (strnlen(argv[*opt], MAX_FILE_LEN) >= MAX_FILE_LEN - 1)
return 1;
* IN:
* @major Major number of the device.
* @minor Minor number of the device.
+ * @wwn WWN identifier of the device (0 if unknown).
+ * @part_nr Partition number (0 if unknown).
* @flags Flags for common options and system state.
*
* RETURNS:
* The name of the device.
***************************************************************************
*/
-char *get_sa_devname(unsigned int major, unsigned int minor, unsigned int flags)
+char *get_sa_devname(unsigned int major, unsigned int minor, unsigned long long wwn[],
+ unsigned int part_nr, unsigned int flags)
{
char *dev_name = NULL, *persist_dev_name = NULL;
+ static char sid[64];
+ char xsid[32] = "", pn[16] = "";
if (DISPLAY_PERSIST_NAME_S(flags)) {
persist_dev_name = get_persistent_name_from_pretty(get_devname(major, minor, TRUE));
dev_name = persist_dev_name;
}
else {
- if ((USE_PRETTY_OPTION(flags)) && (major == dm_major)) {
+ if ((USE_STABLE_ID(flags)) && (wwn[0] != 0)) {
+ if (wwn[1] != 0) {
+ sprintf(xsid, "%016llx", wwn[1]);
+ }
+ if (part_nr) {
+ sprintf(pn, "-%d", part_nr);
+ }
+ snprintf(sid, sizeof(sid), "%#016llx%s%s", wwn[0], xsid, pn);
+ dev_name = sid;
+ }
+ else if ((USE_PRETTY_OPTION(flags)) && (major == dm_major)) {
dev_name = transform_devmapname(major, minor);
}
sdc = (struct stats_disk *) ((char *) a->buf[curr] + i * a->msize);
nr += add_list_item(&(a->item_list),
- get_sa_devname(sdc->major, sdc->minor, flags),
+ get_sa_devname(sdc->major, sdc->minor, sdc->wwn,
+ sdc->part_nr, flags),
MAX_DEV_LEN);
}
static double *spmin, *spmax;
static char **out;
static int *outsize;
- char *item_name;
+ char *dev_name, *item_name;
double rkB, wkB, dkB, aqusz;
int i, j, k, pos, restart, *unregistered;
* Allocate arrays (#0..7) that will contain the graphs data
* and the min/max values.
* Also allocate one additional array (#8) for each disk device:
- * spmax + 8 will contain the device major number,
- * spmin + 8 will contain the device minor number,
+ * out + 8 will contain the device name (WWN id, pretty name or devm-n),
* outsize + 8 will contain a positive value (TRUE) if the device
* has either still not been registered, or has been unregistered.
*/
for (i = 0; i < a->nr[curr]; i++) {
sdc = (struct stats_disk *) ((char *) a->buf[curr] + i * a->msize);
- /* Get device name */
- item_name = get_sa_devname(sdc->major, sdc->minor, flags);
+ /* Get device name */
+ dev_name = get_sa_devname(sdc->major, sdc->minor,
+ sdc->wwn, sdc->part_nr, flags);
if (a->item_list != NULL) {
/* A list of devices has been entered on the command line */
- if (!search_list_item(a->item_list, item_name))
+ if (!search_list_item(a->item_list, dev_name))
/* Device not found */
continue;
}
/* Look for corresponding graph */
for (k = 0; k < a->item_list_sz; k++) {
- if ((sdc->major == *(spmax + k * nr_arrays + 8)) &&
- (sdc->minor == *(spmin + k * nr_arrays + 8)))
+ item_name = *(out + k * nr_arrays + 8);
+ if (!strcmp(dev_name, item_name))
/* Graph found! */
break;
}
if (k == a->item_list_sz) {
/* Graph not found: Look for first free entry */
for (k = 0; k < a->item_list_sz; k++) {
- if (*(spmax + k * nr_arrays + 8) == -DBL_MAX)
+ item_name = *(out + k * nr_arrays + 8);
+ if (!strcmp(item_name, ""))
break;
}
if (k == a->item_list_sz) {
/* No free graph entry: Ignore it (should never happen) */
#ifdef DEBUG
fprintf(stderr, "%s: Name=%s major=%d minor=%d\n",
- __FUNCTION__, item_name, sdc->major, sdc->minor);
+ __FUNCTION__, dev_name, sdc->major, sdc->minor);
#endif
continue;
}
}
*unregistered = FALSE;
- if (*(spmax + pos + 8) == -DBL_MAX) {
- /* Save device major and minor numbers (if not already done) */
- *(spmax + pos + 8) = sdc->major;
- *(spmin + pos + 8) = sdc->minor;
+ item_name = *(out + pos + 8);
+ if (!item_name[0]) {
+ /* Save device name (WWN id or pretty name) if not already done */
+ strncpy(item_name, dev_name, CHUNKSIZE);
+ item_name[CHUNKSIZE - 1] = '\0';
}
j = check_disk_reg(a, curr, !curr, i);
if (!**(out + pos))
continue;
- /* Get device name */
- item_name = get_sa_devname(*(spmax + pos + 8), *(spmin + pos + 8), flags);
-
+ item_name = *(out + pos + 8);
if (draw_activity_graphs(a->g_nr, g_type,
title, g_title, item_name, group,
spmin + pos, spmax + pos, out + pos, outsize + pos,
}
/* Get device name */
- dev_name = get_sa_devname(sdc->major, sdc->minor, flags);
+ dev_name = get_sa_devname(sdc->major, sdc->minor,
+ sdc->wwn, sdc->part_nr, flags);
if (a->item_list != NULL) {
/* A list of devices has been entered on the command line */