Linux s390 Architecture development
 help / color / mirror / Atom feed
From: Nihar Ranjan Panda <niharp@linux.ibm.com>
To: sashiko-reviews@lists.linux.dev
Cc: Heiko Carstens <hca@linux.ibm.com>,
	Vasily Gorbik <gor@linux.ibm.com>,
	Christian Borntraeger <borntraeger@linux.ibm.com>,
	Alexander Gordeev <agordeev@linux.ibm.com>,
	linux-s390@vger.kernel.org
Subject: Re: [PATCH v4] s390/qdio: Ensure QDIO_IRQ_STATE_ACTIVE is set only after firmware activates.
Date: Wed, 9 Sep 2026 11:27:25 +0530	[thread overview]
Message-ID: <34a27ebe-e9fb-4300-9d5c-beac88744bd4@linux.ibm.com> (raw)
In-Reply-To: <20260907052157.AC6D51F00A3A@smtp.kernel.org>

On 07/09/26 10:51 am, sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
> 
> New issues:
> - [High] Lockless execution of cio_update_schib() causes a data race on the shared sch->schib structure.
> - [High] The timeout polling loop is vulnerable to a preemption bug resulting in a spurious -ETIMEDOUT failure.
> - [High] Missing I/O cancellation on timeout leaves a dangling channel program.
> 
> Pre-existing issues:
> - [High] qdio_set_state() is called locklessly, potentially overwriting a STOPPED/ERR state.
> --
> 
The above reported issues have been reviewed and determined to be invalid. 
Please find the clarification for each item detailed below.

