Integrate FreeBSD diskio support.
authorNikos Ntarmos <ntarmos@cs.uoi.gr>
Thu, 14 May 2009 22:52:18 +0000 (01:52 +0300)
committerBrenden Matthews <brenden@rty.ca>
Sun, 24 May 2009 03:08:32 +0000 (21:08 -0600)
This diff moves Linux-specific parts of diskio.c into linux.c and uses
the remaining diskio functions to correctly implement this functionality
for FreeBSD. It also hooks diskio.c to the FreeBSD build.

Signed-off-by: Brenden Matthews <brenden@rty.ca>

src/Makefile.am
src/diskio.c
src/diskio.h
src/freebsd.c
src/linux.c

index 794b351..53bcfd5 100644 (file)
@@ -77,7 +77,7 @@ endif
 #endif
 
 if BUILD_FREEBSD
-freebsd = freebsd.c
+freebsd = freebsd.c diskio.c
 PTHREAD_LIBS =  -pthread
 endif
 
index 6a53a07..ce4b22b 100644 (file)
 #include "common.h"
 #include <stdlib.h>
 #include <limits.h>
-/* The following ifdefs were adapted from gkrellm */
-#include <linux/major.h>
-
-#if !defined(MD_MAJOR)
-#define MD_MAJOR 9
-#endif
-
-#if !defined(LVM_BLK_MAJOR)
-#define LVM_BLK_MAJOR 58
-#endif
-
-#if !defined(NBD_MAJOR)
-#define NBD_MAJOR 43
-#endif
+#include <sys/stat.h>
 
 /* this is the root of all per disk stats,
  * also containing the totals. */
