[users at i-scream] [PATCH] finer grained filesystem stats

Roman Neuhauser neuhauser at sigpipe.cz
Wed Mar 23 11:16:26 GMT 2005


Hello,

current sg_get_fs_stats() glosses over the numbers a bit too much for my
needs. Since filesystem statistics (that sg_get_fs_stats() doesn't
provide) are the only thing I need from libstatgrab ATM it's quite
important for me that something like this is accepted in the mainline.
IOW if there's something you don't like about the patch, just let me
know.

I don't have access to any Solaris or HP-UX systems, but the
ALLBSD/LINUX branches seem to compile and run just fine; tested with
statgrab (sg_get_fs_stats()) and pecl-statgrab (sg_get_fs_stats2()).

I'd like to point out / explain a few details of the patch, please do
provide feedback on any aspect of the code.

* I introduced a few macros in order to streamline the code a bit and
hide away the differences:

#ifdef ALLBSD
#define MP_FSTYPENAME(mp) (mp)->f_fstypename
#define FS_FRSIZE(fs)     (long long) (*fs)->f_bsize
#define FS_FAVAIL(fs)     -1LL
...
#endif
#if defined(LINUX) || defined(CYGWIN) || defined(HPUX)
#define MP_FSTYPENAME(mp) (mp)->mnt_type
#define FS_FRSIZE(fs)     (long long) (fs).f_frsize
...
#endif
#ifdef SOLARIS
#define MP_FSTYPENAME(mp) (mp).mnt_fstype
#define FS_FRSIZE(fs)     (long long) (fs).f_frsize
...
#endif

The names are chosen to copy the more used name of the appropriate
struct member, with exceptions where the name IMO better describes
the value.

These macros allowed me to reduce a good deal of duplicated code
in sg_get_fs_stats(), or rather, its descendant, sg_get_fs_stats2().

* The interface to the finegrained statistics is

  typedef struct {
      char *special;
      char *fstype;
      char *mountp;
      long long iosize;
      long long frsize;
      long long frcnt;
      long long frfree;
      long long fravail;
      long long icnt;
      long long ifree;
      long long iavail;
  } sg_fs_stats2;
 
  sg_fs_stats2 *sg_get_fs_stats2(int *entries);

Again, I have chosen names that are more common or better describe
the data: there's sg_fs_stats2.special instead of device_name, because
devices are not the only thing that back a filesystem: see nfs.
"special" is also used in freebsd mount(8) man page.

* I switched the LINUX || CYGWIN || HPUX case from statfs.h to statvfs.h
as it seems that statvfs.h does report available inodes; at least that's
what statvfs(2) claims on RHEL3:

           fsfilcnt_t     f_favail;   /* # free inodes for non-root */

although I'm not really sure about it: the numbers it contains look
suspiciously same as the ones that df -i gives me in IFree.

* sg_get_fs_stats2() returns a pointer to a static variable just like 
sg_get_fs_stats()

* sg_get_fs_stats() has been converted to call sg_get_fs_stats(),
reducing code complexity and duplication some more

* I didn't touch statgrab or saidar. Should I?

Thanks for any feedback.

-- 
How many Vietnam vets does it take to screw in a light bulb?
You don't know, man.  You don't KNOW.
Cause you weren't THERE.             http://bash.org/?255991
-------------- next part --------------
? .swp
? src/libstatgrab/.disk_stats.c.swp
Index: src/libstatgrab/disk_stats.c
===================================================================
RCS file: /cvs/i-scream/projects/libstatgrab/src/libstatgrab/disk_stats.c,v
retrieving revision 1.80
diff -u -r1.80 disk_stats.c
--- src/libstatgrab/disk_stats.c	24 Feb 2005 12:34:45 -0000	1.80
+++ src/libstatgrab/disk_stats.c	23 Mar 2005 10:25:38 -0000
@@ -43,6 +43,7 @@
 #if defined(LINUX) || defined(CYGWIN)
 #include <mntent.h>
 #include <sys/vfs.h>
+#include <sys/statvfs.h>
 #endif
 
 #ifdef LINUX
@@ -90,6 +91,46 @@
 #define DISK_BATCH 30
 #endif
 
