[gvfs] Cache mountinfo lookups



commit 74ea19992c60e0bd2e9f1a9e925b349909f1bdd8
Author: Alexander Larsson <alexl redhat com>
Date:   Thu Jun 18 10:55:15 2009 +0200

    Cache mountinfo lookups

 metadata/metatree.c |  270 +++++++++++++++++++++++++++++++-------------------
 1 files changed, 167 insertions(+), 103 deletions(-)
---
diff --git a/metadata/metatree.c b/metadata/metatree.c
index dad41d8..744f54e 100644
--- a/metadata/metatree.c
+++ b/metadata/metatree.c
@@ -11,6 +11,7 @@
 #include <glib.h>
 #include <glib/gstdio.h>
 #include <errno.h>
+#include <poll.h>
 #include "crc32.h"
 
 #define MAGIC "\xda\x1ameta"
@@ -1873,81 +1874,25 @@ struct _MetaLookupCache {
 };
 
 #ifdef __linux__
-static gboolean
-mountinfo_strequal_escaped (const char *s,
-			    const char *escaped)
-{
-  char c;
-  while (*s != 0 && *escaped != ' ' && *escaped != 0)
-    {
-      if (*escaped == '\\')
-	{
-	  escaped++;
-	  c = *escaped++ - '0';
-	  c <<= 3;
-	  c |= *escaped++ - '0';
-	  c <<= 3;
-	  c |= *escaped++ - '0';
-	}
-      else
-	c = *escaped++;
-
-      if (c != *s++)
-	return FALSE;
-    }
-  if (*s == 0 && (*escaped == 0 || *escaped == ' '))
-    return TRUE;
-  return FALSE;
-}
 
-static char *
-mountinfo_unescape (const char *escaped)
-{
-  char *res, *s;
-  char c;
-  gsize len;
-
-  s = strchr (escaped, ' ');
-  if (s)
-    len = s - escaped;
-  else
-    len = strlen (escaped);
-  res = malloc (len + 1);
-  s = res;
+typedef struct {
+  char *mountpoint;
+  char *root;
+} MountinfoEntry;
 
-  while (*escaped != 0 && *escaped != ' ')
-    {
-      if (*escaped == '\\')
-	{
-	  escaped++;
-	  c = *escaped++ - '0';
-	  c <<= 3;
-	  c |= *escaped++ - '0';
-	  c <<= 3;
-	  c |= *escaped++ - '0';
-	}
-      else
-	c = *escaped++;
-      *s++ = c;
-    }
-  *s = 0;
-  return res;
-}
+static gboolean mountinfo_initialized = FALSE;
+static int mountinfo_fd = -1;
+static MountinfoEntry *mountinfo_roots = NULL;
+G_LOCK_DEFINE_STATIC (mountinfo);
 
 /* We want to avoid mmap and stat as these are not ideal
    operations for a proc file */
 static char *
-read_contents (char *filename)
+read_contents (int fd)
 {
   char *data;
   gsize len;
   gsize bytes_read;
-  int fd;
-
-  fd = open (filename, O_RDONLY);
-
-  if (fd == -1)
-    return NULL;
 
   len = 4096;
   data = g_malloc (len);
@@ -1970,7 +1915,6 @@ read_contents (char *filename)
 	  if (errno != EINTR)
 	    {
 	      g_free (data);
-	      close (fd);
 	      return NULL;
 	    }
 	}
@@ -1979,7 +1923,6 @@ read_contents (char *filename)
       else
 	bytes_read += rc;
     }
-  close (fd);
 
   /* zero terminate */
   if (len - bytes_read < 1)
@@ -1988,62 +1931,183 @@ read_contents (char *filename)
 
   return (char *)data;
 }
-#endif
-
 
 static char *
