/*
 *  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
 }
 
