]> granicus.if.org Git - sysstat/blobdiff - rd_stats.c
sar/sadc: Add stable identifier support for disks statistics
[sysstat] / rd_stats.c
index 89350c3de43be4a86195129c5d6d9d1428ba5cd1..2569fae28e8c91f9d8fd71e820e4bed36c4ffdc8 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * rd_stats.c: Read system statistics
- * (C) 1999-2017 by Sebastien GODARD (sysstat <at> orange.fr)
+ * (C) 1999-2019 by Sebastien GODARD (sysstat <at> orange.fr)
  *
  ***************************************************************************
  * This program is free software; you can redistribute it and/or modify it *
@@ -32,7 +32,6 @@
 
 #include "common.h"
 #include "rd_stats.h"
-#include "ioconf.h"
 
 #ifdef USE_NLS
 #include <locale.h>
@@ -208,7 +207,7 @@ __nr_t read_stat_irq(struct stats_irq *st_irq, __nr_t nr_alloc)
                                i = strcspn(line + pos + 1, " ");
                                pos += i + 1;
                        }
-                       while ((i > 0) && (pos < sizeof(line)));
+                       while ((i > 0) && (pos < (sizeof(line) - 1)));
 
                        break;
                }
@@ -244,71 +243,71 @@ __nr_t read_meminfo(struct stats_memory *st_memory)
 
                if (!strncmp(line, "MemTotal:", 9)) {
                        /* Read the total amount of memory in kB */
-                       sscanf(line + 9, "%lu", &st_memory->tlmkb);
+                       sscanf(line + 9, "%llu", &st_memory->tlmkb);
                }
                else if (!strncmp(line, "MemFree:", 8)) {
                        /* Read the amount of free memory in kB */
-                       sscanf(line + 8, "%lu", &st_memory->frmkb);
+                       sscanf(line + 8, "%llu", &st_memory->frmkb);
                }
                else if (!strncmp(line, "MemAvailable:", 13)) {
                        /* Read the amount of available memory in kB */
-                       sscanf(line + 13, "%lu", &st_memory->availablekb);
+                       sscanf(line + 13, "%llu", &st_memory->availablekb);
                }
                else if (!strncmp(line, "Buffers:", 8)) {
                        /* Read the amount of buffered memory in kB */
-                       sscanf(line + 8, "%lu", &st_memory->bufkb);
+                       sscanf(line + 8, "%llu", &st_memory->bufkb);
                }
                else if (!strncmp(line, "Cached:", 7)) {
                        /* Read the amount of cached memory in kB */
-                       sscanf(line + 7, "%lu", &st_memory->camkb);
+                       sscanf(line + 7, "%llu", &st_memory->camkb);
                }
                else if (!strncmp(line, "SwapCached:", 11)) {
                        /* Read the amount of cached swap in kB */
-                       sscanf(line + 11, "%lu", &st_memory->caskb);
+                       sscanf(line + 11, "%llu", &st_memory->caskb);
                }
                else if (!strncmp(line, "Active:", 7)) {
                        /* Read the amount of active memory in kB */
-                       sscanf(line + 7, "%lu", &st_memory->activekb);
+                       sscanf(line + 7, "%llu", &st_memory->activekb);
                }
                else if (!strncmp(line, "Inactive:", 9)) {
                        /* Read the amount of inactive memory in kB */
-                       sscanf(line + 9, "%lu", &st_memory->inactkb);
+                       sscanf(line + 9, "%llu", &st_memory->inactkb);
                }
                else if (!strncmp(line, "SwapTotal:", 10)) {
                        /* Read the total amount of swap memory in kB */
-                       sscanf(line + 10, "%lu", &st_memory->tlskb);
+                       sscanf(line + 10, "%llu", &st_memory->tlskb);
                }
                else if (!strncmp(line, "SwapFree:", 9)) {
                        /* Read the amount of free swap memory in kB */
-                       sscanf(line + 9, "%lu", &st_memory->frskb);
+                       sscanf(line + 9, "%llu", &st_memory->frskb);
                }
                else if (!strncmp(line, "Dirty:", 6)) {
                        /* Read the amount of dirty memory in kB */
-                       sscanf(line + 6, "%lu", &st_memory->dirtykb);
+                       sscanf(line + 6, "%llu", &st_memory->dirtykb);
                }
                else if (!strncmp(line, "Committed_AS:", 13)) {
                        /* Read the amount of commited memory in kB */
-                       sscanf(line + 13, "%lu", &st_memory->comkb);
+                       sscanf(line + 13, "%llu", &st_memory->comkb);
                }
                else if (!strncmp(line, "AnonPages:", 10)) {
                        /* Read the amount of pages mapped into userspace page tables in kB */
-                       sscanf(line + 10, "%lu", &st_memory->anonpgkb);
+                       sscanf(line + 10, "%llu", &st_memory->anonpgkb);
                }
                else if (!strncmp(line, "Slab:", 5)) {
                        /* Read the amount of in-kernel data structures cache in kB */
-                       sscanf(line + 5, "%lu", &st_memory->slabkb);
+                       sscanf(line + 5, "%llu", &st_memory->slabkb);
                }
                else if (!strncmp(line, "KernelStack:", 12)) {
                        /* Read the kernel stack utilization in kB */
-                       sscanf(line + 12, "%lu", &st_memory->kstackkb);
+                       sscanf(line + 12, "%llu", &st_memory->kstackkb);
                }
                else if (!strncmp(line, "PageTables:", 11)) {
                        /* Read the amount of memory dedicated to the lowest level of page tables in kB */
-                       sscanf(line + 11, "%lu", &st_memory->pgtblkb);
+                       sscanf(line + 11, "%llu", &st_memory->pgtblkb);
                }
                else if (!strncmp(line, "VmallocUsed:", 12)) {
                        /* Read the amount of vmalloc area which is used in kB */
-                       sscanf(line + 12, "%lu", &st_memory->vmusedkb);
+                       sscanf(line + 12, "%llu", &st_memory->vmusedkb);
                }
        }
 
