Commit 1962a288 authored by Alessandro Rubini's avatar Alessandro Rubini

core and doc: fix: the cset spinlock must be called in irqsave mode

This is a bug fix for overlooks in this same series of commits. I
won't fix each lock when it is introduced before proposing for master,
because it takes too much time.
Signed-off-by: Alessandro Rubini's avatarAlessandro Rubini <rubini@gnudd.com>
Acked-by: 's avatarFederico Vaga <federico.vaga@gmail.com>
parent 08787f26
......@@ -2399,15 +2399,17 @@ The following locks are defined used in ZIO core and data structures:
@cindex cset lock
@item zio_cset->lock
@c FIXME: trigger-related flags and locks
The cset structure includes a lock that is used to
serialize access to the @code{ti->flags} bits (e.g.:
@code{ZIO_TI_ARMED}, that signals that a trigger is pending).
serialize access the I/O operations, as well as trigger-related
events (i.e. the @code{ti->flags} bits like
@code{ZIO_TI_ARMED}).
I/O itself is serialized by trigger code in the ZIO core:
only one trigger event
can be pending for each cset, using the ARMED flag. The cset
itself, then, can use this same lock to serialize other activities
and prevent a trigger to be armed during such activities.
While taking this lock interrupts must be disabled, because trigger
operations usually happen in interrupt context.
@item zio_buffer_type->lock
@itemx zio_trigger_type->lock
......
......@@ -39,6 +39,7 @@ static void __zio_internal_abort_free(struct zio_cset *cset)
int zio_trigger_abort_disable(struct zio_cset *cset, int disable)
{
struct zio_ti *ti = cset->ti;
unsigned long flags;
int ret;
/*
......@@ -46,7 +47,7 @@ int zio_trigger_abort_disable(struct zio_cset *cset, int disable)
* Since the whole data_done procedure happens in locked context,
* there is no concurrency with an already-completing trigger event.
*/
spin_lock(&cset->lock);
spin_lock_irqsave(&cset->lock, flags);
if (ti->flags & ZIO_TI_ARMED) {
if (ti->t_op->abort)
ti->t_op->abort(ti);
......@@ -59,7 +60,7 @@ int zio_trigger_abort_disable(struct zio_cset *cset, int disable)
ret = ti->flags &= ZIO_STATUS;
if (disable)
ti->flags |= ZIO_DISABLED;
spin_unlock(&cset->lock);
spin_unlock_irqrestore(&cset->lock, flags);
return ret;
}
EXPORT_SYMBOL(zio_trigger_abort_disable);
......@@ -118,19 +119,21 @@ static void __zio_arm_output_trigger(struct zio_ti *ti)
*/
void zio_arm_trigger(struct zio_ti *ti)
{
unsigned long flags;
/* If the trigger runs too early, ti->cset is still NULL */
if (!ti->cset)
return;
/* check if trigger is disabled or previous instance is pending */
spin_lock(&ti->cset->lock);
spin_lock_irqsave(&ti->cset->lock, flags);
if (unlikely((ti->flags & ZIO_STATUS) == ZIO_DISABLED ||
(ti->flags & ZIO_TI_ARMED))) {
spin_unlock(&ti->cset->lock);
spin_unlock_irqrestore(&ti->cset->lock, flags);
return;
}
ti->flags |= ZIO_TI_ARMED;
spin_unlock(&ti->cset->lock);
spin_unlock_irqrestore(&ti->cset->lock, flags);
if (likely((ti->flags & ZIO_DIR) == ZIO_DIR_INPUT))
__zio_arm_input_trigger(ti);
......@@ -150,8 +153,9 @@ EXPORT_SYMBOL(zio_arm_trigger);
void zio_trigger_data_done(struct zio_cset *cset)
{
int self_timed = zio_cset_is_self_timed(cset);
unsigned long flags;
spin_lock(&cset->lock);
spin_lock_irqsave(&cset->lock, flags);
if (cset->ti->t_op->data_done)
cset->ti->t_op->data_done(cset);
......@@ -159,7 +163,7 @@ void zio_trigger_data_done(struct zio_cset *cset)
zio_generic_data_done(cset);
cset->ti->flags &= ~ZIO_TI_ARMED;
spin_unlock(&cset->lock);
spin_unlock_irqrestore(&cset->lock, flags);
/*
* If it is self-timed, re-arm the trigger immediately.
......
......@@ -278,6 +278,7 @@ int zio_change_current_trigger(struct zio_cset *cset, char *name)
{
struct zio_trigger_type *trig, *trig_old = cset->trig;
struct zio_ti *ti, *ti_old = cset->ti;
unsigned long flags;
int err, i;
pr_debug("%s\n", __func__);
......@@ -307,11 +308,11 @@ int zio_change_current_trigger(struct zio_cset *cset, char *name)
zio_trigger_put(trig_old, cset->zdev->owner);
/* Set new trigger and rename "trigger-tmp" to "trigger" */
spin_lock(&cset->lock);
spin_lock_irqsave(&cset->lock, flags);
cset->trig = trig;
cset->ti = ti;
err = device_rename(&ti->head.dev, "trigger");
spin_unlock(&cset->lock);
spin_unlock_irqrestore(&cset->lock, flags);
WARN(err, "%s: cannot rename trigger folder for"
" cset%d\n", __func__, cset->index);
......
......@@ -150,7 +150,7 @@ static void __zattr_propagate_value(struct zio_obj_head *head,
struct zio_attribute *zattr)
{
int i, j;
unsigned long tflags;
unsigned long flags, tflags;
struct zio_ti *ti;
struct zio_device *zdev;
struct zio_channel *chan;
......@@ -186,12 +186,12 @@ static void __zattr_propagate_value(struct zio_obj_head *head,
case ZIO_TI:
ti = to_zio_ti(&head->dev);
/* If trigger params change, we need to abort and restart */
spin_lock(&ti->cset->lock);
spin_lock_irqsave(&ti->cset->lock, flags);
tflags = ti->flags;
if (tflags & ZIO_TI_ARMED) {
spin_unlock(&ti->cset->lock);
spin_unlock_irqrestore(&ti->cset->lock, flags);
zio_trigger_abort_disable(ti->cset, 1);
spin_lock(&ti->cset->lock);
spin_lock_irqsave(&ti->cset->lock, flags);
}
__ctrl_update_nsamples(ti);
/* Update attributes in all "current_ctrl" struct */
......@@ -202,7 +202,7 @@ static void __zattr_propagate_value(struct zio_obj_head *head,
}
/* The new paramaters are in place, rearm/enable the trigger */
ti->flags = tflags & ~ZIO_TI_ARMED;
spin_unlock(&ti->cset->lock);
spin_unlock_irqrestore(&ti->cset->lock, flags);
if (tflags & ZIO_TI_ARMED)
zio_arm_trigger(ti);
break;
......@@ -332,7 +332,7 @@ int __zattr_dev_init_ctrl(struct zio_device *zdev)
*/
static void __zobj_enable(struct device *dev, unsigned int enable)
{
unsigned long *flags;
unsigned long *zf, flags;
int i, status;
struct zio_obj_head *head;
struct zio_device *zdev;
......@@ -342,13 +342,13 @@ static void __zobj_enable(struct device *dev, unsigned int enable)
pr_debug("%s\n", __func__);
head = to_zio_head(dev);
flags = zio_get_from_obj(to_zio_head(dev), flags);
status = !((*flags) & ZIO_STATUS);
zf = zio_get_from_obj(to_zio_head(dev), flags);
status = !((*zf) & ZIO_STATUS);
/* if the status is not changing */
if (!(enable ^ status))
return;
/* change status */
*flags = (*flags & (~ZIO_STATUS)) | status;
*zf = (*zf & (~ZIO_STATUS)) | status;
switch (head->zobj_type) {
case ZIO_DEV:
pr_debug("%s: zdev\n", __func__);
......@@ -378,12 +378,12 @@ static void __zobj_enable(struct device *dev, unsigned int enable)
pr_debug("%s: zti\n", __func__);
ti = to_zio_ti(dev);
spin_lock(&ti->cset->lock);
spin_lock_irqsave(&ti->cset->lock, flags);
zio_trigger_abort_disable(ti->cset, 0);
/* trigger instance callback */
if (ti->t_op->change_status)
ti->t_op->change_status(ti, status);
spin_unlock(&ti->cset->lock);
spin_unlock_irqrestore(&ti->cset->lock, flags);
break;
/* following objects can't be enabled/disabled */
case ZIO_BUF:
......
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