iio: buffer: make sure O_NONBLOCK is respected
authorNuno Sá <nuno.sa@analog.com>
Thu, 16 Feb 2023 10:14:51 +0000 (11:14 +0100)
committerJonathan Cameron <Jonathan.Cameron@huawei.com>
Sat, 18 Feb 2023 14:07:58 +0000 (14:07 +0000)
For output buffers, there's no guarantee that the buffer won't be full
in the first iteration of the loop in which case we would block
independently of userspace passing O_NONBLOCK or not. Fix it by always
checking the flag before going to sleep.

While at it (and as it's a bit related), refactored the loop so that the
stop condition is 'written != n', i.e, run the loop until all data has
been copied into the IIO buffers. This makes the code a bit simpler.

Fixes: 9eeee3b0bf190 ("iio: Add output buffer support")
Signed-off-by: Nuno Sá <nuno.sa@analog.com>
Reviewed-by: Lars-Peter Clausen <lars@metafoo.de>
Link: https://lore.kernel.org/r/20230216101452.591805-3-nuno.sa@analog.com
Cc: <Stable@vger.kernel.org>
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
drivers/iio/industrialio-buffer.c

index 6340d8e1430b6a984dae767e4476a78d87229bab..a7a080bed1808f1f763bdb6dfff7c939c95a2bc8 100644 (file)
@@ -203,21 +203,24 @@ static ssize_t iio_buffer_write(struct file *filp, const char __user *buf,
                                break;
                        }
 
+                       if (filp->f_flags & O_NONBLOCK) {
+                               if (!written)
+                                       ret = -EAGAIN;
+                               break;
+                       }
+
                        wait_woken(&wait, TASK_INTERRUPTIBLE,
                                        MAX_SCHEDULE_TIMEOUT);
                        continue;
                }
 
                ret = rb->access->write(rb, n - written, buf + written);
-               if (ret == 0 && (filp->f_flags & O_NONBLOCK))
-                       ret = -EAGAIN;
+               if (ret < 0)
+                       break;
 
-               if (ret > 0) {
-                       written += ret;
-                       if (written != n && !(filp->f_flags & O_NONBLOCK))
-                               continue;
-               }
-       } while (ret == 0);
+               written += ret;
+
+       } while (written != n);
        remove_wait_queue(&rb->pollq, &wait);
 
        return ret < 0 ? ret : written;