static CFStringRef BSDNameForBlockStorageDevice( io_registry_entry_t service ) { // This should be an IOBlockStorageDevice. It'll have one child, an IOBlockStorageDriver, // which will have one child of its own, an IOMedia. We get the BSD name from the IOMedia. static CFStringRef kUnknownDiskBSDName = CFSTR("disk[??]"); kern_return_t kr = KERN_SUCCESS; io_registry_entry_t driver = MACH_PORT_NULL; kr = IORegistryEntryGetChildEntry( service, kIOServicePlane, &driver ); if ( driver == MACH_PORT_NULL ) return ( kUnknownDiskBSDName ); if ( IOObjectConformsTo(driver, kIOBlockStorageDriverClass) == FALSE ) return ( kUnknownDiskBSDName ); io_registry_entry_t media = MACH_PORT_NULL; kr = IORegistryEntryGetChildEntry( driver, kIOServicePlane, &media ); IOObjectRelease( driver ); if ( media == MACH_PORT_NULL ) return ( kUnknownDiskBSDName ); if ( IOObjectConformsTo(media, kIOMediaClass) == FALSE ) return ( kUnknownDiskBSDName ); CFStringRef str = IORegistryEntryCreateCFProperty( media, CFSTR("BSD Name"), NULL, 0 ); if ( str == NULL ) str = kUnknownDiskBSDName; IOObjectRelease( media ); return ( str ); }
/*! Finds the IOMedia object associated with the LUN object. * @param LUN the IO registry object corresponding to a LUN. * @return the IOMedia object for the LUN. */ io_object_t iSCSIIORegistryFindIOMediaForLUN(io_object_t LUN) { io_object_t entry = IO_OBJECT_NULL; IORegistryEntryGetChildEntry(LUN,kIOServicePlane,&entry); // Descend down the tree and find the first IOMedia class while(entry != IO_OBJECT_NULL) { CFStringRef class = IOObjectCopyClass(entry); if(class && CFStringCompare(class,CFSTR(kIOMediaClass),0) == kCFCompareEqualTo) { CFRelease(class); return entry; } if(class) CFRelease(class); // Descend down into the tree next time IOIteratorNext() is called io_object_t child; IORegistryEntryGetChildEntry(entry,kIOServicePlane,&child); IOObjectRelease(entry); entry = child; } return IO_OBJECT_NULL; }
/*! Gets an iterator for traversing iSCSI LUNs for a specified target in the * I/O registry. * @param targetIQN the name of the target. * @param iterator the iterator used to traverse LUNs for the specified target. * @return a kernel error code indicating the result of the operation. */ kern_return_t iSCSIIORegistryGetLUNs(CFStringRef targetIQN,io_iterator_t * iterator) { if(!iterator) return kIOReturnBadArgument; io_object_t parallelDevice = iSCSIIORegistryGetTargetEntry(targetIQN); if(parallelDevice == IO_OBJECT_NULL) return kIOReturnNotFound; // The children of the IOSCSIParallelInterfaceDevice are IOSCSITargetDevices io_object_t target; IORegistryEntryGetChildEntry(parallelDevice,kIOServicePlane,&target); if(target == IO_OBJECT_NULL) { IOObjectRelease(parallelDevice); return kIOReturnNotFound; } // The children of the target (IOSCSITargetDevice) are the LUNs kern_return_t result = IORegistryEntryGetChildIterator(target,kIOServicePlane,iterator); IOObjectRelease(parallelDevice); IOObjectRelease(target); return result; }
int AoEProperties::number_of_targets(void) { io_registry_entry_t ControllerInterface = NULL; io_iterator_t Controllers = NULL; io_registry_entry_t Controller = NULL; int nCount = 0; if ( 0==m_OurObject ) return 0; IORegistryEntryGetChildEntry(m_OurObject, kIOServicePlane, &ControllerInterface); IORegistryEntryGetChildIterator(ControllerInterface, kIOServicePlane, &Controllers); while ( (Controller = IOIteratorNext(Controllers)) ) { IOObjectRelease(Controller); ++nCount; } if ( Controllers ) IOObjectRelease(Controllers); if ( ControllerInterface ) IOObjectRelease(ControllerInterface); return nCount; }
/*! Creates a dictionary of properties associated with the target. These * include the following keys: * * kIOPropertySCSIVendorIdentification (CFStringRef) * kIOPropertySCSIProductIdentification (CFStringRef) * kIOPropertyiSCSIQualifiedNameKey (CFStringRef) * kIOPropertySCSITargetIdentifierKey (CFNumberRef) * * @param target the target IO registry object. * @return a dictionary of values for the properties, or NULL if the object * could not be found. */ CFDictionaryRef iSCSIIORegistryCreateCFPropertiesForTarget(io_object_t target) { // Get the IOSCSITargetDevice object (child of IOParallelInterfaceDevice or "target") io_object_t child; IORegistryEntryGetChildEntry(target,kIOServicePlane,&child); if(child == IO_OBJECT_NULL) return NULL; CFStringRef vendor = IORegistryEntryCreateCFProperty( child,CFSTR(kIOPropertySCSIVendorIdentification),kCFAllocatorDefault,0); if(!vendor) vendor = CFSTR(""); CFStringRef product = IORegistryEntryCreateCFProperty( child,CFSTR(kIOPropertySCSIProductIdentification),kCFAllocatorDefault,0); if(!product) product = CFSTR(""); CFDictionaryRef protocolDict = IORegistryEntryCreateCFProperty( child,CFSTR(kIOPropertyProtocolCharacteristicsKey),kCFAllocatorDefault,0); CFStringRef targetIQN = CFDictionaryGetValue(protocolDict,CFSTR(kIOPropertyiSCSIQualifiedNameKey)); CFNumberRef targetId = CFDictionaryGetValue(protocolDict,CFSTR(kIOPropertySCSITargetIdentifierKey)); const void * keys[] = { CFSTR(kIOPropertySCSIVendorIdentification), CFSTR(kIOPropertySCSIProductIdentification), CFSTR(kIOPropertySCSITargetIdentifierKey), CFSTR(kIOPropertyiSCSIQualifiedNameKey)}; const void * values[] = { vendor, product, targetId, targetIQN }; CFDictionaryRef propertiesDict = CFDictionaryCreate(kCFAllocatorDefault, keys,values, sizeof(values)/sizeof(void*), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFRelease(vendor); CFRelease(product); CFRelease(protocolDict); return propertiesDict; }
int AoEProperties::get_property(CFTypeRef* pType, CFStringRef Property, int nNumber) { io_registry_entry_t ControllerInterface; io_iterator_t Controllers; io_registry_entry_t Controller; int nCount; int nShelf; ControllerInterface = NULL; Controllers = NULL; Controller = NULL; nCount = 0; nShelf = 0; *pType = NULL; if ( 0==m_OurObject ) return 0; IORegistryEntryGetChildEntry(m_OurObject, kIOServicePlane, &ControllerInterface); IORegistryEntryGetChildIterator(ControllerInterface, kIOServicePlane, &Controllers); while ( (Controller = IOIteratorNext(Controllers)) ) { if ( nNumber==nCount ) { *pType = IORegistryEntryCreateCFProperty(Controller,Property,kCFAllocatorDefault,0); if ( *pType ) CFRetain(*pType); IOObjectRelease(Controller); break; } IOObjectRelease(Controller); ++nCount; } if ( Controllers ) IOObjectRelease(Controllers); if ( ControllerInterface ) IOObjectRelease(ControllerInterface); return (*pType && (nCount==nNumber)) ? 0 : -1; }
/*! Applies a callback function all IOMedia objects of a particular target. * @param target search children of this node for IOMedia objects. * @param callback the callback function to call on each IOMedia object. * @param context a user-defined parameter to pass to the callback function. */ void iSCSIIORegistryIOMediaApplyFunction(io_object_t target, iSCSIIOMediaCallback callback, void * context) { io_object_t entry = IO_OBJECT_NULL; io_iterator_t iterator = IO_OBJECT_NULL; IORegistryEntryGetChildIterator(target,kIOServicePlane,&iterator); // Iterate over all children of the target object while((entry = IOIteratorNext(iterator)) != IO_OBJECT_NULL) { // Recursively call this function for each child of the target iSCSIIORegistryIOMediaApplyFunction(entry,callback,context); // Find the IOMedia's root provider class (IOBlockStorageDriver) and // get the first child. This ensures that we grab the IOMedia object // for the disk itself and not each individual partition CFStringRef providerClass = IORegistryEntryCreateCFProperty(entry,CFSTR(kIOClassKey),kCFAllocatorDefault,0); if(providerClass && CFStringCompare(providerClass,CFSTR(kIOBlockStorageDriverClass),0) == kCFCompareEqualTo) { // Apply callback function to the child (the child is the the // IOMedia object that pertains to the whole disk) io_object_t child; IORegistryEntryGetChildEntry(entry,kIOServicePlane,&child); callback(child,context); IOObjectRelease(child); } if(providerClass) CFRelease(providerClass); IOObjectRelease(entry); } IOObjectRelease(iterator); }
static int disk_read (void) { #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; CFStringRef tmp_cf_string_ref; 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[DATA_MAX_NAME_LEN]; char disk_name_bsd[DATA_MAX_NAME_LEN]; /* Get the list of all disk objects. */ if (IOServiceGetMatchingServices (io_master_port, IOServiceMatching (kIOBlockStorageDriverClass), &disk_list) != kIOReturnSuccess) { ERROR ("disk plugin: IOServiceGetMatchingServices failed."); return (-1); } 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.. */ DEBUG ("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) { ERROR ("disk-plugin: IORegistryEntryCreateCFProperties failed."); IOObjectRelease (disk_child); IOObjectRelease (disk); continue; } if (props_dict == NULL) { DEBUG ("IORegistryEntryCreateCFProperties (disk) failed."); IOObjectRelease (disk_child); IOObjectRelease (disk); continue; } /* tmp_cf_string_ref doesn't need to be released. */ tmp_cf_string_ref = (CFStringRef) CFDictionaryGetValue (props_dict, CFSTR(kIOBSDNameKey)); if (!tmp_cf_string_ref) { DEBUG ("disk plugin: CFDictionaryGetValue(" "kIOBSDNameKey) failed."); CFRelease (props_dict); IOObjectRelease (disk_child); IOObjectRelease (disk); continue; } assert (CFGetTypeID (tmp_cf_string_ref) == CFStringGetTypeID ()); memset (disk_name_bsd, 0, sizeof (disk_name_bsd)); CFStringGetCString (tmp_cf_string_ref, disk_name_bsd, sizeof (disk_name_bsd), kCFStringEncodingUTF8); if (disk_name_bsd[0] == 0) { ERROR ("disk plugin: CFStringGetCString() failed."); CFRelease (props_dict); IOObjectRelease (disk_child); IOObjectRelease (disk); continue; } DEBUG ("disk plugin: disk_name_bsd = \"%s\"", disk_name_bsd); stats_dict = (CFDictionaryRef) CFDictionaryGetValue (props_dict, CFSTR (kIOBlockStorageDriverStatisticsKey)); if (stats_dict == NULL) { DEBUG ("disk plugin: CFDictionaryGetValue (" "%s) failed.", kIOBlockStorageDriverStatisticsKey); CFRelease (props_dict); IOObjectRelease (disk_child); IOObjectRelease (disk); continue; } if (IORegistryEntryCreateCFProperties (disk_child, (CFMutableDictionaryRef *) &child_dict, kCFAllocatorDefault, kNilOptions) != kIOReturnSuccess) { DEBUG ("disk plugin: IORegistryEntryCreateCFProperties (" "disk_child) failed."); IOObjectRelease (disk_child); CFRelease (props_dict); IOObjectRelease (disk); continue; } /* kIOBSDNameKey */ 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); /* This property describes the number of nanoseconds spent * performing writes since the block storage driver was * instantiated. It is one of the statistic entries listed * under the top-level kIOBlockStorageDriverStatisticsKey * property table. It has an OSNumber value. */ write_tme = dict_get_value (stats_dict, kIOBlockStorageDriverStatisticsTotalWriteTimeKey); if (use_bsd_name) sstrncpy (disk_name, disk_name_bsd, sizeof (disk_name)); else ssnprintf (disk_name, sizeof (disk_name), "%i-%i", disk_major, disk_minor); DEBUG ("disk plugin: disk_name = \"%s\"", disk_name); if ((read_byt != -1LL) || (write_byt != -1LL)) disk_submit (disk_name, "disk_octets", read_byt, write_byt); if ((read_ops != -1LL) || (write_ops != -1LL)) disk_submit (disk_name, "disk_ops", read_ops, write_ops); if ((read_tme != -1LL) || (write_tme != -1LL)) disk_submit (disk_name, "disk_time", read_tme / 1000, write_tme / 1000); 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 *fields[32]; int numfields; int fieldshift = 0; int minor = 0; derive_t read_sectors = 0; derive_t write_sectors = 0; derive_t read_ops = 0; derive_t read_merged = 0; derive_t read_time = 0; derive_t write_ops = 0; derive_t write_merged = 0; derive_t write_time = 0; int is_disk = 0; diskstats_t *ds, *pre_ds; if ((fh = fopen ("/proc/diskstats", "r")) == NULL) { fh = fopen ("/proc/partitions", "r"); if (fh == NULL) { ERROR ("disk plugin: fopen (/proc/{diskstats,partitions}) failed."); return (-1); } /* Kernel is 2.4.* */ fieldshift = 1; } while (fgets (buffer, sizeof (buffer), fh) != NULL) { char *disk_name; numfields = strsplit (buffer, fields, 32); if ((numfields != (14 + fieldshift)) && (numfields != 7)) continue; minor = atoll (fields[1]); disk_name = fields[2 + fieldshift]; for (ds = disklist, pre_ds = disklist; ds != NULL; pre_ds = ds, ds = ds->next) if (strcmp (disk_name, ds->name) == 0) break; if (ds == NULL) { if ((ds = (diskstats_t *) calloc (1, sizeof (diskstats_t))) == NULL) continue; if ((ds->name = strdup (disk_name)) == NULL) { free (ds); continue; } if (pre_ds == NULL) disklist = ds; else pre_ds->next = ds; } is_disk = 0; if (numfields == 7) { /* Kernel 2.6, Partition */ read_ops = atoll (fields[3]); read_sectors = atoll (fields[4]); write_ops = atoll (fields[5]); write_sectors = atoll (fields[6]); } else if (numfields == (14 + fieldshift)) { read_ops = atoll (fields[3 + fieldshift]); write_ops = atoll (fields[7 + fieldshift]); read_sectors = atoll (fields[5 + fieldshift]); write_sectors = atoll (fields[9 + fieldshift]); if ((fieldshift == 0) || (minor == 0)) { is_disk = 1; read_merged = atoll (fields[4 + fieldshift]); read_time = atoll (fields[6 + fieldshift]); write_merged = atoll (fields[8 + fieldshift]); write_time = atoll (fields[10+ fieldshift]); } } else { DEBUG ("numfields = %i; => unknown file format.", numfields); continue; } { derive_t diff_read_sectors; derive_t diff_write_sectors; /* If the counter wraps around, it's only 32 bits.. */ if (read_sectors < ds->read_sectors) diff_read_sectors = 1 + read_sectors + (UINT_MAX - ds->read_sectors); else diff_read_sectors = read_sectors - ds->read_sectors; if (write_sectors < ds->write_sectors) diff_write_sectors = 1 + write_sectors + (UINT_MAX - ds->write_sectors); else diff_write_sectors = write_sectors - ds->write_sectors; ds->read_bytes += 512 * diff_read_sectors; ds->write_bytes += 512 * diff_write_sectors; ds->read_sectors = read_sectors; ds->write_sectors = write_sectors; } /* Calculate the average time an io-op needs to complete */ if (is_disk) { derive_t diff_read_ops; derive_t diff_write_ops; derive_t diff_read_time; derive_t diff_write_time; if (read_ops < ds->read_ops) diff_read_ops = 1 + read_ops + (UINT_MAX - ds->read_ops); else diff_read_ops = read_ops - ds->read_ops; DEBUG ("disk plugin: disk_name = %s; read_ops = %"PRIi64"; " "ds->read_ops = %"PRIi64"; diff_read_ops = %"PRIi64";", disk_name, read_ops, ds->read_ops, diff_read_ops); if (write_ops < ds->write_ops) diff_write_ops = 1 + write_ops + (UINT_MAX - ds->write_ops); else diff_write_ops = write_ops - ds->write_ops; if (read_time < ds->read_time) diff_read_time = 1 + read_time + (UINT_MAX - ds->read_time); else diff_read_time = read_time - ds->read_time; if (write_time < ds->write_time) diff_write_time = 1 + write_time + (UINT_MAX - ds->write_time); else diff_write_time = write_time - ds->write_time; if (diff_read_ops != 0) ds->avg_read_time += disk_calc_time_incr ( diff_read_time, diff_read_ops); if (diff_write_ops != 0) ds->avg_write_time += disk_calc_time_incr ( diff_write_time, diff_write_ops); ds->read_ops = read_ops; ds->read_time = read_time; ds->write_ops = write_ops; ds->write_time = write_time; } /* if (is_disk) */ /* Don't write to the RRDs if we've just started.. */ ds->poll_count++; if (ds->poll_count <= 2) { DEBUG ("disk plugin: (ds->poll_count = %i) <= " "(min_poll_count = 2); => Not writing.", ds->poll_count); continue; } if ((read_ops == 0) && (write_ops == 0)) { DEBUG ("disk plugin: ((read_ops == 0) && " "(write_ops == 0)); => Not writing."); continue; } if ((ds->read_bytes != 0) || (ds->write_bytes != 0)) disk_submit (disk_name, "disk_octets", ds->read_bytes, ds->write_bytes); if ((ds->read_ops != 0) || (ds->write_ops != 0)) disk_submit (disk_name, "disk_ops", read_ops, write_ops); if ((ds->avg_read_time != 0) || (ds->avg_write_time != 0)) disk_submit (disk_name, "disk_time", ds->avg_read_time, ds->avg_write_time); if (is_disk) { disk_submit (disk_name, "disk_merged", read_merged, write_merged); } /* if (is_disk) */ } /* while (fgets (buffer, sizeof (buffer), fh) != NULL) */ fclose (fh); /* #endif defined(KERNEL_LINUX) */ #elif HAVE_LIBKSTAT # if HAVE_KSTAT_IO_T_WRITES && HAVE_KSTAT_IO_T_NWRITES && HAVE_KSTAT_IO_T_WTIME # define KIO_ROCTETS reads # define KIO_WOCTETS writes # define KIO_ROPS nreads # define KIO_WOPS nwrites # define KIO_RTIME rtime # define KIO_WTIME wtime # elif HAVE_KSTAT_IO_T_NWRITTEN && HAVE_KSTAT_IO_T_WRITES && HAVE_KSTAT_IO_T_WTIME # define KIO_ROCTETS nread # define KIO_WOCTETS nwritten # define KIO_ROPS reads # define KIO_WOPS writes # define KIO_RTIME rtime # define KIO_WTIME wtime # else # error "kstat_io_t does not have the required members" # endif static kstat_io_t kio; int i; if (kc == NULL) return (-1); for (i = 0; i < numdisk; i++) { if (kstat_read (kc, ksp[i], &kio) == -1) continue; if (strncmp (ksp[i]->ks_class, "disk", 4) == 0) { disk_submit (ksp[i]->ks_name, "disk_octets", kio.KIO_ROCTETS, kio.KIO_WOCTETS); disk_submit (ksp[i]->ks_name, "disk_ops", kio.KIO_ROPS, kio.KIO_WOPS); /* FIXME: Convert this to microseconds if necessary */ disk_submit (ksp[i]->ks_name, "disk_time", kio.KIO_RTIME, kio.KIO_WTIME); } else if (strncmp (ksp[i]->ks_class, "partition", 9) == 0) { disk_submit (ksp[i]->ks_name, "disk_octets", kio.KIO_ROCTETS, kio.KIO_WOCTETS); disk_submit (ksp[i]->ks_name, "disk_ops", kio.KIO_ROPS, kio.KIO_WOPS); } } /* #endif defined(HAVE_LIBKSTAT) */ #elif defined(HAVE_LIBSTATGRAB) sg_disk_io_stats *ds; int disks, counter; char name[DATA_MAX_NAME_LEN]; if ((ds = sg_get_disk_io_stats(&disks)) == NULL) return (0); for (counter=0; counter < disks; counter++) { strncpy(name, ds->disk_name, sizeof(name)); name[sizeof(name)-1] = '\0'; /* strncpy doesn't terminate longer strings */ disk_submit (name, "disk_octets", ds->read_bytes, ds->write_bytes); ds++; } /* #endif defined(HAVE_LIBSTATGRAB) */ #elif defined(HAVE_PERFSTAT) derive_t read_sectors; derive_t write_sectors; derive_t read_time; derive_t write_time; derive_t read_ops; derive_t write_ops; perfstat_id_t firstpath; int rnumdisk; int i; if ((numdisk = perfstat_disk(NULL, NULL, sizeof(perfstat_disk_t), 0)) < 0) { char errbuf[1024]; WARNING ("disk plugin: perfstat_disk: %s", sstrerror (errno, errbuf, sizeof (errbuf))); return (-1); } if (numdisk != pnumdisk || stat_disk==NULL) { if (stat_disk!=NULL) free(stat_disk); stat_disk = (perfstat_disk_t *)calloc(numdisk, sizeof(perfstat_disk_t)); } pnumdisk = numdisk; firstpath.name[0]='\0'; if ((rnumdisk = perfstat_disk(&firstpath, stat_disk, sizeof(perfstat_disk_t), numdisk)) < 0) { char errbuf[1024]; WARNING ("disk plugin: perfstat_disk : %s", sstrerror (errno, errbuf, sizeof (errbuf))); return (-1); } for (i = 0; i < rnumdisk; i++) { read_sectors = stat_disk[i].rblks*stat_disk[i].bsize; write_sectors = stat_disk[i].wblks*stat_disk[i].bsize; disk_submit (stat_disk[i].name, "disk_octets", read_sectors, write_sectors); read_ops = stat_disk[i].xrate; write_ops = stat_disk[i].xfers - stat_disk[i].xrate; disk_submit (stat_disk[i].name, "disk_ops", read_ops, write_ops); read_time = stat_disk[i].rserv; read_time *= ((double)(_system_configuration.Xint)/(double)(_system_configuration.Xfrac)) / 1000000.0; write_time = stat_disk[i].wserv; write_time *= ((double)(_system_configuration.Xint)/(double)(_system_configuration.Xfrac)) / 1000000.0; disk_submit (stat_disk[i].name, "disk_time", read_time, write_time); } #endif /* defined(HAVE_PERFSTAT) */ return (0); } /* int disk_read */
int do_macos_iokit(int update_every, usec_t dt) { (void)dt; static int do_io = -1, do_space = -1, do_inodes = -1, do_bandwidth = -1; if (unlikely(do_io == -1)) { do_io = config_get_boolean("plugin:macos:iokit", "disk i/o", 1); do_space = config_get_boolean("plugin:macos:sysctl", "space usage for all disks", 1); do_inodes = config_get_boolean("plugin:macos:sysctl", "inodes usage for all disks", 1); do_bandwidth = config_get_boolean("plugin:macos:sysctl", "bandwidth", 1); } RRDSET *st; mach_port_t master_port; io_registry_entry_t drive, drive_media; io_iterator_t drive_list; CFDictionaryRef properties, statistics; CFStringRef name; CFNumberRef number; kern_return_t status; collected_number total_disk_reads = 0; collected_number total_disk_writes = 0; struct diskstat { char name[MAXDRIVENAME]; collected_number bytes_read; collected_number bytes_write; collected_number reads; collected_number writes; collected_number time_read; collected_number time_write; collected_number latency_read; collected_number latency_write; } diskstat; struct cur_diskstat { collected_number duration_read_ns; collected_number duration_write_ns; collected_number busy_time_ns; } cur_diskstat; struct prev_diskstat { collected_number bytes_read; collected_number bytes_write; collected_number operations_read; collected_number operations_write; collected_number duration_read_ns; collected_number duration_write_ns; collected_number busy_time_ns; } prev_diskstat; // NEEDED BY: do_space, do_inodes struct statfs *mntbuf; int mntsize, i; char mntonname[MNAMELEN + 1]; char title[4096 + 1]; // NEEDED BY: do_bandwidth struct ifaddrs *ifa, *ifap; /* Get ports and services for drive statistics. */ if (unlikely(IOMasterPort(bootstrap_port, &master_port))) { error("MACOS: IOMasterPort() failed"); do_io = 0; error("DISABLED: system.io"); /* Get the list of all drive objects. */ } else if (unlikely(IOServiceGetMatchingServices(master_port, IOServiceMatching("IOBlockStorageDriver"), &drive_list))) { error("MACOS: IOServiceGetMatchingServices() failed"); do_io = 0; error("DISABLED: system.io"); } else { while ((drive = IOIteratorNext(drive_list)) != 0) { properties = 0; statistics = 0; number = 0; bzero(&diskstat, sizeof(diskstat)); /* Get drive media object. */ status = IORegistryEntryGetChildEntry(drive, kIOServicePlane, &drive_media); if (unlikely(status != KERN_SUCCESS)) { IOObjectRelease(drive); continue; } /* Get drive media properties. */ if (likely(!IORegistryEntryCreateCFProperties(drive_media, (CFMutableDictionaryRef *)&properties, kCFAllocatorDefault, 0))) { /* Get disk name. */ if (likely(name = (CFStringRef)CFDictionaryGetValue(properties, CFSTR(kIOBSDNameKey)))) { CFStringGetCString(name, diskstat.name, MAXDRIVENAME, kCFStringEncodingUTF8); } } /* Release. */ CFRelease(properties); IOObjectRelease(drive_media); /* Obtain the properties for this drive object. */ if (unlikely(IORegistryEntryCreateCFProperties(drive, (CFMutableDictionaryRef *)&properties, kCFAllocatorDefault, 0))) { error("MACOS: IORegistryEntryCreateCFProperties() failed"); do_io = 0; error("DISABLED: system.io"); break; } else if (likely(properties)) { /* Obtain the statistics from the drive properties. */ if (likely(statistics = (CFDictionaryRef)CFDictionaryGetValue(properties, CFSTR(kIOBlockStorageDriverStatisticsKey)))) { // -------------------------------------------------------------------- /* Get bytes read. */ if (likely(number = (CFNumberRef)CFDictionaryGetValue(statistics, CFSTR(kIOBlockStorageDriverStatisticsBytesReadKey)))) { CFNumberGetValue(number, kCFNumberSInt64Type, &diskstat.bytes_read); total_disk_reads += diskstat.bytes_read; } /* Get bytes written. */ if (likely(number = (CFNumberRef)CFDictionaryGetValue(statistics, CFSTR(kIOBlockStorageDriverStatisticsBytesWrittenKey)))) { CFNumberGetValue(number, kCFNumberSInt64Type, &diskstat.bytes_write); total_disk_writes += diskstat.bytes_write; } st = rrdset_find_bytype("disk", diskstat.name); if (unlikely(!st)) { st = rrdset_create("disk", diskstat.name, NULL, diskstat.name, "disk.io", "Disk I/O Bandwidth", "kilobytes/s", 2000, update_every, RRDSET_TYPE_AREA); rrddim_add(st, "reads", NULL, 1, 1024, RRDDIM_INCREMENTAL); rrddim_add(st, "writes", NULL, -1, 1024, RRDDIM_INCREMENTAL); } else rrdset_next(st); prev_diskstat.bytes_read = rrddim_set(st, "reads", diskstat.bytes_read); prev_diskstat.bytes_write = rrddim_set(st, "writes", diskstat.bytes_write); rrdset_done(st); // -------------------------------------------------------------------- /* Get number of reads. */ if (likely(number = (CFNumberRef)CFDictionaryGetValue(statistics, CFSTR(kIOBlockStorageDriverStatisticsReadsKey)))) { CFNumberGetValue(number, kCFNumberSInt64Type, &diskstat.reads); } /* Get number of writes. */ if (likely(number = (CFNumberRef)CFDictionaryGetValue(statistics, CFSTR(kIOBlockStorageDriverStatisticsWritesKey)))) { CFNumberGetValue(number, kCFNumberSInt64Type, &diskstat.writes); } st = rrdset_find_bytype("disk_ops", diskstat.name); if (unlikely(!st)) { st = rrdset_create("disk_ops", diskstat.name, NULL, diskstat.name, "disk.ops", "Disk Completed I/O Operations", "operations/s", 2001, update_every, RRDSET_TYPE_LINE); st->isdetail = 1; rrddim_add(st, "reads", NULL, 1, 1, RRDDIM_INCREMENTAL); rrddim_add(st, "writes", NULL, -1, 1, RRDDIM_INCREMENTAL); } else rrdset_next(st); prev_diskstat.operations_read = rrddim_set(st, "reads", diskstat.reads); prev_diskstat.operations_write = rrddim_set(st, "writes", diskstat.writes); rrdset_done(st); // -------------------------------------------------------------------- /* Get reads time. */ if (likely(number = (CFNumberRef)CFDictionaryGetValue(statistics, CFSTR(kIOBlockStorageDriverStatisticsTotalReadTimeKey)))) { CFNumberGetValue(number, kCFNumberSInt64Type, &diskstat.time_read); } /* Get writes time. */ if (likely(number = (CFNumberRef)CFDictionaryGetValue(statistics, CFSTR(kIOBlockStorageDriverStatisticsTotalWriteTimeKey)))) { CFNumberGetValue(number, kCFNumberSInt64Type, &diskstat.time_write); } st = rrdset_find_bytype("disk_util", diskstat.name); if (unlikely(!st)) { st = rrdset_create("disk_util", diskstat.name, NULL, diskstat.name, "disk.util", "Disk Utilization Time", "% of time working", 2004, update_every, RRDSET_TYPE_AREA); st->isdetail = 1; rrddim_add(st, "utilization", NULL, 1, 10000000, RRDDIM_INCREMENTAL); } else rrdset_next(st); cur_diskstat.busy_time_ns = (diskstat.time_read + diskstat.time_write); prev_diskstat.busy_time_ns = rrddim_set(st, "utilization", cur_diskstat.busy_time_ns); rrdset_done(st); // -------------------------------------------------------------------- /* Get reads latency. */ if (likely(number = (CFNumberRef)CFDictionaryGetValue(statistics, CFSTR(kIOBlockStorageDriverStatisticsLatentReadTimeKey)))) { CFNumberGetValue(number, kCFNumberSInt64Type, &diskstat.latency_read); } /* Get writes latency. */ if (likely(number = (CFNumberRef)CFDictionaryGetValue(statistics, CFSTR(kIOBlockStorageDriverStatisticsLatentWriteTimeKey)))) { CFNumberGetValue(number, kCFNumberSInt64Type, &diskstat.latency_write); } st = rrdset_find_bytype("disk_iotime", diskstat.name); if (unlikely(!st)) { st = rrdset_create("disk_iotime", diskstat.name, NULL, diskstat.name, "disk.iotime", "Disk Total I/O Time", "milliseconds/s", 2022, update_every, RRDSET_TYPE_LINE); st->isdetail = 1; rrddim_add(st, "reads", NULL, 1, 1000000, RRDDIM_INCREMENTAL); rrddim_add(st, "writes", NULL, -1, 1000000, RRDDIM_INCREMENTAL); } else rrdset_next(st); cur_diskstat.duration_read_ns = diskstat.time_read + diskstat.latency_read; cur_diskstat.duration_write_ns = diskstat.time_write + diskstat.latency_write; prev_diskstat.duration_read_ns = rrddim_set(st, "reads", cur_diskstat.duration_read_ns); prev_diskstat.duration_write_ns = rrddim_set(st, "writes", cur_diskstat.duration_write_ns); rrdset_done(st); // -------------------------------------------------------------------- // calculate differential charts // only if this is not the first time we run if (likely(dt)) { // -------------------------------------------------------------------- st = rrdset_find_bytype("disk_await", diskstat.name); if (unlikely(!st)) { st = rrdset_create("disk_await", diskstat.name, NULL, diskstat.name, "disk.await", "Average Completed I/O Operation Time", "ms per operation", 2005, update_every, RRDSET_TYPE_LINE); st->isdetail = 1; rrddim_add(st, "reads", NULL, 1, 1000000, RRDDIM_ABSOLUTE); rrddim_add(st, "writes", NULL, -1, 1000000, RRDDIM_ABSOLUTE); } else rrdset_next(st); rrddim_set(st, "reads", (diskstat.reads - prev_diskstat.operations_read) ? (cur_diskstat.duration_read_ns - prev_diskstat.duration_read_ns) / (diskstat.reads - prev_diskstat.operations_read) : 0); rrddim_set(st, "writes", (diskstat.writes - prev_diskstat.operations_write) ? (cur_diskstat.duration_write_ns - prev_diskstat.duration_write_ns) / (diskstat.writes - prev_diskstat.operations_write) : 0); rrdset_done(st); // -------------------------------------------------------------------- st = rrdset_find_bytype("disk_avgsz", diskstat.name); if (unlikely(!st)) { st = rrdset_create("disk_avgsz", diskstat.name, NULL, diskstat.name, "disk.avgsz", "Average Completed I/O Operation Bandwidth", "kilobytes per operation", 2006, update_every, RRDSET_TYPE_AREA); st->isdetail = 1; rrddim_add(st, "reads", NULL, 1, 1024, RRDDIM_ABSOLUTE); rrddim_add(st, "writes", NULL, -1, 1024, RRDDIM_ABSOLUTE); } else rrdset_next(st); rrddim_set(st, "reads", (diskstat.reads - prev_diskstat.operations_read) ? (diskstat.bytes_read - prev_diskstat.bytes_read) / (diskstat.reads - prev_diskstat.operations_read) : 0); rrddim_set(st, "writes", (diskstat.writes - prev_diskstat.operations_write) ? (diskstat.bytes_write - prev_diskstat.bytes_write) / (diskstat.writes - prev_diskstat.operations_write) : 0); rrdset_done(st); // -------------------------------------------------------------------- st = rrdset_find_bytype("disk_svctm", diskstat.name); if (unlikely(!st)) { st = rrdset_create("disk_svctm", diskstat.name, NULL, diskstat.name, "disk.svctm", "Average Service Time", "ms per operation", 2007, update_every, RRDSET_TYPE_LINE); st->isdetail = 1; rrddim_add(st, "svctm", NULL, 1, 1000000, RRDDIM_ABSOLUTE); } else rrdset_next(st); rrddim_set(st, "svctm", ((diskstat.reads - prev_diskstat.operations_read) + (diskstat.writes - prev_diskstat.operations_write)) ? (cur_diskstat.busy_time_ns - prev_diskstat.busy_time_ns) / ((diskstat.reads - prev_diskstat.operations_read) + (diskstat.writes - prev_diskstat.operations_write)) : 0); rrdset_done(st); } } /* Release. */ CFRelease(properties); } /* Release. */ IOObjectRelease(drive); } IOIteratorReset(drive_list); /* Release. */ IOObjectRelease(drive_list); } if (likely(do_io)) { st = rrdset_find_bytype("system", "io"); if (unlikely(!st)) { st = rrdset_create("system", "io", NULL, "disk", NULL, "Disk I/O", "kilobytes/s", 150, update_every, RRDSET_TYPE_AREA); rrddim_add(st, "in", NULL, 1, 1024, RRDDIM_INCREMENTAL); rrddim_add(st, "out", NULL, -1, 1024, RRDDIM_INCREMENTAL); } else rrdset_next(st); rrddim_set(st, "in", total_disk_reads); rrddim_set(st, "out", total_disk_writes); rrdset_done(st); } // Can be merged with FreeBSD plugin // -------------------------------------------------------------------------- if (likely(do_space || do_inodes)) { // there is no mount info in sysctl MIBs if (unlikely(!(mntsize = getmntinfo(&mntbuf, MNT_NOWAIT)))) { error("MACOS: getmntinfo() failed"); do_space = 0; error("DISABLED: disk_space.X"); do_inodes = 0; error("DISABLED: disk_inodes.X"); } else { for (i = 0; i < mntsize; i++) { if (mntbuf[i].f_flags == MNT_RDONLY || mntbuf[i].f_blocks == 0 || // taken from gnulib/mountlist.c and shortened to FreeBSD related fstypes strcmp(mntbuf[i].f_fstypename, "autofs") == 0 || strcmp(mntbuf[i].f_fstypename, "procfs") == 0 || strcmp(mntbuf[i].f_fstypename, "subfs") == 0 || strcmp(mntbuf[i].f_fstypename, "devfs") == 0 || strcmp(mntbuf[i].f_fstypename, "none") == 0) continue; // -------------------------------------------------------------------------- if (likely(do_space)) { st = rrdset_find_bytype("disk_space", mntbuf[i].f_mntonname); if (unlikely(!st)) { snprintfz(title, 4096, "Disk Space Usage for %s [%s]", mntbuf[i].f_mntonname, mntbuf[i].f_mntfromname); st = rrdset_create("disk_space", mntbuf[i].f_mntonname, NULL, mntbuf[i].f_mntonname, "disk.space", title, "GB", 2023, update_every, RRDSET_TYPE_STACKED); rrddim_add(st, "avail", NULL, mntbuf[i].f_bsize, GIGA_FACTOR, RRDDIM_ABSOLUTE); rrddim_add(st, "used", NULL, mntbuf[i].f_bsize, GIGA_FACTOR, RRDDIM_ABSOLUTE); rrddim_add(st, "reserved_for_root", "reserved for root", mntbuf[i].f_bsize, GIGA_FACTOR, RRDDIM_ABSOLUTE); } else rrdset_next(st); rrddim_set(st, "avail", (collected_number) mntbuf[i].f_bavail); rrddim_set(st, "used", (collected_number) (mntbuf[i].f_blocks - mntbuf[i].f_bfree)); rrddim_set(st, "reserved_for_root", (collected_number) (mntbuf[i].f_bfree - mntbuf[i].f_bavail)); rrdset_done(st); } // -------------------------------------------------------------------------- if (likely(do_inodes)) { st = rrdset_find_bytype("disk_inodes", mntbuf[i].f_mntonname); if (unlikely(!st)) { snprintfz(title, 4096, "Disk Files (inodes) Usage for %s [%s]", mntbuf[i].f_mntonname, mntbuf[i].f_mntfromname); st = rrdset_create("disk_inodes", mntbuf[i].f_mntonname, NULL, mntbuf[i].f_mntonname, "disk.inodes", title, "Inodes", 2024, update_every, RRDSET_TYPE_STACKED); rrddim_add(st, "avail", NULL, 1, 1, RRDDIM_ABSOLUTE); rrddim_add(st, "used", NULL, 1, 1, RRDDIM_ABSOLUTE); rrddim_add(st, "reserved_for_root", "reserved for root", 1, 1, RRDDIM_ABSOLUTE); } else rrdset_next(st); rrddim_set(st, "avail", (collected_number) mntbuf[i].f_ffree); rrddim_set(st, "used", (collected_number) (mntbuf[i].f_files - mntbuf[i].f_ffree)); rrdset_done(st); } } } } // Can be merged with FreeBSD plugin // -------------------------------------------------------------------- if (likely(do_bandwidth)) { if (unlikely(getifaddrs(&ifap))) { error("MACOS: getifaddrs()"); do_bandwidth = 0; error("DISABLED: system.ipv4"); } else { for (ifa = ifap; ifa; ifa = ifa->ifa_next) { if (ifa->ifa_addr->sa_family != AF_LINK) continue; // -------------------------------------------------------------------- st = rrdset_find_bytype("net", ifa->ifa_name); if (unlikely(!st)) { st = rrdset_create("net", ifa->ifa_name, NULL, ifa->ifa_name, "net.net", "Bandwidth", "kilobits/s", 7000, update_every, RRDSET_TYPE_AREA); rrddim_add(st, "received", NULL, 8, 1024, RRDDIM_INCREMENTAL); rrddim_add(st, "sent", NULL, -8, 1024, RRDDIM_INCREMENTAL); } else rrdset_next(st); rrddim_set(st, "received", IFA_DATA(ibytes)); rrddim_set(st, "sent", IFA_DATA(obytes)); rrdset_done(st); // -------------------------------------------------------------------- st = rrdset_find_bytype("net_packets", ifa->ifa_name); if (unlikely(!st)) { st = rrdset_create("net_packets", ifa->ifa_name, NULL, ifa->ifa_name, "net.packets", "Packets", "packets/s", 7001, update_every, RRDSET_TYPE_LINE); st->isdetail = 1; rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL); rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL); rrddim_add(st, "multicast_received", NULL, 1, 1, RRDDIM_INCREMENTAL); rrddim_add(st, "multicast_sent", NULL, -1, 1, RRDDIM_INCREMENTAL); } else rrdset_next(st); rrddim_set(st, "received", IFA_DATA(ipackets)); rrddim_set(st, "sent", IFA_DATA(opackets)); rrddim_set(st, "multicast_received", IFA_DATA(imcasts)); rrddim_set(st, "multicast_sent", IFA_DATA(omcasts)); rrdset_done(st); // -------------------------------------------------------------------- st = rrdset_find_bytype("net_errors", ifa->ifa_name); if (unlikely(!st)) { st = rrdset_create("net_errors", ifa->ifa_name, NULL, ifa->ifa_name, "net.errors", "Interface Errors", "errors/s", 7002, update_every, RRDSET_TYPE_LINE); st->isdetail = 1; rrddim_add(st, "inbound", NULL, 1, 1, RRDDIM_INCREMENTAL); rrddim_add(st, "outbound", NULL, -1, 1, RRDDIM_INCREMENTAL); } else rrdset_next(st); rrddim_set(st, "inbound", IFA_DATA(ierrors)); rrddim_set(st, "outbound", IFA_DATA(oerrors)); rrdset_done(st); // -------------------------------------------------------------------- st = rrdset_find_bytype("net_drops", ifa->ifa_name); if (unlikely(!st)) { st = rrdset_create("net_drops", ifa->ifa_name, NULL, ifa->ifa_name, "net.drops", "Interface Drops", "drops/s", 7003, update_every, RRDSET_TYPE_LINE); st->isdetail = 1; rrddim_add(st, "inbound", NULL, 1, 1, RRDDIM_INCREMENTAL); } else rrdset_next(st); rrddim_set(st, "inbound", IFA_DATA(iqdrops)); rrdset_done(st); // -------------------------------------------------------------------- st = rrdset_find_bytype("net_events", ifa->ifa_name); if (unlikely(!st)) { st = rrdset_create("net_events", ifa->ifa_name, NULL, ifa->ifa_name, "net.events", "Network Interface Events", "events/s", 7006, update_every, RRDSET_TYPE_LINE); st->isdetail = 1; rrddim_add(st, "frames", NULL, 1, 1, RRDDIM_INCREMENTAL); rrddim_add(st, "collisions", NULL, -1, 1, RRDDIM_INCREMENTAL); rrddim_add(st, "carrier", NULL, -1, 1, RRDDIM_INCREMENTAL); } else rrdset_next(st); rrddim_set(st, "collisions", IFA_DATA(collisions)); rrdset_done(st); } freeifaddrs(ifap); } } return 0; }
static int disk_read (void) { #if HAVE_IOKIT_IOKITLIB_H io_registry_entry_t disk; io_registry_entry_t disk_child; io_iterator_t disk_list; CFMutableDictionaryRef props_dict, child_dict; CFDictionaryRef stats_dict; CFStringRef tmp_cf_string_ref; kern_return_t status; signed long long read_ops, read_byt, read_tme; signed long long write_ops, write_byt, write_tme; int disk_major, disk_minor; char disk_name[DATA_MAX_NAME_LEN]; char child_disk_name_bsd[DATA_MAX_NAME_LEN], props_disk_name_bsd[DATA_MAX_NAME_LEN]; /* Get the list of all disk objects. */ if (IOServiceGetMatchingServices (io_master_port, IOServiceMatching (kIOBlockStorageDriverClass), &disk_list) != kIOReturnSuccess) { ERROR ("disk plugin: IOServiceGetMatchingServices failed."); return (-1); } while ((disk = IOIteratorNext (disk_list)) != 0) { props_dict = NULL; stats_dict = NULL; child_dict = NULL; /* get child of disk entry and corresponding property dictionary */ if ((status = IORegistryEntryGetChildEntry (disk, kIOServicePlane, &disk_child)) != kIOReturnSuccess) { /* This fails for example for DVD/CD drives, which we want to ignore anyway */ DEBUG ("IORegistryEntryGetChildEntry (disk) failed: 0x%08x", status); IOObjectRelease (disk); continue; } if (IORegistryEntryCreateCFProperties (disk_child, (CFMutableDictionaryRef *) &child_dict, kCFAllocatorDefault, kNilOptions) != kIOReturnSuccess || child_dict == NULL) { ERROR ("disk plugin: IORegistryEntryCreateCFProperties (disk_child) failed."); IOObjectRelease (disk_child); IOObjectRelease (disk); continue; } /* extract name and major/minor numbers */ memset (child_disk_name_bsd, 0, sizeof (child_disk_name_bsd)); tmp_cf_string_ref = (CFStringRef) CFDictionaryGetValue (child_dict, CFSTR(kIOBSDNameKey)); if (tmp_cf_string_ref) { assert (CFGetTypeID (tmp_cf_string_ref) == CFStringGetTypeID ()); CFStringGetCString (tmp_cf_string_ref, child_disk_name_bsd, sizeof (child_disk_name_bsd), kCFStringEncodingUTF8); } disk_major = (int) dict_get_value (child_dict, kIOBSDMajorKey); disk_minor = (int) dict_get_value (child_dict, kIOBSDMinorKey); DEBUG ("disk plugin: child_disk_name_bsd=\"%s\" major=%d minor=%d", child_disk_name_bsd, disk_major, disk_minor); CFRelease (child_dict); IOObjectRelease (disk_child); /* get property dictionary of the disk entry itself */ if (IORegistryEntryCreateCFProperties (disk, (CFMutableDictionaryRef *) &props_dict, kCFAllocatorDefault, kNilOptions) != kIOReturnSuccess || props_dict == NULL) { ERROR ("disk-plugin: IORegistryEntryCreateCFProperties failed."); IOObjectRelease (disk); continue; } /* extract name and stats dictionary */ memset (props_disk_name_bsd, 0, sizeof (props_disk_name_bsd)); tmp_cf_string_ref = (CFStringRef) CFDictionaryGetValue (props_dict, CFSTR(kIOBSDNameKey)); if (tmp_cf_string_ref) { assert (CFGetTypeID (tmp_cf_string_ref) == CFStringGetTypeID ()); CFStringGetCString (tmp_cf_string_ref, props_disk_name_bsd, sizeof (props_disk_name_bsd), kCFStringEncodingUTF8); } stats_dict = (CFDictionaryRef) CFDictionaryGetValue (props_dict, CFSTR (kIOBlockStorageDriverStatisticsKey)); if (stats_dict == NULL) { ERROR ("disk plugin: CFDictionaryGetValue (%s) failed.", kIOBlockStorageDriverStatisticsKey); CFRelease (props_dict); IOObjectRelease (disk); continue; } DEBUG ("disk plugin: props_disk_name_bsd=\"%s\"", props_disk_name_bsd); /* choose name */ if (use_bsd_name) { if (child_disk_name_bsd[0] != 0) sstrncpy (disk_name, child_disk_name_bsd, sizeof (disk_name)); else if (props_disk_name_bsd[0] != 0) sstrncpy (disk_name, props_disk_name_bsd, sizeof (disk_name)); else { ERROR ("disk plugin: can't find bsd disk name."); ssnprintf (disk_name, sizeof (disk_name), "%i-%i", disk_major, disk_minor); } } else ssnprintf (disk_name, sizeof (disk_name), "%i-%i", disk_major, disk_minor); /* extract the stats */ 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); CFRelease (props_dict); IOObjectRelease (disk); /* and submit */ DEBUG ("disk plugin: disk_name = \"%s\"", disk_name); if ((read_byt != -1LL) || (write_byt != -1LL)) disk_submit (disk_name, "disk_octets", read_byt, write_byt); if ((read_ops != -1LL) || (write_ops != -1LL)) disk_submit (disk_name, "disk_ops", read_ops, write_ops); if ((read_tme != -1LL) || (write_tme != -1LL)) disk_submit (disk_name, "disk_time", read_tme / 1000, write_tme / 1000); } IOObjectRelease (disk_list); /* #endif HAVE_IOKIT_IOKITLIB_H */ #elif KERNEL_FREEBSD int retry, dirty; void *snap = NULL; struct devstat *snap_iter; struct gident *geom_id; const char *disk_name; long double read_time, write_time; for (retry = 0, dirty = 1; retry < 5 && dirty == 1; retry++) { if (snap != NULL) geom_stats_snapshot_free(snap); /* Get a fresh copy of stats snapshot */ snap = geom_stats_snapshot_get(); if (snap == NULL) { ERROR("disk plugin: geom_stats_snapshot_get() failed."); return (-1); } /* Check if we have dirty read from this snapshot */ dirty = 0; geom_stats_snapshot_reset(snap); while ((snap_iter = geom_stats_snapshot_next(snap)) != NULL) { if (snap_iter->id == NULL) continue; geom_id = geom_lookupid(&geom_tree, snap_iter->id); /* New device? refresh GEOM tree */ if (geom_id == NULL) { geom_deletetree(&geom_tree); if (geom_gettree(&geom_tree) != 0) { ERROR("disk plugin: geom_gettree() failed"); geom_stats_snapshot_free(snap); return (-1); } geom_id = geom_lookupid(&geom_tree, snap_iter->id); } /* * This should be rare: the device come right before we take the * snapshot and went away right after it. We will handle this * case later, so don't mark dirty but silently ignore it. */ if (geom_id == NULL) continue; /* Only collect PROVIDER data */ if (geom_id->lg_what != ISPROVIDER) continue; /* Only collect data when rank is 1 (physical devices) */ if (((struct gprovider *)(geom_id->lg_ptr))->lg_geom->lg_rank != 1) continue; /* Check if this is a dirty read quit for another try */ if (snap_iter->sequence0 != snap_iter->sequence1) { dirty = 1; break; } } } /* Reset iterator */ geom_stats_snapshot_reset(snap); for (;;) { snap_iter = geom_stats_snapshot_next(snap); if (snap_iter == NULL) break; if (snap_iter->id == NULL) continue; geom_id = geom_lookupid(&geom_tree, snap_iter->id); if (geom_id == NULL) continue; if (geom_id->lg_what != ISPROVIDER) continue; if (((struct gprovider *)(geom_id->lg_ptr))->lg_geom->lg_rank != 1) continue; /* Skip dirty reads, if present */ if (dirty && (snap_iter->sequence0 != snap_iter->sequence1)) continue; disk_name = ((struct gprovider *)geom_id->lg_ptr)->lg_name; if ((snap_iter->bytes[DEVSTAT_READ] != 0) || (snap_iter->bytes[DEVSTAT_WRITE] != 0)) { disk_submit(disk_name, "disk_octets", (derive_t)snap_iter->bytes[DEVSTAT_READ], (derive_t)snap_iter->bytes[DEVSTAT_WRITE]); } if ((snap_iter->operations[DEVSTAT_READ] != 0) || (snap_iter->operations[DEVSTAT_WRITE] != 0)) { disk_submit(disk_name, "disk_ops", (derive_t)snap_iter->operations[DEVSTAT_READ], (derive_t)snap_iter->operations[DEVSTAT_WRITE]); } read_time = devstat_compute_etime(&snap_iter->duration[DEVSTAT_READ], NULL); write_time = devstat_compute_etime(&snap_iter->duration[DEVSTAT_WRITE], NULL); if ((read_time != 0) || (write_time != 0)) { disk_submit (disk_name, "disk_time", (derive_t)(read_time*1000), (derive_t)(write_time*1000)); } } geom_stats_snapshot_free(snap); #elif KERNEL_LINUX FILE *fh; char buffer[1024]; char *fields[32]; int numfields; int fieldshift = 0; int minor = 0; derive_t read_sectors = 0; derive_t write_sectors = 0; derive_t read_ops = 0; derive_t read_merged = 0; derive_t read_time = 0; derive_t write_ops = 0; derive_t write_merged = 0; derive_t write_time = 0; gauge_t in_progress = NAN; derive_t io_time = 0; derive_t weighted_time = 0; int is_disk = 0; diskstats_t *ds, *pre_ds; if ((fh = fopen ("/proc/diskstats", "r")) == NULL) { fh = fopen ("/proc/partitions", "r"); if (fh == NULL) { ERROR ("disk plugin: fopen (/proc/{diskstats,partitions}) failed."); return (-1); } /* Kernel is 2.4.* */ fieldshift = 1; } #if HAVE_LIBUDEV handle_udev = udev_new(); #endif while (fgets (buffer, sizeof (buffer), fh) != NULL) { char *disk_name; char *output_name; numfields = strsplit (buffer, fields, 32); if ((numfields != (14 + fieldshift)) && (numfields != 7)) continue; minor = atoll (fields[1]); disk_name = fields[2 + fieldshift]; for (ds = disklist, pre_ds = disklist; ds != NULL; pre_ds = ds, ds = ds->next) if (strcmp (disk_name, ds->name) == 0) break; if (ds == NULL) { if ((ds = (diskstats_t *) calloc (1, sizeof (diskstats_t))) == NULL) continue; if ((ds->name = strdup (disk_name)) == NULL) { free (ds); continue; } if (pre_ds == NULL) disklist = ds; else pre_ds->next = ds; } is_disk = 0; if (numfields == 7) { /* Kernel 2.6, Partition */ read_ops = atoll (fields[3]); read_sectors = atoll (fields[4]); write_ops = atoll (fields[5]); write_sectors = atoll (fields[6]); } else if (numfields == (14 + fieldshift)) { read_ops = atoll (fields[3 + fieldshift]); write_ops = atoll (fields[7 + fieldshift]); read_sectors = atoll (fields[5 + fieldshift]); write_sectors = atoll (fields[9 + fieldshift]); if ((fieldshift == 0) || (minor == 0)) { is_disk = 1; read_merged = atoll (fields[4 + fieldshift]); read_time = atoll (fields[6 + fieldshift]); write_merged = atoll (fields[8 + fieldshift]); write_time = atoll (fields[10+ fieldshift]); in_progress = atof (fields[11 + fieldshift]); io_time = atof (fields[12 + fieldshift]); weighted_time = atof (fields[13 + fieldshift]); } } else { DEBUG ("numfields = %i; => unknown file format.", numfields); continue; } { derive_t diff_read_sectors; derive_t diff_write_sectors; /* If the counter wraps around, it's only 32 bits.. */ if (read_sectors < ds->read_sectors) diff_read_sectors = 1 + read_sectors + (UINT_MAX - ds->read_sectors); else diff_read_sectors = read_sectors - ds->read_sectors; if (write_sectors < ds->write_sectors) diff_write_sectors = 1 + write_sectors + (UINT_MAX - ds->write_sectors); else diff_write_sectors = write_sectors - ds->write_sectors; ds->read_bytes += 512 * diff_read_sectors; ds->write_bytes += 512 * diff_write_sectors; ds->read_sectors = read_sectors; ds->write_sectors = write_sectors; } /* Calculate the average time an io-op needs to complete */ if (is_disk) { derive_t diff_read_ops; derive_t diff_write_ops; derive_t diff_read_time; derive_t diff_write_time; if (read_ops < ds->read_ops) diff_read_ops = 1 + read_ops + (UINT_MAX - ds->read_ops); else diff_read_ops = read_ops - ds->read_ops; DEBUG ("disk plugin: disk_name = %s; read_ops = %"PRIi64"; " "ds->read_ops = %"PRIi64"; diff_read_ops = %"PRIi64";", disk_name, read_ops, ds->read_ops, diff_read_ops); if (write_ops < ds->write_ops) diff_write_ops = 1 + write_ops + (UINT_MAX - ds->write_ops); else diff_write_ops = write_ops - ds->write_ops; if (read_time < ds->read_time) diff_read_time = 1 + read_time + (UINT_MAX - ds->read_time); else diff_read_time = read_time - ds->read_time; if (write_time < ds->write_time) diff_write_time = 1 + write_time + (UINT_MAX - ds->write_time); else diff_write_time = write_time - ds->write_time; if (diff_read_ops != 0) ds->avg_read_time += disk_calc_time_incr ( diff_read_time, diff_read_ops); if (diff_write_ops != 0) ds->avg_write_time += disk_calc_time_incr ( diff_write_time, diff_write_ops); ds->read_ops = read_ops; ds->read_time = read_time; ds->write_ops = write_ops; ds->write_time = write_time; } /* if (is_disk) */ /* Don't write to the RRDs if we've just started.. */ ds->poll_count++; if (ds->poll_count <= 2) { DEBUG ("disk plugin: (ds->poll_count = %i) <= " "(min_poll_count = 2); => Not writing.", ds->poll_count); continue; } if ((read_ops == 0) && (write_ops == 0)) { DEBUG ("disk plugin: ((read_ops == 0) && " "(write_ops == 0)); => Not writing."); continue; } output_name = disk_name; #if HAVE_LIBUDEV char *alt_name = disk_udev_attr_name (handle_udev, disk_name, conf_udev_name_attr); if (alt_name != NULL) output_name = alt_name; #endif if ((ds->read_bytes != 0) || (ds->write_bytes != 0)) disk_submit (output_name, "disk_octets", ds->read_bytes, ds->write_bytes); if ((ds->read_ops != 0) || (ds->write_ops != 0)) disk_submit (output_name, "disk_ops", read_ops, write_ops); if ((ds->avg_read_time != 0) || (ds->avg_write_time != 0)) disk_submit (output_name, "disk_time", ds->avg_read_time, ds->avg_write_time); if (is_disk) { disk_submit (output_name, "disk_merged", read_merged, write_merged); submit_in_progress (output_name, in_progress); submit_io_time (output_name, io_time, weighted_time); } /* if (is_disk) */ #if HAVE_LIBUDEV /* release udev-based alternate name, if allocated */ sfree (alt_name); #endif } /* while (fgets (buffer, sizeof (buffer), fh) != NULL) */ #if HAVE_LIBUDEV udev_unref(handle_udev); #endif fclose (fh); /* #endif defined(KERNEL_LINUX) */ #elif HAVE_LIBKSTAT # if HAVE_KSTAT_IO_T_WRITES && HAVE_KSTAT_IO_T_NWRITES && HAVE_KSTAT_IO_T_WTIME # define KIO_ROCTETS reads # define KIO_WOCTETS writes # define KIO_ROPS nreads # define KIO_WOPS nwrites # define KIO_RTIME rtime # define KIO_WTIME wtime # elif HAVE_KSTAT_IO_T_NWRITTEN && HAVE_KSTAT_IO_T_WRITES && HAVE_KSTAT_IO_T_WTIME # define KIO_ROCTETS nread # define KIO_WOCTETS nwritten # define KIO_ROPS reads # define KIO_WOPS writes # define KIO_RTIME rtime # define KIO_WTIME wtime # else # error "kstat_io_t does not have the required members" # endif static kstat_io_t kio; int i; if (kc == NULL) return (-1); for (i = 0; i < numdisk; i++) { if (kstat_read (kc, ksp[i], &kio) == -1) continue; if (strncmp (ksp[i]->ks_class, "disk", 4) == 0) { disk_submit (ksp[i]->ks_name, "disk_octets", kio.KIO_ROCTETS, kio.KIO_WOCTETS); disk_submit (ksp[i]->ks_name, "disk_ops", kio.KIO_ROPS, kio.KIO_WOPS); /* FIXME: Convert this to microseconds if necessary */ disk_submit (ksp[i]->ks_name, "disk_time", kio.KIO_RTIME, kio.KIO_WTIME); } else if (strncmp (ksp[i]->ks_class, "partition", 9) == 0) { disk_submit (ksp[i]->ks_name, "disk_octets", kio.KIO_ROCTETS, kio.KIO_WOCTETS); disk_submit (ksp[i]->ks_name, "disk_ops", kio.KIO_ROPS, kio.KIO_WOPS); } } /* #endif defined(HAVE_LIBKSTAT) */ #elif defined(HAVE_LIBSTATGRAB) sg_disk_io_stats *ds; # if HAVE_LIBSTATGRAB_0_90 size_t disks; # else int disks; #endif int counter; char name[DATA_MAX_NAME_LEN]; if ((ds = sg_get_disk_io_stats(&disks)) == NULL) return (0); for (counter=0; counter < disks; counter++) { strncpy(name, ds->disk_name, sizeof(name)); name[sizeof(name)-1] = '\0'; /* strncpy doesn't terminate longer strings */ disk_submit (name, "disk_octets", ds->read_bytes, ds->write_bytes); ds++; } /* #endif defined(HAVE_LIBSTATGRAB) */ #elif defined(HAVE_PERFSTAT) derive_t read_sectors; derive_t write_sectors; derive_t read_time; derive_t write_time; derive_t read_ops; derive_t write_ops; perfstat_id_t firstpath; int rnumdisk; int i; if ((numdisk = perfstat_disk(NULL, NULL, sizeof(perfstat_disk_t), 0)) < 0) { char errbuf[1024]; WARNING ("disk plugin: perfstat_disk: %s", sstrerror (errno, errbuf, sizeof (errbuf))); return (-1); } if (numdisk != pnumdisk || stat_disk==NULL) { if (stat_disk!=NULL) free(stat_disk); stat_disk = (perfstat_disk_t *)calloc(numdisk, sizeof(perfstat_disk_t)); } pnumdisk = numdisk; firstpath.name[0]='\0'; if ((rnumdisk = perfstat_disk(&firstpath, stat_disk, sizeof(perfstat_disk_t), numdisk)) < 0) { char errbuf[1024]; WARNING ("disk plugin: perfstat_disk : %s", sstrerror (errno, errbuf, sizeof (errbuf))); return (-1); } for (i = 0; i < rnumdisk; i++) { read_sectors = stat_disk[i].rblks*stat_disk[i].bsize; write_sectors = stat_disk[i].wblks*stat_disk[i].bsize; disk_submit (stat_disk[i].name, "disk_octets", read_sectors, write_sectors); read_ops = stat_disk[i].xrate; write_ops = stat_disk[i].xfers - stat_disk[i].xrate; disk_submit (stat_disk[i].name, "disk_ops", read_ops, write_ops); read_time = stat_disk[i].rserv; read_time *= ((double)(_system_configuration.Xint)/(double)(_system_configuration.Xfrac)) / 1000000.0; write_time = stat_disk[i].wserv; write_time *= ((double)(_system_configuration.Xint)/(double)(_system_configuration.Xfrac)) / 1000000.0; disk_submit (stat_disk[i].name, "disk_time", read_time, write_time); } #endif /* defined(HAVE_PERFSTAT) */ return (0); } /* int disk_read */
CFStringRef AoEProperties::get_targets_bsd_name(int nTargetNumber) { io_registry_entry_t ControllerInterface; io_iterator_t Controllers; io_registry_entry_t Controller; io_registry_entry_t Device; io_registry_entry_t DiskDriver; io_registry_entry_t StorageDevice; io_registry_entry_t StorageDriver; io_registry_entry_t Disk; CFStringRef Name; CFNumberRef Target; int nTargetNum; DiskDriver = NULL; StorageDevice = NULL; StorageDriver = NULL; Device = NULL; Disk = NULL; ControllerInterface = NULL; Controllers = NULL; Controller = NULL; Name = NULL; if ( 0==m_OurObject ) return 0; IORegistryEntryGetChildEntry(m_OurObject, kIOServicePlane, &ControllerInterface); IORegistryEntryGetChildIterator(ControllerInterface, kIOServicePlane, &Controllers); // First, find the Controller... while ( (Controller = IOIteratorNext(Controllers)) ) { Target = (CFNumberRef) IORegistryEntryCreateCFProperty(Controller, CFSTR(TARGET_PROPERTY), kCFAllocatorDefault, 0); CFNumberGetValue(Target, kCFNumberIntType, &nTargetNum); CFRelease(Target); if ( nTargetNumber==nTargetNum ) { // Now we have the controller, descend through children IORegistryEntryGetChildEntry(Controller, kIOServicePlane, &Device); IORegistryEntryGetChildEntry(Device, kIOServicePlane, &DiskDriver); IORegistryEntryGetChildEntry(DiskDriver, kIOServicePlane, &StorageDevice); IORegistryEntryGetChildEntry(StorageDevice, kIOServicePlane, &StorageDriver); IORegistryEntryGetChildEntry(StorageDriver, kIOServicePlane, &Disk); if ( Disk ) { Name = (CFStringRef) IORegistryEntryCreateCFProperty(Disk, CFSTR("BSD Name"), kCFAllocatorDefault, 0); if ( Name ) CFRetain(Name); } break; } IOObjectRelease(Controller); } if ( Controllers ) IOObjectRelease(Controllers); if ( DiskDriver ) IOObjectRelease(DiskDriver); if ( StorageDevice ) IOObjectRelease(StorageDevice); if ( StorageDriver ) IOObjectRelease(StorageDriver); if ( Disk ) IOObjectRelease(Disk); if ( Device ) IOObjectRelease(Device); if ( ControllerInterface ) IOObjectRelease(ControllerInterface); return (Name && (nTargetNum==nTargetNumber)) ? Name : NULL; }