• Eric Dumazet's avatar
    fs/file.c: __fget() and dup2() atomicity rules · 5ba97d28
    Eric Dumazet authored
    __fget() does lockless fetch of pointer from the descriptor
    table, attempts to grab a reference and treats "it was already
    zero" as "it's already gone from the table, we just hadn't
    seen the store, let's fail".  Unfortunately, that breaks the
    atomicity of dup2() - __fget() might see the old pointer,
    notice that it's been already dropped and treat that as
    "it's closed".  What we should be getting is either the
    old file or new one, depending whether we come before or after
    dup2().
    
    Dmitry had following test failing sometimes :
    
    int fd;
    void *Thread(void *x) {
      char buf;
      int n = read(fd, &buf, 1);
      if (n != 1)
        exit(printf("read failed: n=%d errno=%d\n", n, errno));
      return 0;
    }
    
    int main()
    {
      fd = open("/dev/urandom", O_RDONLY);
      int fd2 = open("/dev/urandom", O_RDONLY);
      if (fd == -1 || fd2 == -1)
        exit(printf("open failed\n"));
      pthread_t th;
      pthread_create(&th, 0, Thread, 0);
      if (dup2(fd2, fd) == -1)
        exit(printf("dup2 failed\n"));
      pthread_join(th, 0);
      if (close(fd) == -1)
        exit(printf("close failed\n"));
      if (close(fd2) == -1)
        exit(printf("close failed\n"));
      printf("DONE\n");
      return 0;
    }
    Signed-off-by: default avatarEric Dumazet <edumazet@google.com>
    Reported-by: default avatarDmitry Vyukov <dvyukov@google.com>
    Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
    5ba97d28
file.c 22.4 KB