about summary refs log tree commit diff
path: root/nscd
diff options
context:
space:
mode:
Diffstat (limited to 'nscd')
-rw-r--r--nscd/connections.c148
1 files changed, 83 insertions, 65 deletions
diff --git a/nscd/connections.c b/nscd/connections.c
index feda2237f5..56c327971b 100644
--- a/nscd/connections.c
+++ b/nscd/connections.c
@@ -976,9 +976,25 @@ cannot change socket to nonblocking mode: %s"),
 }
 
 
+/* Register the file in FINFO as a traced file for the database DBS[DBIX].
+
+   We support registering multiple files per database. Each call to
+   register_traced_file adds to the list of registered files.
+
+   When we prune the database, either through timeout or a request to
+   invalidate, we will check to see if any of the registered files has changed.
+   When we accept new connections to handle a cache request we will also
+   check to see if any of the registered files has changed.
+
+   If we have inotify support then we install an inotify fd to notify us of
+   file deletion or modification, both of which will require we invalidate
+   the cache for the database.  Without inotify support we stat the file and
+   store st_mtime to determine if the file has been modified.  */
 void
 register_traced_file (size_t dbidx, struct traced_file *finfo)
 {
+  /* If the database is disabled or file checking is disabled
+     then ignore the registration.  */
   if (! dbs[dbidx].enabled || ! dbs[dbidx].check_file)
     return;
 
@@ -1870,6 +1886,63 @@ restart_p (time_t now)
 /* Array for times a connection was accepted.  */
 static time_t *starttime;
 
+#ifdef HAVE_INOTIFY
+/* Inotify event for changed file.  */
+union __inev
+{
+  struct inotify_event i;
+# ifndef PATH_MAX
+#  define PATH_MAX 1024
+# endif
+  char buf[sizeof (struct inotify_event) + PATH_MAX];
+};
+
+/* Process the inotify event in INEV. If the event matches any of the files
+   registered with a database then mark that database as requiring its cache
+   to be cleared. We indicate the cache needs clearing by setting
+   TO_CLEAR[DBCNT] to true for the matching database.  */
+static inline void
+inotify_check_files (bool *to_clear, union __inev *inev)
+{
+  /* Check which of the files changed.  */
+  for (size_t dbcnt = 0; dbcnt < lastdb; ++dbcnt)
+    {
+      struct traced_file *finfo = dbs[dbcnt].traced_files;
+
+      while (finfo != NULL)
+	{
+	  /* Inotify event watch descriptor matches.  */
+	  if (finfo->inotify_descr == inev->i.wd)
+	    {
+	      /* Mark cache as needing to be cleared and reinitialize.  */
+	      to_clear[dbcnt] = true;
+	      if (finfo->call_res_init)
+	        res_init ();
+	      return;
+	    }
+
+	  finfo = finfo->next;
+        }
+    }
+}
+
+/* If an entry in the array of booleans TO_CLEAR is TRUE then clear the cache
+   for the associated database, otherwise do nothing. The TO_CLEAR array must
+   have LASTDB entries.  */
+static inline void
+clear_db_cache (bool *to_clear)
+{
+  for (size_t dbcnt = 0; dbcnt < lastdb; ++dbcnt)
+    if (to_clear[dbcnt])
+      {
+	pthread_mutex_lock (&dbs[dbcnt].prune_lock);
+	dbs[dbcnt].clear_cache = 1;
+	pthread_mutex_unlock (&dbs[dbcnt].prune_lock);
+	pthread_cond_signal (&dbs[dbcnt].prune_cond);
+      }
+}
+
+#endif
 
 static void
 __attribute__ ((__noreturn__))
@@ -1976,15 +2049,10 @@ main_loop_poll (void)
 	      if (conns[1].revents != 0)
 		{
 		  bool to_clear[lastdb] = { false, };
-		  union
-		  {
-# ifndef PATH_MAX
-#  define PATH_MAX 1024
-# endif
-		    struct inotify_event i;
-		    char buf[sizeof (struct inotify_event) + PATH_MAX];
-		  } inev;
+		  union __inev inev;
 
+		  /* Read all inotify events for files registered via
+		     register_traced_file().  */
 		  while (1)
 		    {
 		      ssize_t nb = TEMP_FAILURE_RETRY (read (inotify_fd, &inev,
@@ -2010,35 +2078,11 @@ disabled inotify after read error %d"),
 			}
 
 		      /* Check which of the files changed.  */
-		      for (size_t dbcnt = 0; dbcnt < lastdb; ++dbcnt)
-			{
-			  struct traced_file *finfo = dbs[dbcnt].traced_files;
-
-			  while (finfo != NULL)
-			    {
-			      if (finfo->inotify_descr == inev.i.wd)
-				{
-				  to_clear[dbcnt] = true;
-				  if (finfo->call_res_init)
-				    res_init ();
-				  goto next;
-				}
-
-			      finfo = finfo->next;
-			    }
-			}
-		    next:;
+		      inotify_check_files (to_clear, &inev);
 		    }
 
 		  /* Actually perform the cache clearing.  */
-		  for (size_t dbcnt = 0; dbcnt < lastdb; ++dbcnt)
-		    if (to_clear[dbcnt])
-		      {
-			pthread_mutex_lock (&dbs[dbcnt].prune_lock);
-			dbs[dbcnt].clear_cache = 1;
-			pthread_mutex_unlock (&dbs[dbcnt].prune_lock);
-			pthread_cond_signal (&dbs[dbcnt].prune_cond);
-		      }
+		  clear_db_cache (to_clear);
 
 		  --n;
 		}
@@ -2208,12 +2252,10 @@ main_loop_epoll (int efd)
 	else if (revs[cnt].data.fd == inotify_fd)
 	  {
 	    bool to_clear[lastdb] = { false, };
-	    union
-	    {
-	      struct inotify_event i;
-	      char buf[sizeof (struct inotify_event) + PATH_MAX];
-	    } inev;
+	    union __inev inev;
 
+	    /* Read all inotify events for files registered via
+	       register_traced_file().  */
 	    while (1)
 	      {
 		ssize_t nb = TEMP_FAILURE_RETRY (read (inotify_fd, &inev,
@@ -2235,35 +2277,11 @@ main_loop_epoll (int efd)
 		  }
 
 		/* Check which of the files changed.  */
-		for (size_t dbcnt = 0; dbcnt < lastdb; ++dbcnt)
-		  {
-		    struct traced_file *finfo = dbs[dbcnt].traced_files;
-
-		    while (finfo != NULL)
-		      {
-			if (finfo->inotify_descr == inev.i.wd)
-			  {
-			    to_clear[dbcnt] = true;
-			    if (finfo->call_res_init)
-			      res_init ();
-			    goto next;
-			  }
-
-			finfo = finfo->next;
-		      }
-		  }
-	      next:;
+		inotify_check_files(to_clear, &inev);
 	      }
 
 	    /* Actually perform the cache clearing.  */
-	    for (size_t dbcnt = 0; dbcnt < lastdb; ++dbcnt)
-	      if (to_clear[dbcnt])
-		{
-		  pthread_mutex_lock (&dbs[dbcnt].prune_lock);
-		  dbs[dbcnt].clear_cache = 1;
-		  pthread_mutex_unlock (&dbs[dbcnt].prune_lock);
-		  pthread_cond_signal (&dbs[dbcnt].prune_cond);
-		}
+	    clear_db_cache (to_clear);
 	  }
 # endif
 # ifdef HAVE_NETLINK