@@ -354,6 +353,106 @@ void read_uptime(unsigned long long *uptime)
        }
 }
 
+/*
+ ***************************************************************************
+ * Compute "extended" device statistics (service time, etc.).
+ *
+ * IN:
+ * @sdc                Structure with current device statistics.
+ * @sdp                Structure with previous device statistics.
+ * @itv                Interval of time in 1/100th of a second.
+ *
+ * OUT:
+ * @xds                Structure with extended statistics.
+ ***************************************************************************
+*/
+void compute_ext_disk_stats(struct stats_disk *sdc, struct stats_disk *sdp,
+                           unsigned long long itv, struct ext_disk_stats *xds)
+{
+       xds->util  = S_VALUE(sdp->tot_ticks, sdc->tot_ticks, itv);
+       /*
+        * Kernel gives ticks already in milliseconds for all platforms
+        * => no need for further scaling.
+        */
+       xds->await = (sdc->nr_ios - sdp->nr_ios) ?
+               ((sdc->rd_ticks - sdp->rd_ticks) + (sdc->wr_ticks - sdp->wr_ticks) + (sdc->dc_ticks - sdp->dc_ticks)) /
+               ((double) (sdc->nr_ios - sdp->nr_ios)) : 0.0;
+       xds->arqsz = (sdc->nr_ios - sdp->nr_ios) ?
+               ((sdc->rd_sect - sdp->rd_sect) + (sdc->wr_sect - sdp->wr_sect) + (sdc->dc_sect - sdp->dc_sect)) /
+               ((double) (sdc->nr_ios - sdp->nr_ios)) : 0.0;
+}
+
+/*
+ ***************************************************************************
+ * Since ticks may vary slightly from CPU to CPU, we'll want
+ * to recalculate itv based on this CPU's tick count, rather
+ * than that reported by the "cpu" line. Otherwise we
+ * occasionally end up with slightly skewed figures, with
+ * the skew being greater as the time interval grows shorter.
+ *
+ * IN:
+ * @scc        Current sample statistics for current CPU.
+ * @scp        Previous sample statistics for current CPU.
+ *
+ * RETURNS:
+ * Interval of time based on current CPU, expressed in jiffies.
+ ***************************************************************************
+ */
+unsigned long long get_per_cpu_interval(struct stats_cpu *scc,
+                                       struct stats_cpu *scp)
+{
+       unsigned long long ishift = 0LL;
+
+       if ((scc->cpu_user - scc->cpu_guest) < (scp->cpu_user - scp->cpu_guest)) {
+               /*
+                * Sometimes the nr of jiffies spent in guest mode given by the guest
+                * counter in /proc/stat is slightly higher than that included in
+                * the user counter. Update the interval value accordingly.
+                */
+               ishift += (scp->cpu_user - scp->cpu_guest) -
+                         (scc->cpu_user - scc->cpu_guest);
+       }
+       if ((scc->cpu_nice - scc->cpu_guest_nice) < (scp->cpu_nice - scp->cpu_guest_nice)) {
+               /*
+                * Idem for nr of jiffies spent in guest_nice mode.
+                */
+               ishift += (scp->cpu_nice - scp->cpu_guest_nice) -
+                         (scc->cpu_nice - scc->cpu_guest_nice);
+       }
+
+       /*
+        * Workaround for CPU coming back online: With recent kernels
+        * some fields (user, nice, system) restart from their previous value,
+        * whereas others (idle, iowait) restart from zero.
+        * For the latter we need to set their previous value to zero to
+        * avoid getting an interval value < 0.
+        * (I don't know how the other fields like hardirq, steal... behave).
+        * Don't assume the CPU has come back from offline state if previous
+        * value was greater than ULLONG_MAX - 0x7ffff (the counter probably
+        * overflew).
+        */
+       if ((scc->cpu_idle < scp->cpu_idle) && (scp->cpu_idle < (ULLONG_MAX - 0x7ffff))) {
+               scp->cpu_idle = 0;
+       }
+       if ((scc->cpu_iowait < scp->cpu_iowait) && (scp->cpu_iowait < (ULLONG_MAX - 0x7ffff))) {
+               scp->cpu_iowait = 0;
+       }
+
+       /*
+        * Don't take cpu_guest and cpu_guest_nice into account
+        * because cpu_user and cpu_nice already include them.
+        */
+       return ((scc->cpu_user    + scc->cpu_nice   +
+                scc->cpu_sys     + scc->cpu_iowait +
+                scc->cpu_idle    + scc->cpu_steal  +
+                scc->cpu_hardirq + scc->cpu_softirq) -
+               (scp->cpu_user    + scp->cpu_nice   +
+                scp->cpu_sys     + scp->cpu_iowait +
+                scp->cpu_idle    + scp->cpu_steal  +
+                scp->cpu_hardirq + scp->cpu_softirq) +
+                ishift);
+}
+
 #ifdef SOURCE_SADC
 /*---------------- BEGIN: FUNCTIONS USED BY SADC ONLY ---------------------*/
 
