[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
bug#21460: Race condition in tests/tail-2/assert.sh
From: |
Ludovic Courtès |
Subject: |
bug#21460: Race condition in tests/tail-2/assert.sh |
Date: |
Fri, 11 Sep 2015 22:55:01 +0200 |
User-agent: |
Gnus/5.13 (Gnus v5.13) Emacs/24.5 (gnu/linux) |
Paul Eggert <address@hidden> skribis:
> Ludovic Courtès wrote:
>> I think the problem happens when ‘tail’ opens ‘foo’ right in between of
>> the two notifications: ‘foo’ is still there, and so ‘tail’ doesn’t
>> report anything.
>>
>> Does that make sense?
>
> Yes, though if the link count is indeed zero, I'm surprised that
> 'tail' can open the file -- that sounds like a bug in the kernel.
Attached is a reproducer; just run it in a loop for a couple of seconds:
--8<---------------cut here---------------start------------->8---
$ while ./a.out ; do : ; done
funny, errno = Success, nlink = 0
Aborted (core dumped)
--8<---------------cut here---------------end--------------->8---
I’m not sure if that’s a kernel bug. Strictly speaking, inotify works
as expected: we get a notification for nlink--, which doesn’t mean the
file has vanished.
The conclusion for ‘tail’ would be to wait for the IN_DELETE_SELF event
before considering the file to be gone. WDYT?
(That ‘inotify_rm_watch’ returns EINVAL *is* a bug IMO, but not
worrisome.)
Thanks,
Ludo’.
#define _GNU_SOURCE 1
#include <stdlib.h>
#include <unistd.h>
#include <sys/inotify.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#include <assert.h>
int
main ()
{
int file = creat ("foo", S_IRUSR | S_IWUSR);
assert_perror (errno);
close (file);
int notifications = inotify_init ();
assert_perror (errno);
int watch = inotify_add_watch (notifications, "foo",
IN_MODIFY | IN_ATTRIB
| IN_DELETE_SELF | IN_MOVE_SELF);
assert_perror (errno);
if (fork () == 0)
{
unlink ("foo");
assert_perror (errno);
exit (EXIT_SUCCESS);
}
struct inotify_event event;
ssize_t count = read (notifications, &event, sizeof event);
assert (count == sizeof event);
assert (event.mask == IN_ATTRIB);
struct stat st;
stat ("foo", &st);
if (errno != ENOENT)
{
printf ("funny, errno = %m, nlink = %li\n",
st.st_nlink);
abort ();
}
count = read (notifications, &event, sizeof event);
assert (count == sizeof event);
assert (event.mask == IN_DELETE_SELF);
/* Bug #2: this returns EINVAL for no good reason. */
/* inotify_rm_watch (notifications, watch); */
/* assert_perror (errno); */
return EXIT_SUCCESS;
}
bug#21459: Race condition in tests/tail-2/assert.sh, Pádraig Brady, 2015/09/11