15758982 SUNBT7118090 snmpwalk of hrStorageIndex takes minutes due to excessive ioctls s11-update
authorLijo George<lijo.x.george@oracle.com>
Thu, 19 Mar 2015 12:58:30 -0700
branchs11-update
changeset 3991 8b170efb5356
parent 3989 cc7f2e59f3c0
child 3994 3781477accf3
15758982 SUNBT7118090 snmpwalk of hrStorageIndex takes minutes due to excessive ioctls 16439911 snmpd stuck looping on ioctl(13, MNTIOC_GETMNTENT,) wo traffic
components/net-snmp/patches/027.7118090.hr_filesys.patch
components/net-snmp/patches/052.16439911.hr_filesys.patch
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/net-snmp/patches/027.7118090.hr_filesys.patch	Thu Mar 19 12:58:30 2015 -0700
@@ -0,0 +1,253 @@
+This fix has been submitted upstream as part of a combined patch
+which has fixes for this CR (15758982) and another CR (16439911)
+with corresponding patch 048.16439911.hr_filesys.patch 
+This can be found in the following location.
+https://sourceforge.net/p/net-snmp/patches/1287/.
+
+This patch has not been accepted yet.
+/*
+ *  This patch fixes the performance issue observed while retrieving the
+ *  hrStorage parameters in systems with large number of mountpoints
+ *  parameters using snmpwalk.
+ *
+ *  This issue is happening due to the overhead of large number of
+ *  ioctl() system calls in getmntent() function called by the
+ *  Get_Next_HR_FileSys() function.
+ *
+ *  We see that in the Get_Next_HR_FileSys() function, inorder to access
+ *  the last mountpoint, the /etc/mnttab is opened and we walk through
+ *  all the mnttab entries for all filesystems till the end. This is the
+ *  reason we find a large number of the MNTIOC_GETMNTENT ioctl() calls.
+ *
+ *  To reduce the overhead of the getmntent() calls, we maintain a cache
+ *  of all the /etc/mnttab entries and walk through the cache instead of
+ *  opening /etc/mnttab and walking all the entries for each mountpoint.
+ *  This functionality is provided by the load_mnttab_cache_solaris()
+ *  function called from the Init_HR_FileSys() function.
+ */
+--- net-snmp-5.4.1.orig/agent/mibgroup/host/hr_filesys.c	2007-05-18 11:08:01.000000000 -0700
++++ net-snmp-5.4.1/agent/mibgroup/host/hr_filesys.c	2013-01-17 03:36:28.181493003 -0800
+@@ -31,6 +31,10 @@
+ #include <sys/mount.h>
+ #endif
+ 
++#ifdef solaris2
++#include <sys/stat.h>
++#endif
++
+ #include <ctype.h>
+ #if HAVE_STRING_H
+ #include <string.h>
+@@ -85,7 +89,11 @@
+ #ifdef solaris2
+ 
+ struct mnttab   HRFS_entry_struct;
+-struct mnttab  *HRFS_entry = &HRFS_entry_struct;
++struct mnttab  *HRFS_entry;
++struct mnttab	*HRFS_list;
++static int fscount;
++static time_t last_access = -1;
++
+ #define	HRFS_name	mnt_special
+ #define	HRFS_mount	mnt_mountp
+ #define	HRFS_type	mnt_fstype
+@@ -167,6 +175,9 @@
+ static u_char  *when_dumped(char *filesys, int level, size_t * length);
+ int             header_hrfilesys(struct variable *, oid *, size_t *, int,
+                                  size_t *, WriteMethod **);
++#ifdef solaris2
++static int      load_mnttab_cache_solaris(void);
++#endif
+ 
+         /*********************
+ 	 *
+@@ -606,8 +617,14 @@
+     HRFS_index = 1;
+     if (fp != NULL)
+         fclose(fp);
++#ifdef solaris2
++    if(!load_mnttab_cache_solaris())
++        return;
++#else    
+     fp = fopen(ETC_MNTTAB, "r");
+ #endif
++
++#endif
+ }
+ 
+ const char     *HRFS_ignores[] = {
+@@ -663,6 +680,117 @@
+     0
+ };
+ 
++#ifdef solaris2
++
++/*
++ *  This function has been introduced to reduce the overhead
++ *  of the getmntent() calls used to fetch the details of
++ *  the /etc/mnttab entries in Init_HR_FileSys().
++ *
++ *  We maintain a cache of all the /etc/mnttab entries and
++ *  walk through the cache instead of opening /etc/mnttab and
++ *  walking all the entries for each mountpoint.
++ */
++
++static int 
++load_mnttab_cache_solaris()
++{
++    char buf[512] = {NULL};
++    int i = 0;
++    struct stat file_stat;
++    const char **cpp;
++    char *ch;
++    int token_flag = 0;
++    int skip_flag = 0;
++    int ignore_flag = 0;
++    int j = 0;
++    int lines = 0;
++    int ret = 0;
++    HRFS_index = 0;
++
++    stat(ETC_MNTTAB, &file_stat);
++    if (last_access == -1 || last_access != file_stat.st_mtime) {
++        fp = fopen(ETC_MNTTAB, "r");
++        if(fp == NULL)
++        {
++            DEBUGMSGTL(("host/hr_filesys", "fopen failed for mnttab.\n"));
++            return -1;
++        }
++        
++        /* find the number of valid entries in mnttab. */
++        
++        while ((fgets((char *) &buf, sizeof(buf), fp)) != NULL) {
++            j = 0;
++            skip_flag = 0;
++            token_flag = 0;
++
++            /* tokenize the mnttab entries to fetch the fstype
++             * which determines the valid entries.
++             */
++
++            ch = strtok(buf, " \t");
++            while (ch != NULL) {
++                j++;
++                if(j == 3) {
++                    for (cpp = HRFS_ignores; *cpp != NULL; ++cpp) {
++                        if(!strncmp(ch, *cpp, strlen(ch))) {
++                            skip_flag = 1;
++                            break;
++                        }
++                    }
++                    token_flag = 1;
++                }
++                if(token_flag)
++                    break;
++                ch = strtok(NULL, " \t");
++             }
++             if(!skip_flag)
++                 lines++;
++        }
++        fclose(fp);
++
++        fscount = lines;
++        HRFS_list = (struct mnttab *) malloc (sizeof(struct mnttab) * fscount);
++        if(HRFS_list == NULL) {
++            DEBUGMSGTL(("host/hr_filesys", "Memory allocation for mnttab cache failed.\n"));
++            return -1;
++        }
++
++        fp = fopen(ETC_MNTTAB, "r");
++        if(fp == NULL) {
++            DEBUGMSGTL(("host/hr_filesys", "fopen failed for mnttab.\n"));
++            free(HRFS_list);
++            return -1;
++        }
++
++        while (i < fscount) {
++            if (getmntent(fp, &HRFS_entry_struct) == 0) {
++                 for (cpp = HRFS_ignores; *cpp != NULL; ++cpp) {
++                     if (!strcmp(HRFS_entry_struct.HRFS_type, *cpp)) {
++                         ignore_flag = 1;
++                         break;
++                     }
++                 }
++
++                 if(!ignore_flag) {
++                     HRFS_list[i].mnt_special = strdup(HRFS_entry_struct.mnt_special);
++                     HRFS_list[i].mnt_mountp = strdup(HRFS_entry_struct.mnt_mountp);
++                     HRFS_list[i].mnt_fstype = strdup(HRFS_entry_struct.mnt_fstype);
++                     HRFS_list[i].mnt_mntopts = strdup(HRFS_entry_struct.mnt_mntopts);
++                     i++;
++                 }
++
++                 ignore_flag = 0;
++            }
++        }
++
++        HRFS_entry = HRFS_list;
++        last_access = file_stat.st_mtime;
++    }
++    return ret;
++}
++#endif
++
+ int
+ Get_Next_HR_FileSys(void)
+ {
+@@ -699,17 +827,18 @@
+ #else
+     const char    **cpp;
+ 
+-    if (fp == NULL)
+-        return -1;
+ 
+ #ifdef solaris2
+-    if (getmntent(fp, HRFS_entry) != 0)
++    if (HRFS_index >= fscount)
+         return -1;
++    HRFS_entry = &HRFS_list[HRFS_index];
++        return ++HRFS_index;
+ #else
++    if (fp == NULL)
++        return -1;
+     HRFS_entry = getmntent(fp);
+     if (HRFS_entry == NULL)
+         return -1;
+-#endif                          /* solaris2 */
+ 
+     for (cpp = HRFS_ignores; *cpp != NULL; ++cpp)
+         if (!strcmp(HRFS_entry->HRFS_type, *cpp))
+@@ -728,6 +857,8 @@
+     }
+ 
+     return HRFS_index++;
++#endif
++
+ #endif                          /* HAVE_GETFSSTAT */
+ }
+ 
+@@ -791,9 +922,24 @@
+         HRFS_entry = NULL;
+     }
+ #else
++    int i = 0;
+     if (fp != NULL)
+         fclose(fp);
+     fp = NULL;
++
++#ifdef solaris2
++while (i < fscount) {
++    free(HRFS_list[i].mnt_special);
++    free(HRFS_list[i].mnt_mountp);
++    free(HRFS_list[i].mnt_fstype);
++    free(HRFS_list[i].mnt_mntopts);
++    i++;
++}
++    if (HRFS_list != NULL)
++        free(HRFS_list);
++    last_access = -1;
++#endif
++
+ #endif
+ }
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/net-snmp/patches/052.16439911.hr_filesys.patch	Thu Mar 19 12:58:30 2015 -0700
@@ -0,0 +1,144 @@
+This fix has been submitted upstream as part of a combined patch
+which has fixes for CR15758982(027.7118090.hr_filesys.patch) and this CR(16439911).
+This can be found in the following location.
+https://sourceforge.net/p/net-snmp/patches/1287/. 
+
+This patch has not been accepted yet. 
+--- net-snmp-5.4.1.old/agent/mibgroup/host/hr_filesys.c	2014-07-15 01:53:05.131000348 -0700
++++ net-snmp-5.4.1/agent/mibgroup/host/hr_filesys.c	2014-07-15 01:48:04.221278640 -0700
+@@ -698,20 +698,25 @@
+ static int 
+ load_mnttab_cache_solaris()
+ {
+-    char buf[512] = {NULL};
++    char buf[MNT_LINE_MAX] = {NULL};
+     int i = 0;
+     struct stat file_stat;
+     const char **cpp;
+-    char *ch;
++    char *ch, *token_ptr;
+     int token_flag = 0;
+     int skip_flag = 0;
+     int ignore_flag = 0;
+     int j = 0;
+     int lines = 0;
+     int ret = 0;
++    int chk_mnt = -1;
+     HRFS_index = 0;
+ 
+-    stat(ETC_MNTTAB, &file_stat);
++    if(stat(ETC_MNTTAB, &file_stat) != 0)
++    {
++        DEBUGMSGTL(("host/hr_filesys", "stat failed for mnttab.\n"));
++        return -1;
++    }
+     if (last_access == -1 || last_access != file_stat.st_mtime) {
+         fp = fopen(ETC_MNTTAB, "r");
+         if(fp == NULL)
+@@ -731,7 +736,7 @@
+              * which determines the valid entries.
+              */
+ 
+-            ch = strtok(buf, " \t");
++            ch = strtok_r(buf, " \t", &token_ptr);
+             while (ch != NULL) {
+                 j++;
+                 if(j == 3) {
+@@ -745,7 +750,7 @@
+                 }
+                 if(token_flag)
+                     break;
+-                ch = strtok(NULL, " \t");
++                ch = strtok_r(NULL, " \t", &token_ptr);
+              }
+              if(!skip_flag)
+                  lines++;
+@@ -765,25 +770,43 @@
+             free(HRFS_list);
+             return -1;
+         }
+-
+-        while (i < fscount) {
+-            if (getmntent(fp, &HRFS_entry_struct) == 0) {
+-                 for (cpp = HRFS_ignores; *cpp != NULL; ++cpp) {
+-                     if (!strcmp(HRFS_entry_struct.HRFS_type, *cpp)) {
+-                         ignore_flag = 1;
+-                         break;
+-                     }
++        while ((chk_mnt = getmntent(fp, &HRFS_entry_struct)) != -1) {
++             if(chk_mnt != 0)
++                 continue;
++             for (cpp = HRFS_ignores; *cpp != NULL; ++cpp) {
++                 if (!strcmp(HRFS_entry_struct.mnt_fstype, *cpp)) {
++                     ignore_flag = 1;
++                     break;
+                  }
+-
+-                 if(!ignore_flag) {
+-                     HRFS_list[i].mnt_special = strdup(HRFS_entry_struct.mnt_special);
+-                     HRFS_list[i].mnt_mountp = strdup(HRFS_entry_struct.mnt_mountp);
+-                     HRFS_list[i].mnt_fstype = strdup(HRFS_entry_struct.mnt_fstype);
+-                     HRFS_list[i].mnt_mntopts = strdup(HRFS_entry_struct.mnt_mntopts);
+-                     i++;
++             }
++             if(!ignore_flag) {
++                 if(i >= fscount)
++                 {
++                    DEBUGMSGTL(("host/hr_filesys","increasing cachesize from %d to %d",fscount,i+1));
++                    HRFS_list = realloc(HRFS_list, sizeof(struct mnttab) * (i+1));
++                    fscount = i+1;
++                    if(HRFS_list == NULL)
++                    {
++                        DEBUGMSGTL(("host/hr_filesys","\nrealloc failed for mnttab cache.\n"));
++                        return -1;
++                    }
+                  }
+-
+-                 ignore_flag = 0;
++                 HRFS_list[i].mnt_special = strdup(HRFS_entry_struct.mnt_special);
++                 HRFS_list[i].mnt_mountp = strdup(HRFS_entry_struct.mnt_mountp);
++                 HRFS_list[i].mnt_fstype = strdup(HRFS_entry_struct.mnt_fstype);
++                 HRFS_list[i].mnt_mntopts = strdup(HRFS_entry_struct.mnt_mntopts);
++                 i++;
++             }
++             ignore_flag = 0;
++        }
++        if(i < fscount)
++        {
++            DEBUGMSGTL(("host/hr_filesys","\ndecreasing cachesize from %d to %d\n",fscount,i));
++            HRFS_list = realloc(HRFS_list, sizeof(struct mnttab) * i );
++            if(HRFS_list == NULL)
++            {
++                DEBUGMSGTL(("host/hr_filesys","\nrealloc failed for mnttab cache.\n"));
++                return -1;
+             }
+         }
+ 
+@@ -925,19 +948,19 @@
+         HRFS_entry = NULL;
+     }
+ #else
+-    int i = 0;
+     if (fp != NULL)
+         fclose(fp);
+     fp = NULL;
+ 
+ #ifdef solaris2
+-while (i < fscount) {
+-    free(HRFS_list[i].mnt_special);
+-    free(HRFS_list[i].mnt_mountp);
+-    free(HRFS_list[i].mnt_fstype);
+-    free(HRFS_list[i].mnt_mntopts);
+-    i++;
+-}
++    int i = 0;
++    while (i < fscount) {
++        free(HRFS_list[i].mnt_special);
++        free(HRFS_list[i].mnt_mountp);
++        free(HRFS_list[i].mnt_fstype);
++        free(HRFS_list[i].mnt_mntopts);
++        i++;
++    }
+     if (HRFS_list != NULL)
+         free(HRFS_list);
+     last_access = -1;