@@ -451,14 +550,14 @@ __nr_t read_loadavg(struct stats_queue *st_queue)
 {
        FILE *fp;
        char line[8192];
-       int load_tmp[3];
+       unsigned int load_tmp[3];
        int rc;
 
        if ((fp = fopen(LOADAVG, "r")) == NULL)
                return 0;
 
        /* Read load averages and queue length */
-       rc = fscanf(fp, "%d.%u %d.%u %d.%u %lu/%u %*d\n",
+       rc = fscanf(fp, "%u.%u %u.%u %u.%u %llu/%llu %*d\n",
                    &load_tmp[0], &st_queue->load_avg_1,
                    &load_tmp[1], &st_queue->load_avg_5,
                    &load_tmp[2], &st_queue->load_avg_15,
@@ -487,7 +586,7 @@ __nr_t read_loadavg(struct stats_queue *st_queue)
 
                if (!strncmp(line, "procs_blocked ", 14)) {
                        /* Read number of processes blocked */
-                       sscanf(line + 14, "%lu", &st_queue->procs_blocked);
+                       sscanf(line + 14, "%llu", &st_queue->procs_blocked);
                        break;
                }
        }
@@ -623,27 +722,42 @@ __nr_t read_diskstats_io(struct stats_io *st_io)
        char line[1024];
        char dev_name[MAX_NAME_LEN];
        unsigned int major, minor;
-       unsigned long rd_ios, wr_ios, rd_sec, wr_sec;
+       unsigned long rd_ios, wr_ios, dc_ios;
+       unsigned long rd_sec, wr_sec, dc_sec;
 
        if ((fp = fopen(DISKSTATS, "r")) == NULL)
                return 0;
 
        while (fgets(line, sizeof(line), fp) != NULL) {
 
-               if (sscanf(line, "%u %u %s %lu %*u %lu %*u %lu %*u %lu",
+               /* Discard I/O stats may be not available */
+               dc_ios = dc_sec = 0;
+
+               if (sscanf(line,
+                          "%u %u %s "
+                          "%lu %*u %lu %*u "
+                          "%lu %*u %lu %*u "
+                          "%*u %*u %*u "
+                          "%lu %*u %lu",
                           &major, &minor, dev_name,
-                          &rd_ios, &rd_sec, &wr_ios, &wr_sec) == 7) {
+                          &rd_ios, &rd_sec,
+                          &wr_ios, &wr_sec,
+                          &dc_ios, &dc_sec) >= 7) {
 
                        if (is_device(dev_name, IGNORE_VIRTUAL_DEVICES)) {
                                /*
                                 * OK: It's a (real) device and not a partition.
                                 * Note: Structure should have been initialized first!
                                 */
-                               st_io->dk_drive      += (unsigned long long) rd_ios + (unsigned long long) wr_ios;
+                               st_io->dk_drive      += (unsigned long long) rd_ios +
+                                                       (unsigned long long) wr_ios +
+                                                       (unsigned long long) dc_ios;
                                st_io->dk_drive_rio  += rd_ios;
                                st_io->dk_drive_rblk += rd_sec;
                                st_io->dk_drive_wio  += wr_ios;
                                st_io->dk_drive_wblk += wr_sec;
+                               st_io->dk_drive_dio  += dc_ios;
+                               st_io->dk_drive_dblk += dc_sec;
                        }
                }
        }
@@ -677,8 +791,9 @@ __nr_t read_diskstats_disk(struct stats_disk *st_disk, __nr_t nr_alloc,
        char line[1024];
        char dev_name[MAX_NAME_LEN];
        struct stats_disk *st_disk_i;
-       unsigned int major, minor, rd_ticks, wr_ticks, tot_ticks, rq_ticks;
-       unsigned long rd_ios, wr_ios, rd_sec, wr_sec;
+       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)
@@ -686,13 +801,22 @@ __nr_t read_diskstats_disk(struct stats_disk *st_disk, __nr_t nr_alloc,
 
        while (fgets(line, sizeof(line), fp) != NULL) {
 
-               if (sscanf(line, "%u %u %s %lu %*u %lu %u %lu %*u %lu"
-                          " %u %*u %u %u",
+               /* Discard I/O stats may be not available */
+               dc_ios = dc_sec = dc_ticks = 0;
+
+               if (sscanf(line,
+                          "%u %u %s "
+                          "%lu %*u %lu %u "
+                          "%lu %*u %lu %u "
+                          "%*u %u %u "
+                          "%lu %*u %lu %u",
                           &major, &minor, dev_name,
-                          &rd_ios, &rd_sec, &rd_ticks, &wr_ios, &wr_sec, &wr_ticks,
-                          &tot_ticks, &rq_ticks) == 11) {
+                          &rd_ios, &rd_sec, &rd_ticks,
+                          &wr_ios, &wr_sec, &wr_ticks,
+                          &tot_ticks, &rq_ticks,
+                          &dc_ios, &dc_sec, &dc_ticks) >= 11) {
 
-                       if (!rd_ios && !wr_ios)
+                       if (!rd_ios && !wr_ios && !dc_ios)
                                /* Unused device: Ignore it */
                                continue;
                        if (read_part || is_device(dev_name, ACCEPT_VIRTUAL_DEVICES)) {
@@ -705,13 +829,26 @@ __nr_t read_diskstats_disk(struct stats_disk *st_disk, __nr_t nr_alloc,
                                st_disk_i = st_disk + dsk_read++;
                                st_disk_i->major     = major;
                                st_disk_i->minor     = minor;
-                               st_disk_i->nr_ios    = (unsigned long long) rd_ios + (unsigned long long) wr_ios;
+                               st_disk_i->nr_ios    = (unsigned long long) rd_ios +
+                                                      (unsigned long long) wr_ios +
+                                                      (unsigned long long) dc_ios;
                                st_disk_i->rd_sect   = rd_sec;
                                st_disk_i->wr_sect   = wr_sec;
+                               st_disk_i->dc_sect   = dc_sec;
                                st_disk_i->rd_ticks  = rd_ticks;
                                st_disk_i->wr_ticks  = wr_ticks;
+                               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;
+                               }
                        }
                }
        }
@@ -803,12 +940,12 @@ __nr_t read_tty_driver_serial(struct stats_serial *st_serial, __nr_t nr_alloc)
 __nr_t read_kernel_tables(struct stats_ktables *st_ktables)
 {
        FILE *fp;
-       unsigned int parm;
+       unsigned long long parm;
        int rc = 0;
 
        /* Open /proc/sys/fs/dentry-state file */
        if ((fp = fopen(FDENTRY_STATE, "r")) != NULL) {
-               rc = fscanf(fp, "%*d %u",
+               rc = fscanf(fp, "%*d %llu",
                            &st_ktables->dentry_stat);
                fclose(fp);
                if (rc == 0) {
@@ -818,7 +955,7 @@ __nr_t read_kernel_tables(struct stats_ktables *st_ktables)
 
        /* Open /proc/sys/fs/file-nr file */
        if ((fp = fopen(FFILE_NR, "r")) != NULL) {
-               rc = fscanf(fp, "%u %u",
+               rc = fscanf(fp, "%llu %llu",
                            &st_ktables->file_used, &parm);
                fclose(fp);
                /*
@@ -835,7 +972,7 @@ __nr_t read_kernel_tables(struct stats_ktables *st_ktables)
 
        /* Open /proc/sys/fs/inode-state file */
        if ((fp = fopen(FINODE_STATE, "r")) != NULL) {
-               rc = fscanf(fp, "%u %u",
+               rc = fscanf(fp, "%llu %llu",
                            &st_ktables->inode_used, &parm);
                fclose(fp);
                /*
@@ -852,7 +989,7 @@ __nr_t read_kernel_tables(struct stats_ktables *st_ktables)
 
        /* Open /proc/sys/kernel/pty/nr file */
        if ((fp = fopen(PTY_NR, "r")) != NULL) {
-               rc = fscanf(fp, "%u",
+               rc = fscanf(fp, "%llu",
                            &st_ktables->pty_nr);
                fclose(fp);
                if (rc == 0) {
@@ -1418,6 +1555,7 @@ __nr_t read_net_eicmp(struct stats_net_eicmp *st_net_eicmp)
 {
        FILE *fp;
        char line[1024];
+       static char format[256] = "";
        int sw = FALSE;
 
        if ((fp = fopen(NET_SNMP, "r")) == NULL)
@@ -1427,8 +1565,7 @@ __nr_t read_net_eicmp(struct stats_net_eicmp *st_net_eicmp)
 
                if (!strncmp(line, "Icmp:", 5)) {
                        if (sw) {
-                               sscanf(line + 5, "%*u %lu %lu %lu %lu %lu %lu %*u %*u "
-                                      "%*u %*u %*u %*u %*u %lu %lu %lu %lu %lu %lu",
+                               sscanf(line + 5, format,
                                       &st_net_eicmp->InErrors,
                                       &st_net_eicmp->InDestUnreachs,
                                       &st_net_eicmp->InTimeExcds,
@@ -1445,6 +1582,25 @@ __nr_t read_net_eicmp(struct stats_net_eicmp *st_net_eicmp)
                                break;
                        }
                        else {
+                               if (!strlen(format)) {
+                                       if (strstr(line, "InCsumErrors")) {
+                                               /*
+                                                * New format: InCsumErrors field exists at position #3.
+                                                * Capture: 2,4,5,6,7,8,16,17,18,19,20,21
+                                                */
+                                               strcpy(format, "%*u %lu %*u %lu %lu %lu %lu %lu %*u %*u "
+                                                              "%*u %*u %*u %*u %*u %lu %lu %lu %lu %lu %lu");
+                                       }
+                                       else {
+                                               /*
+                                                * Old format: InCsumErrors field doesn't exist.
+                                                * Capture: 2,3,4,5,6,7,15,16,17,18,19,20
+                                                */
+                                               strcpy(format, "%*u %lu %lu %lu %lu %lu %lu %*u %*u "
+                                                              "%*u %*u %*u %*u %*u %lu %lu %lu %lu %lu %lu");
+
+                                       }
+                               }
                                sw = TRUE;
                        }
                }
@@ -2044,11 +2200,19 @@ __nr_t read_meminfo_huge(struct stats_huge *st_huge)
 
                if (!strncmp(line, "HugePages_Total:", 16)) {
                        /* Read the total number of huge pages */
-                       sscanf(line + 16, "%lu", &st_huge->tlhkb);
+                       sscanf(line + 16, "%llu", &st_huge->tlhkb);
                }
                else if (!strncmp(line, "HugePages_Free:", 15)) {
                        /* Read the number of free huge pages */
-                       sscanf(line + 15, "%lu", &st_huge->frhkb);
+                       sscanf(line + 15, "%llu", &st_huge->frhkb);
+               }
+               else if (!strncmp(line, "HugePages_Rsvd:", 15)) {
+                       /* Read the number of reserved huge pages */
+                       sscanf(line + 15, "%llu", &st_huge->rsvdhkb);
+               }
+               else if (!strncmp(line, "HugePages_Surp:", 15)) {
+                       /* Read the number of surplus huge pages */
+                       sscanf(line + 15, "%llu", &st_huge->surphkb);
                }
                else if (!strncmp(line, "Hugepagesize:", 13)) {
                        /* Read the default size of a huge page in kB */
@@ -2061,6 +2225,9 @@ __nr_t read_meminfo_huge(struct stats_huge *st_huge)
        /* We want huge pages stats in kB and not expressed in a number of pages */
        st_huge->tlhkb *= szhkb;
        st_huge->frhkb *= szhkb;
+       st_huge->rsvdhkb *= szhkb;
+       st_huge->surphkb *= szhkb;
+
        return 1;
 }
 
@@ -2326,9 +2493,9 @@ __nr_t read_bus_usb_dev(struct stats_pwr_usb *st_pwr_usb, __nr_t nr_alloc)
 __nr_t read_filesystem(struct stats_filesystem *st_filesystem, __nr_t nr_alloc)
 {
        FILE *fp;
-       char line[512], fs_name[128], mountp[256];
+       char line[512], fs_name[MAX_FS_LEN], mountp[256], type[128];
        int skip = 0, skip_next = 0;
-       char *pos = 0;
+       char *pos = 0, *pos2 = 0;
        __nr_t fs_read = 0;
        struct stats_filesystem *st_filesystem_i;
        struct statvfs buf;
@@ -2353,6 +2520,19 @@ __nr_t read_filesystem(struct stats_filesystem *st_filesystem, __nr_t nr_alloc)
                        if (pos == NULL)
                                continue;
 
+                       /*
+                        * Find second field separator position,
+                        * read filesystem type,
+                        * if filesystem type is autofs, skip it
+                       */
+                       pos2 = strchr(pos + 1, ' ');
+                       if (pos2 == NULL)
+                               continue;
+
+                       sscanf(pos2 + 1, "%127s", type);
+                       if(strcmp(type, "autofs") == 0)
+                               continue;
+
                        /* Read current filesystem name */
                        sscanf(line, "%127s", fs_name);
                        /*
@@ -2373,7 +2553,7 @@ __nr_t read_filesystem(struct stats_filesystem *st_filesystem, __nr_t nr_alloc)
                         * It's important to have read the whole mount point name
                         * for statvfs() to work properly (see above).
                         */
-                       if ((statvfs(mountp, &buf) < 0) || (!buf.f_blocks))
+                       if ((__statvfs(mountp, &buf) < 0) || (!buf.f_blocks))
                                continue;
 
                        if (fs_read + 1 > nr_alloc) {
@@ -2426,14 +2606,14 @@ __nr_t read_fchost(struct stats_fchost *st_fc, __nr_t nr_alloc)
        unsigned long rx_frames, tx_frames, rx_words, tx_words;
 
        /* Each host, if present, will have its own hostX entry within SYSFS_FCHOST */
-       if ((dir = opendir(SYSFS_FCHOST)) == NULL)
+       if ((dir = __opendir(SYSFS_FCHOST)) == NULL)
                return 0; /* No FC hosts */
 
        /*
         * Read each of the counters via sysfs, where they are
         * returned as hex values (e.g. 0x72400).
         */
-       while ((drd = readdir(dir)) != NULL) {
+       while ((drd = __readdir(dir)) != NULL) {
                rx_frames = tx_frames = rx_words = tx_words = 0;
 
                if (!strncmp(drd->d_name, "host", 4)) {
@@ -2484,12 +2664,12 @@ __nr_t read_fchost(struct stats_fchost *st_fc, __nr_t nr_alloc)
                        st_fc_i->f_txframes = tx_frames;
                        st_fc_i->f_rxwords  = rx_words;
                        st_fc_i->f_txwords  = tx_words;
-                       strncpy(st_fc_i->fchost_name, drd->d_name, MAX_FCH_LEN);
+                       memcpy(st_fc_i->fchost_name, drd->d_name, MAX_FCH_LEN);
                        st_fc_i->fchost_name[MAX_FCH_LEN - 1] = '\0';
                }
        }
 
-       closedir(dir);
+       __closedir(dir);
        return fch_read;
 }
 
@@ -2500,58 +2680,47 @@ __nr_t read_fchost(struct stats_fchost *st_fc, __nr_t nr_alloc)
  * IN:
  * @st_softnet Structure where stats will be saved.
  * @nr_alloc   Total number of structures allocated. Value is >= 0.
+ * @online_cpu_bitmap
+ *             Bitmap listing online CPU.
  *
  * OUT:
  * @st_softnet Structure with statistics.
  *
  * RETURNS:
- * Number of CPU for which statistics have been read.
- * 1 means CPU "all", 2 means CPU 0, 3 means CPU 1, etc.
- * Or -1 if the buffer was too small and needs to be reallocated.
+ * 1 if stats have been sucessfully read, or 0 otherwise.
  ***************************************************************************
  */
-__nr_t read_softnet(struct stats_softnet *st_softnet, __nr_t nr_alloc)
+int read_softnet(struct stats_softnet *st_softnet, __nr_t nr_alloc,
+                 unsigned char online_cpu_bitmap[])
 {
        FILE *fp;
        struct stats_softnet *st_softnet_i;
        char line[1024];
-       __nr_t cpu_read = 1;    /* For CPU "all" */
+       int cpu;
 
        /* Open /proc/net/softnet_stat file */
        if ((fp = fopen(NET_SOFTNET, "r")) == NULL)
                return 0;
 
-       /*
-        * Init a structure that will contain the values for CPU "all".
-        * CPU "all" doesn't exist in /proc/net/softnet_stat file, so
-        * we compute its values as the sum of the values of each CPU.
-        */
-       memset(st_softnet, 0, sizeof(struct stats_softnet));
-
-       while (fgets(line, sizeof(line), fp) != NULL) {
+       for (cpu = 1; cpu < nr_alloc; cpu++) {
+               if (!(online_cpu_bitmap[(cpu - 1) >> 3] & (1 << ((cpu - 1) & 0x07))))
+                       /* CPU is offline */
+                       continue;
 
-               if (cpu_read + 1 > nr_alloc) {
-                       cpu_read = -1;
+               if (fgets(line, sizeof(line), fp) == NULL)
                        break;
-               }
 
-               st_softnet_i = st_softnet + cpu_read++;
+               st_softnet_i = st_softnet + cpu;
                sscanf(line, "%x %x %x %*x %*x %*x %*x %*x %*x %x %x",
                       &st_softnet_i->processed,
                       &st_softnet_i->dropped,
                       &st_softnet_i->time_squeeze,
                       &st_softnet_i->received_rps,
                       &st_softnet_i->flow_limit);
-
-               st_softnet->processed += st_softnet_i->processed;
-               st_softnet->dropped += st_softnet_i->dropped;
-               st_softnet->time_squeeze += st_softnet_i->time_squeeze;
-               st_softnet->received_rps += st_softnet_i->received_rps;
-               st_softnet->flow_limit += st_softnet_i->flow_limit;
        }
 
        fclose(fp);
-       return cpu_read;
+       return 1;
 }
 
 /*------------------ END: FUNCTIONS USED BY SADC ONLY ---------------------*/