-static struct diskio_stat stats = {
+struct diskio_stat stats = {
        .next = NULL,
        .sample = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
        .sample_read = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
@@ -75,30 +62,48 @@ void clear_diskio_stats(void)
 
 struct diskio_stat *prepare_diskio_stat(const char *s)
 {
+       struct stat sb;
+       char stat_name[text_buffer_size], device_name[text_buffer_size];
        struct diskio_stat *cur = &stats;
 
        if (!s)
                return &stats;
 
+#if defined(__FreeBSD__)
+       if (strncmp(s, "/dev/", 5) == 0) {
+               // supplied a /dev/device arg, so cut off the /dev part
+               strncpy(device_name, s + 5, text_buffer_size);
+       } else
+#endif
+       strncpy(device_name, s, text_buffer_size);
+
+       snprintf(stat_name, text_buffer_size, "/dev/%s", device_name);
+
+       if (stat(stat_name, &sb)) {
+               ERR("diskio device '%s' does not exist", s);
+               return 0;
+       }
+
        /* lookup existing */
        while (cur->next) {
                cur = cur->next;
-               if (!strcmp(cur->dev, s))
+               if (!strcmp(cur->dev, device_name)) {
                        return cur;
+               }
        }
 
        /* no existing found, make a new one */
-       cur->next = malloc(sizeof(struct diskio_stat));
+       cur->next = calloc(1, sizeof(struct diskio_stat));
        cur = cur->next;
-       memset(cur, 0, sizeof(struct diskio_stat));
-       cur->dev = strndup(s, text_buffer_size);
+       cur->dev = strndup(device_name, text_buffer_size);
        cur->last = UINT_MAX;
        cur->last_read = UINT_MAX;
        cur->last_write = UINT_MAX;
+
        return cur;
 }
 
-static void update_diskio_values(struct diskio_stat *ds,
+void update_diskio_values(struct diskio_stat *ds,
                unsigned int reads, unsigned int writes)
 {
        int i;
@@ -140,54 +145,3 @@ static void update_diskio_values(struct diskio_stat *ds,
        ds->last = ds->last_read + ds->last_write;
 }
 
-void update_diskio(void)
-{
-       FILE *fp;
-       static int rep = 0;
-
-       struct diskio_stat *cur;
-       char buf[512], devbuf[64];
-       unsigned int major, minor;
-       unsigned int reads, writes;
-       unsigned int total_reads=0, total_writes=0;
-       int col_count = 0;
-
-       stats.current = 0;
-       stats.current_read = 0;
-       stats.current_write = 0;
-
-       if (!(fp = open_file("/proc/diskstats", &rep))) {
-               return;
-       }
-
-       /* read reads and writes from all disks (minor = 0), including cd-roms
-        * and floppies, and sum them up */
-       while (fgets(buf, 512, fp)) {
-               col_count = sscanf(buf, "%u %u %s %*u %*u %u %*u %*u %*u %u", &major,
-                       &minor, devbuf, &reads, &writes);
-               /* ignore subdevices (they have only 3 matching entries in their line)
-                * and virtual devices (LVM, network block devices, RAM disks, Loopback)
-                *
-                * XXX: ignore devices which are part of a SW RAID (MD_MAJOR) */
-               if (col_count == 5 && major != LVM_BLK_MAJOR && major != NBD_MAJOR
-                               && major != RAMDISK_MAJOR && major != LOOP_MAJOR && minor==0) {
-                       total_reads += reads;
-                       total_writes += writes;
-               } else {
-                       col_count = sscanf(buf, "%u %u %s %*u %u %*u %u",
-                               &major, &minor, devbuf, &reads, &writes);
-                       if (col_count != 5) {
-                               continue;
-                       }
-               }
-               cur = stats.next;
-               while (cur && strcmp(devbuf, cur->dev))
-                       cur = cur->next;
-
-               if (cur)
-                       update_diskio_values(cur, reads, writes);
-       }
-       update_diskio_values(&stats, total_reads, total_writes);
-       fclose(fp);
-}
-
index 0cc9003..373f5d5 100644 (file)
@@ -43,8 +43,11 @@ struct diskio_stat {
        double last_write;
 };
 
-struct diskio_stat *prepare_diskio_stat(const char *s);
+extern struct diskio_stat stats;
+
+struct diskio_stat *prepare_diskio_stat(const char *);
 void update_diskio(void);
 void clear_diskio_stats(void);
+void update_diskio_values(struct diskio_stat *, unsigned int, unsigned int);
 
 #endif /* DISKIO_H_ */
index b170a67..20c4e27 100644 (file)
 inline void proc_find_top(struct process **cpu, struct process **mem);
 
 static short cpu_setup = 0;
-static struct diskio_stat stats = {
-       .next = NULL,
-       .current = 0,
-       .current_read = 0,
-       .current_write = 0,
-       .last = UINT_MAX,
-       .last_read = UINT_MAX,
-       .last_write = UINT_MAX,
-};
 
 static int getsysctl(char *name, void *ptr, size_t len)
 {
@@ -658,59 +649,49 @@ cleanup:
 
 void update_diskio()
 {
-       int devs_count, num_selected, num_selections;
+       int devs_count, num_selected, num_selections, dn;
        struct device_selection *dev_select = NULL;
        long select_generation;
-       int dn;
        static struct statinfo statinfo_cur;
+       char device_name[text_buffer_size];
        struct diskio_stat *cur;
+       unsigned int reads, writes;
+       unsigned int total_reads = 0, total_writes = 0;
+
 
-       bzero(&statinfo_cur, sizeof(statinfo_cur));
+       memset(&statinfo_cur, 0, sizeof(statinfo_cur));
        statinfo_cur.dinfo = (struct devinfo *)calloc(1, sizeof(struct devinfo));
        stats.current = stats.current_read = stats.current_write = 0;
 
-       if (devstat_getdevs(NULL, &statinfo_cur) < 0)
+       if (devstat_getdevs(NULL, &statinfo_cur) < 0) {
+               free(statinfo_cur.dinfo);
                return;
+       }
 
        devs_count = statinfo_cur.dinfo->numdevs;
        if (devstat_selectdevs(&dev_select, &num_selected, &num_selections,
                        &select_generation, statinfo_cur.dinfo->generation,
                        statinfo_cur.dinfo->devices, devs_count, NULL, 0, NULL, 0,
                        DS_SELECT_ONLY, MAXSHOWDEVS, 1) >= 0) {
-               for (dn = 0; dn < devs_count; ++dn) {
+               for (dn = 0; dn < devs_count; dn++) {
                        int di;
                        struct devstat *dev;
 
                        di = dev_select[dn].position;
                        dev = &statinfo_cur.dinfo->devices[di];
+                       snprintf(device_name, text_buffer_size, "%s%d",
+                                       dev_select[dn].device_name, dev_select[dn].unit_number);
 
+                       total_reads += (reads = dev->bytes[DEVSTAT_READ] / 512);
+                       total_writes += (writes = dev->bytes[DEVSTAT_WRITE] / 512);
                        for (cur = stats.next; cur; cur = cur->next) {
-                               if (cur->dev && !strcmp(dev_select[dn].device_name, cur->dev)) {
-                                       cur->current = (dev->bytes[DEVSTAT_READ] +
-                                                       dev->bytes[DEVSTAT_WRITE] - cur->last) / 1024;
-                                       cur->current_read = (dev->bytes[DEVSTAT_READ] -
-                                                       cur->last_read) / 1024;
-                                       cur->current_write = (dev->bytes[DEVSTAT_WRITE] -
-                                                       cur->last_write) / 1024;
-                                       if (dev->bytes[DEVSTAT_READ] + dev->bytes[DEVSTAT_WRITE] <
-                                                       cur->last) {
-                                               cur->current = 0;
-                                       }
-                                       if (dev->bytes[DEVSTAT_READ] < cur->last_read) {
-                                               cur->current_read = 0;
-                                               cur->current = cur->current_write;
-                                       }
-                                       if (dev->bytes[DEVSTAT_WRITE] < cur->last_write) {
-                                               cur->current_write = 0;
-                                               cur->current = cur->current_read;
-                                       }
-                                       cur->last = dev->bytes[DEVSTAT_READ] +
-                                               dev->bytes[DEVSTAT_WRITE];
-                                       cur->last_read = dev->bytes[DEVSTAT_READ];
-                                       cur->last_write = dev->bytes[DEVSTAT_WRITE];
+                               if (cur->dev && !strcmp(device_name, cur->dev)) {
+                                       update_diskio_values(cur, reads, writes);
+                                       break;
                                }
                        }
                }
+               update_diskio_values(&stats, total_reads, total_writes);
 
                free(dev_select);
        }
@@ -718,60 +699,6 @@ void update_diskio()
        free(statinfo_cur.dinfo);
 }
 
-void clear_diskio_stats()
-{
-       struct diskio_stat *cur;
-       while (stats.next) {
-               cur = stats.next;
-               stats.next = stats.next->next;
-               free(cur);
-       }
-}
-
-struct diskio_stat *prepare_diskio_stat(const char *s)
-{
-       struct diskio_stat *new = 0;
-       struct stat sb;
-       int found = 0;
-       char device[text_buffer_size], fbuf[text_buffer_size];
-       static int rep = 0;
-       /* lookup existing or get new */
-       struct diskio_stat *cur = &stats;
-
-       if (!s)
-               return cur;
-
-       while (cur->next) {
-               cur = cur->next;
-               if (!strcmp(cur->dev, s))
-                       return cur;
-       }
-
-       /* new dev */
-       if (!(cur->next = calloc(1, sizeof(struct diskio_stat)))) {
-               ERR("out of memory allocating new disk stats struct");
-               return NULL;
-       }
-       cur = cur->next;
-       cur->last = cur->last_read = cur->last_write = UINT_MAX;
-       if (strncmp(s, "/dev/", 5) == 0) {
-               // supplied a /dev/device arg, so cut off the /dev part
-               cur->dev = strndup(s + 5, text_buffer_size);
-       } else {
-               cur->dev = strndup(s, text_buffer_size);
-       }
-       /*
-        * check that device actually exists
-        */
-       snprintf(device, text_buffer_size, "/dev/%s", new->dev);
-
-       if (stat(device, &sb)) {
-               ERR("diskio device '%s' does not exist", s);
-               return 0;
-       }
-       return cur;
-}
-
 /* While topless is obviously better, top is also not bad. */
 
 int comparecpu(const void *a, const void *b)
index eb90895..74fceb3 100644 (file)
@@ -30,6 +30,7 @@
 #include "logging.h"
 #include "common.h"
 #include "linux.h"
+#include "diskio.h"
 #include <dirent.h>
 #include <ctype.h>
 #include <errno.h>
 #include <linux/route.h>
 #include <math.h>
 
+/* The following ifdefs were adapted from gkrellm */
+#include <linux/major.h>
+
+#if !defined(MD_MAJOR)
+#define MD_MAJOR 9
+#endif
+
+#if !defined(LVM_BLK_MAJOR)
+#define LVM_BLK_MAJOR 58
+#endif
+
+#if !defined(NBD_MAJOR)
+#define NBD_MAJOR 43
+#endif
+
 #ifdef HAVE_IWLIB
 #include <iwlib.h>
 #endif
@@ -2131,3 +2147,52 @@ const char *get_disk_protect_queue(const char *disk)
        return (state > 0) ? "frozen" : "free  ";
 }
 
+void update_diskio(void)
+{
+       FILE *fp;
+       static int rep = 0;
+       char buf[512], devbuf[64];
+       unsigned int major, minor;
+       int col_count = 0;
+       struct diskio_stat *cur;
+       unsigned int reads, writes;
+       unsigned int total_reads = 0, total_writes = 0;
+
+       stats.current = 0;
+       stats.current_read = 0;
+       stats.current_write = 0;
+
+       if (!(fp = open_file("/proc/diskstats", &rep))) {
+               return;
+       }
+
+       /* read reads and writes from all disks (minor = 0), including cd-roms
+        * and floppies, and sum them up */
+       while (fgets(buf, 512, fp)) {
+               col_count = sscanf(buf, "%u %u %s %*u %*u %u %*u %*u %*u %u", &major,
+                       &minor, devbuf, &reads, &writes);
+               /* ignore subdevices (they have only 3 matching entries in their line)
+                * and virtual devices (LVM, network block devices, RAM disks, Loopback)
+                *
+                * XXX: ignore devices which are part of a SW RAID (MD_MAJOR) */
+               if (col_count == 5 && major != LVM_BLK_MAJOR && major != NBD_MAJOR
+                               && major != RAMDISK_MAJOR && major != LOOP_MAJOR) {
+                       total_reads += reads;
+                       total_writes += writes;
+               } else {
+                       col_count = sscanf(buf, "%u %u %s %*u %u %*u %u",
+                               &major, &minor, devbuf, &reads, &writes);
+                       if (col_count != 5) {
+                               continue;
+                       }
+               }
+               cur = stats.next;
+               while (cur && strcmp(devbuf, cur->dev))
+                       cur = cur->next;
+
+               if (cur)
+                       update_diskio_values(cur, reads, writes);
+       }
+       update_diskio_values(&stats, total_reads, total_writes);
+       fclose(fp);
+}