]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
tun: honor IOCB_NOWAIT flag
authorJens Axboe <axboe@kernel.dk>
Fri, 20 Nov 2020 14:59:54 +0000 (07:59 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 8 Dec 2020 09:42:00 +0000 (10:42 +0100)
[ Upstream commit 5aac0390a63b8718237a61dd0d24a29201d1c94a ]

tun only checks the file O_NONBLOCK flag, but it should also be checking
the iocb IOCB_NOWAIT flag. Any fops using ->read/write_iter() should check
both, otherwise it breaks users that correctly expect O_NONBLOCK semantics
if IOCB_NOWAIT is set.

Signed-off-by: Jens Axboe <axboe@kernel.dk>
Link: https://lore.kernel.org/r/e9451860-96cc-c7c7-47b8-fe42cadd5f4c@kernel.dk
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/net/tun.c

index 7959b5c2d11f1cdcc4d549546abeff694415e8a1..b5f47d37ea1be51dc8d4a86b2b662e6f143dd476 100644 (file)
@@ -1979,12 +1979,15 @@ static ssize_t tun_chr_write_iter(struct kiocb *iocb, struct iov_iter *from)
        struct tun_file *tfile = file->private_data;
        struct tun_struct *tun = tun_get(tfile);
        ssize_t result;
+       int noblock = 0;
 
        if (!tun)
                return -EBADFD;
 
-       result = tun_get_user(tun, tfile, NULL, from,
-                             file->f_flags & O_NONBLOCK, false);
+       if ((file->f_flags & O_NONBLOCK) || (iocb->ki_flags & IOCB_NOWAIT))
+               noblock = 1;
+
+       result = tun_get_user(tun, tfile, NULL, from, noblock, false);
 
        tun_put(tun);
        return result;
@@ -2203,10 +2206,15 @@ static ssize_t tun_chr_read_iter(struct kiocb *iocb, struct iov_iter *to)
        struct tun_file *tfile = file->private_data;
        struct tun_struct *tun = tun_get(tfile);
        ssize_t len = iov_iter_count(to), ret;
+       int noblock = 0;
 
        if (!tun)
                return -EBADFD;
-       ret = tun_do_read(tun, tfile, to, file->f_flags & O_NONBLOCK, NULL);
+
+       if ((file->f_flags & O_NONBLOCK) || (iocb->ki_flags & IOCB_NOWAIT))
+               noblock = 1;
+
+       ret = tun_do_read(tun, tfile, to, noblock, NULL);
        ret = min_t(ssize_t, ret, len);
        if (ret > 0)
                iocb->ki_pos = ret;