/* * Copyright (c) 2006 * Protium Computing, Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Protium Computing, Inc. * 4. The name of Protium Computing, Inc. may not be used to endorse or * promote products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY PROTIUM COMPUTING ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL PROTIUM COMPUTING BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include struct watch_table { char *wt_path; int wt_status; int wt_reads; int wt_writes; #define WT_INVALID 0 #define WT_VALID 1 #define WT_CHECK 2 } iowt[] = { { "/sys/block/hda/stat", WT_CHECK, 0, 0}, { "/sys/block/hdb/stat", WT_CHECK, 0, 0}, { "/sys/block/hdc/stat", WT_CHECK, 0, 0}, { "/sys/block/hdd/stat", WT_CHECK, 0, 0}, { NULL, WT_INVALID, -1, -1} }; /* * disk_activity() returns back the total number of read and writes done * by the devices listed in the io watch table since the last call to * disk_activity. The number of reads and writes are determined by * opening and reading each of the valid files listed in the io watch * table.The number of reads and writes are stored in the io watch table so * that the next call to this routine can compare the current number of read * and writes to those stored in the io watch table. The difference for * each device is summed in the activity variable. The routine lazy * evaluates the existance of the devices in the table. * * For the storcenter, we are only concerned with internal drives. * * The wt_path element must point at a diskstat file in the sysfs filesystem. * File format can be found at: /usr/src/linux/Documentation/iostats.txt * For this routine: * nr, nw - number read and writes * nmr, nmw - number of merged reads and writes * nsr, nsw - number of the sectors read and written * tr, tw - time spent reading and writing * nio - raw number of ios * tio, wtio - time spent and weighted time spent doing io */ int disk_activity() { int activity = 0; char mesg[256]; int rc, nr, nmr, nsr, tr, nw, nmw, nsw, tw, nio, tio, wtio; FILE *f; struct stat st; struct watch_table *w; for (w = iowt; w->wt_path; w++) { /* * If status ids set to check, do the lazy existence * evaluation. If stat fails set to invalid. Don't * worry about perms here. */ if ((w->wt_status == WT_CHECK) && (stat(w->wt_path, &st) < 0)) { sprintf(mesg, "%s not available", w->wt_path); syslog(LOG_INFO, mesg); w->wt_status = WT_INVALID; } /* * Short circuit the loop if invalid. */ if (w->wt_status == WT_INVALID) continue; /* * If it can't be opened rdonly, set to invalid */ if ((f = fopen(w->wt_path, "r")) < 0) { sprintf(mesg, "Unable to open %s, no longer watching", w->wt_path); syslog(LOG_INFO, mesg); w->wt_status = WT_INVALID; continue; } rc = fscanf(f, "%d %d %d %d %d %d %d %d %d %d %d", &nr, &nmr, &nsr, &tr, &nw, &nmw, &nsw, &tw, &nio, &tio, &wtio); fclose(f); if (rc != 11) { sprintf(mesg, "Unable to read %s", w->wt_path); syslog(LOG_INFO, mesg); continue; } /* * If we haven't seen any activity on this device before * then just save the values and go on. This, although * not strictly necessary, prevents the initial call to * disk_activity returning back the base set io activity. * Remember it takes two calls to get a true difference. */ if ((w->wt_reads == 0) && (w->wt_writes == 0)) { w->wt_reads = nr; w->wt_writes = nw; continue; } activity += (nr - w->wt_reads); activity += (nw - w->wt_writes); w->wt_reads = nr; w->wt_writes = nw; /* printf("%s: %d %d %d %d %d %d %d %d %d %d %d\n", w->wt_path, nr, nmr, nsr, tr, nw, nmw, nsw, tw, nio, tio, wtio); */ } return(activity); }