Re: Things I wish I'd known about Inotify

From: David Herrmann
Date: Fri Apr 04 2014 - 09:00:44 EST


Hi

On Thu, Apr 3, 2014 at 8:34 AM, Michael Kerrisk (man-pages)
<mtk.manpages@xxxxxxxxx> wrote:
> With that in mind, I've drafted some substantial additions to the
> inotify(7) man page. I would be very happy if folk on the "To:" list
> could comment on the text below, since I believe you all have a lot of
> practical experience with Inotify. (Of course, I also welcome comments
> from anyone else.) In particular, I would like comments on the
> accuracy of the various technical points (especially those relating to
> matching up related IN_MOVED_FROM and IN_MOVED_TO events), as well as
> pointers on any other pitfalls that the programmers should be wary of
> that should be added to the page.

1)
IN_IGNORED is async and _immediate_ in case a file got deleted. So if
you use watch-descriptors as keys for your objects, an _already_ used
key might be returned by inotify_add_watch() if an IN_IGNORED is
queued for the old watch (which implicitly destroys the watch). Once
you read the IN_IGNORED from the queue, there is usually no way to
know whether it's generated by the old watch or by the new. The
man-page mentions this in:
"IN_IGNORED: Watch was removed explicitly (inotify_rm_watch(2)) or
automatically (file was deleted, or filesystem was unmounted)."
I think we should add a note to BUGS that mentions this race (which is
really not obvious from the description).

This race could be fixed by requiring an explicit inotify_rm_watch()
if an IN_IGNORED was generated asynchronously.

2)
inotify_add_watch() is based on inodes. So if you call it on
hardlinks, you will modify the existing watch instead of creating a
new one. This is often really annoying and I think an IN_FORCE_NEW
flag that disables this would be really nice. Imagine the following
code:

wd1 = inotify_add_watch(fd, A);
wd2 = inotify_add_watch(fd, B);
...
inotify_rm_watch(fd, wd2);
wd3 = inotify_add_watch(fd, C);
...
inotify_rm_watch(fd, wd1);
...
inotify_rm_watch(fd, wd3);

If A and B are hardlinks to the same file, then wd1==wd2. Therefore,
after wd2 was removed, we _might_ end up with wd3==wd1 and thus remove
wd3 early (which obviously is not intended). So simple code like this
doesn't work. You have to verify whether returned handles are
duplicates or new. An IN_FORCE_NEW flag would really help here.

Thanks
David
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/