Commit a90aba09 authored by Alessandro Rubini's avatar Alessandro Rubini

chardev: return POLLERR if user disables the trigger

Unfortunately, we sometimes have threads that block in the I/O
operation (the use case is input), and need to be notified when
another thread aborts the scheduled operation.  This sometimes applies
to a user-requested reconfiguration of the trigger.

This commit awakes processes sleeping on a cset when the trigger is
disabled by a sysfs store, and the chardev interface returns POLLERR
in the poll/select functions for control devices.

We chose not to affect the data device nor read and write. This means
all simple code (scripts, simple demos etc) is not affected.  But
full-featured applications, which rely on poll, have this additional
notification if they check the POLLERR bit.

Note: select(2) reports files both readable and writable when the drive
returns POLLERR, so applications should really use poll(2) instead.
Signed-off-by: Alessandro Rubini's avatarAlessandro Rubini <rubini@gnudd.com>
parent 9753a9ac
......@@ -309,9 +309,15 @@ static int zio_can_r_ctrl(struct zio_f_priv *priv)
return ret_ok;
}
}
/* We want to re-read control. Get a new block */
chan->user_block = zio_buffer_retr_block(bi);
ret = chan->user_block ? ret_ok : 0;
ret = 0;
if (chan->user_block)
ret = ret_ok;
else if (unlikely(bi->cset->ti->flags & ZIO_DISABLED))
ret = POLLERR;
mutex_unlock(&chan->user_lock);
return ret;
}
......@@ -355,6 +361,7 @@ static int zio_can_w_ctrl(struct zio_f_priv *priv)
struct zio_block *block;
struct zio_control *ctrl;
const int ret_ok = POLLOUT | POLLWRNORM;
int ret;
/*
* A control can always be written. Writing a control means a
......@@ -378,8 +385,12 @@ static int zio_can_w_ctrl(struct zio_f_priv *priv)
/* if no block is there, get a new one */
if (!block)
block = chan->user_block = __zio_write_allocblock(bi);
mutex_unlock(&chan->user_lock);
return block ? ret_ok : 0;
ret = 0;
if (block)
ret = ret_ok;
else if (unlikely(bi->cset->ti->flags & ZIO_DISABLED))
ret = POLLERR;
return ret;
}
static int zio_can_w_data(struct zio_f_priv *priv)
......@@ -413,7 +424,7 @@ static ssize_t zio_generic_read(struct file *f, char __user *ubuf,
struct zio_bi *bi = chan->bi;
struct zio_block *block;
int (*can_read)(struct zio_f_priv *);
int fault;
int fault, rflags;
dev_dbg(&bi->head.dev, "%s:%d type %s\n", __func__, __LINE__,
priv->type == ZIO_CDEV_CTRL ? "ctrl" : "data");
......@@ -429,7 +440,8 @@ static ssize_t zio_generic_read(struct file *f, char __user *ubuf,
}
while (1) {
if (!can_read(priv)) {
rflags = can_read(priv);
if (rflags == 0 || rflags == POLLERR) {
if (f->f_flags & O_NONBLOCK)
return -EAGAIN;
wait_event_interruptible(bi->q, can_read(priv));
......@@ -486,7 +498,7 @@ static ssize_t zio_generic_write(struct file *f, const char __user *ubuf,
struct zio_bi *bi = chan->bi;
struct zio_block *block;
int (*can_write)(struct zio_f_priv *);
int fault;
int fault, wflags;
dev_dbg(&bi->head.dev, "%s:%d type %s\n", __func__, __LINE__,
priv->type == ZIO_CDEV_CTRL ? "ctrl" : "data");
......@@ -502,7 +514,8 @@ static ssize_t zio_generic_write(struct file *f, const char __user *ubuf,
}
while(1) {
if (!can_write(priv)) {
wflags = can_write(priv);
if (wflags == 0 || wflags == POLLERR) {
if (f->f_flags & O_NONBLOCK)
return -EAGAIN;
wait_event_interruptible(bi->q, can_write(priv));
......
......@@ -12,6 +12,7 @@
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/sysfs.h>
#include <linux/version.h>
......@@ -446,12 +447,19 @@ static void __zobj_enable(struct device *dev, unsigned int enable)
dev_dbg(dev, "(ti)\n");
ti = to_zio_ti(dev);
cset = ti->cset;
zio_trigger_abort_disable(ti->cset, 0);
spin_lock_irqsave(&ti->cset->lock, flags);
if (ti->t_op->change_status)
ti->t_op->change_status(ti, status);
spin_unlock_irqrestore(&ti->cset->lock, flags);
/* A user-forced disable sends POLLERR to waiters */
for (i = 0; i < cset->n_chan; ++i) {
chan = cset->chan + i;
wake_up_interruptible(&chan->bi->q);
}
break;
/* following objects can't be enabled/disabled */
case ZIO_BI:
dev_dbg(dev, "(buf)\n");
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment