linux-block.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] aoe: consolidate flags update to prevent race condition
@ 2024-06-11  3:52 Gui-Dong Han
  2024-06-12 16:54 ` Jens Axboe
  0 siblings, 1 reply; 3+ messages in thread
From: Gui-Dong Han @ 2024-06-11  3:52 UTC (permalink / raw)
  To: justin, axboe; +Cc: linux-block, linux-kernel, baijiaju1990, Gui-Dong Han

In aoecmd_sleepwork, there is a race condition caused by two consecutive
writes to the 'flags' variable within a critical section. If a read 
operation occurs between these writes, an intermediate state may be 
read, potentially causing bugs.

To address this issue, the 'flags' variable should be updated in a 
single operation to ensure atomicity and prevent any intermediate state
from being read.

Fixes: 3ae1c24e395b ("[PATCH] aoe [2/8]: support dynamic resizing of AoE devices")
Signed-off-by: Gui-Dong Han <hanguidong02@outlook.com>
---
 drivers/block/aoe/aoecmd.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c
index cc9077b588d7..37d556f019c0 100644
--- a/drivers/block/aoe/aoecmd.c
+++ b/drivers/block/aoe/aoecmd.c
@@ -897,8 +897,7 @@ aoecmd_sleepwork(struct work_struct *work)
 		set_capacity_and_notify(d->gd, d->ssize);
 
 		spin_lock_irq(&d->lock);
-		d->flags |= DEVFL_UP;
-		d->flags &= ~DEVFL_NEWSIZE;
+		d->flags = (d->flags | DEVFL_UP) & ~DEVFL_NEWSIZE;
 		spin_unlock_irq(&d->lock);
 	}
 }
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [PATCH] aoe: consolidate flags update to prevent race condition
  2024-06-11  3:52 [PATCH] aoe: consolidate flags update to prevent race condition Gui-Dong Han
@ 2024-06-12 16:54 ` Jens Axboe
  2025-02-25  3:13   ` Gui-Dong Han
  0 siblings, 1 reply; 3+ messages in thread
From: Jens Axboe @ 2024-06-12 16:54 UTC (permalink / raw)
  To: Gui-Dong Han, justin; +Cc: linux-block, linux-kernel, baijiaju1990

On 6/10/24 9:52 PM, Gui-Dong Han wrote:
> In aoecmd_sleepwork, there is a race condition caused by two consecutive
> writes to the 'flags' variable within a critical section. If a read 
> operation occurs between these writes, an intermediate state may be 
> read, potentially causing bugs.
> 
> To address this issue, the 'flags' variable should be updated in a 
> single operation to ensure atomicity and prevent any intermediate state
> from being read.
> 
> Fixes: 3ae1c24e395b ("[PATCH] aoe [2/8]: support dynamic resizing of AoE devices")
> Signed-off-by: Gui-Dong Han <hanguidong02@outlook.com>
> ---
>  drivers/block/aoe/aoecmd.c | 3 +--
>  1 file changed, 1 insertion(+), 2 deletions(-)
> 
> diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c
> index cc9077b588d7..37d556f019c0 100644
> --- a/drivers/block/aoe/aoecmd.c
> +++ b/drivers/block/aoe/aoecmd.c
> @@ -897,8 +897,7 @@ aoecmd_sleepwork(struct work_struct *work)
>  		set_capacity_and_notify(d->gd, d->ssize);
>  
>  		spin_lock_irq(&d->lock);
> -		d->flags |= DEVFL_UP;
> -		d->flags &= ~DEVFL_NEWSIZE;
> +		d->flags = (d->flags | DEVFL_UP) & ~DEVFL_NEWSIZE;
>  		spin_unlock_irq(&d->lock);
>  	}

It's modified under the lock, and any reader should do so as well. If
not, there's a race regardless of your change or not.

-- 
Jens Axboe


^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH] aoe: consolidate flags update to prevent race condition
  2024-06-12 16:54 ` Jens Axboe
@ 2025-02-25  3:13   ` Gui-Dong Han
  0 siblings, 0 replies; 3+ messages in thread
From: Gui-Dong Han @ 2025-02-25  3:13 UTC (permalink / raw)
  To: Jens Axboe, justin@coraid.com
  Cc: linux-block@vger.kernel.org, linux-kernel@vger.kernel.org,
	baijiaju1990@gmail.com

Hi Jens,

Thank you for your feedback. Let me clarify the rationale behind this change.

On 2024-06-12 10:54, Jens Axboe wrote:
> It's modified under the lock, and any reader should do so as well. If
> not, there's a race regardless of your change or not.

The existing implementation contains multiple unsynchronized reads of d->flags.
For example, in aoecmd_sleepwork() itself:

void aoecmd_sleepwork(struct work_struct *work)
{
    struct aoedev *d = container_of(work, struct aoedev, work);

    /* These flag checks are performed WITHOUT LOCKING: */
    if (d->flags & DEVFL_GDALLOC) <--- Unsynchronized read
        aoeblk_gdalloc(d);
    if (d->flags & DEVFL_NEWSIZE) {  <--- Unsynchronized read
        set_capacity_and_notify(d->gd, d->ssize);
        spin_lock_irq(&d->lock);
        d->flags |= DEVFL_UP;        <--- Two separate writes
        d->flags &= ~DEVFL_NEWSIZE;  <--- to flags under lock
        spin_unlock_irq(&d->lock);
    }
}

The problematic sequence would be:
1. Thread A sets DEVFL_UP under lock
2. Thread B (or same thread) reads d->flags without lock, sees DEVFL_UP set but
   DEVFL_NEWSIZE still present (before the second write clears it)
3. This could lead to unexpected behavior since DEVFL_NEWSIZE indicates a state
   transition that should be atomic with DEVFL_UP setting

By consolidating the flag updates into a single atomic operation under lock:

d->flags = (d->flags | DEVFL_UP) & ~DEVFL_NEWSIZE;

We ensure any unsynchronized reader (like the DEVFL_NEWSIZE check in this same
function) will either see both changes or neither, avoiding intermediate states.

Would you agree this provides stronger consistency guarantees for readers that
(per current code) don't take the lock when checking flags?

Best regards,
Gui-Dong Han

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2025-02-25  3:13 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-06-11  3:52 [PATCH] aoe: consolidate flags update to prevent race condition Gui-Dong Han
2024-06-12 16:54 ` Jens Axboe
2025-02-25  3:13   ` Gui-Dong Han

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).