[asterisk-commits] kmoore: branch 10 r342277 - in /branches/10: ./ pbx/pbx_spool.c

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Tue Oct 25 11:08:10 CDT 2011


Author: kmoore
Date: Tue Oct 25 11:08:04 2011
New Revision: 342277

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=342277
Log:
Merged revisions 342276 via svnmerge from 
https://origsvn.digium.com/svn/asterisk/branches/1.8

........
  r342276 | kmoore | 2011-10-25 11:06:57 -0500 (Tue, 25 Oct 2011) | 18 lines
  
  Fix spool handling to allow call files to be hardlinked into place
  
  This fixes the inotify code to handle call files being hardlinked into the
  spool directory.
  
  The smsq utility does this, instead of rename(), to ensure that it cannot
  accidentally overwrite an existing spool file. A rename() might do that, but
  link() will definitely not.
  
  The inotify code had broken this, because it would wait for an IN_CLOSE_WRITE
  event on the file... which was never forthcoming, since it was never opened.
  Now we look for IN_OPEN events following the IN_CREATE event, and only wait
  for an IN_CLOSE_WRITE if the file was actually opened.
  
  Patch-by: dwmw2
  (closes issue ASTERISK-18331)
  Review: https://reviewboard.asterisk.org/r/1391/
........

Modified:
    branches/10/   (props changed)
    branches/10/pbx/pbx_spool.c

Propchange: branches/10/
------------------------------------------------------------------------------
Binary property 'branch-1.8-merged' - no diff available.

Modified: branches/10/pbx/pbx_spool.c
URL: http://svnview.digium.com/svn/asterisk/branches/10/pbx/pbx_spool.c?view=diff&rev=342277&r1=342276&r2=342277
==============================================================================
--- branches/10/pbx/pbx_spool.c (original)
+++ branches/10/pbx/pbx_spool.c Tue Oct 25 11:08:04 2011
@@ -471,6 +471,7 @@
 #if defined(HAVE_INOTIFY)
 /* Only one thread is accessing this list, so no lock is necessary */
 static AST_LIST_HEAD_NOLOCK_STATIC(createlist, direntry);
+static AST_LIST_HEAD_NOLOCK_STATIC(openlist, direntry);
 #endif
 
 static void queue_file(const char *filename, time_t when)
@@ -551,14 +552,47 @@
 		return;
 	}
 	strcpy(cur->name, filename);
+	/* We'll handle this file unless an IN_OPEN event occurs within 2 seconds */
+	cur->mtime = time(NULL) + 2;
 	AST_LIST_INSERT_TAIL(&createlist, cur, list);
+}
+
+static void queue_file_open(const char *filename)
+{
+	struct direntry *cur;
+
+	AST_LIST_TRAVERSE_SAFE_BEGIN(&createlist, cur, list) {
+		if (!strcmp(cur->name, filename)) {
+			AST_LIST_REMOVE_CURRENT(list);
+			AST_LIST_INSERT_TAIL(&openlist, cur, list);
+			break;
+		}
+	}
+	AST_LIST_TRAVERSE_SAFE_END
+}
+
+static void queue_created_files(void)
+{
+	struct direntry *cur;
+	time_t now = time(NULL);
+
+	AST_LIST_TRAVERSE_SAFE_BEGIN(&createlist, cur, list) {
+		if (cur->mtime > now) {
+			break;
+		}
+
+		AST_LIST_REMOVE_CURRENT(list);
+		queue_file(cur->name, 0);
+		ast_free(cur);
+	}
+	AST_LIST_TRAVERSE_SAFE_END
 }
 
 static void queue_file_write(const char *filename)
 {
 	struct direntry *cur;
 	/* Only queue entries where an IN_CREATE preceded the IN_CLOSE_WRITE */
-	AST_LIST_TRAVERSE_SAFE_BEGIN(&createlist, cur, list) {
+	AST_LIST_TRAVERSE_SAFE_BEGIN(&openlist, cur, list) {
 		if (!strcmp(cur->name, filename)) {
 			AST_LIST_REMOVE_CURRENT(list);
 			ast_free(cur);
@@ -605,7 +639,7 @@
 	}
 
 #ifdef HAVE_INOTIFY
-	inotify_add_watch(inotify_fd, qdir, IN_CREATE | IN_CLOSE_WRITE | IN_MOVED_TO);
+	inotify_add_watch(inotify_fd, qdir, IN_CREATE | IN_OPEN | IN_CLOSE_WRITE | IN_MOVED_TO);
 #endif
 
 	/* First, run through the directory and clear existing entries */
@@ -641,14 +675,35 @@
 			/* Convert from seconds to milliseconds, unless there's nothing
 			 * in the queue already, in which case, we wait forever. */
 			int waittime = next == INT_MAX ? -1 : (next - now) * 1000;
+			if (!AST_LIST_EMPTY(&createlist)) {
+				waittime = 1000;
+			}
 			/* When a file arrives, add it to the queue, in mtime order. */
 			if ((res = poll(&pfd, 1, waittime)) > 0 && (stage = 1) &&
 				(res = read(inotify_fd, &buf, sizeof(buf))) >= sizeof(*iev)) {
 				ssize_t len = 0;
 				/* File(s) added to directory, add them to my list */
 				for (iev = (void *) buf; res >= sizeof(*iev); iev = (struct inotify_event *) (((char *) iev) + len)) {
+					/* For an IN_MOVED_TO event, simply process the file. However, if
+					 * we get an IN_CREATE event it *might* be an open(O_CREAT) or it
+					 * might be a hardlink (like smsq does, since rename() might
+					 * overwrite an existing file). So we have to see if we get a
+					 * subsequent IN_OPEN event on the same file. If we do, keep it
+					 * on the openlist and wait for the corresponding IN_CLOSE_WRITE.
+					 * If we *don't* see an IN_OPEN event, then it was a hard link so
+					 * it can be processed immediately.
+					 *
+					 * Unfortunately, although open(O_CREAT) is an atomic file system
+					 * operation, the inotify subsystem doesn't give it to us in a
+					 * single event with both IN_CREATE|IN_OPEN set. It's two separate
+					 * events, and the kernel doesn't even give them to us at the same
+					 * time. We can read() from inotify_fd after the IN_CREATE event,
+					 * and get *nothing* from it. The IN_OPEN arrives only later! So
+					 * we have a very short timeout of 2 seconds. */
 					if (iev->mask & IN_CREATE) {
 						queue_file_create(iev->name);
+					} else if (iev->mask & IN_OPEN) {
+						queue_file_open(iev->name);
 					} else if (iev->mask & IN_CLOSE_WRITE) {
 						queue_file_write(iev->name);
 					} else if (iev->mask & IN_MOVED_TO) {
@@ -679,6 +734,7 @@
 			time(&now);
 		}
 
+		queue_created_files();
 		/* Empty the list of all entries ready to be processed */
 		AST_LIST_LOCK(&dirlist);
 		while (!AST_LIST_EMPTY(&dirlist) && AST_LIST_FIRST(&dirlist)->mtime <= now) {




More information about the asterisk-commits mailing list