+#ifdef ALLBSD
+#define MP_FSTYPENAME(mp) (mp)->f_fstypename
+#define MP_DEVNAME(mp)    (mp)->f_mntfromname
+#define MP_MOUNTP(mp)     (mp)->f_mntonname
+#define FS_FRSIZE(fs)     (long long) (*fs)->f_bsize
+#define FS_BSIZE(fs)      (long long) (*fs)->f_iosize
+#define FS_BLOCKS(fs)     (long long) (*fs)->f_blocks
+#define FS_BFREE(fs)      (long long) (*fs)->f_bfree
+#define FS_BAVAIL(fs)     (long long) (*fs)->f_bavail
+#define FS_FILES(fs)      (long long) (*fs)->f_files
+#define FS_FFREE(fs)      (long long) (*fs)->f_ffree
+#define FS_FAVAIL(fs)     -1LL
+#endif
+#if defined(LINUX) || defined(CYGWIN) || defined(HPUX)
+#define MP_FSTYPENAME(mp) (mp)->mnt_type
+#define MP_DEVNAME(mp)    (mp)->mnt_fsname
+#define MP_MOUNTP(mp)     (mp)->mnt_dir
+#define FS_FRSIZE(fs)     (long long) (fs).f_frsize
+#define FS_BSIZE(fs)      (long long) (fs).f_bsize
+#define FS_BLOCKS(fs)     (long long) (fs).f_blocks
+#define FS_BFREE(fs)      (long long) (fs).f_bfree
+#define FS_BAVAIL(fs)     (long long) (fs).f_bavail
+#define FS_FILES(fs)      (long long) (fs).f_files
+#define FS_FFREE(fs)      (long long) (fs).f_ffree
+#define FS_FAVAIL(fs)     (long long) (fs).f_favail
+#endif
+#ifdef SOLARIS
+#define MP_FSTYPENAME(mp) (mp).mnt_fstype
+#define MP_DEVNAME(mp)    (mp).mnt_special
+#define MP_MOUNTP(mp)     (mp).mnt_mountp
+#define FS_FRSIZE(fs)     (long long) (fs).f_frsize
+#define FS_BSIZE(fs)      (long long) (fs).f_bsize
+#define FS_BLOCKS(fs)     (long long) (fs).f_blocks
+#define FS_BFREE(fs)      (long long) (fs).f_bfree
+#define FS_BAVAIL(fs)     (long long) (fs).f_bavail
+#define FS_FILES(fs)      (long long) (fs).f_files
+#define FS_FFREE(fs)      (long long) (fs).f_ffree
+#define FS_FAVAIL(fs)     (long long) (fs).f_favail
+#endif
+
 static void disk_stat_init(sg_fs_stats *d) {
 	d->device_name = NULL;
 	d->fs_type = NULL;
@@ -102,6 +143,18 @@
 	free(d->mnt_point);
 }
 
