Message ID | 1435590630.4110.107.camel@edumazet-glaptop2.roam.corp.google.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On Mon, Jun 29, 2015 at 05:10:30PM +0200, Eric Dumazet wrote: > From: Eric Dumazet <edumazet@google.com> > > __fget() makes sure a file refcount is not zero before > taking a reference. It should also fetch again file pointer > in order to respect dup2() atomicity requirements. > > It should either read a NULL pointer or a file on which > a refcount can be taken. Hmm... The problem is real, but I wonder if one could trigger a long spin there... -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Mon, 2015-06-29 at 18:46 +0100, Al Viro wrote: > On Mon, Jun 29, 2015 at 05:10:30PM +0200, Eric Dumazet wrote: > > From: Eric Dumazet <edumazet@google.com> > > > > __fget() makes sure a file refcount is not zero before > > taking a reference. It should also fetch again file pointer > > in order to respect dup2() atomicity requirements. > > > > It should either read a NULL pointer or a file on which > > a refcount can be taken. > > Hmm... The problem is real, but I wonder if one could trigger a long > spin there... I do not believe we can spin a long time. By the time do_dup2() calls filp_close(tofree, files), we already have a stable fdt->fd[fd], because of spin_unlock(&files->file_lock) was called before filp_close() A loop would require threads doing dup2() calls like crazy on same destination fd. -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
diff --git a/fs/file.c b/fs/file.c index 93c5f89c248b..492bd74c4433 100644 --- a/fs/file.c +++ b/fs/file.c @@ -635,11 +635,17 @@ static struct file *__fget(unsigned int fd, fmode_t mask) struct file *file; rcu_read_lock(); +loop: file = fcheck_files(files, fd); if (file) { - /* File object ref couldn't be taken */ - if ((file->f_mode & mask) || !get_file_rcu(file)) + /* File object ref couldn't be taken. + * dup2() atomicity guarantee is the reason + * we loop to catch the new file (or NULL pointer) + */ + if (file->f_mode & mask) file = NULL; + else if (!get_file_rcu(file)) + goto loop; } rcu_read_unlock();