-get_extra_prefix_for_mount (const char *mountpoint)
+mountinfo_unescape (const char *escaped)
 {
-#ifdef __linux__
-  gchar *contents;
-  char *res;
-  char *line;
-  char *line_root;
-  char *line_mountpoint;
+  char *res, *s;
+  char c;
+  gsize len;
 
-  if (mountpoint &&
-      (contents = read_contents ("/proc/self/mountinfo")) != NULL)
+  s = strchr (escaped, ' ');
+  if (s)
+    len = s - escaped;
+  else
+    len = strlen (escaped);
+  res = malloc (len + 1);
+  s = res;
+
+  while (*escaped != 0 && *escaped != ' ')
     {
-      line = contents;
-      while (line != NULL && *line != 0)
+      if (*escaped == '\\')
 	{
-	  /* parent id */
-	  line = strchr (line, ' ');
-	  line_mountpoint = NULL;
+	  escaped++;
+	  c = *escaped++ - '0';
+	  c <<= 3;
+	  c |= *escaped++ - '0';
+	  c <<= 3;
+	  c |= *escaped++ - '0';
+	}
+      else
+	c = *escaped++;
+      *s++ = c;
+    }
+  *s = 0;
+  return res;
+}
+
+static MountinfoEntry *
+parse_mountinfo (const char *contents)
+{
+  GArray *a;
+  const char *line;
+  const char *line_root;
+  const char *line_mountpoint;
+
+  a = g_array_new (TRUE, TRUE, sizeof (MountinfoEntry));
+
+  line = contents;
+  while (line != NULL && *line != 0)
+    {
+      /* parent id */
+      line = strchr (line, ' ');
+      line_mountpoint = NULL;
+      if (line)
+	{
+	  /* major:minor */
+	  line = strchr (line+1, ' ');
 	  if (line)
 	    {
-	      /* major:minor */
+	      /* root */
 	      line = strchr (line+1, ' ');
+	      line_root = line + 1;
 	      if (line)
 		{
-		  /* root */
+		  /* mountpoint */
 		  line = strchr (line+1, ' ');
-		  line_root = line + 1;
-		  if (line)
-		    {
-		      /* mountpoint */
-		      line = strchr (line+1, ' ');
-		      line_mountpoint = line + 1;
-		    }
+		  line_mountpoint = line + 1;
 		}
 	    }
+	}
 
-	  if (line_mountpoint &&
-	      mountinfo_strequal_escaped (mountpoint, line_mountpoint))
-	    {
-	      res = mountinfo_unescape (line_root);
-	      g_free (contents);
-	      return res;
-	    }
+      if (line_mountpoint && !(line_root[0] == '/' && line_root[1] == ' '))
+	{
+	  MountinfoEntry new_entry;
 
-	  line = strchr (line, '\n');
-	  if (line)
-	    line++;
+	  new_entry.mountpoint = mountinfo_unescape (line_mountpoint);
+	  new_entry.root = mountinfo_unescape (line_root);
+
+	  g_array_append_val (a, new_entry);
 	}
 
-      g_free (contents);
+      line = strchr (line, '\n');
+      if (line)
+	line++;
     }
 
+  return (MountinfoEntry *)g_array_free (a, FALSE);
+}
+
+static void
+free_mountinfo (void)
+{
+  int i;
+
+  if (mountinfo_roots)
+    {
+      for (i = 0; mountinfo_roots[i].mountpoint != NULL; i++)
+	{
+	  g_free (mountinfo_roots[i].mountpoint);
+	  g_free (mountinfo_roots[i].root);
+	}
+      g_free (mountinfo_roots);
+      mountinfo_roots = NULL;
+    }
+}
+
+static void
+update_mountinfo (void)
+{
+  char *contents;
+  int res;
+  gboolean first;
+  struct pollfd pfd;
+
+  first = FALSE;
+  if (!mountinfo_initialized)
+    {
+      mountinfo_initialized = TRUE;
+      mountinfo_fd = open ("/proc/self/mountinfo", O_RDONLY);
+      first = TRUE;
+    }
+
+  if (mountinfo_fd == -1)
+    return;
+
+  if (!first)
+    {
+      pfd.fd = mountinfo_fd;
+      pfd.events = POLLIN | POLLOUT | POLLPRI;
+      pfd.revents = 0;
+      res = poll (&pfd, 1, 0);
+      if (res == 0)
+	return;
+    }
+
+  free_mountinfo ();
+  contents = read_contents (mountinfo_fd);
+  lseek (mountinfo_fd, SEEK_SET, 0);
+  if (contents)
+    mountinfo_roots = parse_mountinfo (contents);
+}
+
+static const char *
+find_mountinfo_root_for_mountpoint (const char *mountpoint)
+{
+  char *res;
+  int i;
+
+  res = NULL;
+
+  G_LOCK (mountinfo);
+
+  update_mountinfo ();
+
+  if (mountinfo_roots)
+    {
+      for (i = 0; mountinfo_roots[i].mountpoint != NULL; i++)
+	{
+	  if (strcmp (mountinfo_roots[i].mountpoint, mountpoint) == 0)
+	    {
+	      res = g_strdup (mountinfo_roots[i].root);
+	      break;
+	    }
+	}
+    }
+
+  G_UNLOCK (mountinfo);
+
+  return res;
+}
+
+#endif
+
+
+static char *
+get_extra_prefix_for_mount (const char *mountpoint)
+{
+#ifdef __linux__
+  return find_mountinfo_root_for_mountpoint (mountpoint);
 #endif
   return NULL;
 }



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]