1 | /* |
2 | KSysGuard, the KDE System Guard |
3 | |
4 | Copyright (c) 2006 Greg Martyn <greg.martyn@gmail.com> |
5 | |
6 | This program is free software; you can redistribute it and/or |
7 | modify it under the terms of version 2 or later of the GNU General Public |
8 | License as published by the Free Software Foundation. |
9 | |
10 | This program is distributed in the hope that it will be useful, |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | GNU General Public License for more details. |
14 | |
15 | You should have received a copy of the GNU General Public License |
16 | along with this program; if not, write to the Free Software |
17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
18 | |
19 | */ |
20 | |
21 | /* This file will read from /proc/diskstats. |
22 | /proc/diskstats support should exist in kernel versions 2.4.20, 2.5.45, 2.6 and up |
23 | */ |
24 | |
25 | #include <sys/time.h> /* for gettimeofday */ |
26 | #include <string.h> /* for strcmp */ |
27 | #include <stdlib.h> /* for malloc */ |
28 | |
29 | #include <sys/types.h> |
30 | #include <sys/stat.h> |
31 | #include <fcntl.h> |
32 | #include <unistd.h> |
33 | #include <ctype.h> |
34 | |
35 | #include "Command.h" |
36 | #include "ksysguardd.h" |
37 | |
38 | #include "diskstats.h" |
39 | |
40 | #define DISKSTATSBUFSIZE (32 * 1024) |
41 | #define DISKDEVNAMELEN 20 |
42 | |
43 | #define STRINGIFY(x) #x |
44 | #define TOSTRING(x) STRINGIFY(x) |
45 | |
46 | typedef struct |
47 | { |
48 | unsigned long delta; |
49 | unsigned long old; |
50 | } DiskLoadSample; |
51 | |
52 | typedef struct |
53 | { |
54 | /* 5 types of samples are taken: |
55 | total, rio, wio, rBlk, wBlk */ |
56 | DiskLoadSample s[ 5 ]; |
57 | } DiskLoadInfo; |
58 | |
59 | typedef struct DiskIOInfo |
60 | { |
61 | int major; |
62 | int minor; |
63 | char* devname; |
64 | |
65 | int alive; |
66 | DiskLoadSample total; /* Total accesses - Fields 1+5 */ |
67 | DiskLoadSample rio; /* Read Accesses - Field 1 - # of reads issued */ |
68 | DiskLoadSample wio; /* Write Accesses - Field 5 - # of writes completed */ |
69 | DiskLoadSample rblk; /* Read Data - Field 3 - # of sectors read */ |
70 | DiskLoadSample wblk; /* Written Data - Field 7 - # of sectors written */ |
71 | DiskLoadSample rtim; /* - Field 4 - # of milliseconds spent reading */ |
72 | DiskLoadSample wtim; /* - Field 8 - # of milliseconds spent writing */ |
73 | unsigned int ioqueue; /* - Field 9 - # of I/Os currently in progress */ |
74 | struct DiskIOInfo* next; |
75 | } DiskIOInfo; |
76 | |
77 | /* We have observed deviations of up to 5% in the accuracy of the timer |
78 | * interrupts. So we try to measure the interrupt interval and use this |
79 | * value to calculate timing dependant values. */ |
80 | static float timeInterval = 0; |
81 | static struct timeval lastSampling; |
82 | static struct timeval currSampling; |
83 | static struct SensorModul* StatSM; |
84 | |
85 | static DiskLoadInfo* DiskLoad = 0; |
86 | static DiskIOInfo* DiskIO = 0; |
87 | |
88 | static int Dirty = 0; |
89 | |
90 | static void cleanup26DiskList( void ); |
91 | static int process26DiskIO( const char* buf ); |
92 | |
93 | void initDiskstats( struct SensorModul* sm ) { |
94 | StatSM = sm; |
95 | processDiskstats(); /* This causes the disks monitors to be added */ |
96 | } |
97 | |
98 | void exitDiskstats( void ) { |
99 | free( DiskLoad ); |
100 | DiskLoad = 0; |
101 | } |
102 | |
103 | int updateDiskstats( void ) { |
104 | Dirty = 1; |
105 | return 0; |
106 | } |
107 | void processDiskstats( void ) { |
108 | |
109 | char buf[1024]; |
110 | FILE *file = NULL; |
111 | |
112 | gettimeofday( &currSampling, 0 ); |
113 | /* Process values from /proc/diskstats (Linux >= 2.6.x) */ |
114 | if ( ( file = fopen( "/proc/diskstats" , "r" ) ) == NULL ) |
115 | return; /* unable to open file. disable this module. */ |
116 | |
117 | |
118 | /* Process values from /proc/diskstats (Linux >= 2.6.x) */ |
119 | while (fgets(buf, sizeof(buf) - 1, file) != NULL) { |
120 | process26DiskIO(buf); |
121 | } |
122 | fclose( file ); |
123 | |
124 | /* save exact time interval between this and the last read of /proc/stat */ |
125 | timeInterval = currSampling.tv_sec - lastSampling.tv_sec + |
126 | ( currSampling.tv_usec - lastSampling.tv_usec ) / 1000000.0; |
127 | lastSampling = currSampling; |
128 | cleanup26DiskList(); |
129 | Dirty = 0; |
130 | } |
131 | |
132 | static int process26DiskIO( const char* buf ) { |
133 | /* Process values from /proc/diskstats (Linux >= 2.6.x) */ |
134 | |
135 | /* For each disk /proc/diskstats includes lines as follows: |
136 | * 3 0 hda 1314558 74053 26451438 14776742 1971172 4607401 52658448 202855090 0 9597019 217637839 |
137 | * 3 1 hda1 178 360 0 0 |
138 | * 3 2 hda2 354 360 0 0 |
139 | * 3 3 hda3 354 360 0 0 |
140 | * 3 4 hda4 0 0 0 0 |
141 | * 3 5 hda5 529506 9616000 4745856 37966848 |
142 | * |
143 | * - See Documentation/iostats.txt for details on the changes |
144 | */ |
145 | int major, minor; |
146 | char devname[DISKDEVNAMELEN]; |
147 | unsigned long total, |
148 | rio, rmrg, rblk, rtim, |
149 | wio, wmrg, wblk, wtim, |
150 | ioqueue, iotim, iotimw; |
151 | DiskIOInfo *ptr = DiskIO; |
152 | DiskIOInfo *last = 0; |
153 | char sensorName[128]; |
154 | |
155 | /* |
156 | From kernel 2.6.22.1's Documentation/iostats.txt: |
157 | |
158 | First 3 fields of line are major, minor, devname |
159 | Then: |
160 | Field 1 -- # of reads issued |
161 | This is the total number of reads completed successfully. |
162 | Field 2 -- # of reads merged, field 6 -- # of writes merged |
163 | Reads and writes which are adjacent to each other may be merged for |
164 | efficiency. Thus two 4K reads may become one 8K read before it is |
165 | ultimately handed to the disk, and so it will be counted (and queued) |
166 | as only one I/O. This field lets you know how often this was done. |
167 | Field 3 -- # of sectors read |
168 | This is the total number of sectors read successfully. |
169 | Field 4 -- # of milliseconds spent reading |
170 | This is the total number of milliseconds spent by all reads (as |
171 | measured from __make_request() to end_that_request_last()). |
172 | Field 5 -- # of writes completed |
173 | This is the total number of writes completed successfully. |
174 | Field 7 -- # of sectors written |
175 | This is the total number of sectors written successfully. |
176 | Field 8 -- # of milliseconds spent writing |
177 | This is the total number of milliseconds spent by all writes (as |
178 | measured from __make_request() to end_that_request_last()). |
179 | Field 9 -- # of I/Os currently in progress |
180 | The only field that should go to zero. Incremented as requests are |
181 | given to appropriate request_queue_t and decremented as they finish. |
182 | Field 10 -- # of milliseconds spent doing I/Os |
183 | This field is increases so long as field 9 is nonzero. |
184 | Field 11 -- weighted # of milliseconds spent doing I/Os |
185 | This field is incremented at each I/O start, I/O completion, I/O |
186 | merge, or read of these stats by the number of I/Os in progress |
187 | (field 9) times the number of milliseconds spent doing I/O since the |
188 | last update of this field. This can provide an easy measure of both |
189 | I/O completion time and the backlog that may be accumulating. |
190 | */ |
191 | |
192 | switch (sscanf(buf, "%d %d %" TOSTRING(DISKDEVNAMELEN) "s %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu" , |
193 | &major, &minor, devname, |
194 | &rio, &rmrg, &rblk, &rtim, |
195 | &wio, &wmrg, &wblk, &wtim, |
196 | &ioqueue, &iotim, &iotimw)) |
197 | { |
198 | case 7: |
199 | /* Partition stats entry */ |
200 | /* Adjust read fields rio rmrg rblk rtim -> rio rblk wio wblk */ |
201 | wblk = rtim; |
202 | wio = rblk; |
203 | rblk = rmrg; |
204 | |
205 | total = rio + wio; |
206 | |
207 | break; |
208 | case 14: |
209 | /* Disk stats entry */ |
210 | total = rio + wio; |
211 | |
212 | break; |
213 | default: |
214 | /* Something unexpected */ |
215 | return -1; |
216 | } |
217 | devname[DISKDEVNAMELEN-1] = 0; |
218 | |
219 | last = 0; |
220 | ptr = DiskIO; |
221 | while (ptr) { |
222 | if (ptr->major == major && ptr->minor == minor) |
223 | { |
224 | /* The IO device has already been registered. */ |
225 | ptr->total.delta = total - ptr->total.old; |
226 | ptr->total.old = total; |
227 | ptr->rio.delta = rio - ptr->rio.old; |
228 | ptr->rio.old = rio; |
229 | ptr->wio.delta = wio - ptr->wio.old; |
230 | ptr->wio.old = wio; |
231 | ptr->rblk.delta = rblk - ptr->rblk.old; |
232 | ptr->rblk.old = rblk; |
233 | ptr->wblk.delta = wblk - ptr->wblk.old; |
234 | ptr->wblk.old = wblk; |
235 | ptr->rtim.delta = rtim - ptr->rtim.old; |
236 | ptr->rtim.old = rtim; |
237 | ptr->wtim.delta = wtim - ptr->wtim.old; |
238 | ptr->wtim.old = wtim; |
239 | /* fyi: ipqueue doesn't have a delta */ |
240 | ptr->ioqueue = ioqueue; |
241 | |
242 | ptr->alive = 1; |
243 | break; |
244 | } |
245 | |
246 | last = ptr; |
247 | ptr = ptr->next; |
248 | } |
249 | |
250 | if (!ptr) { |
251 | /* The IO device has not been registered yet. We need to add it. */ |
252 | ptr = (DiskIOInfo*)malloc( sizeof( DiskIOInfo ) ); |
253 | ptr->major = major; |
254 | ptr->minor = minor; |
255 | ptr->devname = devname; |
256 | ptr->total.delta = 0; |
257 | ptr->total.old = total; |
258 | ptr->rio.delta = 0; |
259 | ptr->rio.old = rio; |
260 | ptr->wio.delta = 0; |
261 | ptr->wio.old = wio; |
262 | ptr->rblk.delta = 0; |
263 | ptr->rblk.old = rblk; |
264 | ptr->wblk.delta = 0; |
265 | ptr->wblk.old = wblk; |
266 | ptr->rtim.delta = 0; |
267 | ptr->rtim.old = rtim; |
268 | ptr->wtim.delta = 0; |
269 | ptr->wtim.old = wtim; |
270 | /* fyi: ipqueue doesn't have a delta */ |
271 | ptr->ioqueue = ioqueue; |
272 | |
273 | ptr->alive = 1; |
274 | ptr->next = 0; |
275 | if (last) { |
276 | /* Append new entry at end of list. */ |
277 | last->next = ptr; |
278 | } |
279 | else { |
280 | /* List is empty, so we insert the fist element into the list. */ |
281 | DiskIO = ptr; |
282 | } |
283 | |
284 | sprintf(sensorName, "disk/%s_(%d:%d)/Rate/totalio" , devname, major, minor); |
285 | registerMonitor(sensorName, "float" , print26DiskIO, print26DiskIOInfo, |
286 | StatSM); |
287 | sprintf(sensorName, "disk/%s_(%d:%d)/Rate/rio" , devname, major, minor); |
288 | registerMonitor(sensorName, "float" , print26DiskIO, print26DiskIOInfo, |
289 | StatSM); |
290 | sprintf(sensorName, "disk/%s_(%d:%d)/Rate/wio" , devname, major, minor); |
291 | registerMonitor(sensorName, "float" , print26DiskIO, print26DiskIOInfo, |
292 | StatSM); |
293 | sprintf(sensorName, "disk/%s_(%d:%d)/Rate/rblk" , devname, major, minor); |
294 | registerMonitor(sensorName, "float" , print26DiskIO, print26DiskIOInfo, |
295 | StatSM); |
296 | sprintf(sensorName, "disk/%s_(%d:%d)/Rate/wblk" , devname, major, minor); |
297 | registerMonitor(sensorName, "float" , print26DiskIO, print26DiskIOInfo, |
298 | StatSM); |
299 | |
300 | sprintf(sensorName, "disk/%s_(%d:%d)/Delta/totalio" , devname, major, minor); |
301 | registerMonitor(sensorName, "integer" , print26DiskIO, print26DiskIOInfo, |
302 | StatSM); |
303 | sprintf(sensorName, "disk/%s_(%d:%d)/Delta/rio" , devname, major, minor); |
304 | registerMonitor(sensorName, "integer" , print26DiskIO, print26DiskIOInfo, |
305 | StatSM); |
306 | sprintf(sensorName, "disk/%s_(%d:%d)/Delta/wio" , devname, major, minor); |
307 | registerMonitor(sensorName, "integer" , print26DiskIO, print26DiskIOInfo, |
308 | StatSM); |
309 | sprintf(sensorName, "disk/%s_(%d:%d)/Delta/rblk" , devname, major, minor); |
310 | registerMonitor(sensorName, "integer" , print26DiskIO, print26DiskIOInfo, |
311 | StatSM); |
312 | sprintf(sensorName, "disk/%s_(%d:%d)/Delta/wblk" , devname, major, minor); |
313 | registerMonitor(sensorName, "integer" , print26DiskIO, print26DiskIOInfo, |
314 | StatSM); |
315 | sprintf(sensorName, "disk/%s_(%d:%d)/Delta/rtim" , devname, major, minor); |
316 | registerMonitor(sensorName, "integer" , print26DiskIO, print26DiskIOInfo, |
317 | StatSM); |
318 | sprintf(sensorName, "disk/%s_(%d:%d)/Delta/wtim" , devname, major, minor); |
319 | registerMonitor(sensorName, "integer" , print26DiskIO, print26DiskIOInfo, |
320 | StatSM); |
321 | |
322 | sprintf(sensorName, "disk/%s_(%d:%d)/ioqueue" , devname, major, minor); |
323 | registerMonitor(sensorName, "integer" , print26DiskIO, print26DiskIOInfo, |
324 | StatSM); |
325 | } |
326 | |
327 | return 0; |
328 | } |
329 | |
330 | static void cleanup26DiskList( void ) { |
331 | DiskIOInfo* ptr = DiskIO; |
332 | DiskIOInfo* last = 0; |
333 | |
334 | while ( ptr ) { |
335 | if ( ptr->alive == 0 ) { |
336 | DiskIOInfo* newPtr; |
337 | char sensorName[ 128 ]; |
338 | |
339 | /* Disk device has disappeared. We have to remove it from |
340 | * the list and unregister the monitors. */ |
341 | sprintf( sensorName, "disk/%s_(%d:%d)/Rate/totalio" , ptr->devname, ptr->major, ptr->minor ); |
342 | removeMonitor( sensorName ); |
343 | sprintf( sensorName, "disk/%s_(%d:%d)/Rate/rio" , ptr->devname, ptr->major, ptr->minor ); |
344 | removeMonitor( sensorName ); |
345 | sprintf( sensorName, "disk/%s_(%d:%d)/Rate/wio" , ptr->devname, ptr->major, ptr->minor ); |
346 | removeMonitor( sensorName ); |
347 | sprintf( sensorName, "disk/%s_(%d:%d)/Rate/rblk" , ptr->devname, ptr->major, ptr->minor ); |
348 | removeMonitor( sensorName ); |
349 | sprintf( sensorName, "disk/%s_(%d:%d)/Rate/wblk" , ptr->devname, ptr->major, ptr->minor ); |
350 | removeMonitor( sensorName ); |
351 | |
352 | sprintf( sensorName, "disk/%s_(%d:%d)/Delta/totalio" , ptr->devname, ptr->major, ptr->minor ); |
353 | removeMonitor( sensorName ); |
354 | sprintf( sensorName, "disk/%s_(%d:%d)/Delta/rio" , ptr->devname, ptr->major, ptr->minor ); |
355 | removeMonitor( sensorName ); |
356 | sprintf( sensorName, "disk/%s_(%d:%d)/Delta/wio" , ptr->devname, ptr->major, ptr->minor ); |
357 | removeMonitor( sensorName ); |
358 | sprintf( sensorName, "disk/%s_(%d:%d)/Delta/rblk" , ptr->devname, ptr->major, ptr->minor ); |
359 | removeMonitor( sensorName ); |
360 | sprintf( sensorName, "disk/%s_(%d:%d)/Delta/wblk" , ptr->devname, ptr->major, ptr->minor ); |
361 | removeMonitor( sensorName ); |
362 | sprintf( sensorName, "disk/%s_(%d:%d)/Delta/rtim" , ptr->devname, ptr->major, ptr->minor ); |
363 | removeMonitor( sensorName ); |
364 | sprintf( sensorName, "disk/%s_(%d:%d)/Delta/wtim" , ptr->devname, ptr->major, ptr->minor ); |
365 | removeMonitor( sensorName ); |
366 | |
367 | sprintf( sensorName, "disk/%s_(%d:%d)/ioqueue" , ptr->devname, ptr->major, ptr->minor ); |
368 | removeMonitor( sensorName ); |
369 | |
370 | if ( last ) { |
371 | last->next = ptr->next; |
372 | newPtr = ptr->next; |
373 | } |
374 | else { |
375 | DiskIO = ptr->next; |
376 | newPtr = DiskIO; |
377 | last = 0; |
378 | } |
379 | |
380 | free ( ptr ); |
381 | ptr = newPtr; |
382 | } |
383 | else { |
384 | ptr->alive = 0; |
385 | last = ptr; |
386 | ptr = ptr->next; |
387 | } |
388 | } |
389 | } |
390 | |
391 | void print26DiskIO( const char* cmd ) { |
392 | int major, minor; |
393 | char devname[DISKDEVNAMELEN]; |
394 | char name[ 17 ]; |
395 | DiskIOInfo* ptr; |
396 | |
397 | if ( Dirty ) |
398 | processDiskstats(); |
399 | |
400 | if(sscanf( cmd, "disk/%[^_]_(%d:%d)/Rate/%16s" , devname, &major, &minor, name ) == 4) { |
401 | /* Show rate of change in sensor values in this interval */ |
402 | |
403 | ptr = DiskIO; |
404 | while ( ptr && ( ptr->major != major || ptr->minor != minor ) ) |
405 | ptr = ptr->next; |
406 | |
407 | if ( !ptr ) { |
408 | print_error( "RECONFIGURE" ); |
409 | output( "0\n" ); |
410 | |
411 | log_error( "Disk device disappeared" ); |
412 | return; |
413 | } |
414 | |
415 | if ( strcmp( name, "totalio" ) == 0 ) |
416 | output( "%f\n" , (float)( ptr->total.delta / timeInterval ) ); |
417 | else if ( strcmp( name, "rio" ) == 0 ) |
418 | output( "%f\n" , (float)( ptr->rio.delta / timeInterval ) ); |
419 | else if ( strcmp( name, "wio" ) == 0 ) |
420 | output( "%f\n" , (float)( ptr->wio.delta / timeInterval ) ); |
421 | else if ( strcmp( name, "rblk" ) == 0 ) |
422 | output( "%f\n" , (float)( ptr->rblk.delta / ( timeInterval * 2 ) ) ); |
423 | else if ( strcmp( name, "wblk" ) == 0 ) |
424 | output( "%f\n" , (float)( ptr->wblk.delta / ( timeInterval * 2 ) ) ); |
425 | else { |
426 | output( "0\n" ); |
427 | log_error( "Unknown disk device property \'%s\'" , name ); |
428 | } |
429 | } |
430 | else if(sscanf( cmd, "disk/%[^_]_(%d:%d)/Delta/%16s" , devname, &major, &minor, name ) == 4) { |
431 | /* Show change in sensor values per this interval */ |
432 | |
433 | ptr = DiskIO; |
434 | while ( ptr && ( ptr->major != major || ptr->minor != minor ) ) |
435 | ptr = ptr->next; |
436 | |
437 | if ( !ptr ) { |
438 | print_error( "RECONFIGURE" ); |
439 | output( "0\n" ); |
440 | |
441 | log_error( "Disk device disappeared" ); |
442 | return; |
443 | } |
444 | |
445 | if ( strcmp( name, "totalio" ) == 0 ) |
446 | output( "%lu\n" , ptr->total.delta ); |
447 | else if ( strcmp( name, "rio" ) == 0 ) |
448 | output( "%lu\n" , ptr->rio.delta ); |
449 | else if ( strcmp( name, "wio" ) == 0 ) |
450 | output( "%lu\n" , ptr->wio.delta ); |
451 | else if ( strcmp( name, "rblk" ) == 0 ) |
452 | output( "%lu\n" , ptr->rblk.delta ); |
453 | else if ( strcmp( name, "wblk" ) == 0 ) |
454 | output( "%lu\n" , ptr->wblk.delta ); |
455 | else if ( strcmp( name, "rtim" ) == 0 ) |
456 | output( "%lu\n" , ptr->rtim.delta ); |
457 | else if ( strcmp( name, "wtim" ) == 0 ) |
458 | output( "%lu\n" , ptr->wtim.delta ); |
459 | else { |
460 | output( "0\n" ); |
461 | log_error( "Unknown disk device property \'%s\'" , name ); |
462 | } |
463 | } |
464 | else if(sscanf( cmd, "disk/%[^_]_(%d:%d)/%16s" , devname, &major, &minor, name ) == 4) { |
465 | /* Show raw sensor values */ |
466 | |
467 | ptr = DiskIO; |
468 | while ( ptr && ( ptr->major != major || ptr->minor != minor ) ) |
469 | ptr = ptr->next; |
470 | |
471 | if ( !ptr ) { |
472 | print_error( "RECONFIGURE" ); |
473 | output( "0\n" ); |
474 | |
475 | log_error( "Disk device disappeared" ); |
476 | return; |
477 | } |
478 | |
479 | if ( strcmp( name, "ioqueue" ) == 0 ) |
480 | output( "%u\n" , ptr->ioqueue ); |
481 | else { |
482 | output( "0\n" ); |
483 | log_error( "Unknown disk device property \'%s\'" , name ); |
484 | } |
485 | } |
486 | } |
487 | |
488 | void print26DiskIOInfo( const char* cmd ) { |
489 | int major, minor; |
490 | char devname[DISKDEVNAMELEN]; |
491 | char name[ 17 ]; |
492 | DiskIOInfo* ptr = DiskIO; |
493 | |
494 | /* For now we print the same info regardless of whether it was a rate, delta, or raw monitor */ |
495 | if(sscanf( cmd, "disk/%[^_]_(%d:%d)/Rate/%16s" , devname, &major, &minor, name ) == 4) { |
496 | } |
497 | else if(sscanf( cmd, "disk/%[^_]_(%d:%d)/Delta/%16s" , devname, &major, &minor, name ) == 4) { |
498 | } |
499 | else if(sscanf( cmd, "disk/%[^_]_(%d:%d)/%16s" , devname, &major, &minor, name ) == 4) { |
500 | } |
501 | else { |
502 | output( "Dummy\t0\t0\t\n" ); |
503 | log_error( "Request for unknown device property \'%s\'" , cmd ); |
504 | } |
505 | |
506 | while ( ptr && ( ptr->major != major || ptr->minor != minor ) ) |
507 | ptr = ptr->next; |
508 | |
509 | if ( !ptr ) { |
510 | /* Disk device has disappeared. Print a dummy answer. */ |
511 | output( "Dummy\t0\t0\t\n" ); |
512 | return; |
513 | } |
514 | |
515 | /* remove trailing '?' */ |
516 | name[ strlen( name ) - 1 ] = '\0'; |
517 | |
518 | if ( strcmp( name, "totalio" ) == 0 ) |
519 | output( "Total accesses device %s (%d:%d)\t0\t0\t1/s\n" , |
520 | devname, major, minor ); |
521 | else if ( strcmp( name, "rio" ) == 0 ) |
522 | output( "Read data device %s (%d:%d)\t0\t0\t1/s\n" , |
523 | devname, major, minor ); |
524 | else if ( strcmp( name, "wio" ) == 0 ) |
525 | output( "Write data device %s (%d:%d)\t0\t0\t1/s\n" , |
526 | devname, major, minor ); |
527 | else if ( strcmp( name, "rblk" ) == 0 ) |
528 | output( "Read accesses device %s (%d:%d)\t0\t0\tKB/s\n" , |
529 | devname, major, minor ); |
530 | else if ( strcmp( name, "wblk" ) == 0 ) |
531 | output( "Write accesses device %s (%d:%d)\t0\t0\tKB/s\n" , |
532 | devname, major, minor ); |
533 | else if ( strcmp( name, "rtim" ) == 0 ) |
534 | output( "# of milliseconds spent reading device %s (%d:%d)\t0\t0\ts\n" , |
535 | devname, major, minor ); |
536 | else if ( strcmp( name, "wtim" ) == 0 ) |
537 | output( "# of milliseconds spent writing device %s (%d:%d)\t0\t0\ts\n" , |
538 | devname, major, minor ); |
539 | else if ( strcmp( name, "ioqueue" ) == 0 ) |
540 | output( "# of I/Os currently in progress on device %s (%d:%d)\t0\t0\t\n" , |
541 | devname, major, minor ); |
542 | else { |
543 | output( "Dummy\t0\t0\t\n" ); |
544 | log_error( "Request for unknown device property \'%s\'" , name ); |
545 | } |
546 | } |
547 | |