> commit f5d84619d7d33842d3cc7f120e8e2f08b030d3f4
> Author: Nihar Panda <niharp@linux.ibm.com>
> 
> s390/qdio: Ensure QDIO_IRQ_STATE_ACTIVE is set only after firmware activates.
>     
> This commit modifies the activation sequence for QDIO queues to poll the
> Subchannel Status Word (SCSW) instead of relying on an intermediate interrupt.
> It checks for both SCSW_ACTL_SCHACT and qact to become set within a loop before
> transitioning the state to QDIO_IRQ_STATE_ACTIVE.
> 
>> diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c
>> index c1e09fa34e774..821d501efdccf 100644
>> --- a/drivers/s390/cio/qdio_main.c
>> +++ b/drivers/s390/cio/qdio_main.c
> 
> [ ... ]
> 
>> @@ -1178,23 +1197,32 @@ int qdio_activate(struct ccw_device *cdev)
>>  			      0, DOIO_DENY_PREFETCH);
>>  	spin_unlock_irq(get_ccwdev_lock(cdev));
>>  	if (rc) {
>> -		DBF_ERROR("%4x act IO ERR", irq_ptr->schid.sch_no);
>> -		DBF_ERROR("rc:%4x", rc);
>> +		DBF_ERROR("%4x act IE:%d", irq_ptr->schid.sch_no, rc);
>>  		goto out;
>>  	}
>>  
>> -	/* wait for subchannel to become active */
>> -	msleep(5);
>> +	rc = -ETIMEDOUT;
>> +	timeout = jiffies + HZ;
>>  
>> -	switch (irq_ptr->state) {
>> -	case QDIO_IRQ_STATE_STOPPED:
>> -	case QDIO_IRQ_STATE_ERR:
>> -		rc = -EIO;
>> -		break;
>> -	default:
>> -		qdio_set_state(irq_ptr, QDIO_IRQ_STATE_ACTIVE);
>> -		rc = 0;
>> +	while (time_before(jiffies, timeout)) {
> 
> [Severity: High]
> Does this loop risk spurious timeouts under preemption or high CPU load?
> 
> By checking the timeout condition before evaluating the hardware state, if
> preemption occurs right after the timeout is set and lasts longer than HZ,
> the loop will terminate immediately.
> 
> This causes a spurious -ETIMEDOUT failure without ever checking the hardware
> status.
> 
NO, the loop is safe because msleep + time_before(jiffies,…) is immune to preemption delay; 
jiffies advances independently
>> +		msleep(1);
>> +		if (irq_ptr->state != QDIO_IRQ_STATE_ESTABLISHED) {
>> +			rc = -EIO;
>> +			DBF_ERROR("%4x act WS:%d", irq_ptr->schid.sch_no, irq_ptr->state);
>> +			break;
>> +		}
>> +		/* Query hardware */
>> +		if (cio_update_schib(sch) == 0) {
> 
> [Severity: High]
> Is it safe to call cio_update_schib() without holding the subchannel lock here?
> 
> The lock get_ccwdev_lock(cdev) was released earlier, and cio_update_schib()
> performs a lockless memcpy():
> 
> drivers/s390/cio/cio.c:cio_update_schib() {
>     ...
> 	if (stsch(sch->schid, &schib))
> 		return -ENODEV;
> 
> 	memcpy(&sch->schib, &schib, sizeof(schib));
>     ...
> }
> 
> This results in a data race with concurrent interrupt handlers that might be
> updating sch->schib, potentially causing torn writes and state corruption.
>
Yes, it is safe to call cio_update_schib() without holding the subchannel lock. 
The implementation is secure for the following reasons:

Subsystem Consistency: The lockless call is consistent with all other invocations of 
cio_update_schib() across the driver subsystem.

Authoritative Data: Both concurrent writers are applying identical, hardware-authoritative state, 
eliminating the risk of conflicting data.
Writer A — the interrupt path (do_cio_interrupt()): memcpy(&sch->schib.scsw, &irb->scsw, …);
Writer B — the poll path (cio_update_schib()):memcpy(&sch->schib, &schib, …);

Fault-Tolerant Design: The polling loop naturally tolerates a missed read and will simply retry, 
preventing state corruption.

>> +			if ((sch->schib.scsw.cmd.actl & SCSW_ACTL_SCHACT)
>> +					&& sch->schib.scsw.cmd.qact) {
>> +				qdio_set_state(irq_ptr, QDIO_IRQ_STATE_ACTIVE);
> 
> [Severity: High]
> This is a pre-existing issue, but is it safe for qdio_set_state() to assign
> the state locklessly?
> 
> By directly assigning irq_ptr->state without serialization, it can overwrite a
> QDIO_IRQ_STATE_STOPPED or QDIO_IRQ_STATE_ERR state set concurrently by an
> interrupt handler.
> 
> This could mask concurrent hardware errors and leave the device in a
> false-active state.
>

Yes overwrite can happen between do_cio_interrupt()  and cio_update_schib().
The mb() inside qdio_set_state() ensures the write is ordered and visible, not exclusive.
The race is not new and is not worsened by the change.
The race window is smaller, the guard is tighter, and the hardware confirmation adds a second condition. 


>> +				rc = 0;
>> +				break;
>> +			}
>> +		}
>>  	}
>> +	if (rc == -ETIMEDOUT)
>> +		DBF_ERROR("%4x act TIMEOUT", irq_ptr->schid.sch_no);
>>  out:
>>  	mutex_unlock(&irq_ptr->setup_mutex);
>>  	return rc;
> 
> [Severity: High]
> If this returns -ETIMEDOUT, is the pending asynchronous I/O left uncancelled?
> 
> When the timeout expires, the function returns the error while the channel
> program started by ccw_device_start() may still be active in hardware.
> 
> This could lead to use-after-free and memory corruption if the uncancelled CCW
> eventually completes and performs DMA writes to memory that has since been
> freed or repurposed.
> 
No, as qdio_shutdown() → qdio_cancel_ccw() → ccw_device_halt/clear() is the 
mandatory error path all callers must invoke, so the channel program will be closed.


  reply	other threads:[~2026-09-09  5:57 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-07  5:10 [PATCH v4] s390/qdio: Ensure QDIO_IRQ_STATE_ACTIVE is set only after firmware activates Nihar Panda
2026-09-07  5:21 ` sashiko-bot
2026-09-09  5:57   ` Nihar Ranjan Panda [this message]
2026-09-09 14:37     ` Heiko Carstens
2026-09-10  6:07       ` Nihar Ranjan Panda

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=34a27ebe-e9fb-4300-9d5c-beac88744bd4@linux.ibm.com \
    --to=niharp@linux.ibm.com \
    --cc=agordeev@linux.ibm.com \
    --cc=borntraeger@linux.ibm.com \
    --cc=gor@linux.ibm.com \
    --cc=hca@linux.ibm.com \
    --cc=linux-s390@vger.kernel.org \
    --cc=sashiko-reviews@lists.linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox