diff --git a/ksysguardd/Linux/diskstat.c b/ksysguardd/Linux/diskstat.c index 3b849aaa..0f9f5af9 100644 --- a/ksysguardd/Linux/diskstat.c +++ b/ksysguardd/Linux/diskstat.c @@ -1,409 +1,410 @@ /* KSysGuard, the KDE System Guard Copyright (c) 2001 Tobias Koenig This program is free software; you can redistribute it and/or modify it under the terms of version 2 of the GNU General Public License as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #define _XOPEN_SOURCE /* isascii */ #include #include #include #include #include #include #include #include #include "Command.h" #include "ccont.h" #include "diskstat.h" #include "ksysguardd.h" typedef struct { char device[ 256 ]; char mntpnt[ 256 ]; struct statvfs statvfs; } DiskInfo; static CONTAINER DiskStatList = 0; static CONTAINER OldDiskStatList = 0; static struct SensorModul* DiskStatSM; char *getMntPnt( const char* cmd ); static void sanitize(char *str) { if(str == NULL) return; while (*str != 0) { if(*str == '\t' || *str == '\n' || *str == '\r' || *str == ' ' || !isascii(*str) ) *str = '?'; ++str; } } char *getMntPnt( const char* cmd ) { static char device[ 1025 ]; char* ptr; memset( device, 0, sizeof( device ) ); sscanf( cmd, "partitions%1024s", device ); ptr = strrchr( device, '/' ); if( ptr ) { *ptr = '\0'; } return (char*)device; } unsigned long getTotal( const char* mntpnt ) { DiskInfo* disk_info; unsigned long total = 0; int is_all = strcmp( mntpnt, "/all" ) == 0; for ( disk_info = first_ctnr( DiskStatList ); disk_info; disk_info = next_ctnr( DiskStatList ) ) { if ( !strcmp( mntpnt, disk_info->mntpnt ) || is_all ) { unsigned long totalSizeKB = disk_info->statvfs.f_blocks * (disk_info->statvfs.f_frsize/1024); if ( is_all ) { total += totalSizeKB; } else { return totalSizeKB; } } } return total; } /* ----------------------------- public part ------------------------------- */ static char monitor[ 1024 ]; static void registerMonitors(const char* mntpnt) { snprintf( monitor, sizeof( monitor ), "partitions%s/usedspace", mntpnt ); registerMonitor( monitor, "integer", printDiskStatUsed, printDiskStatUsedInfo, DiskStatSM ); snprintf( monitor, sizeof( monitor ), "partitions%s/freespace", mntpnt ); registerMonitor( monitor, "integer", printDiskStatFree, printDiskStatFreeInfo, DiskStatSM ); snprintf( monitor, sizeof( monitor ), "partitions%s/filllevel", mntpnt ); registerMonitor( monitor, "integer", printDiskStatPercent, printDiskStatPercentInfo, DiskStatSM ); snprintf( monitor, sizeof( monitor ), "partitions%s/total", mntpnt ); registerMonitor( monitor, "integer", printDiskStatTotal, printDiskStatTotalInfo, DiskStatSM ); } static void removeMonitors(const char* mntpnt) { snprintf( monitor, sizeof( monitor ), "partitions%s/usedspace", mntpnt ); removeMonitor( monitor ); snprintf( monitor, sizeof( monitor ), "partitions%s/freespace", mntpnt ); removeMonitor( monitor ); snprintf( monitor, sizeof( monitor ), "partitions%s/filllevel", mntpnt ); removeMonitor( monitor ); snprintf( monitor, sizeof( monitor ), "partitions%s/total", mntpnt ); removeMonitor( monitor ); } void initDiskStat( struct SensorModul* sm ) { DiskInfo* disk_info; DiskStatList = NULL; OldDiskStatList = NULL; DiskStatSM = sm; if ( updateDiskStat() < 0 ) return; registerMonitor( "partitions/list", "listview", printDiskStat, printDiskStatInfo, sm ); registerMonitors( "/all" ); for ( disk_info = first_ctnr( DiskStatList ); disk_info; disk_info = next_ctnr( DiskStatList ) ) { registerMonitors(disk_info->mntpnt); } } void exitDiskStat( void ) { DiskInfo* disk_info; removeMonitor( "partitions/list" ); removeMonitors( "/all" ); for ( disk_info = first_ctnr( DiskStatList ); disk_info; disk_info = next_ctnr( DiskStatList ) ) { removeMonitors(disk_info->mntpnt); } destr_ctnr( DiskStatList, free ); if(OldDiskStatList) destr_ctnr( OldDiskStatList, free ); } void checkDiskStat( void ) { updateDiskStat(); DiskInfo* disk_info_new; DiskInfo* disk_info_old; int changed = 0; for ( disk_info_new = first_ctnr( DiskStatList ); disk_info_new; disk_info_new = next_ctnr( DiskStatList ) ) { int found = 0; for ( disk_info_old = first_ctnr( OldDiskStatList ); disk_info_old; disk_info_old = next_ctnr( OldDiskStatList ) ) { if(strcmp(disk_info_new->mntpnt, disk_info_old->mntpnt) == 0) { free( remove_ctnr( OldDiskStatList ) ); found = 1; continue; } } if(!found) { /* register all the devices that did not exist before*/ registerMonitors(disk_info_new->mntpnt); changed++; } } /*Now remove all the devices that do not exist anymore*/ for ( disk_info_old = first_ctnr( OldDiskStatList ); disk_info_old; disk_info_old = next_ctnr( OldDiskStatList ) ) { removeMonitors(disk_info_old->mntpnt); changed++; } destr_ctnr( OldDiskStatList, free ); OldDiskStatList = NULL; updateDiskStat(); if(changed) print_error( "RECONFIGURE" ); /*Let ksysguard know that we've added a sensor*/ } int updateDiskStat( void ) { DiskInfo *disk_info; FILE *fh; struct mntent *mnt_info; if ( ( fh = setmntent( "/etc/mtab", "r" ) ) == NULL ) { print_error( "Cannot open \'/etc/mtab\'!\n" ); return -1; } if(OldDiskStatList == 0) { OldDiskStatList = DiskStatList; DiskStatList = new_ctnr(); } else { empty_ctnr(DiskStatList); } while ( ( mnt_info = getmntent( fh ) ) != NULL ) { /* * An entry which device name doesn't start with a '/' is * either a dummy file system or a network file system. * Add special handling for smbfs and cifs as is done by * coreutils as well. */ if ( (mnt_info->mnt_fsname[0] != '/') || + !strncmp( mnt_info->mnt_fsname, "/dev/loop", 9 ) || !strcmp( mnt_info->mnt_type, "smbfs" ) || !strcmp( mnt_info->mnt_type, "cifs" ) || !strcmp( mnt_info->mnt_type, "proc" ) || !strcmp( mnt_info->mnt_type, "devfs" ) || !strcmp( mnt_info->mnt_type, "usbfs" ) || !strcmp( mnt_info->mnt_type, "sysfs" ) || !strcmp( mnt_info->mnt_type, "tmpfs" ) || !strcmp( mnt_info->mnt_type, "devpts" ) ) continue; /* Skip these file systems */ if ( ( disk_info = (DiskInfo *)malloc( sizeof( DiskInfo ) ) ) == NULL ) continue; memset( disk_info, 0, sizeof( DiskInfo ) ); if ( statvfs( mnt_info->mnt_dir, &(disk_info->statvfs) ) < 0 ) continue; strncpy( disk_info->device, mnt_info->mnt_fsname, sizeof( disk_info->device ) ); disk_info->device[ sizeof(disk_info->device) -1] = 0; strncpy( disk_info->mntpnt, mnt_info->mnt_dir, sizeof( disk_info->mntpnt ) ); disk_info->mntpnt[ sizeof(disk_info->mntpnt) - 1] = 0; sanitize(disk_info->mntpnt); push_ctnr( DiskStatList, disk_info ); } endmntent( fh ); return 0; } int calculatePercentageUsed( unsigned long totalSizeKB, unsigned long available) { if (!available) return 0; unsigned long totalSizeKBdividedBy100 = (50 + totalSizeKB )/ 100; if (!totalSizeKBdividedBy100) return 0; int percentageUsed = 100 - available / totalSizeKBdividedBy100; /* Percentage is 1 - available / totalSizeKB, meaning that we count root-only reserved space as "used" here */ /* If we have rounded down to 0%, make it 1%, like "df" does */ if (percentageUsed == 0) return 1; return percentageUsed; } void printDiskStat( const char* cmd ) { DiskInfo* disk_info; (void)cmd; for ( disk_info = first_ctnr( DiskStatList ); disk_info; disk_info = next_ctnr( DiskStatList ) ) { /* See man statvfs(2) for meaning of fields */ unsigned long totalSizeKB = disk_info->statvfs.f_blocks * (disk_info->statvfs.f_frsize/1024); unsigned long usedKB = totalSizeKB - (disk_info->statvfs.f_bfree * (disk_info->statvfs.f_bsize/1024)); /* used is the total size minus free blocks including those for root only */ unsigned long available = disk_info->statvfs.f_bavail * (disk_info->statvfs.f_bsize/1024); /* available is only those for non-root. So available + used != total because some are reserved for root */ int percentageUsed = calculatePercentageUsed(totalSizeKB, available); output( "%s\t%ld\t%ld\t%ld\t%d\t%s\n", disk_info->device, totalSizeKB, usedKB, available, percentageUsed, disk_info->mntpnt ); } output( "\n" ); } void printDiskStatInfo( const char* cmd ) { (void)cmd; output( "Device\tSize\tUsed\tAvailable\tUsed %%\tMount point\nM\tKB\tKB\tKB\t%%\ts\n" ); } void printDiskStatUsed( const char* cmd ) { char *mntpnt = (char*)getMntPnt( cmd ); DiskInfo* disk_info; unsigned long total = 0; int is_all = strcmp( mntpnt, "/all" ) == 0; for ( disk_info = first_ctnr( DiskStatList ); disk_info; disk_info = next_ctnr( DiskStatList ) ) { if ( !strcmp( mntpnt, disk_info->mntpnt ) || is_all ) { unsigned long totalSizeKB = disk_info->statvfs.f_blocks * (disk_info->statvfs.f_frsize/1024); unsigned long usedKB = totalSizeKB - (disk_info->statvfs.f_bfree * (disk_info->statvfs.f_bsize/1024)); /* used is the total size minus free blocks including those for root only */ if ( !is_all ) { output( "%ld\n", usedKB ); } else { total += usedKB; } } } if ( is_all ) { output( "%ld\n", total ); } output( "\n" ); } void printDiskStatUsedInfo( const char* cmd ) { char *mntpnt = getMntPnt( cmd ); output( "Used\t0\t%ld\tKB\n", getTotal( mntpnt ) ); } void printDiskStatFree( const char* cmd ) { char *mntpnt = (char*)getMntPnt( cmd ); DiskInfo* disk_info; unsigned long total = 0; int is_all = strcmp( mntpnt, "/all" ) == 0; for ( disk_info = first_ctnr( DiskStatList ); disk_info; disk_info = next_ctnr( DiskStatList ) ) { if ( !strcmp( mntpnt, disk_info->mntpnt ) || is_all ) { unsigned long available = disk_info->statvfs.f_bavail * (disk_info->statvfs.f_bsize/1024); /* available is only those for non-root. So available + used != total because some are reserved for root */ if ( !is_all ) { output( "%ld\n", available ); } else { total += available; } } } if ( is_all ) { output( "%ld\n", total ); } output( "\n" ); } void printDiskStatFreeInfo( const char* cmd ) { char *mntpnt = (char*)getMntPnt( cmd ); output( "Available\t0\t%ld\tKB\n", getTotal( mntpnt ) ); } void printDiskStatPercent( const char* cmd ) { char *mntpnt = (char*)getMntPnt( cmd ); DiskInfo* disk_info; unsigned long totalSize = 0; unsigned long totalAvailable = 0; int is_all = strcmp( mntpnt, "/all" ) == 0; for ( disk_info = first_ctnr( DiskStatList ); disk_info; disk_info = next_ctnr( DiskStatList ) ) { if ( !strcmp( mntpnt, disk_info->mntpnt ) || is_all ) { unsigned long totalSizeKB = disk_info->statvfs.f_blocks * (disk_info->statvfs.f_frsize/1024); unsigned long available = disk_info->statvfs.f_bavail * (disk_info->statvfs.f_bsize/1024); /* available is only those for non-root. So available + used != total because some are reserved for root */ if ( is_all ) { totalSize += totalSizeKB; totalAvailable += available; } else { int percentageUsed = calculatePercentageUsed(totalSizeKB, available); output( "%d\n", percentageUsed ); } } } if ( is_all ) { int percentageUsed = calculatePercentageUsed(totalSize, totalAvailable); output( "%d\n", percentageUsed ); } output( "\n" ); } void printDiskStatPercentInfo( const char* cmd ) { (void)cmd; output( "Percentage Used\t0\t100\t%%\n" ); } void printDiskStatTotal( const char* cmd ) { char *mntpnt = (char*)getMntPnt( cmd ); output( "%ld\n\n", getTotal( mntpnt ) ); } void printDiskStatTotalInfo( const char* cmd ) { (void)cmd; output( "Total Size\t0\t0\tKB\n" ); } diff --git a/ksysguardd/Linux/diskstats.c b/ksysguardd/Linux/diskstats.c index bd0271d8..456a0e4f 100644 --- a/ksysguardd/Linux/diskstats.c +++ b/ksysguardd/Linux/diskstats.c @@ -1,546 +1,550 @@ /* KSysGuard, the KDE System Guard Copyright (c) 2006 Greg Martyn This program is free software; you can redistribute it and/or modify it under the terms of version 2 or later of the GNU General Public License as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* This file will read from /proc/diskstats. /proc/diskstats support should exist in kernel versions 2.4.20, 2.5.45, 2.6 and up */ #include /* for gettimeofday */ #include /* for strcmp */ #include /* for malloc */ #include #include #include #include #include #include "Command.h" #include "ksysguardd.h" #include "diskstats.h" #define DISKSTATSBUFSIZE (32 * 1024) #define DISKDEVNAMELEN 20 #define STRINGIFY(x) #x #define TOSTRING(x) STRINGIFY(x) typedef struct { unsigned long delta; unsigned long old; } DiskLoadSample; typedef struct { /* 5 types of samples are taken: total, rio, wio, rBlk, wBlk */ DiskLoadSample s[ 5 ]; } DiskLoadInfo; typedef struct DiskIOInfo { int major; int minor; char* devname; int alive; DiskLoadSample total; /* Total accesses - Fields 1+5 */ DiskLoadSample rio; /* Read Accesses - Field 1 - # of reads issued */ DiskLoadSample wio; /* Write Accesses - Field 5 - # of writes completed */ DiskLoadSample rblk; /* Read Data - Field 3 - # of sectors read */ DiskLoadSample wblk; /* Written Data - Field 7 - # of sectors written */ DiskLoadSample rtim; /* - Field 4 - # of milliseconds spent reading */ DiskLoadSample wtim; /* - Field 8 - # of milliseconds spent writing */ unsigned int ioqueue; /* - Field 9 - # of I/Os currently in progress */ struct DiskIOInfo* next; } DiskIOInfo; /* We have observed deviations of up to 5% in the accuracy of the timer * interrupts. So we try to measure the interrupt interval and use this * value to calculate timing dependent values. */ static float timeInterval = 0; static struct timeval lastSampling; static struct timeval currSampling; static struct SensorModul* StatSM; static DiskLoadInfo* DiskLoad = 0; static DiskIOInfo* DiskIO = 0; static int Dirty = 0; static void cleanup26DiskList( void ); static int process26DiskIO( const char* buf ); void initDiskstats( struct SensorModul* sm ) { StatSM = sm; processDiskstats(); /* This causes the disks monitors to be added */ } void exitDiskstats( void ) { free( DiskLoad ); DiskLoad = 0; } int updateDiskstats( void ) { Dirty = 1; return 0; } void processDiskstats( void ) { char buf[1024]; FILE *file = NULL; gettimeofday( &currSampling, 0 ); /* Process values from /proc/diskstats (Linux >= 2.6.x) */ if ( ( file = fopen( "/proc/diskstats", "r" ) ) == NULL ) return; /* unable to open file. disable this module. */ /* Process values from /proc/diskstats (Linux >= 2.6.x) */ while (fgets(buf, sizeof(buf) - 1, file) != NULL) { process26DiskIO(buf); } fclose( file ); /* save exact time interval between this and the last read of /proc/stat */ timeInterval = currSampling.tv_sec - lastSampling.tv_sec + ( currSampling.tv_usec - lastSampling.tv_usec ) / 1000000.0; lastSampling = currSampling; cleanup26DiskList(); Dirty = 0; } static int process26DiskIO( const char* buf ) { /* Process values from /proc/diskstats (Linux >= 2.6.x) */ /* For each disk /proc/diskstats includes lines as follows: * 3 0 hda 1314558 74053 26451438 14776742 1971172 4607401 52658448 202855090 0 9597019 217637839 * 3 1 hda1 178 360 0 0 * 3 2 hda2 354 360 0 0 * 3 3 hda3 354 360 0 0 * 3 4 hda4 0 0 0 0 * 3 5 hda5 529506 9616000 4745856 37966848 * * - See Documentation/iostats.txt for details on the changes */ int major, minor; char devname[DISKDEVNAMELEN]; unsigned long total, rio, rmrg, rblk, rtim, wio, wmrg, wblk, wtim, ioqueue, iotim, iotimw; DiskIOInfo *ptr = DiskIO; DiskIOInfo *last = 0; char sensorName[128]; /* From kernel 2.6.22.1's Documentation/iostats.txt: First 3 fields of line are major, minor, devname Then: Field 1 -- # of reads issued This is the total number of reads completed successfully. Field 2 -- # of reads merged, field 6 -- # of writes merged Reads and writes which are adjacent to each other may be merged for efficiency. Thus two 4K reads may become one 8K read before it is ultimately handed to the disk, and so it will be counted (and queued) as only one I/O. This field lets you know how often this was done. Field 3 -- # of sectors read This is the total number of sectors read successfully. Field 4 -- # of milliseconds spent reading This is the total number of milliseconds spent by all reads (as measured from __make_request() to end_that_request_last()). Field 5 -- # of writes completed This is the total number of writes completed successfully. Field 7 -- # of sectors written This is the total number of sectors written successfully. Field 8 -- # of milliseconds spent writing This is the total number of milliseconds spent by all writes (as measured from __make_request() to end_that_request_last()). Field 9 -- # of I/Os currently in progress The only field that should go to zero. Incremented as requests are given to appropriate request_queue_t and decremented as they finish. Field 10 -- # of milliseconds spent doing I/Os This field is increases so long as field 9 is nonzero. Field 11 -- weighted # of milliseconds spent doing I/Os This field is incremented at each I/O start, I/O completion, I/O merge, or read of these stats by the number of I/Os in progress (field 9) times the number of milliseconds spent doing I/O since the last update of this field. This can provide an easy measure of both I/O completion time and the backlog that may be accumulating. */ switch (sscanf(buf, "%d %d %" TOSTRING(DISKDEVNAMELEN) "s %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu", &major, &minor, devname, &rio, &rmrg, &rblk, &rtim, &wio, &wmrg, &wblk, &wtim, &ioqueue, &iotim, &iotimw)) { case 7: /* Partition stats entry */ /* Adjust read fields rio rmrg rblk rtim -> rio rblk wio wblk */ wblk = rtim; wio = rblk; rblk = rmrg; total = rio + wio; break; case 14: /* Disk stats entry */ total = rio + wio; break; default: /* Something unexpected */ return -1; } devname[DISKDEVNAMELEN-1] = 0; + + if (!strncmp(devname, "/dev/loop", 9)) { + return -1; + } last = 0; ptr = DiskIO; while (ptr) { if (ptr->major == major && ptr->minor == minor) { /* The IO device has already been registered. */ ptr->total.delta = total - ptr->total.old; ptr->total.old = total; ptr->rio.delta = rio - ptr->rio.old; ptr->rio.old = rio; ptr->wio.delta = wio - ptr->wio.old; ptr->wio.old = wio; ptr->rblk.delta = rblk - ptr->rblk.old; ptr->rblk.old = rblk; ptr->wblk.delta = wblk - ptr->wblk.old; ptr->wblk.old = wblk; ptr->rtim.delta = rtim - ptr->rtim.old; ptr->rtim.old = rtim; ptr->wtim.delta = wtim - ptr->wtim.old; ptr->wtim.old = wtim; /* fyi: ipqueue doesn't have a delta */ ptr->ioqueue = ioqueue; ptr->alive = 1; break; } last = ptr; ptr = ptr->next; } if (!ptr) { /* The IO device has not been registered yet. We need to add it. */ ptr = (DiskIOInfo*)malloc( sizeof( DiskIOInfo ) ); ptr->major = major; ptr->minor = minor; ptr->devname = devname; ptr->total.delta = 0; ptr->total.old = total; ptr->rio.delta = 0; ptr->rio.old = rio; ptr->wio.delta = 0; ptr->wio.old = wio; ptr->rblk.delta = 0; ptr->rblk.old = rblk; ptr->wblk.delta = 0; ptr->wblk.old = wblk; ptr->rtim.delta = 0; ptr->rtim.old = rtim; ptr->wtim.delta = 0; ptr->wtim.old = wtim; /* fyi: ipqueue doesn't have a delta */ ptr->ioqueue = ioqueue; ptr->alive = 1; ptr->next = 0; if (last) { /* Append new entry at end of list. */ last->next = ptr; } else { /* List is empty, so we insert the fist element into the list. */ DiskIO = ptr; } sprintf(sensorName, "disk/%s_(%d:%d)/Rate/totalio", devname, major, minor); registerMonitor(sensorName, "float", print26DiskIO, print26DiskIOInfo, StatSM); sprintf(sensorName, "disk/%s_(%d:%d)/Rate/rio", devname, major, minor); registerMonitor(sensorName, "float", print26DiskIO, print26DiskIOInfo, StatSM); sprintf(sensorName, "disk/%s_(%d:%d)/Rate/wio", devname, major, minor); registerMonitor(sensorName, "float", print26DiskIO, print26DiskIOInfo, StatSM); sprintf(sensorName, "disk/%s_(%d:%d)/Rate/rblk", devname, major, minor); registerMonitor(sensorName, "float", print26DiskIO, print26DiskIOInfo, StatSM); sprintf(sensorName, "disk/%s_(%d:%d)/Rate/wblk", devname, major, minor); registerMonitor(sensorName, "float", print26DiskIO, print26DiskIOInfo, StatSM); sprintf(sensorName, "disk/%s_(%d:%d)/Delta/totalio", devname, major, minor); registerMonitor(sensorName, "integer", print26DiskIO, print26DiskIOInfo, StatSM); sprintf(sensorName, "disk/%s_(%d:%d)/Delta/rio", devname, major, minor); registerMonitor(sensorName, "integer", print26DiskIO, print26DiskIOInfo, StatSM); sprintf(sensorName, "disk/%s_(%d:%d)/Delta/wio", devname, major, minor); registerMonitor(sensorName, "integer", print26DiskIO, print26DiskIOInfo, StatSM); sprintf(sensorName, "disk/%s_(%d:%d)/Delta/rblk", devname, major, minor); registerMonitor(sensorName, "integer", print26DiskIO, print26DiskIOInfo, StatSM); sprintf(sensorName, "disk/%s_(%d:%d)/Delta/wblk", devname, major, minor); registerMonitor(sensorName, "integer", print26DiskIO, print26DiskIOInfo, StatSM); sprintf(sensorName, "disk/%s_(%d:%d)/Delta/rtim", devname, major, minor); registerMonitor(sensorName, "integer", print26DiskIO, print26DiskIOInfo, StatSM); sprintf(sensorName, "disk/%s_(%d:%d)/Delta/wtim", devname, major, minor); registerMonitor(sensorName, "integer", print26DiskIO, print26DiskIOInfo, StatSM); sprintf(sensorName, "disk/%s_(%d:%d)/ioqueue", devname, major, minor); registerMonitor(sensorName, "integer", print26DiskIO, print26DiskIOInfo, StatSM); } return 0; } static void cleanup26DiskList( void ) { DiskIOInfo* ptr = DiskIO; DiskIOInfo* last = 0; while ( ptr ) { if ( ptr->alive == 0 ) { DiskIOInfo* newPtr; char sensorName[ 128 ]; /* Disk device has disappeared. We have to remove it from * the list and unregister the monitors. */ sprintf( sensorName, "disk/%s_(%d:%d)/Rate/totalio", ptr->devname, ptr->major, ptr->minor ); removeMonitor( sensorName ); sprintf( sensorName, "disk/%s_(%d:%d)/Rate/rio", ptr->devname, ptr->major, ptr->minor ); removeMonitor( sensorName ); sprintf( sensorName, "disk/%s_(%d:%d)/Rate/wio", ptr->devname, ptr->major, ptr->minor ); removeMonitor( sensorName ); sprintf( sensorName, "disk/%s_(%d:%d)/Rate/rblk", ptr->devname, ptr->major, ptr->minor ); removeMonitor( sensorName ); sprintf( sensorName, "disk/%s_(%d:%d)/Rate/wblk", ptr->devname, ptr->major, ptr->minor ); removeMonitor( sensorName ); sprintf( sensorName, "disk/%s_(%d:%d)/Delta/totalio", ptr->devname, ptr->major, ptr->minor ); removeMonitor( sensorName ); sprintf( sensorName, "disk/%s_(%d:%d)/Delta/rio", ptr->devname, ptr->major, ptr->minor ); removeMonitor( sensorName ); sprintf( sensorName, "disk/%s_(%d:%d)/Delta/wio", ptr->devname, ptr->major, ptr->minor ); removeMonitor( sensorName ); sprintf( sensorName, "disk/%s_(%d:%d)/Delta/rblk", ptr->devname, ptr->major, ptr->minor ); removeMonitor( sensorName ); sprintf( sensorName, "disk/%s_(%d:%d)/Delta/wblk", ptr->devname, ptr->major, ptr->minor ); removeMonitor( sensorName ); sprintf( sensorName, "disk/%s_(%d:%d)/Delta/rtim", ptr->devname, ptr->major, ptr->minor ); removeMonitor( sensorName ); sprintf( sensorName, "disk/%s_(%d:%d)/Delta/wtim", ptr->devname, ptr->major, ptr->minor ); removeMonitor( sensorName ); sprintf( sensorName, "disk/%s_(%d:%d)/ioqueue", ptr->devname, ptr->major, ptr->minor ); removeMonitor( sensorName ); if ( last ) { last->next = ptr->next; newPtr = ptr->next; } else { DiskIO = ptr->next; newPtr = DiskIO; last = 0; } free ( ptr ); ptr = newPtr; } else { ptr->alive = 0; last = ptr; ptr = ptr->next; } } } void print26DiskIO( const char* cmd ) { int major, minor; char devname[DISKDEVNAMELEN]; char name[ 17 ]; DiskIOInfo* ptr; if ( Dirty ) processDiskstats(); if(sscanf( cmd, "disk/%[^_]_(%d:%d)/Rate/%16s", devname, &major, &minor, name ) == 4) { /* Show rate of change in sensor values in this interval */ ptr = DiskIO; while ( ptr && ( ptr->major != major || ptr->minor != minor ) ) ptr = ptr->next; if ( !ptr ) { print_error( "RECONFIGURE" ); output( "0\n" ); log_error( "Disk device disappeared" ); return; } if ( strcmp( name, "totalio" ) == 0 ) output( "%f\n", (float)( ptr->total.delta / timeInterval ) ); else if ( strcmp( name, "rio" ) == 0 ) output( "%f\n", (float)( ptr->rio.delta / timeInterval ) ); else if ( strcmp( name, "wio" ) == 0 ) output( "%f\n", (float)( ptr->wio.delta / timeInterval ) ); else if ( strcmp( name, "rblk" ) == 0 ) output( "%f\n", (float)( ptr->rblk.delta / ( timeInterval * 2 ) ) ); else if ( strcmp( name, "wblk" ) == 0 ) output( "%f\n", (float)( ptr->wblk.delta / ( timeInterval * 2 ) ) ); else { output( "0\n" ); log_error( "Unknown disk device property \'%s\'", name ); } } else if(sscanf( cmd, "disk/%[^_]_(%d:%d)/Delta/%16s", devname, &major, &minor, name ) == 4) { /* Show change in sensor values per this interval */ ptr = DiskIO; while ( ptr && ( ptr->major != major || ptr->minor != minor ) ) ptr = ptr->next; if ( !ptr ) { print_error( "RECONFIGURE" ); output( "0\n" ); log_error( "Disk device disappeared" ); return; } if ( strcmp( name, "totalio" ) == 0 ) output( "%lu\n", ptr->total.delta ); else if ( strcmp( name, "rio" ) == 0 ) output( "%lu\n", ptr->rio.delta ); else if ( strcmp( name, "wio" ) == 0 ) output( "%lu\n", ptr->wio.delta ); else if ( strcmp( name, "rblk" ) == 0 ) output( "%lu\n", ptr->rblk.delta ); else if ( strcmp( name, "wblk" ) == 0 ) output( "%lu\n", ptr->wblk.delta ); else if ( strcmp( name, "rtim" ) == 0 ) output( "%lu\n", ptr->rtim.delta ); else if ( strcmp( name, "wtim" ) == 0 ) output( "%lu\n", ptr->wtim.delta ); else { output( "0\n" ); log_error( "Unknown disk device property \'%s\'", name ); } } else if(sscanf( cmd, "disk/%[^_]_(%d:%d)/%16s", devname, &major, &minor, name ) == 4) { /* Show raw sensor values */ ptr = DiskIO; while ( ptr && ( ptr->major != major || ptr->minor != minor ) ) ptr = ptr->next; if ( !ptr ) { print_error( "RECONFIGURE" ); output( "0\n" ); log_error( "Disk device disappeared" ); return; } if ( strcmp( name, "ioqueue" ) == 0 ) output( "%u\n", ptr->ioqueue ); else { output( "0\n" ); log_error( "Unknown disk device property \'%s\'", name ); } } } void print26DiskIOInfo( const char* cmd ) { int major, minor; char devname[DISKDEVNAMELEN]; char name[ 17 ]; DiskIOInfo* ptr = DiskIO; /* For now we print the same info regardless of whether it was a rate, delta, or raw monitor */ if(sscanf( cmd, "disk/%[^_]_(%d:%d)/Rate/%16s", devname, &major, &minor, name ) == 4) { } else if(sscanf( cmd, "disk/%[^_]_(%d:%d)/Delta/%16s", devname, &major, &minor, name ) == 4) { } else if(sscanf( cmd, "disk/%[^_]_(%d:%d)/%16s", devname, &major, &minor, name ) == 4) { } else { output( "Dummy\t0\t0\t\n" ); log_error( "Request for unknown device property \'%s\'", cmd ); } while ( ptr && ( ptr->major != major || ptr->minor != minor ) ) ptr = ptr->next; if ( !ptr ) { /* Disk device has disappeared. Print a dummy answer. */ output( "Dummy\t0\t0\t\n" ); return; } /* remove trailing '?' */ name[ strlen( name ) - 1 ] = '\0'; if ( strcmp( name, "totalio" ) == 0 ) output( "Total accesses device %s (%d:%d)\t0\t0\t1/s\n", devname, major, minor ); else if ( strcmp( name, "rio" ) == 0 ) output( "Read data device %s (%d:%d)\t0\t0\t1/s\n", devname, major, minor ); else if ( strcmp( name, "wio" ) == 0 ) output( "Write data device %s (%d:%d)\t0\t0\t1/s\n", devname, major, minor ); else if ( strcmp( name, "rblk" ) == 0 ) output( "Read accesses device %s (%d:%d)\t0\t0\tKB/s\n", devname, major, minor ); else if ( strcmp( name, "wblk" ) == 0 ) output( "Write accesses device %s (%d:%d)\t0\t0\tKB/s\n", devname, major, minor ); else if ( strcmp( name, "rtim" ) == 0 ) output( "# of milliseconds spent reading device %s (%d:%d)\t0\t0\ts\n", devname, major, minor ); else if ( strcmp( name, "wtim" ) == 0 ) output( "# of milliseconds spent writing device %s (%d:%d)\t0\t0\ts\n", devname, major, minor ); else if ( strcmp( name, "ioqueue" ) == 0 ) output( "# of I/Os currently in progress on device %s (%d:%d)\t0\t0\t\n", devname, major, minor ); else { output( "Dummy\t0\t0\t\n" ); log_error( "Request for unknown device property \'%s\'", name ); } }