/* *************************************************************************** * Display disk stats header. * * OUT: * @fctr Conversion factor. *************************************************************************** */ void write_disk_stat_header(int *fctr) { if (DISPLAY_EXTENDED(flags)) { /* Extended stats */ printf("Device: rrqm/s wrqm/s r/s w/s"); if (DISPLAY_MEGABYTES(flags)) { printf(" rMB/s wMB/s"); *fctr = 2048; } else if (DISPLAY_KILOBYTES(flags)) { printf(" rkB/s wkB/s"); *fctr = 2; } else { printf(" rsec/s wsec/s"); } printf(" avgrq-sz avgqu-sz await r_await w_await svctm %%util\n"); } else { /* Basic stats */ printf("Device: tps"); if (DISPLAY_KILOBYTES(flags)) { printf(" kB_read/s kB_wrtn/s kB_read kB_wrtn\n"); *fctr = 2; } else if (DISPLAY_MEGABYTES(flags)) { printf(" MB_read/s MB_wrtn/s MB_read MB_wrtn\n"); *fctr = 2048; } else { printf(" Blk_read/s Blk_wrtn/s Blk_read Blk_wrtn\n"); } } }
/* *************************************************************************** * Read sysfs stat for current block device or partition. * * IN: * @curr Index in array for current sample statistics. * @filename File name where stats will be read. * @dev_name Device or partition name. * * RETURNS: * 0 if file couldn't be opened, 1 otherwise. *************************************************************************** */ int read_sysfs_file_stat(int curr, char *filename, char *dev_name) { FILE *fp; struct io_stats sdev; int i; unsigned int ios_pgr, tot_ticks, rq_ticks, wr_ticks; unsigned long rd_ios, rd_merges_or_rd_sec, wr_ios, wr_merges; unsigned long rd_sec_or_wr_ios, wr_sec, rd_ticks_or_wr_sec; /* Try to read given stat file */ if ((fp = fopen(filename, "r")) == NULL) return 0; i = fscanf(fp, "%lu %lu %lu %lu %lu %lu %lu %u %u %u %u", &rd_ios, &rd_merges_or_rd_sec, &rd_sec_or_wr_ios, &rd_ticks_or_wr_sec, &wr_ios, &wr_merges, &wr_sec, &wr_ticks, &ios_pgr, &tot_ticks, &rq_ticks); if (i == 11) { /* Device or partition */ sdev.rd_ios = rd_ios; sdev.rd_merges = rd_merges_or_rd_sec; sdev.rd_sectors = rd_sec_or_wr_ios; sdev.rd_ticks = (unsigned int) rd_ticks_or_wr_sec; sdev.wr_ios = wr_ios; sdev.wr_merges = wr_merges; sdev.wr_sectors = wr_sec; sdev.wr_ticks = wr_ticks; sdev.ios_pgr = ios_pgr; sdev.tot_ticks = tot_ticks; sdev.rq_ticks = rq_ticks; } else if (i == 4) { /* Partition without extended statistics */ sdev.rd_ios = rd_ios; sdev.rd_sectors = rd_merges_or_rd_sec; sdev.wr_ios = rd_sec_or_wr_ios; sdev.wr_sectors = rd_ticks_or_wr_sec; } if ((i == 11) || !DISPLAY_EXTENDED(flags)) { /* * In fact, we _don't_ save stats if it's a partition without * extended stats and yet we want to display ext stats. */ save_stats(dev_name, curr, &sdev, iodev_nr, st_hdr_iodev); } fclose(fp); return 1; }
/* *************************************************************************** * Read stats from /proc/diskstats. * * IN: * @curr Index in array for current sample statistics. *************************************************************************** */ void read_diskstats_stat(int curr) { FILE *fp; char line[256], dev_name[MAX_NAME_LEN]; char *dm_name; struct io_stats sdev; int i; unsigned int ios_pgr, tot_ticks, rq_ticks, wr_ticks; unsigned long rd_ios, rd_merges_or_rd_sec, rd_ticks_or_wr_sec, wr_ios; unsigned long wr_merges, rd_sec_or_wr_ios, wr_sec; char *ioc_dname; unsigned int major, minor; /* Every I/O device entry is potentially unregistered */ set_entries_unregistered(iodev_nr, st_hdr_iodev); if ((fp = fopen(DISKSTATS, "r")) == NULL) return; while (fgets(line, sizeof(line), fp) != NULL) { /* major minor name rio rmerge rsect ruse wio wmerge wsect wuse running use aveq */ i = sscanf(line, "%u %u %s %lu %lu %lu %lu %lu %lu %lu %u %u %u %u", &major, &minor, dev_name, &rd_ios, &rd_merges_or_rd_sec, &rd_sec_or_wr_ios, &rd_ticks_or_wr_sec, &wr_ios, &wr_merges, &wr_sec, &wr_ticks, &ios_pgr, &tot_ticks, &rq_ticks); if (i == 14) { /* Device or partition */ if (!dlist_idx && !DISPLAY_PARTITIONS(flags) && !is_device(dev_name, ACCEPT_VIRTUAL_DEVICES)) continue; sdev.rd_ios = rd_ios; sdev.rd_merges = rd_merges_or_rd_sec; sdev.rd_sectors = rd_sec_or_wr_ios; sdev.rd_ticks = (unsigned int) rd_ticks_or_wr_sec; sdev.wr_ios = wr_ios; sdev.wr_merges = wr_merges; sdev.wr_sectors = wr_sec; sdev.wr_ticks = wr_ticks; sdev.ios_pgr = ios_pgr; sdev.tot_ticks = tot_ticks; sdev.rq_ticks = rq_ticks; } else if (i == 7) { /* Partition without extended statistics */ if (DISPLAY_EXTENDED(flags) || (!dlist_idx && !DISPLAY_PARTITIONS(flags))) continue; sdev.rd_ios = rd_ios; sdev.rd_sectors = rd_merges_or_rd_sec; sdev.wr_ios = rd_sec_or_wr_ios; sdev.wr_sectors = rd_ticks_or_wr_sec; } else /* Unknown entry: Ignore it */ continue; if ((ioc_dname = ioc_name(major, minor)) != NULL) { if (strcmp(dev_name, ioc_dname) && strcmp(ioc_dname, K_NODEV)) { /* * No match: Use name generated from sysstat.ioconf data * (if different from "nodev") works around known issues * with EMC PowerPath. */ strncpy(dev_name, ioc_dname, MAX_NAME_LEN - 1); dev_name[MAX_NAME_LEN - 1] = '\0'; } } if ((DISPLAY_DEVMAP_NAME(flags)) && (major == dm_major)) { /* * If the device is a device mapper device, try to get its * assigned name of its logical device. */ dm_name = transform_devmapname(major, minor); if (dm_name) { strncpy(dev_name, dm_name, MAX_NAME_LEN - 1); dev_name[MAX_NAME_LEN - 1] = '\0'; } } save_stats(dev_name, curr, &sdev, iodev_nr, st_hdr_iodev); } fclose(fp); /* Free structures corresponding to unregistered devices */ free_unregistered_entries(iodev_nr, st_hdr_iodev); }
/* *************************************************************************** * Main entry to the iostat program. *************************************************************************** */ int main(int argc, char **argv) { int it = 0; int opt = 1; int i, report_set = FALSE; long count = 1; struct utsname header; struct io_dlist *st_dev_list_i; struct tm rectime; char *t, *persist_devname, *devname; #ifdef USE_NLS /* Init National Language Support */ init_nls(); #endif /* Get HZ */ get_HZ(); /* Allocate structures for device list */ if (argc > 1) { salloc_dev_list(argc - 1 + count_csvalues(argc, argv)); } /* Process args... */ while (opt < argc) { /* -p option used individually. See below for grouped use */ if (!strcmp(argv[opt], "-p")) { flags |= I_D_PARTITIONS; if (argv[++opt] && (strspn(argv[opt], DIGITS) != strlen(argv[opt])) && (strncmp(argv[opt], "-", 1))) { flags |= I_D_UNFILTERED; for (t = strtok(argv[opt], ","); t; t = strtok(NULL, ",")) { if (!strcmp(t, K_ALL)) { flags |= I_D_PART_ALL; } else { devname = device_name(t); if (DISPLAY_PERSIST_NAME_I(flags)) { /* Get device persistent name */ persist_devname = get_pretty_name_from_persistent(devname); if (persist_devname != NULL) { devname = persist_devname; } } /* Store device name */ i = update_dev_list(&dlist_idx, devname); st_dev_list_i = st_dev_list + i; st_dev_list_i->disp_part = TRUE; } } opt++; } else { flags |= I_D_PART_ALL; } } else if (!strcmp(argv[opt], "-g")) { /* * Option -g: Stats for a group of devices. * group_name contains the last group name entered on * the command line. If we define an additional one, save * the previous one in the list. We do that this way because we * want the group name to appear in the list _after_ all * the devices included in that group. The last group name * will be saved in the list later, in presave_device_list() function. */ if (group_nr > 0) { update_dev_list(&dlist_idx, group_name); } if (argv[++opt]) { /* * MAX_NAME_LEN - 2: one char for the heading space, * and one for the trailing '\0'. */ snprintf(group_name, MAX_NAME_LEN, " %-.*s", MAX_NAME_LEN - 2, argv[opt++]); } else { usage(argv[0]); } group_nr++; } else if (!strcmp(argv[opt], "-j")) { if (argv[++opt]) { if (strnlen(argv[opt], MAX_FILE_LEN) >= MAX_FILE_LEN - 1) { usage(argv[0]); } strncpy(persistent_name_type, argv[opt], MAX_FILE_LEN - 1); persistent_name_type[MAX_FILE_LEN - 1] = '\0'; strtolower(persistent_name_type); /* Check that this is a valid type of persistent device name */ if (!get_persistent_type_dir(persistent_name_type)) { fprintf(stderr, _("Invalid type of persistent device name\n")); exit(1); } /* * Persistent names are usually long: Display * them as human readable by default. */ flags |= I_D_PERSIST_NAME + I_D_HUMAN_READ; opt++; } else { usage(argv[0]); } } #ifdef DEBUG else if (!strcmp(argv[opt], "--debuginfo")) { flags |= I_D_DEBUG; opt++; } #endif else if (!strncmp(argv[opt], "-", 1)) { for (i = 1; *(argv[opt] + i); i++) { switch (*(argv[opt] + i)) { case 'c': /* Display cpu usage */ flags |= I_D_CPU; report_set = TRUE; break; case 'd': /* Display disk utilization */ flags |= I_D_DISK; report_set = TRUE; break; case 'h': /* * Display device utilization report * in a human readable format. */ flags |= I_D_HUMAN_READ; break; case 'k': if (DISPLAY_MEGABYTES(flags)) { usage(argv[0]); } /* Display stats in kB/s */ flags |= I_D_KILOBYTES; break; case 'm': if (DISPLAY_KILOBYTES(flags)) { usage(argv[0]); } /* Display stats in MB/s */ flags |= I_D_MEGABYTES; break; case 'N': /* Display device mapper logical name */ flags |= I_D_DEVMAP_NAME; break; case 'p': /* If option -p is grouped then it cannot take an arg */ flags |= I_D_PARTITIONS + I_D_PART_ALL; break; case 'T': /* Display stats only for the groups */ flags |= I_D_GROUP_TOTAL_ONLY; break; case 't': /* Display timestamp */ flags |= I_D_TIMESTAMP; break; case 'x': /* Display extended stats */ flags |= I_D_EXTENDED; break; case 'y': /* Don't display stats since system restart */ flags |= I_D_OMIT_SINCE_BOOT; break; case 'z': /* Omit output for devices with no activity */ flags |= I_D_ZERO_OMIT; break; case 'V': /* Print version number and exit */ print_version(); break; default: usage(argv[0]); } } opt++; } else if (!isdigit(argv[opt][0])) { /* * By default iostat doesn't display unused devices. * If some devices are explictly entered on the command line * then don't apply this rule any more. */ flags |= I_D_UNFILTERED; if (strcmp(argv[opt], K_ALL)) { /* Store device name entered on the command line */ devname = device_name(argv[opt++]); if (DISPLAY_PERSIST_NAME_I(flags)) { persist_devname = get_pretty_name_from_persistent(devname); if (persist_devname != NULL) { devname = persist_devname; } } update_dev_list(&dlist_idx, devname); } else { opt++; } } else if (!it) { interval = atol(argv[opt++]); if (interval < 0) { usage(argv[0]); } count = -1; it = 1; } else if (it > 0) { count = atol(argv[opt++]); if ((count < 1) || !interval) { usage(argv[0]); } it = -1; } else { usage(argv[0]); } } if (!interval) { count = 1; } /* Default: Display CPU and DISK reports */ if (!report_set) { flags |= I_D_CPU + I_D_DISK; } /* * Also display DISK reports if options -p, -x or a device has been entered * on the command line. */ if (DISPLAY_PARTITIONS(flags) || DISPLAY_EXTENDED(flags) || DISPLAY_UNFILTERED(flags)) { flags |= I_D_DISK; } /* Option -T can only be used with option -g */ if (DISPLAY_GROUP_TOTAL_ONLY(flags) && !group_nr) { usage(argv[0]); } /* Select disk output unit (kB/s or blocks/s) */ set_disk_output_unit(); /* Ignore device list if '-p ALL' entered on the command line */ if (DISPLAY_PART_ALL(flags)) { dlist_idx = 0; } if (DISPLAY_DEVMAP_NAME(flags)) { dm_major = get_devmap_major(); } /* Init structures according to machine architecture */ io_sys_init(); if (group_nr > 0) { /* * If groups of devices have been defined * then save devices and groups in the list. */ presave_device_list(); } get_localtime(&rectime, 0); /* Get system name, release number and hostname */ uname(&header); if (print_gal_header(&rectime, header.sysname, header.release, header.nodename, header.machine, cpu_nr)) { flags |= I_D_ISO; } printf("\n"); /* Set a handler for SIGALRM */ memset(&alrm_act, 0, sizeof(alrm_act)); alrm_act.sa_handler = alarm_handler; sigaction(SIGALRM, &alrm_act, NULL); alarm(interval); /* Main loop */ rw_io_stat_loop(count, &rectime); /* Free structures */ io_sys_free(); sfree_dev_list(); return 0; }
/* *************************************************************************** * Print everything now (stats and uptime). * * IN: * @curr Index in array for current sample statistics. * @rectime Current date and time. *************************************************************************** */ void write_stats(int curr, struct tm *rectime) { int dev, i, fctr = 1; unsigned long long itv; struct io_hdr_stats *shi; struct io_dlist *st_dev_list_i; /* Test stdout */ TEST_STDOUT(STDOUT_FILENO); /* Print time stamp */ if (DISPLAY_TIMESTAMP(flags)) { if (DISPLAY_ISO(flags)) { strftime(timestamp, sizeof(timestamp), "%FT%T%z", rectime); } else { strftime(timestamp, sizeof(timestamp), "%x %X", rectime); } printf("%s\n", timestamp); #ifdef DEBUG if (DISPLAY_DEBUG(flags)) { fprintf(stderr, "%s\n", timestamp); } #endif } /* Interval is multiplied by the number of processors */ itv = get_interval(uptime[!curr], uptime[curr]); if (DISPLAY_CPU(flags)) { #ifdef DEBUG if (DISPLAY_DEBUG(flags)) { /* Debug output */ fprintf(stderr, "itv=%llu st_cpu[curr]{ cpu_user=%llu cpu_nice=%llu " "cpu_sys=%llu cpu_idle=%llu cpu_iowait=%llu cpu_steal=%llu " "cpu_hardirq=%llu cpu_softirq=%llu cpu_guest=%llu " "cpu_guest_nice=%llu }\n", itv, st_cpu[curr]->cpu_user, st_cpu[curr]->cpu_nice, st_cpu[curr]->cpu_sys, st_cpu[curr]->cpu_idle, st_cpu[curr]->cpu_iowait, st_cpu[curr]->cpu_steal, st_cpu[curr]->cpu_hardirq, st_cpu[curr]->cpu_softirq, st_cpu[curr]->cpu_guest, st_cpu[curr]->cpu_guest_nice); } #endif /* Display CPU utilization */ write_cpu_stat(curr, itv); } if (cpu_nr > 1) { /* On SMP machines, reduce itv to one processor (see note above) */ itv = get_interval(uptime0[!curr], uptime0[curr]); } if (DISPLAY_DISK(flags)) { struct io_stats *ioi, *ioj; shi = st_hdr_iodev; /* Display disk stats header */ write_disk_stat_header(&fctr); for (i = 0; i < iodev_nr; i++, shi++) { if (shi->used) { if (dlist_idx && !HAS_SYSFS(flags)) { /* * With /proc/diskstats, stats for every device * are read even if we have entered a list on devices * on the command line. Thus we need to check * if stats for current device are to be displayed. */ for (dev = 0; dev < dlist_idx; dev++) { st_dev_list_i = st_dev_list + dev; if (!strcmp(shi->name, st_dev_list_i->dev_name)) break; } if (dev == dlist_idx) /* Device not found in list: Don't display it */ continue; } ioi = st_iodev[curr] + i; ioj = st_iodev[!curr] + i; if (!DISPLAY_UNFILTERED(flags)) { if (!ioi->rd_ios && !ioi->wr_ios) continue; } if (DISPLAY_ZERO_OMIT(flags)) { if ((ioi->rd_ios == ioj->rd_ios) && (ioi->wr_ios == ioj->wr_ios)) /* No activity: Ignore it */ continue; } if (DISPLAY_GROUP_TOTAL_ONLY(flags)) { if (shi->status != DISK_GROUP) continue; } #ifdef DEBUG if (DISPLAY_DEBUG(flags)) { /* Debug output */ fprintf(stderr, "name=%s itv=%llu fctr=%d ioi{ rd_sectors=%lu " "wr_sectors=%lu rd_ios=%lu rd_merges=%lu rd_ticks=%u " "wr_ios=%lu wr_merges=%lu wr_ticks=%u ios_pgr=%u tot_ticks=%u " "rq_ticks=%u }\n", shi->name, itv, fctr, ioi->rd_sectors, ioi->wr_sectors, ioi->rd_ios, ioi->rd_merges, ioi->rd_ticks, ioi->wr_ios, ioi->wr_merges, ioi->wr_ticks, ioi->ios_pgr, ioi->tot_ticks, ioi->rq_ticks ); } #endif if (DISPLAY_EXTENDED(flags)) { write_ext_stat(curr, itv, fctr, shi, ioi, ioj); } else { write_basic_stat(curr, itv, fctr, shi, ioi, ioj); } } } printf("\n"); } }
/* *************************************************************************** * Read stats from /proc/diskstats *************************************************************************** */ void read_diskstats_stat(int curr, int flags) { FILE *fp; char line[256], dev_name[MAX_NAME_LEN]; struct io_stats sdev; int i; unsigned long rd_ios, rd_merges_or_rd_sec, rd_ticks_or_wr_sec, wr_ios; unsigned long ios_pgr, tot_ticks, rq_ticks, wr_merges, wr_ticks; unsigned long long rd_sec_or_wr_ios, wr_sec; char *ioc_dname; unsigned int major, minor; /* Every I/O device entry is potentially unregistered */ set_entries_inactive(iodev_nr); if ((fp = fopen(DISKSTATS, "r")) == NULL) return; while (fgets(line, 256, fp) != NULL) { /* major minor name rio rmerge rsect ruse wio wmerge wsect wuse running use aveq */ i = sscanf(line, "%u %u %s %lu %lu %llu %lu %lu %lu %llu %lu %lu %lu %lu", &major, &minor, dev_name, &rd_ios, &rd_merges_or_rd_sec, &rd_sec_or_wr_ios, &rd_ticks_or_wr_sec, &wr_ios, &wr_merges, &wr_sec, &wr_ticks, &ios_pgr, &tot_ticks, &rq_ticks); if (i == 14) { /* Device */ sdev.rd_ios = rd_ios; sdev.rd_merges = rd_merges_or_rd_sec; sdev.rd_sectors = rd_sec_or_wr_ios; sdev.rd_ticks = rd_ticks_or_wr_sec; sdev.wr_ios = wr_ios; sdev.wr_merges = wr_merges; sdev.wr_sectors = wr_sec; sdev.wr_ticks = wr_ticks; sdev.ios_pgr = ios_pgr; sdev.tot_ticks = tot_ticks; sdev.rq_ticks = rq_ticks; } else if (i == 7) { /* Partition */ if (DISPLAY_EXTENDED(flags) || (!dlist_idx && !DISPLAY_PARTITIONS(flags))) continue; sdev.rd_ios = rd_ios; sdev.rd_sectors = rd_merges_or_rd_sec; sdev.wr_ios = rd_sec_or_wr_ios; sdev.wr_sectors = rd_ticks_or_wr_sec; } else /* Unknown entry: ignore it */ continue; if ((ioc_dname = ioc_name(major, minor)) != NULL) { if (strcmp(dev_name, ioc_dname) && strcmp(ioc_dname, K_NODEV)) /* * No match: Use name generated from sysstat.ioconf data (if different * from "nodev") works around known issues with EMC PowerPath. */ strcpy(dev_name, ioc_dname); } save_dev_stats(dev_name, curr, &sdev); } fclose(fp); /* Free structures corresponding to unregistered devices */ free_inactive_entries(iodev_nr); }
/* *************************************************************************** * Read stats from /proc/stat file... * Useful at least for CPU utilization. * May be useful to get disk stats if /sys not available. *************************************************************************** */ void read_proc_stat(int curr, int flags) { FILE *fp; char line[8192]; int pos, i; unsigned long v_tmp[4]; unsigned int v_major, v_index; struct io_stats *st_iodev_tmp[4]; unsigned long long cc_idle, cc_iowait, cc_steal; unsigned long long cc_user, cc_nice, cc_system, cc_hardirq, cc_softirq; /* * Prepare pointers on the 4 disk structures in case we have a * /proc/stat file with "disk_rblk", etc. entries. */ for (i = 0; i < 4; i++) st_iodev_tmp[i] = st_iodev[curr] + i; if ((fp = fopen(STAT, "r")) == NULL) { perror("fopen"); exit(2); } while (fgets(line, 8192, fp) != NULL) { if (!strncmp(line, "cpu ", 4)) { /* * Read the number of jiffies spent in the different modes, * and compute system uptime in jiffies (1/100ths of a second * if HZ=100). * Some fields are only present in 2.6 kernels. */ comm_stats[curr].cpu_iowait = 0; /* For pre 2.6 kernels */ comm_stats[curr].cpu_steal = 0; cc_hardirq = cc_softirq = 0; /* CPU counters became unsigned long long with kernel 2.6.5 */ sscanf(line + 5, "%llu %llu %llu %llu %llu %llu %llu %llu", &(comm_stats[curr].cpu_user), &(comm_stats[curr].cpu_nice), &(comm_stats[curr].cpu_system), &(comm_stats[curr].cpu_idle), &(comm_stats[curr].cpu_iowait), &cc_hardirq, &cc_softirq, &(comm_stats[curr].cpu_steal)); /* * Time spent in system mode also includes time spent servicing * hard interrupts and softirqs. */ comm_stats[curr].cpu_system += cc_hardirq + cc_softirq; /* * Compute system uptime in jiffies. * Uptime is multiplied by the number of processors. */ comm_stats[curr].uptime = comm_stats[curr].cpu_user + comm_stats[curr].cpu_nice + comm_stats[curr].cpu_system + comm_stats[curr].cpu_idle + comm_stats[curr].cpu_iowait + comm_stats[curr].cpu_steal; } else if ((!strncmp(line, "cpu0", 4)) && (cpu_nr > 1)) { /* * Read CPU line for proc#0 (if available). * This is necessary to compute time interval since * processors may be disabled (offline) sometimes. * (Assume that proc#0 can never be offline). */ cc_iowait = cc_hardirq = cc_softirq = cc_steal = 0; sscanf(line + 5, "%llu %llu %llu %llu %llu %llu %llu %llu", &cc_user, &cc_nice, &cc_system, &cc_idle, &cc_iowait, &cc_hardirq, &cc_softirq, &cc_steal); comm_stats[curr].uptime0 = cc_user + cc_nice + cc_system + cc_idle + cc_iowait + cc_hardirq + cc_softirq + cc_steal; } else if (DISPLAY_EXTENDED(flags) || HAS_DISKSTATS(flags) || HAS_PPARTITIONS(flags) || HAS_SYSFS(flags)) /* * When displaying extended statistics, or if /proc/diskstats or * /proc/partitions exists, or /sys is mounted, * we just need to get CPU info from /proc/stat. */ continue; else if (!strncmp(line, "disk_rblk ", 10)) { /* * Read the number of blocks read from disk. * A block is of indeterminate size. * The size may vary depending on the device type. */ sscanf(line + 10, "%lu %lu %lu %lu", &v_tmp[0], &v_tmp[1], &v_tmp[2], &v_tmp[3]); st_iodev_tmp[0]->dk_drive_rblk = v_tmp[0]; st_iodev_tmp[1]->dk_drive_rblk = v_tmp[1]; st_iodev_tmp[2]->dk_drive_rblk = v_tmp[2]; st_iodev_tmp[3]->dk_drive_rblk = v_tmp[3]; } else if (!strncmp(line, "disk_wblk ", 10)) { /* Read the number of blocks written to disk */ sscanf(line + 10, "%lu %lu %lu %lu", &v_tmp[0], &v_tmp[1], &v_tmp[2], &v_tmp[3]); st_iodev_tmp[0]->dk_drive_wblk = v_tmp[0]; st_iodev_tmp[1]->dk_drive_wblk = v_tmp[1]; st_iodev_tmp[2]->dk_drive_wblk = v_tmp[2]; st_iodev_tmp[3]->dk_drive_wblk = v_tmp[3]; } else if (!strncmp(line, "disk ", 5)) { /* Read the number of I/O done since the last reboot */ sscanf(line + 5, "%lu %lu %lu %lu", &v_tmp[0], &v_tmp[1], &v_tmp[2], &v_tmp[3]); st_iodev_tmp[0]->dk_drive = v_tmp[0]; st_iodev_tmp[1]->dk_drive = v_tmp[1]; st_iodev_tmp[2]->dk_drive = v_tmp[2]; st_iodev_tmp[3]->dk_drive = v_tmp[3]; } else if (!strncmp(line, "disk_io: ", 9)) { struct io_stats sdev; char dev_name[MAX_NAME_LEN]; pos = 9; /* Every disk_io entry is potentially unregistered */ set_entries_inactive(iodev_nr); /* Read disks I/O statistics (for 2.4 kernels) */ while (pos < strlen(line) - 1) { /* Beware: a CR is already included in the line */ sscanf(line + pos, "(%u,%u):(%lu,%*u,%lu,%*u,%lu) ", &v_major, &v_index, &v_tmp[0], &v_tmp[1], &v_tmp[2]); sprintf(dev_name, "dev%d-%d", v_major, v_index); sdev.dk_drive = v_tmp[0]; sdev.dk_drive_rblk = v_tmp[1]; sdev.dk_drive_wblk = v_tmp[2]; save_dev_stats(dev_name, curr, &sdev); pos += strcspn(line + pos, " ") + 1; } /* Free structures corresponding to unregistered disks */ free_inactive_entries(iodev_nr); } } fclose(fp); }