+static void disk_stat_init2(sg_fs_stats2 *d) {
+	d->special = NULL;
+	d->fstype = NULL;
+	d->mountp = NULL;
+}
+
+static void disk_stat_destroy2(sg_fs_stats2 *d) {
+	free(d->special);
+	free(d->fstype);
+	free(d->mountp);
+}
+
 static int is_valid_fs_type(const char *type) {
 	const char *types[] = VALID_FS_TYPES;
 	int i;
@@ -118,13 +171,64 @@
 	VECTOR_DECLARE_STATIC(disk_stats, sg_fs_stats, 10,
 			      disk_stat_init, disk_stat_destroy);
 
+	sg_fs_stats *disk_ptr;
+	sg_fs_stats2 *disk_ptr2, *disk_stats2;
+	int i, num_disks=0;
+
+    disk_stats2 = sg_get_fs_stats2(&num_disks);
+
+    if (VECTOR_RESIZE(disk_stats, num_disks) < 0) {
+        return NULL;
+    }
+    for (i = 0; i < num_disks; i++) {
+        disk_ptr  = disk_stats + i;
+        disk_ptr2 = disk_stats2++;
+        /* Maybe make this char[bigenough] and do strncpy's and put a null in the end? 
+         * Downside is its a bit hungry for a lot of mounts, as MNT_MAX_SIZE would prob 
+         * be upwards of a k each 
+         */
+        if (sg_update_string(&disk_ptr->device_name, disk_ptr2->special) < 0) {
+            return NULL;
+        }
+        if (sg_update_string(&disk_ptr->fs_type, disk_ptr2->fstype) < 0) {
+            return NULL;
+        }
+        if (sg_update_string(&disk_ptr->mnt_point, disk_ptr2->mountp) < 0) {
+            return NULL;
+        }
+
+        disk_ptr->size = disk_ptr2->frsize * disk_ptr2->frcnt;
+        disk_ptr->avail = disk_ptr2->frsize * disk_ptr2->fravail;
+        disk_ptr->used = disk_ptr->size - disk_ptr2->frsize * disk_ptr2->frfree;
+
+        disk_ptr->total_inodes = disk_ptr2->icnt;
+
+#ifdef ALLBSD
+        /* Freebsd doesn't have a "available" inodes */
+        disk_ptr->free_inodes=disk_ptr2->ifree;
+#else
+        disk_ptr->free_inodes=disk_ptr2->iavail;
+#endif
+        disk_ptr->used_inodes=disk_ptr->total_inodes-disk_ptr->free_inodes;
+
+    }
+
+	*entries=num_disks;	
+
+	return disk_stats;
+}
+
+sg_fs_stats2 *sg_get_fs_stats2(int *entries){
+	VECTOR_DECLARE_STATIC(disk_stats, sg_fs_stats2, 10,
+			      disk_stat_init2, disk_stat_destroy2);
+
 	int valid_type;
 	int num_disks=0;
 #if defined(LINUX) || defined (SOLARIS) || defined(CYGWIN) || defined(HPUX)
 	FILE *f;
 #endif
 
-	sg_fs_stats *disk_ptr;
+	sg_fs_stats2 *disk_ptr;
 
 #ifdef SOLARIS
 	struct mnttab mp;
@@ -132,14 +236,14 @@
 #endif
 #if defined(LINUX) || defined(CYGWIN) || defined(HPUX)
 	struct mntent *mp;
-	struct statfs fs;
+	struct statvfs fs;
 #endif
 #ifdef ALLBSD
 	int nummnt;
 #ifdef HAVE_STATVFS
-	struct statvfs *mp;
+	struct statvfs *mp, **fs;
 #else
-	struct statfs *mp;
+	struct statfs *mp, **fs;
 #endif
 #endif
 
@@ -149,8 +253,8 @@
 		sg_set_error_with_errno(SG_ERROR_GETMNTINFO, NULL);
 		return NULL;
 	}
