Project

General

Profile

Bug #5188

Fix inotify case where IN_MOVED_TO comes in subsequent read after read contaning IN_MOVED_FROM

Added by Joe User almost 2 years ago. Updated almost 2 years ago.

Status:
Fixed
Priority:
Normal
Assignee:
Category:
PVR / DVR
Target version:
-
Start date:
2018-09-02
Due date:
% Done:

0%

Estimated time:
Found in version:
4.3
Affected Versions:

Description

While trying to move lots of recordings from one directory to another, I found that tvheadend only noticed (via inotify) about 60% of the changes, thus the dvr/log files were not updated.

After some debugging, I tracked the problem down to this note from the man page:

       Applications  should also allow for the possibility that the IN_MOVED_FROM event was the last event that could fit in the buffer returned by the current call to read(2), and the accompanying
       IN_MOVED_TO event might be fetched only on the next read(2), which should be done with a (small) timeout to allow for the fact that insertion of the IN_MOVED_FROM-IN_MOVED_TO event  pair  is
       not atomic, and also the possibility that there may not be any IN_MOVED_TO event.

Also, the mask for IN_CREATE was being set, but never checked for. This also aggravated the problem by producing lots of unnecessary IN_CREATE events in the reads.

I created a pull request, but I am sure you will want to remove the extra tvhdebug lines I included.

Here is the diff:

diff --git a/src/dvr/dvr_inotify.c b/src/dvr/dvr_inotify.c
index 71137df20..a8db57c09 100644
--- a/src/dvr/dvr_inotify.c
+++ b/src/dvr/dvr_inotify.c
@@ -33,7 +33,7 @@
 /* inotify limits */
 #define EVENT_SIZE    ( sizeof (struct inotify_event) )
 #define EVENT_BUF_LEN ( 10 * ( EVENT_SIZE + 16 ) )
-#define EVENT_MASK    IN_CREATE    | IN_DELETE     | IN_DELETE_SELF |\
+#define EVENT_MASK    IN_DELETE     | IN_DELETE_SELF |\
                       IN_MOVE_SELF | IN_MOVED_FROM | IN_MOVED_TO

 static int                         _inot_fd;
@@ -378,6 +378,11 @@ void* _dvr_inotify_thread ( void *p )
   const char *from;
   int fromfd;
   int cookie;
+  char from_prev[50];
+  int fromfd_prev =0;
+  int cookie_prev =0;
+
+  from_prev[0] = '\0';

   while (tvheadend_is_running()) {

@@ -397,6 +402,7 @@ void* _dvr_inotify_thread ( void *p )
     pthread_mutex_lock(&global_lock);
     while ( i < len ) {
       struct inotify_event *ev = (struct inotify_event*)&buf[i];
+    tvhdebug(LS_DVR, "inotify: i= %d   len= %d   ", i, len);
       i += EVENT_SIZE + ev->len;
       if (i > len)
         break;
@@ -406,12 +412,21 @@ void* _dvr_inotify_thread ( void *p )
         from   = ev->name;
         fromfd = ev->wd;
         cookie = ev->cookie;
+      tvhdebug(LS_DVR, "inotify: i= %d   len= %d   from = %s   cookie = %d ", i, len, from, cookie);
         continue;

-      } else if ((ev->mask & IN_MOVED_TO) && from && ev->cookie == cookie) {
-        _dvr_inotify_moved(fromfd, from, ev->name, ev->wd);
-        from = NULL;
-      
+      } else if (ev->mask & IN_MOVED_TO) {
+    tvhdebug(LS_DVR, "inotify: i= %d   len= %d    to_cookie= %d   from_cookie = %d   cookie_prev = %d", i, len, ev->cookie,cookie,cookie_prev);
+          if ( from && ev->cookie == cookie) {
+            _dvr_inotify_moved(fromfd, from, ev->name, ev->wd);
+            from = NULL;
+        cookie = 0;
+          } else if (from_prev[0] != '\0' && ev->cookie == cookie_prev) {
+             _dvr_inotify_moved(fromfd_prev, from_prev, ev->name, ev->wd);
+             from_prev[0] = '\0';
+         cookie_prev = 0;
+      }
+
       /* Removed */
       } else if (ev->mask & IN_DELETE) {
         _dvr_inotify_delete(ev->wd, ev->name);
@@ -424,15 +439,26 @@ void* _dvr_inotify_thread ( void *p )
       } else if (ev->mask & IN_DELETE_SELF) {
         _dvr_inotify_delete_all(ev->wd);
       }
-
+/*
       if (from) {
         _dvr_inotify_moved(fromfd, from, NULL, -1);
         from   = NULL;
         cookie = 0;
       }
+*/
+    }
+    //  if still old "from", assume matching "to" is not coming
+    if (from_prev[0] != '\0') {
+      _dvr_inotify_moved(fromfd_prev, from_prev, NULL, -1);
+      from_prev[0] = '\0';
+      cookie_prev = 0;
     }
+    //  if unmatched "from", save in case matching "to" is coming in next read
     if (from) {
-      _dvr_inotify_moved(fromfd, from, NULL, -1);
+      strcpy ( from_prev, from);
+      fromfd_prev = fromfd;
+      cookie_prev = cookie;
+      tvhdebug(LS_DVR, "inotify: i= %d   len= %d      cookie_prev = %d   from_prev = %s  fd = %d   END OF READ", i, len, cookie_prev, from_prev, fromfd_prev);
     }
     pthread_mutex_unlock(&global_lock);
   }

History

#1

Updated by Jaroslav Kysela almost 2 years ago

Fixed in latest.

#2

Updated by Jaroslav Kysela almost 2 years ago

  • Status changed from New to Fixed

Also available in: Atom PDF