ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/i-scream/projects/libstatgrab/src/libstatgrab/disk_stats.c
Revision: 1.59
Committed: Sun Apr 4 23:55:48 2004 UTC (20 years, 1 month ago) by ats
Content type: text/plain
Branch: MAIN
Changes since 1.58: +10 -23 lines
Log Message:
I like copy_string. We should use it EVERYWHERE. Also, the name needed
changing.

File Contents

# Content
1 /*
2 * i-scream central monitoring system
3 * http://www.i-scream.org
4 * Copyright (C) 2000-2004 i-scream
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 * 02111-1307 USA
20 *
21 * $Id: disk_stats.c,v 1.58 2004/04/04 23:26:23 ats Exp $
22 */
23
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <time.h>
32 #include "statgrab.h"
33 #include "vector.h"
34
35 #ifdef SOLARIS
36 #include <sys/mnttab.h>
37 #include <sys/statvfs.h>
38 #include <kstat.h>
39 #define VALID_FS_TYPES {"ufs", "tmpfs"}
40 #endif
41
42 #if defined(LINUX) || defined(CYGWIN)
43 #include <mntent.h>
44 #include <sys/vfs.h>
45 #include "tools.h"
46 #endif
47
48 #ifdef LINUX
49 #define VALID_FS_TYPES {"adfs", "affs", "befs", "bfs", "efs", "ext2", \
50 "ext3", "vxfs", "hfs", "hfsplus", "hpfs", "jffs", \
51 "jffs2", "minix", "msdos", "ntfs", "qnx4", "ramfs", \
52 "rootfs", "reiserfs", "sysv", "v7", "udf", "ufs", \
53 "umsdos", "vfat", "xfs", "jfs"}
54 #endif
55
56 #ifdef CYGWIN
57 #define VALID_FS_TYPES {"user"}
58 #endif
59
60 #ifdef ALLBSD
61 #include <sys/param.h>
62 #include <sys/ucred.h>
63 #include <sys/mount.h>
64 #endif
65 #if defined(FREEBSD) || defined(DFBSD)
66 #include <sys/dkstat.h>
67 #include <devstat.h>
68 #define VALID_FS_TYPES {"hpfs", "msdosfs", "ntfs", "udf", "ext2fs", \
69 "ufs", "mfs"}
70 #endif
71 #if defined(NETBSD) || defined(OPENBSD)
72 #include <sys/param.h>
73 #include <sys/sysctl.h>
74 #include <sys/disk.h>
75 #define VALID_FS_TYPES {"ffs", "mfs", "msdos", "lfs", "adosfs", "ext2fs", \
76 "ntfs"}
77 #endif
78
79 static void disk_stat_init(disk_stat_t *d) {
80 d->device_name = NULL;
81 d->fs_type = NULL;
82 d->mnt_point = NULL;
83 }
84
85 static void disk_stat_destroy(disk_stat_t *d) {
86 free(d->device_name);
87 free(d->fs_type);
88 free(d->mnt_point);
89 }
90
91 int is_valid_fs_type(const char *type) {
92 const char *types[] = VALID_FS_TYPES;
93 int i;
94
95 for (i = 0; i < (sizeof types / sizeof *types); i++) {
96 if (strcmp(types[i], type) == 0) {
97 return 1;
98 }
99 }
100 return 0;
101 }
102
103 disk_stat_t *get_disk_stats(int *entries){
104 VECTOR_DECLARE_STATIC(disk_stats, disk_stat_t, 10,
105 disk_stat_init, disk_stat_destroy);
106
107 int valid_type;
108 int num_disks=0;
109 #if defined(LINUX) || defined (SOLARIS) || defined(CYGWIN)
110 FILE *f;
111 #endif
112
113 disk_stat_t *disk_ptr;
114
115 #ifdef SOLARIS
116 struct mnttab mp;
117 struct statvfs fs;
118 #endif
119 #if defined(LINUX) || defined(CYGWIN)
120 struct mntent *mp;
121 struct statfs fs;
122 #endif
123 #ifdef ALLBSD
124 int nummnt;
125 struct statfs *mp;
126 #endif
127
128 #ifdef ALLBSD
129 nummnt=getmntinfo(&mp , MNT_LOCAL);
130 if (nummnt<=0){
131 return NULL;
132 }
133 for(;nummnt--; mp++){
134 valid_type = is_valid_fs_type(mp->f_fstypename);
135 #endif
136
137 #if defined(LINUX) || defined(CYGWIN)
138 if ((f=setmntent("/etc/mtab", "r" ))==NULL){
139 return NULL;
140 }
141
142 while((mp=getmntent(f))){
143 if((statfs(mp->mnt_dir, &fs)) !=0){
144 continue;
145 }
146
147 valid_type = is_valid_fs_type(mp->mnt_type);
148 #endif
149
150 #ifdef SOLARIS
151 if ((f=fopen("/etc/mnttab", "r" ))==NULL){
152 return NULL;
153 }
154 while((getmntent(f, &mp)) == 0){
155 if ((statvfs(mp.mnt_mountp, &fs)) !=0){
156 continue;
157 }
158 valid_type = is_valid_fs_type(mp.mnt_fstype);
159 #endif
160
161 if(valid_type){
162 if (VECTOR_RESIZE(disk_stats, num_disks + 1) < 0) {
163 return NULL;
164 }
165 disk_ptr=disk_stats+num_disks;
166
167 #ifdef ALLBSD
168 if (update_string(&disk_ptr->device_name, mp->f_mntfromname) == NULL) {
169 return NULL;
170 }
171 if (update_string(&disk_ptr->fs_type, mp->f_fstypename) == NULL) {
172 return NULL;
173 }
174 if (update_string(&disk_ptr->mnt_point, mp->f_mntonname) == NULL) {
175 return NULL;
176 }
177
178 disk_ptr->size = (long long)mp->f_bsize * (long long) mp->f_blocks;
179 disk_ptr->avail = (long long)mp->f_bsize * (long long) mp->f_bavail;
180 disk_ptr->used = (disk_ptr->size) - ((long long)mp->f_bsize * (long long)mp->f_bfree);
181
182 disk_ptr->total_inodes=(long long)mp->f_files;
183 disk_ptr->free_inodes=(long long)mp->f_ffree;
184 /* Freebsd doesn't have a "available" inodes */
185 disk_ptr->used_inodes=disk_ptr->total_inodes-disk_ptr->free_inodes;
186 #endif
187 #if defined(LINUX) || defined(CYGWIN)
188 if (update_string(&disk_ptr->device_name, mp->mnt_fsname) == NULL) {
189 return NULL;
190 }
191
192 if (update_string(&disk_ptr->fs_type, mp->mnt_type) == NULL) {
193 return NULL;
194 }
195
196 if (update_string(&disk_ptr->mnt_point, mp->mnt_dir) == NULL) {
197 return NULL;
198 }
199 disk_ptr->size = (long long)fs.f_bsize * (long long)fs.f_blocks;
200 disk_ptr->avail = (long long)fs.f_bsize * (long long)fs.f_bavail;
201 disk_ptr->used = (disk_ptr->size) - ((long long)fs.f_bsize * (long long)fs.f_bfree);
202
203 disk_ptr->total_inodes=(long long)fs.f_files;
204 disk_ptr->free_inodes=(long long)fs.f_ffree;
205 /* Linux doesn't have a "available" inodes */
206 disk_ptr->used_inodes=disk_ptr->total_inodes-disk_ptr->free_inodes;
207 #endif
208
209 #ifdef SOLARIS
210 /* Maybe make this char[bigenough] and do strncpy's and put a null in the end?
211 * Downside is its a bit hungry for a lot of mounts, as MNT_MAX_SIZE would prob
212 * be upwards of a k each
213 */
214 if (update_string(&disk_ptr->device_name, mp.mnt_special) == NULL) {
215 return NULL;
216 }
217
218 if (update_string(&disk_ptr->fs_type, mp.mnt_fstype) == NULL) {
219 return NULL;
220 }
221
222 if (update_string(&disk_ptr->mnt_point, mp.mnt_mountp) == NULL) {
223 return NULL;
224 }
225
226 disk_ptr->size = (long long)fs.f_frsize * (long long)fs.f_blocks;
227 disk_ptr->avail = (long long)fs.f_frsize * (long long)fs.f_bavail;
228 disk_ptr->used = (disk_ptr->size) - ((long long)fs.f_frsize * (long long)fs.f_bfree);
229
230 disk_ptr->total_inodes=(long long)fs.f_files;
231 disk_ptr->used_inodes=disk_ptr->total_inodes - (long long)fs.f_ffree;
232 disk_ptr->free_inodes=(long long)fs.f_favail;
233 #endif
234 num_disks++;
235 }
236 }
237
238 *entries=num_disks;
239
240 /* If this fails, there is very little i can do about it, so
241 I'll ignore it :) */
242 #if defined(LINUX) || defined(CYGWIN)
243 endmntent(f);
244 #endif
245 #if defined(SOLARIS)
246 fclose(f);
247 #endif
248
249 return disk_stats;
250
251 }
252
253 static void diskio_stat_init(diskio_stat_t *d) {
254 d->disk_name = NULL;
255 }
256
257 static void diskio_stat_destroy(diskio_stat_t *d) {
258 free(d->disk_name);
259 }
260
261 VECTOR_DECLARE_STATIC(diskio_stats, diskio_stat_t, 10,
262 diskio_stat_init, diskio_stat_destroy);
263
264 #ifdef LINUX
265 typedef struct {
266 int major;
267 int minor;
268 } partition;
269 #endif
270
271 diskio_stat_t *get_diskio_stats(int *entries){
272 int num_diskio;
273 #ifndef LINUX
274 diskio_stat_t *diskio_stats_ptr;
275 #endif
276
277 #ifdef SOLARIS
278 kstat_ctl_t *kc;
279 kstat_t *ksp;
280 kstat_io_t kios;
281 #endif
282 #ifdef LINUX
283 FILE *f;
284 char *line_ptr;
285 int major, minor;
286 int has_pp_stats = 1;
287 VECTOR_DECLARE_STATIC(parts, partition, 16, NULL, NULL);
288 int i, n;
289 time_t now;
290 const char *format;
291 #endif
292 #if defined(FREEBSD) || defined(DFBSD)
293 static struct statinfo stats;
294 static int stats_init = 0;
295 int counter;
296 struct device_selection *dev_sel = NULL;
297 int n_selected, n_selections;
298 long sel_gen;
299 struct devstat *dev_ptr;
300 #endif
301 #ifdef NETBSD
302 struct disk_sysctl *stats;
303 #endif
304 #ifdef OPENBSD
305 int diskcount;
306 char *disknames, *name, *bufpp;
307 char **dk_name;
308 struct diskstats *stats;
309 #endif
310 #ifdef NETBSD
311 #define MIBSIZE 3
312 #endif
313 #ifdef OPENBSD
314 #define MIBSIZE 2
315 #endif
316 #if defined(NETBSD) || defined(OPENBSD)
317 int num_disks, i;
318 int mib[MIBSIZE];
319 size_t size;
320 #endif
321
322 num_diskio=0;
323
324 #ifdef OPENBSD
325 mib[0] = CTL_HW;
326 mib[1] = HW_DISKCOUNT;
327
328 size = sizeof(diskcount);
329 if (sysctl(mib, MIBSIZE, &diskcount, &size, NULL, 0) < 0) {
330 return NULL;
331 }
332
333 mib[0] = CTL_HW;
334 mib[1] = HW_DISKNAMES;
335
336 if (sysctl(mib, MIBSIZE, NULL, &size, NULL, 0) < 0) {
337 return NULL;
338 }
339
340 disknames = malloc(size);
341 if (disknames == NULL) {
342 return NULL;
343 }
344
345 if (sysctl(mib, MIBSIZE, disknames, &size, NULL, 0) < 0) {
346 return NULL;
347 }
348
349 dk_name = calloc(diskcount, sizeof(char *));
350 bufpp = disknames;
351 for (i = 0; i < diskcount && (name = strsep(&bufpp, ",")) != NULL; i++) {
352 dk_name[i] = name;
353 }
354 #endif
355
356 #if defined(NETBSD) || defined(OPENBSD)
357 mib[0] = CTL_HW;
358 mib[1] = HW_DISKSTATS;
359 #ifdef NETBSD
360 mib[2] = sizeof(struct disk_sysctl);
361 #endif
362
363 if (sysctl(mib, MIBSIZE, NULL, &size, NULL, 0) < 0) {
364 return NULL;
365 }
366
367 #ifdef NETBSD
368 num_disks = size / sizeof(struct disk_sysctl);
369 #else
370 num_disks = size / sizeof(struct diskstats);
371 #endif
372
373 stats = malloc(size);
374 if (stats == NULL) {
375 return NULL;
376 }
377
378 if (sysctl(mib, MIBSIZE, stats, &size, NULL, 0) < 0) {
379 return NULL;
380 }
381
382 for (i = 0; i < num_disks; i++) {
383 u_int64_t rbytes, wbytes;
384
385 #ifdef NETBSD
386 #ifdef HAVE_DK_RBYTES
387 rbytes = stats[i].dk_rbytes;
388 wbytes = stats[i].dk_wbytes;
389 #else
390 /* Before 1.7, NetBSD merged reads and writes. */
391 rbytes = wbytes = stats[i].dk_bytes;
392 #endif
393 #else
394 rbytes = wbytes = stats[i].ds_bytes;
395 #endif
396
397 /* Don't keep stats for disks that have never been used. */
398 if (rbytes == 0 && wbytes == 0) {
399 continue;
400 }
401
402 if (VECTOR_RESIZE(diskio_stats, num_diskio + 1) < 0) {
403 return NULL;
404 }
405 diskio_stats_ptr = diskio_stats + num_diskio;
406
407 diskio_stats_ptr->read_bytes = rbytes;
408 diskio_stats_ptr->write_bytes = wbytes;
409 if (diskio_stats_ptr->disk_name != NULL) {
410 free(diskio_stats_ptr->disk_name);
411 }
412 #ifdef NETBSD
413 diskio_stats_ptr->disk_name = strdup(stats[i].dk_name);
414 #else
415 diskio_stats_ptr->disk_name = strdup(dk_name[i]);
416 #endif
417 diskio_stats_ptr->systime = time(NULL);
418
419 num_diskio++;
420 }
421
422 free(stats);
423 #ifdef OPENBSD
424 free(dk_name);
425 free(disknames);
426 #endif
427 #endif
428
429 #if defined(FREEBSD) || defined(DFBSD)
430 if (!stats_init) {
431 stats.dinfo=malloc(sizeof(struct devinfo));
432 if(stats.dinfo==NULL) return NULL;
433 bzero(stats.dinfo, sizeof(struct devinfo));
434 stats_init = 1;
435 }
436 #ifdef FREEBSD5
437 if ((devstat_getdevs(NULL, &stats)) < 0) return NULL;
438 /* Not aware of a get all devices, so i said 999. If we ever
439 * find a machine with more than 999 disks, then i'll change
440 * this number :)
441 */
442 if (devstat_selectdevs(&dev_sel, &n_selected, &n_selections, &sel_gen, stats.dinfo->generation, stats.dinfo->devices, stats.dinfo->numdevs, NULL, 0, NULL, 0, DS_SELECT_ONLY, 999, 1) < 0) return NULL;
443 #else
444 if ((getdevs(&stats)) < 0) return NULL;
445 /* Not aware of a get all devices, so i said 999. If we ever
446 * find a machine with more than 999 disks, then i'll change
447 * this number :)
448 */
449 if (selectdevs(&dev_sel, &n_selected, &n_selections, &sel_gen, stats.dinfo->generation, stats.dinfo->devices, stats.dinfo->numdevs, NULL, 0, NULL, 0, DS_SELECT_ONLY, 999, 1) < 0) return NULL;
450 #endif
451
452 for(counter=0;counter<stats.dinfo->numdevs;counter++){
453 dev_ptr=&stats.dinfo->devices[dev_sel[counter].position];
454
455 /* Throw away devices that have done nothing, ever.. Eg "odd"
456 * devices.. like mem, proc.. and also doesn't report floppy
457 * drives etc unless they are doing stuff :)
458 */
459 #ifdef FREEBSD5
460 if((dev_ptr->bytes[DEVSTAT_READ]==0) && (dev_ptr->bytes[DEVSTAT_WRITE]==0)) continue;
461 #else
462 if((dev_ptr->bytes_read==0) && (dev_ptr->bytes_written==0)) continue;
463 #endif
464
465 if (VECTOR_RESIZE(diskio_stats, num_diskio + 1) < 0) {
466 return NULL;
467 }
468 diskio_stats_ptr=diskio_stats+num_diskio;
469
470 #ifdef FREEBSD5
471 diskio_stats_ptr->read_bytes=dev_ptr->bytes[DEVSTAT_READ];
472 diskio_stats_ptr->write_bytes=dev_ptr->bytes[DEVSTAT_WRITE];
473 #else
474 diskio_stats_ptr->read_bytes=dev_ptr->bytes_read;
475 diskio_stats_ptr->write_bytes=dev_ptr->bytes_written;
476 #endif
477 if(diskio_stats_ptr->disk_name!=NULL) free(diskio_stats_ptr->disk_name);
478 asprintf((&diskio_stats_ptr->disk_name), "%s%d", dev_ptr->device_name, dev_ptr->unit_number);
479 diskio_stats_ptr->systime=time(NULL);
480
481 num_diskio++;
482 }
483 free(dev_sel);
484
485 #endif
486 #ifdef SOLARIS
487 if ((kc = kstat_open()) == NULL) {
488 return NULL;
489 }
490
491 for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
492 if (!strcmp(ksp->ks_class, "disk")) {
493
494 if(ksp->ks_type != KSTAT_TYPE_IO) continue;
495 /* We dont want metadevices appearins as num_diskio */
496 if(strcmp(ksp->ks_module, "md")==0) continue;
497 if((kstat_read(kc, ksp, &kios))==-1){
498 }
499
500 if (VECTOR_RESIZE(diskio_stats, num_diskio + 1) < 0) {
501 kstat_close(kc);
502 return NULL;
503 }
504 diskio_stats_ptr=diskio_stats+num_diskio;
505
506 diskio_stats_ptr->read_bytes=kios.nread;
507
508 diskio_stats_ptr->write_bytes=kios.nwritten;
509
510 if(diskio_stats_ptr->disk_name!=NULL) free(diskio_stats_ptr->disk_name);
511
512 diskio_stats_ptr->disk_name=strdup((char *) get_svr_from_bsd(ksp->ks_name));
513 diskio_stats_ptr->systime=time(NULL);
514 num_diskio++;
515 }
516 }
517
518 kstat_close(kc);
519 #endif
520
521 #ifdef LINUX
522 num_diskio = 0;
523 n = 0;
524
525 /* Read /proc/partitions to find what devices exist. Recent 2.4 kernels
526 have statistics in here too, so we can use those directly.
527 2.6 kernels have /proc/diskstats instead with almost (but not quite)
528 the same format. */
529
530 f = fopen("/proc/diskstats", "r");
531 format = " %d %d %99s %*d %*d %lld %*d %*d %*d %lld";
532 if (f == NULL) {
533 f = fopen("/proc/partitions", "r");
534 format = " %d %d %*d %99s %*d %*d %lld %*d %*d %*d %lld";
535 }
536 if (f == NULL) goto out;
537 now = time(NULL);
538
539 while ((line_ptr = f_read_line(f, "")) != NULL) {
540 char name[100];
541 char *s;
542 long long rsect, wsect;
543
544 int nr = sscanf(line_ptr, format,
545 &major, &minor, name, &rsect, &wsect);
546 if (nr < 3) continue;
547
548 /* Skip device names ending in numbers, since they're
549 partitions. */
550 s = name;
551 while (*s != '\0') s++;
552 --s;
553 if (*s >= '0' && *s <= '9') continue;
554
555 if (nr < 5) {
556 has_pp_stats = 0;
557 rsect = 0;
558 wsect = 0;
559 }
560
561 if (VECTOR_RESIZE(diskio_stats, n + 1) < 0) {
562 goto out;
563 }
564 if (VECTOR_RESIZE(parts, n + 1) < 0) {
565 goto out;
566 }
567
568 if (diskio_stats[n].disk_name != NULL)
569 free(diskio_stats[n].disk_name);
570 diskio_stats[n].disk_name = strdup(name);
571 diskio_stats[n].read_bytes = rsect * 512;
572 diskio_stats[n].write_bytes = wsect * 512;
573 diskio_stats[n].systime = now;
574 parts[n].major = major;
575 parts[n].minor = minor;
576
577 n++;
578 }
579
580 fclose(f);
581 f = NULL;
582
583 if (!has_pp_stats) {
584 /* This is an older kernel where /proc/partitions doesn't
585 contain stats. Read what we can from /proc/stat instead, and
586 fill in the appropriate bits of the list allocated above. */
587
588 f = fopen("/proc/stat", "r");
589 if (f == NULL) goto out;
590 now = time(NULL);
591
592 line_ptr = f_read_line(f, "disk_io:");
593 if (line_ptr == NULL) goto out;
594
595 while((line_ptr=strchr(line_ptr, ' '))!=NULL){
596 long long rsect, wsect;
597
598 if (*++line_ptr == '\0') break;
599
600 if((sscanf(line_ptr,
601 "(%d,%d):(%*d, %*d, %lld, %*d, %lld)",
602 &major, &minor, &rsect, &wsect)) != 4) {
603 continue;
604 }
605
606 /* Find the corresponding device from earlier.
607 Just to add to the fun, "minor" is actually the disk
608 number, not the device minor, so we need to figure
609 out the real minor number based on the major!
610 This list is not exhaustive; if you're running
611 an older kernel you probably don't have fancy
612 I2O hardware anyway... */
613 switch (major) {
614 case 3:
615 case 21:
616 case 22:
617 case 33:
618 case 34:
619 case 36:
620 case 56:
621 case 57:
622 case 88:
623 case 89:
624 case 90:
625 case 91:
626 minor *= 64;
627 break;
628 case 9:
629 case 43:
630 break;
631 default:
632 minor *= 16;
633 break;
634 }
635 for (i = 0; i < n; i++) {
636 if (major == parts[i].major
637 && minor == parts[i].minor)
638 break;
639 }
640 if (i == n) continue;
641
642 /* We read the number of blocks. Blocks are stored in
643 512 bytes */
644 diskio_stats[i].read_bytes = rsect * 512;
645 diskio_stats[i].write_bytes = wsect * 512;
646 diskio_stats[i].systime = now;
647 }
648 }
649
650 num_diskio = n;
651 out:
652 if (f != NULL) fclose(f);
653 #endif
654
655 #ifdef CYGWIN
656 return NULL;
657 #endif
658
659 *entries=num_diskio;
660
661 return diskio_stats;
662 }
663
664 diskio_stat_t *get_diskio_stats_diff(int *entries){
665 VECTOR_DECLARE_STATIC(diff, diskio_stat_t, 1,
666 diskio_stat_init, diskio_stat_destroy);
667 diskio_stat_t *src = NULL, *dest;
668 int i, j, diff_count, new_count;
669
670 if (diskio_stats == NULL) {
671 /* No previous stats, so we can't calculate a difference. */
672 return get_diskio_stats(entries);
673 }
674
675 /* Resize the results array to match the previous stats. */
676 diff_count = VECTOR_SIZE(diskio_stats);
677 if (VECTOR_RESIZE(diff, diff_count) < 0) {
678 return NULL;
679 }
680
681 /* Copy the previous stats into the result. */
682 for (i = 0; i < diff_count; i++) {
683 src = &diskio_stats[i];
684 dest = &diff[i];
685
686 if (dest->disk_name != NULL) {
687 free(dest->disk_name);
688 }
689 dest->disk_name = strdup(src->disk_name);
690 dest->read_bytes = src->read_bytes;
691 dest->write_bytes = src->write_bytes;
692 dest->systime = src->systime;
693 }
694
695 /* Get a new set of stats. */
696 if (get_diskio_stats(&new_count) == NULL) {
697 return NULL;
698 }
699
700 /* For each previous stat... */
701 for (i = 0; i < diff_count; i++) {
702 dest = &diff[i];
703
704 /* ... find the corresponding new stat ... */
705 for (j = 0; j < new_count; j++) {
706 /* Try the new stat in the same position first,
707 since that's most likely to be it. */
708 src = &diskio_stats[(i + j) % new_count];
709 if (strcmp(src->disk_name, dest->disk_name) == 0) {
710 break;
711 }
712 }
713 if (j == new_count) {
714 /* No match found. */
715 continue;
716 }
717
718 /* ... and subtract the previous stat from it to get the
719 difference. */
720 dest->read_bytes = src->read_bytes - dest->read_bytes;
721 dest->write_bytes = src->write_bytes - dest->write_bytes;
722 dest->systime = src->systime - dest->systime;
723 }
724
725 *entries = diff_count;
726 return diff;
727 }
728