-	for(;nummnt--; mp++){
-		valid_type = is_valid_fs_type(mp->f_fstypename);
+	fs = ∓
+	for(;nummnt--; (*fs)++){
 #endif
 
 #if defined(LINUX) || defined(CYGWIN) || defined(HPUX)
@@ -164,11 +268,10 @@
 	}
 
 	while((mp=getmntent(f))){
-		if((statfs(mp->mnt_dir, &fs)) !=0){
+		if((statvfs(mp->mnt_dir, &fs)) !=0){
 			continue;
 		}	
 
-		valid_type = is_valid_fs_type(mp->mnt_type);
 #endif
 
 #ifdef SOLARIS
@@ -180,8 +283,8 @@
 		if ((statvfs(mp.mnt_mountp, &fs)) !=0){
 			continue;
 		}
-		valid_type = is_valid_fs_type(mp.mnt_fstype);
 #endif
+		valid_type = is_valid_fs_type(MP_FSTYPENAME(mp));
 
 		if(valid_type){
 			if (VECTOR_RESIZE(disk_stats, num_disks + 1) < 0) {
@@ -189,73 +292,29 @@
 			}
 			disk_ptr=disk_stats+num_disks;
 
-#ifdef ALLBSD
-			if (sg_update_string(&disk_ptr->device_name, mp->f_mntfromname) < 0) {
-				return NULL;
-			}
-			if (sg_update_string(&disk_ptr->fs_type, mp->f_fstypename) < 0) {
-				return NULL;
-			}
-			if (sg_update_string(&disk_ptr->mnt_point, mp->f_mntonname) < 0) {
-				return NULL;
-			}
-
-			disk_ptr->size = (long long)mp->f_bsize * (long long) mp->f_blocks;
-			disk_ptr->avail = (long long)mp->f_bsize * (long long) mp->f_bavail;
-			disk_ptr->used = (disk_ptr->size) - ((long long)mp->f_bsize * (long long)mp->f_bfree);
-
-			disk_ptr->total_inodes=(long long)mp->f_files;
-			disk_ptr->free_inodes=(long long)mp->f_ffree;
-			/* Freebsd doesn't have a "available" inodes */
-			disk_ptr->used_inodes=disk_ptr->total_inodes-disk_ptr->free_inodes;
-#endif
-#if defined(LINUX) || defined(CYGWIN) || defined(HPUX)
-			if (sg_update_string(&disk_ptr->device_name, mp->mnt_fsname) < 0) {
-				return NULL;
-			}
-				
-			if (sg_update_string(&disk_ptr->fs_type, mp->mnt_type) < 0) {	
-				return NULL;
-			}
-
-			if (sg_update_string(&disk_ptr->mnt_point, mp->mnt_dir) < 0) {
-				return NULL;
-			}
-			disk_ptr->size = (long long)fs.f_bsize * (long long)fs.f_blocks;
-			disk_ptr->avail = (long long)fs.f_bsize * (long long)fs.f_bavail;
-			disk_ptr->used = (disk_ptr->size) - ((long long)fs.f_bsize * (long long)fs.f_bfree);
-
-			disk_ptr->total_inodes=(long long)fs.f_files;
-			disk_ptr->free_inodes=(long long)fs.f_ffree;
-			/* Linux doesn't have a "available" inodes */
-			disk_ptr->used_inodes=disk_ptr->total_inodes-disk_ptr->free_inodes;
-#endif
-
-#ifdef SOLARIS
 			/* Maybe make this char[bigenough] and do strncpy's and put a null in the end? 
 			 * Downside is its a bit hungry for a lot of mounts, as MNT_MAX_SIZE would prob 
 			 * be upwards of a k each 
 			 */
-			if (sg_update_string(&disk_ptr->device_name, mp.mnt_special) < 0) {
+			if (sg_update_string(&disk_ptr->special, MP_DEVNAME(mp)) < 0) {
 				return NULL;
 			}
-
-			if (sg_update_string(&disk_ptr->fs_type, mp.mnt_fstype) < 0) {
+			if (sg_update_string(&disk_ptr->fstype, MP_FSTYPENAME(mp)) < 0) {
 				return NULL;
 			}
-	
-			if (sg_update_string(&disk_ptr->mnt_point, mp.mnt_mountp) < 0) {
+			if (sg_update_string(&disk_ptr->mountp, MP_MOUNTP(mp)) < 0) {
 				return NULL;
 			}
-			
-			disk_ptr->size = (long long)fs.f_frsize * (long long)fs.f_blocks;
-			disk_ptr->avail = (long long)fs.f_frsize * (long long)fs.f_bavail;
-			disk_ptr->used = (disk_ptr->size) - ((long long)fs.f_frsize * (long long)fs.f_bfree);
-		
-			disk_ptr->total_inodes=(long long)fs.f_files;
-			disk_ptr->used_inodes=disk_ptr->total_inodes - (long long)fs.f_ffree;
-			disk_ptr->free_inodes=(long long)fs.f_favail;
-#endif
+
+			disk_ptr->iosize  = FS_BSIZE(fs);
+			disk_ptr->frsize  = FS_FRSIZE(fs);
+			disk_ptr->frcnt   = FS_BLOCKS(fs);
+			disk_ptr->frfree  = FS_BFREE(fs);
+			disk_ptr->fravail = FS_BAVAIL(fs);
+			disk_ptr->icnt    = FS_FILES(fs);
+			disk_ptr->ifree   = FS_FFREE(fs);
+			disk_ptr->iavail  = FS_FAVAIL(fs);
+
 			num_disks++;
 		}
 	}
Index: src/libstatgrab/statgrab.h
===================================================================
RCS file: /cvs/i-scream/projects/libstatgrab/src/libstatgrab/statgrab.h,v
retrieving revision 1.54
diff -u -r1.54 statgrab.h
--- src/libstatgrab/statgrab.h	1 Nov 2004 18:30:17 -0000	1.54
+++ src/libstatgrab/statgrab.h	23 Mar 2005 10:25:38 -0000
@@ -155,7 +155,22 @@
 	long long free_inodes;
 } sg_fs_stats;
 
+typedef struct {
+	char *special;
+	char *fstype;
+	char *mountp;
+	long long iosize;
+	long long frsize;
+	long long frcnt;
+	long long frfree;
+	long long fravail;
+	long long icnt;
+	long long ifree;
+	long long iavail;
+} sg_fs_stats2;
+
 sg_fs_stats *sg_get_fs_stats(int *entries);
+sg_fs_stats2 *sg_get_fs_stats2(int *entries);
 
 int sg_fs_compare_device_name(const void *va, const void *vb);
 int sg_fs_compare_mnt_point(const void *va, const void *vb);


More information about the users mailing list