Bug 14906 - inotify failed when /etc/hosts file change
inotify failed when /etc/hosts file change
Status: NEW
Product: glibc
Classification: Unclassified
Component: nscd
2.11
: P2 normal
: ---
Assigned To: Not yet assigned to anyone
:
Depends on:
Blocks:
  Show dependency treegraph
 
Reported: 2012-12-03 10:36 UTC by Bin Li
Modified: 2012-12-03 10:44 UTC (History)
1 user (show)

See Also:
Host:
Target:
Build:
Last reconfirmed:


Attachments
The test program (844 bytes, text/x-csrc)
2012-12-03 10:36 UTC, Bin Li
Details
the patch for suggested fix (1.41 KB, patch)
2012-12-03 10:42 UTC, Bin Li
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Bin Li 2012-12-03 10:36:26 UTC
Created attachment 6770 [details]
The test program

This test program shows the problem.  I'm creating a watch on /etc/hosts
(looking for modification or deletion), and it's catching only changes of 
the type "echo '#bla' >> /etc/hosts".  It doesn't catch changes via copy
to temporary file, do changes, rename temp file back to /etc/hosts.  That's
what sed -i is using to atomically do the in place changes.

I thought that adding IN_MOVE should help when setting up the watch,
but it doesn't (commented out in the test program).  Even if it would have
helped I would claim the kernel to be broken.  If I include IN_MODIFY
in a watch for /etc/hosts, I'm of course also interested if somebody renames
some random file to the watched filename, as it very certainly is a
modification.

Basically as soon as "sed -i" is done on the file the kernel lost track
of the watch and no changes to the "new" /etc/hosts are tracked anymore.
Comment 1 Bin Li 2012-12-03 10:38:53 UTC
The original bug is from SUSE Linux.
https://bugzilla.novell.com/show_bug.cgi?id=779531

Michael Matz's comments.
--------------------------------
I can make the program work as expected also in the light of overwriting
renames, when I'm handling a IN_IGNORED event by recreating the watch on
/etc/hosts, like this in the inner loop:

      if (buf.wd == watch && (buf.mask & IN_IGNORED) != 0)
        {
          /* Recreate watch */
          watch = inotify_add_watch (fd, "/etc/hosts", IN_DELETE_SELF |
IN_MODIFY /* | IN_MOVE */);
          printf ("Added watch on /etc/hosts, as watch %d\n", watch);
          if (watch < 0)
            bark ("inotify_add_watch");
        }

That's for sure surprising limitation of the interface.  Is this really how
it's supposed to be used?
--------------------------------
Comment 2 Bin Li 2012-12-03 10:40:11 UTC
Miklos Szeredi 2012-10-15 15:27:29 UTC

(In reply to comment #20)
> I can make the program work as expected also in the light of overwriting
> renames, when I'm handling a IN_IGNORED event by recreating the watch on
> /etc/hosts, like this in the inner loop:
> 
>       if (buf.wd == watch && (buf.mask & IN_IGNORED) != 0)
>         {
>           /* Recreate watch */
>           watch = inotify_add_watch (fd, "/etc/hosts", IN_DELETE_SELF |
> IN_MODIFY /* | IN_MOVE */);
>           printf ("Added watch on /etc/hosts, as watch %d\n", watch);
>           if (watch < 0)
>             bark ("inotify_add_watch");
>         }
> 
> That's for sure surprising limitation of the interface.  Is this really how
> it's supposed to be used?

The watch descriptor returned by inotify_add_watch() refers to the inode, not
the path name.  This is analogous to open(2) returning a file descriptor that
refers to the inode, not the pathname.

So yes, adding IN_DELETE_SELF and IN_MOVE_SELF to the watches is a good way to
monitor whether changes to the file _name_ were made.

Note: inotify is an unreliable interface by design and the application should
provide a backup mechanism for theoretical cases when events are lost (e.g. by
checking the modification time of the file periodically).

Also see "Limitations and caveats" section in the inofity(7) manpage.
Comment 3 Bin Li 2012-12-03 10:42:29 UTC
Created attachment 6771 [details]
the patch for suggested fix

Miklos Szeredi 2012-10-18 11:04:49 UTC

I looked at the inotify code in nscd code and it's full of bugs.  Apparently
the cache pruning by inotify wasn't tested to any useful extent.  And latest
upstream version carries all those bugs too.  We can fix all these but that's a
whole little project.  Or there are some simpler options:

a) disable inotify completely and do it the old way (check file modification
times regularly)

b) enable inotify but also check modification times in case the inotify code
fails to work.

c) option b) plus something like comment 20

The attached patch does option b).  I've not tested it.

The glibc package maintainers will have to make the decision on how to fix it,
this patch is just a suggestion.
Comment 4 Bin Li 2012-12-03 10:44:32 UTC
Hi, Maintainer

 I just coy some analyze from Novell's bugzilla, and could you help review the patch in comment#3? Thanks a lot!