X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=src%2Fdisk.c;h=c809fdb6a33c0762b6b002a6a66367e1a884660c;hb=6333effca8747ef0cb16870ccb1226e218817a7e;hp=ded2080626f1a12dfba17f776909127153ce945d;hpb=3c0f5d53afde12740b34a35b2127f9c664342c8f;p=collectd.git diff --git a/src/disk.c b/src/disk.c index ded20806..c809fdb6 100644 --- a/src/disk.c +++ b/src/disk.c @@ -23,10 +23,39 @@ #include "collectd.h" #include "common.h" #include "plugin.h" +#include "utils_debug.h" #define MODULE_NAME "disk" -#if defined(KERNEL_LINUX) || defined(HAVE_LIBKSTAT) +#if HAVE_MACH_MACH_TYPES_H +# include +#endif +#if HAVE_MACH_MACH_INIT_H +# include +#endif +#if HAVE_MACH_MACH_ERROR_H +# include +#endif +#if HAVE_MACH_MACH_PORT_H +# include +#endif +#if HAVE_COREFOUNDATION_COREFOUNDATION_H +# include +#endif +#if HAVE_IOKIT_IOKITLIB_H +# include +#endif +#if HAVE_IOKIT_IOTYPES_H +# include +#endif +#if HAVE_IOKIT_STORAGE_IOBLOCKSTORAGEDRIVER_H +# include +#endif +#if HAVE_IOKIT_IOBSD_H +# include +#endif + +#if HAVE_IOKIT_IOKITLIB_H || KERNEL_LINUX || HAVE_LIBKSTAT # define DISK_HAVE_READ 1 #else # define DISK_HAVE_READ 0 @@ -60,7 +89,11 @@ static char *part_ds_def[] = }; static int part_ds_num = 4; -#ifdef KERNEL_LINUX +#if HAVE_IOKIT_IOKITLIB_H +static mach_port_t io_master_port = MACH_PORT_NULL; +/* #endif HAVE_IOKIT_IOKITLIB_H */ + +#elif KERNEL_LINUX typedef struct diskstats { char *name; @@ -68,8 +101,8 @@ typedef struct diskstats /* This overflows in roughly 1361 year */ unsigned int poll_count; - unsigned int read_sectors; - unsigned int write_sectors; + unsigned long long read_sectors; + unsigned long long write_sectors; unsigned long long read_bytes; unsigned long long write_bytes; @@ -78,9 +111,10 @@ typedef struct diskstats } diskstats_t; static diskstats_t *disklist; -/* #endif defined(KERNEL_LINUX) */ +static int min_poll_count; +/* #endif KERNEL_LINUX */ -#elif defined(HAVE_LIBKSTAT) +#elif HAVE_LIBKSTAT #define MAX_NUMDISK 256 extern kstat_ctl_t *kc; static kstat_t *ksp[MAX_NUMDISK]; @@ -89,7 +123,41 @@ static int numdisk = 0; static void disk_init (void) { -#ifdef HAVE_LIBKSTAT +#if HAVE_IOKIT_IOKITLIB_H + kern_return_t status; + + if (io_master_port != MACH_PORT_NULL) + { + mach_port_deallocate (mach_task_self (), + io_master_port); + io_master_port = MACH_PORT_NULL; + } + + status = IOMasterPort (MACH_PORT_NULL, &io_master_port); + if (status != kIOReturnSuccess) + { + syslog (LOG_ERR, "IOMasterPort failed: %s", + mach_error_string (status)); + io_master_port = MACH_PORT_NULL; + return; + } +/* #endif HAVE_IOKIT_IOKITLIB_H */ + +#elif KERNEL_LINUX + int step; + int heartbeat; + + step = atoi (COLLECTD_STEP); + heartbeat = atoi (COLLECTD_HEARTBEAT); + + assert (step > 0); + assert (heartbeat >= step); + + min_poll_count = 1 + (heartbeat / step); + DBG ("min_poll_count = %i;", min_poll_count); +/* #endif KERNEL_LINUX */ + +#elif HAVE_LIBKSTAT kstat_t *ksp_chain; numdisk = 0; @@ -108,7 +176,7 @@ static void disk_init (void) continue; ksp[numdisk++] = ksp_chain; } -#endif +#endif /* HAVE_LIBKSTAT */ return; } @@ -162,9 +230,13 @@ static void disk_submit (char *disk_name, write_time) >= BUFSIZE) return; + DBG ("disk_name = %s; buf = %s;", + disk_name, buf); + plugin_submit (MODULE_NAME, disk_name, buf); } +#if KERNEL_LINUX || HAVE_LIBKSTAT static void partition_submit (char *part_name, unsigned long long read_count, unsigned long long read_bytes, @@ -181,11 +253,195 @@ static void partition_submit (char *part_name, plugin_submit ("partition", part_name, buf); } +#endif /* KERNEL_LINUX || HAVE_LIBKSTAT */ #undef BUFSIZE +#if HAVE_IOKIT_IOKITLIB_H +static signed long long dict_get_value (CFDictionaryRef dict, const char *key) +{ + signed long long val_int; + CFNumberRef val_obj; + CFStringRef key_obj; + + /* `key_obj' needs to be released. */ + key_obj = CFStringCreateWithCString (kCFAllocatorDefault, key, + kCFStringEncodingASCII); + if (key_obj == NULL) + { + DBG ("CFStringCreateWithCString (%s) failed.", key); + return (-1LL); + } + + /* get => we don't need to release (== free) the object */ + val_obj = (CFNumberRef) CFDictionaryGetValue (dict, key_obj); + + CFRelease (key_obj); + + if (val_obj == NULL) + { + DBG ("CFDictionaryGetValue (%s) failed.", key); + return (-1LL); + } + + if (!CFNumberGetValue (val_obj, kCFNumberSInt64Type, &val_int)) + { + DBG ("CFNumberGetValue (%s) failed.", key); + return (-1LL); + } + + return (val_int); +} +#endif /* HAVE_IOKIT_IOKITLIB_H */ + static void disk_read (void) { -#ifdef KERNEL_LINUX +#if HAVE_IOKIT_IOKITLIB_H + io_registry_entry_t disk; + io_registry_entry_t disk_child; + io_iterator_t disk_list; + CFDictionaryRef props_dict; + CFDictionaryRef stats_dict; + CFDictionaryRef child_dict; + kern_return_t status; + + signed long long read_ops; + signed long long read_byt; + signed long long read_tme; + signed long long write_ops; + signed long long write_byt; + signed long long write_tme; + + int disk_major; + int disk_minor; + char disk_name[64]; + + static complain_t complain_obj; + + /* Get the list of all disk objects. */ + if (IOServiceGetMatchingServices (io_master_port, + IOServiceMatching (kIOBlockStorageDriverClass), + &disk_list) != kIOReturnSuccess) + { + plugin_complain (LOG_ERR, &complain_obj, "disk plugin: " + "IOServiceGetMatchingServices failed."); + return; + } + else if (complain_obj.interval != 0) + { + plugin_relief (LOG_NOTICE, &complain_obj, "disk plugin: " + "IOServiceGetMatchingServices succeeded."); + } + + while ((disk = IOIteratorNext (disk_list)) != 0) + { + props_dict = NULL; + stats_dict = NULL; + child_dict = NULL; + + /* `disk_child' must be released */ + if ((status = IORegistryEntryGetChildEntry (disk, kIOServicePlane, &disk_child)) + != kIOReturnSuccess) + { + /* This fails for example for DVD/CD drives.. */ + DBG ("IORegistryEntryGetChildEntry (disk) failed: 0x%08x", status); + IOObjectRelease (disk); + continue; + } + + /* We create `props_dict' => we need to release it later */ + if (IORegistryEntryCreateCFProperties (disk, + (CFMutableDictionaryRef *) &props_dict, + kCFAllocatorDefault, + kNilOptions) + != kIOReturnSuccess) + { + syslog (LOG_ERR, "disk-plugin: IORegistryEntryCreateCFProperties failed."); + IOObjectRelease (disk_child); + IOObjectRelease (disk); + continue; + } + + if (props_dict == NULL) + { + DBG ("IORegistryEntryCreateCFProperties (disk) failed."); + IOObjectRelease (disk_child); + IOObjectRelease (disk); + continue; + } + + stats_dict = (CFDictionaryRef) CFDictionaryGetValue (props_dict, + CFSTR (kIOBlockStorageDriverStatisticsKey)); + + if (stats_dict == NULL) + { + DBG ("CFDictionaryGetValue (%s) failed.", + kIOBlockStorageDriverStatisticsKey); + CFRelease (props_dict); + IOObjectRelease (disk_child); + IOObjectRelease (disk); + continue; + } + + if (IORegistryEntryCreateCFProperties (disk_child, + (CFMutableDictionaryRef *) &child_dict, + kCFAllocatorDefault, + kNilOptions) + != kIOReturnSuccess) + { + DBG ("IORegistryEntryCreateCFProperties (disk_child) failed."); + IOObjectRelease (disk_child); + CFRelease (props_dict); + IOObjectRelease (disk); + continue; + } + + disk_major = (int) dict_get_value (child_dict, + kIOBSDMajorKey); + disk_minor = (int) dict_get_value (child_dict, + kIOBSDMinorKey); + read_ops = dict_get_value (stats_dict, + kIOBlockStorageDriverStatisticsReadsKey); + read_byt = dict_get_value (stats_dict, + kIOBlockStorageDriverStatisticsBytesReadKey); + read_tme = dict_get_value (stats_dict, + kIOBlockStorageDriverStatisticsTotalReadTimeKey); + write_ops = dict_get_value (stats_dict, + kIOBlockStorageDriverStatisticsWritesKey); + write_byt = dict_get_value (stats_dict, + kIOBlockStorageDriverStatisticsBytesWrittenKey); + write_tme = dict_get_value (stats_dict, + kIOBlockStorageDriverStatisticsTotalWriteTimeKey); + + if (snprintf (disk_name, 64, "%i-%i", disk_major, disk_minor) >= 64) + { + DBG ("snprintf (major, minor) failed."); + CFRelease (child_dict); + IOObjectRelease (disk_child); + CFRelease (props_dict); + IOObjectRelease (disk); + continue; + } + DBG ("disk_name = %s", disk_name); + + if ((read_ops != -1LL) + || (read_byt != -1LL) + || (read_tme != -1LL) + || (write_ops != -1LL) + || (write_byt != -1LL) + || (write_tme != -1LL)) + disk_submit (disk_name, + read_ops, 0ULL, read_byt, read_tme, + write_ops, 0ULL, write_byt, write_tme); + + CFRelease (child_dict); + IOObjectRelease (disk_child); + CFRelease (props_dict); + IOObjectRelease (disk); + } + IOObjectRelease (disk_list); +/* #endif HAVE_IOKIT_IOKITLIB_H */ + +#elif KERNEL_LINUX FILE *fh; char buffer[1024]; char disk_name[128]; @@ -197,30 +453,37 @@ static void disk_read (void) int major = 0; int minor = 0; - unsigned int read_sectors; - unsigned int write_sectors; - - unsigned long long read_count = 0; - unsigned long long read_merged = 0; - unsigned long long read_bytes = 0; - unsigned long long read_time = 0; - unsigned long long write_count = 0; - unsigned long long write_merged = 0; - unsigned long long write_bytes = 0; - unsigned long long write_time = 0; + unsigned long long read_sectors = 0ULL; + unsigned long long write_sectors = 0ULL; + + unsigned long long read_count = 0ULL; + unsigned long long read_merged = 0ULL; + unsigned long long read_bytes = 0ULL; + unsigned long long read_time = 0ULL; + unsigned long long write_count = 0ULL; + unsigned long long write_merged = 0ULL; + unsigned long long write_bytes = 0ULL; + unsigned long long write_time = 0ULL; int is_disk = 0; diskstats_t *ds, *pre_ds; + static complain_t complain_obj; + if ((fh = fopen ("/proc/diskstats", "r")) == NULL) { if ((fh = fopen ("/proc/partitions", "r")) == NULL) + { + plugin_complain (LOG_ERR, &complain_obj, "disk plugin: Failed to open /proc/{diskstats,partitions}."); return; + } /* Kernel is 2.4.* */ fieldshift = 1; } + plugin_relief (LOG_NOTICE, &complain_obj, "disk plugin: Succeeded to open /proc/{diskstats,partitions}."); + while (fgets (buffer, 1024, fh) != NULL) { numfields = strsplit (buffer, fields, 32); @@ -261,17 +524,17 @@ static void disk_read (void) { /* Kernel 2.6, Partition */ read_count = atoll (fields[3]); - read_sectors = atoi (fields[4]); + read_sectors = atoll (fields[4]); write_count = atoll (fields[5]); - write_sectors = atoi (fields[6]); + write_sectors = atoll (fields[6]); } else if (numfields == (14 + fieldshift)) { read_count = atoll (fields[3 + fieldshift]); write_count = atoll (fields[7 + fieldshift]); - read_sectors = atoi (fields[5 + fieldshift]); - write_sectors = atoi (fields[9 + fieldshift]); + read_sectors = atoll (fields[5 + fieldshift]); + write_sectors = atoll (fields[9 + fieldshift]); if ((fieldshift == 0) || (minor == 0)) { @@ -284,19 +547,20 @@ static void disk_read (void) } else { + DBG ("numfields = %i; => unknown file format.", numfields); continue; } - - if (read_sectors >= ds->read_sectors) - ds->read_bytes += 512 * (read_sectors - ds->read_sectors); + /* If the counter wraps around, it's only 32 bits.. */ + if (read_sectors < ds->read_sectors) + ds->read_bytes += 512 * ((0xFFFFFFFF - ds->read_sectors) + read_sectors); else - ds->read_bytes += 512 * ((UINT_MAX - ds->read_sectors) + read_sectors); + ds->read_bytes += 512 * (read_sectors - ds->read_sectors); - if (write_sectors >= ds->write_sectors) - ds->write_bytes += 512 * (write_sectors - ds->write_sectors); + if (write_sectors < ds->write_sectors) + ds->write_bytes += 512 * ((0xFFFFFFFF - ds->write_sectors) + write_sectors); else - ds->write_bytes += 512 * ((UINT_MAX - ds->write_sectors) + write_sectors); + ds->write_bytes += 512 * (write_sectors - ds->write_sectors); ds->read_sectors = read_sectors; ds->write_sectors = write_sectors; @@ -305,11 +569,18 @@ static void disk_read (void) /* Don't write to the RRDs if we've just started.. */ ds->poll_count++; - if (ds->poll_count <= 6) + if (ds->poll_count <= min_poll_count) + { + DBG ("(ds->poll_count = %i) <= (min_poll_count = %i); => Not writing.", + ds->poll_count, min_poll_count); continue; + } if ((read_count == 0) && (write_count == 0)) + { + DBG ("((read_count == 0) && (write_count == 0)); => Not writing."); continue; + } if (is_disk) disk_submit (disk_name, read_count, read_merged, read_bytes, read_time, @@ -321,7 +592,7 @@ static void disk_read (void) fclose (fh); /* #endif defined(KERNEL_LINUX) */ -#elif defined(HAVE_LIBKSTAT) +#elif HAVE_LIBKSTAT static kstat_io_t kio; int i;