* [PATCH] block: avoid long sync_blockdev() under disk->open_mutex during parallel close
@ 2026-10-14 12:02 Tetsuo Handa
2026-10-14 13:07 ` [PATCH v2] " Tetsuo Handa
0 siblings, 1 reply; 8+ messages in thread
From: Tetsuo Handa @ 2026-10-14 12:02 UTC (permalink / raw)
To: LKML
Commit b849dd84b6cc ("bdev: Reduce time holding bd_mutex in sync in
blkdev_close()") introduced a sync_blockdev() call immediately before
holding disk->open_mutex. But this check was racy and best-effort basis.
If more than one process concurrently called bdev_release() and saw
atomic_read(&bdev->bd_openers) > 1, the process which actually hit
the atomic_dec_and_test(&bdev->bd_openers) condition will call
sync_blockdev() from blkdev_flush_mapping() (which could take several
minutes) with disk->open_mutex held.
Kill this race window and make sync_blockdev() always be called before
holding disk->open_mutex, by using a marker that checks whether lockless
sync_blockdev() has raced.
Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
---
block/bdev.c | 41 +++++++++++++++++++++++++++++++++++++--
include/linux/blk_types.h | 1 +
2 files changed, 40 insertions(+), 2 deletions(-)
diff --git a/block/bdev.c b/block/bdev.c
index cd8323083740..07e4cc0e5c2a 100644
--- a/block/bdev.c
+++ b/block/bdev.c
@@ -1167,10 +1167,47 @@ void bdev_release(struct file *bdev_file)
* of the world and we want to avoid long (could be several minute)
* syncs while holding the mutex.
*/
- if (atomic_read(&bdev->bd_openers) == 1)
+ retry:
+ mutex_lock(&disk->open_mutex);
+ if (bdev_is_partition(bdev) &&
+ atomic_read(&bdev_whole(bdev)->bd_openers) == 1) {
+ /*
+ * This "bdev" is a partition, and blkdev_put_whole() from
+ * blkdev_put_part() will trigger blkdev_flush_mapping() on
+ * the whole disk. Therefore, we need to sync the whole disk.
+ */
+ bdev->bdev_syncer = current;
+ mutex_unlock(&disk->open_mutex);
+ sync_blockdev(bdev_whole(bdev));
+ mutex_lock(&disk->open_mutex);
+ /* Need to retry if we raced. */
+ if (bdev->bdev_syncer != current)
+ goto retry;
+ } else if (atomic_read(&bdev->bd_openers) == 1) {
+ /*
+ * If "bdev" is a whole disk, blkdev_put_whole() will trigger
+ * blkdev_flush_mapping() on this disk. Therefore, sync this
+ * "bdev".
+ *
+ * If "bdev" is a partition, blkdev_put_part() will trigger
+ * blkdev_flush_mapping() on this partition, but
+ * blkdev_put_whole() from blkdev_put_part() won't trigger
+ * blkdev_flush_mapping() on the whole disk because we chedked
+ * bdev_whole(bdev)->bd_openers != 1. Therefore, we need to
+ * sync only this "bdev".
+ */
+ bdev->bdev_syncer = current;
+ mutex_unlock(&disk->open_mutex);
sync_blockdev(bdev);
+ mutex_lock(&disk->open_mutex);
+ /* Need to retry if we raced. */
+ if (bdev->bdev_syncer != current)
+ goto retry;
+ } else {
+ /* Mark sync_blockdev() being possibly raced. */
+ bdev->bdev_syncer = NULL;
+ }
- mutex_lock(&disk->open_mutex);
bdev_yield_write_access(bdev_file);
if (holder)
diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h
index 98e21b4cbf32..d79bb4b6100f 100644
--- a/include/linux/blk_types.h
+++ b/include/linux/blk_types.h
@@ -74,6 +74,7 @@ struct block_device {
#ifdef CONFIG_SECURITY
void *bd_security;
#endif
+ struct task_struct *bdev_syncer; /* Not refcounted. */
/*
* keep this out-of-line as it's both big and not needed in the fast
* path
--
2.56.0
^ permalink raw reply [flat|nested] 8+ messages in thread* [PATCH v2] block: avoid long sync_blockdev() under disk->open_mutex during parallel close
2026-10-14 12:02 [PATCH] block: avoid long sync_blockdev() under disk->open_mutex during parallel close Tetsuo Handa
@ 2026-10-14 13:07 ` Tetsuo Handa
2026-10-14 14:12 ` [PATCH v3] " Tetsuo Handa
0 siblings, 1 reply; 8+ messages in thread
From: Tetsuo Handa @ 2026-10-14 13:07 UTC (permalink / raw)
To: LKML
Commit b849dd84b6cc ("bdev: Reduce time holding bd_mutex in sync in
blkdev_close()") introduced a sync_blockdev() call immediately before
holding disk->open_mutex. But this check was racy and best-effort basis.
If more than one process concurrently called bdev_release() and saw
atomic_read(&bdev->bd_openers) > 1, the process which actually hit
the atomic_dec_and_test(&bdev->bd_openers) condition will call
sync_blockdev() from blkdev_flush_mapping() (which could take several
minutes) with disk->open_mutex held.
Kill this race window and make sync_blockdev() always be called before
holding disk->open_mutex, by using a marker that checks whether lockless
sync_blockdev() has raced.
Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
---
Changes in v2:
- Fix errors mentioned by sashiko.
block/bdev.c | 43 +++++++++++++++++++++++++++++++++++++--
include/linux/blk_types.h | 1 +
2 files changed, 42 insertions(+), 2 deletions(-)
diff --git a/block/bdev.c b/block/bdev.c
index cd8323083740..0b24c252206c 100644
--- a/block/bdev.c
+++ b/block/bdev.c
@@ -1167,10 +1167,49 @@ void bdev_release(struct file *bdev_file)
* of the world and we want to avoid long (could be several minute)
* syncs while holding the mutex.
*/
- if (atomic_read(&bdev->bd_openers) == 1)
+ mutex_lock(&disk->open_mutex);
+ retry:
+ if (bdev_is_partition(bdev) &&
+ atomic_read(&bdev_whole(bdev)->bd_openers) == 1) {
+ /*
+ * This "bdev" is a partition, and blkdev_put_whole() from
+ * blkdev_put_part() will trigger blkdev_flush_mapping() on
+ * the whole disk. Therefore, we need to sync both this
+ * partition and the whole disk.
+ */
+ bdev->bdev_syncer = current;
+ mutex_unlock(&disk->open_mutex);
sync_blockdev(bdev);
+ sync_blockdev(bdev_whole(bdev));
+ mutex_lock(&disk->open_mutex);
+ /* Need to retry if we raced. */
+ if (bdev->bdev_syncer != current)
+ goto retry;
+ } else if (atomic_read(&bdev->bd_openers) == 1) {
+ /*
+ * If "bdev" is a whole disk, blkdev_put_whole() will trigger
+ * blkdev_flush_mapping() on this disk. Therefore, sync this
+ * "bdev".
+ *
+ * If "bdev" is a partition, blkdev_put_part() will trigger
+ * blkdev_flush_mapping() on this partition, but
+ * blkdev_put_whole() from blkdev_put_part() won't trigger
+ * blkdev_flush_mapping() on the whole disk because we checked
+ * bdev_whole(bdev)->bd_openers != 1. Therefore, we need to
+ * sync only this "bdev".
+ */
+ bdev->bdev_syncer = current;
+ mutex_unlock(&disk->open_mutex);
+ sync_blockdev(bdev);
+ mutex_lock(&disk->open_mutex);
+ /* Need to retry if we raced. */
+ if (bdev->bdev_syncer != current)
+ goto retry;
+ } else {
+ /* Mark sync_blockdev() being possibly raced. */
+ bdev->bdev_syncer = NULL;
+ }
- mutex_lock(&disk->open_mutex);
bdev_yield_write_access(bdev_file);
if (holder)
diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h
index 98e21b4cbf32..d79bb4b6100f 100644
--- a/include/linux/blk_types.h
+++ b/include/linux/blk_types.h
@@ -74,6 +74,7 @@ struct block_device {
#ifdef CONFIG_SECURITY
void *bd_security;
#endif
+ struct task_struct *bdev_syncer; /* Not refcounted. */
/*
* keep this out-of-line as it's both big and not needed in the fast
* path
--
2.56.0
^ permalink raw reply [flat|nested] 8+ messages in thread* [PATCH v3] block: avoid long sync_blockdev() under disk->open_mutex during parallel close
2026-10-14 13:07 ` [PATCH v2] " Tetsuo Handa
@ 2026-10-14 14:12 ` Tetsuo Handa
2026-10-14 16:21 ` [PATCH v4] " Tetsuo Handa
0 siblings, 1 reply; 8+ messages in thread
From: Tetsuo Handa @ 2026-10-14 14:12 UTC (permalink / raw)
To: LKML
Commit b849dd84b6cc ("bdev: Reduce time holding bd_mutex in sync in
blkdev_close()") introduced a sync_blockdev() call immediately before
holding disk->open_mutex. But this check was racy and best-effort basis.
If more than one process concurrently called bdev_release() and saw
atomic_read(&bdev->bd_openers) > 1, the process which actually hit
the atomic_dec_and_test(&bdev->bd_openers) condition will call
sync_blockdev() from blkdev_flush_mapping() (which could take several
minutes) with disk->open_mutex held.
Kill this race window and make sync_blockdev() always be called before
holding disk->open_mutex, by using a marker that checks whether lockless
sync_blockdev() has raced.
Assisted-by: Gemini-Pro
Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
---
block/bdev.c | 35 +++++++++++++++++++++++++++++++++--
include/linux/blk_types.h | 1 +
2 files changed, 34 insertions(+), 2 deletions(-)
diff --git a/block/bdev.c b/block/bdev.c
index cd8323083740..c71dacd0c2b1 100644
--- a/block/bdev.c
+++ b/block/bdev.c
@@ -1155,6 +1155,7 @@ void bdev_release(struct file *bdev_file)
struct block_device *bdev = file_bdev(bdev_file);
void *holder = bdev_file->private_data;
struct gendisk *disk = bdev->bd_disk;
+ struct block_device *whole;
/* We failed to open that block device. */
if (IS_ERR(holder))
@@ -1167,10 +1168,40 @@ void bdev_release(struct file *bdev_file)
* of the world and we want to avoid long (could be several minute)
* syncs while holding the mutex.
*/
- if (atomic_read(&bdev->bd_openers) == 1)
+ mutex_lock(&disk->open_mutex);
+ whole = bdev_is_partition(bdev) ? bdev_whole(bdev) : NULL;
+ retry:
+ if ((whole && atomic_read(&whole->bd_openers) == 1) ||
+ atomic_read(&bdev->bd_openers) == 1) {
+ bdev->bdev_syncer = current;
+ if (whole)
+ whole->bdev_syncer = current;
+ mutex_unlock(&disk->open_mutex);
sync_blockdev(bdev);
+ if (whole)
+ sync_blockdev(whole);
+ mutex_lock(&disk->open_mutex);
+ if (bdev->bdev_syncer != current ||
+ (whole && whole->bdev_syncer != current))
+ goto retry;
+ } else {
+ /*
+ * Mark sync_blockdev() being possibly raced.
+ *
+ * Theoretically, it is possible for a malicious thread to
+ * trap a victim thread in an infinite "goto retry;" loop
+ * by repeatedly calling open() and close(). In practice,
+ * however, trapping a victim thread in such a loop is
+ * extremely difficult. This is because the bd_opener count
+ * remains elevated between open() and close() calls,
+ * meaning the victim thread will observe bd_opener > 1
+ * and skip synchronization within just a few retries.
+ */
+ bdev->bdev_syncer = NULL;
+ if (whole)
+ whole->bdev_syncer = NULL;
+ }
- mutex_lock(&disk->open_mutex);
bdev_yield_write_access(bdev_file);
if (holder)
diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h
index 98e21b4cbf32..d79bb4b6100f 100644
--- a/include/linux/blk_types.h
+++ b/include/linux/blk_types.h
@@ -74,6 +74,7 @@ struct block_device {
#ifdef CONFIG_SECURITY
void *bd_security;
#endif
+ struct task_struct *bdev_syncer; /* Not refcounted. */
/*
* keep this out-of-line as it's both big and not needed in the fast
* path
--
2.56.0
^ permalink raw reply [flat|nested] 8+ messages in thread* [PATCH v4] block: avoid long sync_blockdev() under disk->open_mutex during parallel close
2026-10-14 14:12 ` [PATCH v3] " Tetsuo Handa
@ 2026-10-14 16:21 ` Tetsuo Handa
2026-10-15 10:25 ` [PATCH v5] " Tetsuo Handa
0 siblings, 1 reply; 8+ messages in thread
From: Tetsuo Handa @ 2026-10-14 16:21 UTC (permalink / raw)
To: LKML
Commit b849dd84b6cc ("bdev: Reduce time holding bd_mutex in sync in
blkdev_close()") introduced a sync_blockdev() call immediately before
holding disk->open_mutex. But this check was racy and best-effort basis.
If more than one process concurrently called bdev_release() and saw
atomic_read(&bdev->bd_openers) > 1, the process which actually hit
the atomic_dec_and_test(&bdev->bd_openers) condition will call
sync_blockdev() from blkdev_flush_mapping() (which could take several
minutes) with disk->open_mutex held.
Kill this race window and make sync_blockdev() always be called before
holding disk->open_mutex, by using a marker that checks whether lockless
sync_blockdev() has raced.
Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
---
block/bdev.c | 37 ++++++++++++++++++++++++++++++++++---
include/linux/blk_types.h | 1 +
2 files changed, 35 insertions(+), 3 deletions(-)
diff --git a/block/bdev.c b/block/bdev.c
index cd8323083740..57f0f57da8c1 100644
--- a/block/bdev.c
+++ b/block/bdev.c
@@ -1167,10 +1167,41 @@ void bdev_release(struct file *bdev_file)
* of the world and we want to avoid long (could be several minute)
* syncs while holding the mutex.
*/
- if (atomic_read(&bdev->bd_openers) == 1)
- sync_blockdev(bdev);
-
mutex_lock(&disk->open_mutex);
+ retry:
+ if (bdev_is_partition(bdev)) {
+ if (atomic_read(&bdev->bd_openers) == 1) {
+ bdev->bdev_syncer = current;
+ mutex_unlock(&disk->open_mutex);
+ sync_blockdev(bdev);
+ /*
+ * Always sync the whole disk despite we need to sync
+ * only when we're the last one, for we can't serialize
+ * concurrent closing of multiple partitions on the
+ * same disk using open_mutex.
+ */
+ sync_blockdev(bdev_whole(bdev));
+ mutex_lock(&disk->open_mutex);
+ if (bdev->bdev_syncer != current)
+ goto retry;
+ } else {
+ /* Mark sync_blockdev() being possibly raced. */
+ bdev->bdev_syncer = NULL;
+ }
+ } else {
+ if (atomic_read(&bdev->bd_openers) == 1) {
+ bdev->bdev_syncer = current;
+ mutex_unlock(&disk->open_mutex);
+ sync_blockdev(bdev);
+ mutex_lock(&disk->open_mutex);
+ if (bdev->bdev_syncer != current)
+ goto retry;
+ } else {
+ /* Mark sync_blockdev() being possibly raced. */
+ bdev->bdev_syncer = NULL;
+ }
+ }
+
bdev_yield_write_access(bdev_file);
if (holder)
diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h
index 98e21b4cbf32..d79bb4b6100f 100644
--- a/include/linux/blk_types.h
+++ b/include/linux/blk_types.h
@@ -74,6 +74,7 @@ struct block_device {
#ifdef CONFIG_SECURITY
void *bd_security;
#endif
+ struct task_struct *bdev_syncer; /* Not refcounted. */
/*
* keep this out-of-line as it's both big and not needed in the fast
* path
--
2.56.0
^ permalink raw reply [flat|nested] 8+ messages in thread* [PATCH v5] block: avoid long sync_blockdev() under disk->open_mutex during parallel close
2026-10-14 16:21 ` [PATCH v4] " Tetsuo Handa
@ 2026-10-15 10:25 ` Tetsuo Handa
2026-10-15 11:18 ` [PATCH v6] " Tetsuo Handa
0 siblings, 1 reply; 8+ messages in thread
From: Tetsuo Handa @ 2026-10-15 10:25 UTC (permalink / raw)
To: LKML
Commit b849dd84b6cc ("bdev: Reduce time holding bd_mutex in sync in
blkdev_close()") introduced a sync_blockdev() call immediately before
holding disk->open_mutex. But this check was racy and best-effort basis.
If more than one thread concurrently called bdev_release() and saw
atomic_read(&bdev->bd_openers) > 1, the thread which actually hit
the atomic_dec_and_test(&bdev->bd_openers) condition will call
sync_blockdev() from blkdev_flush_mapping() (which could take several
minutes) with disk->open_mutex held.
Kill this race window and make sync_blockdev() always be called before
holding disk->open_mutex, by using a counter that tracks how many threads
are calling sync_blockdev() from bdev_release() without disk->open_mutex
held.
Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
---
block/bdev.c | 17 +++++++++++++++--
include/linux/blk_types.h | 1 +
2 files changed, 16 insertions(+), 2 deletions(-)
diff --git a/block/bdev.c b/block/bdev.c
index cd8323083740..309c49842ddc 100644
--- a/block/bdev.c
+++ b/block/bdev.c
@@ -1167,10 +1167,23 @@ void bdev_release(struct file *bdev_file)
* of the world and we want to avoid long (could be several minute)
* syncs while holding the mutex.
*/
- if (atomic_read(&bdev->bd_openers) == 1)
+ mutex_lock(&disk->open_mutex);
+ if (atomic_read(&bdev->bd_openers) == 1 + bdev->bd_closers) {
+ bdev->bd_closers++;
+ mutex_unlock(&disk->open_mutex);
sync_blockdev(bdev);
+ /*
+ * Always sync the whole disk when closing a partition despite
+ * we need to sync the whole disk only when we're also closing
+ * the whole disk, for we can't serialize concurrent closing of
+ * partitions using disk->open_mutex.
+ */
+ if (bdev_is_partition(bdev))
+ sync_blockdev(bdev_whole(bdev));
+ mutex_lock(&disk->open_mutex);
+ bdev->bd_closers--;
+ }
- mutex_lock(&disk->open_mutex);
bdev_yield_write_access(bdev_file);
if (holder)
diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h
index 98e21b4cbf32..04d378818c76 100644
--- a/include/linux/blk_types.h
+++ b/include/linux/blk_types.h
@@ -74,6 +74,7 @@ struct block_device {
#ifdef CONFIG_SECURITY
void *bd_security;
#endif
+ int bd_closers;
/*
* keep this out-of-line as it's both big and not needed in the fast
* path
--
2.56.0
^ permalink raw reply [flat|nested] 8+ messages in thread* [PATCH v6] block: avoid long sync_blockdev() under disk->open_mutex during parallel close
2026-10-15 10:25 ` [PATCH v5] " Tetsuo Handa
@ 2026-10-15 11:18 ` Tetsuo Handa
2026-10-16 15:40 ` [PATCH v7] " Tetsuo Handa
0 siblings, 1 reply; 8+ messages in thread
From: Tetsuo Handa @ 2026-10-15 11:18 UTC (permalink / raw)
To: LKML
Commit b849dd84b6cc ("bdev: Reduce time holding bd_mutex in sync in
blkdev_close()") introduced a sync_blockdev() call immediately before
holding disk->open_mutex. But this check was racy and best-effort basis.
If more than one thread concurrently called bdev_release() and saw
atomic_read(&bdev->bd_openers) > 1, the thread which actually hit
the atomic_dec_and_test(&bdev->bd_openers) condition will call
sync_blockdev() from blkdev_flush_mapping() (which could take several
minutes) with disk->open_mutex held.
Kill this race window and make sync_blockdev() always be called before
holding disk->open_mutex, by using a counter that tracks how many threads
are calling sync_blockdev() from bdev_release() without disk->open_mutex
held.
Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
---
block/bdev.c | 24 ++++++++++++++++++++++--
include/linux/blk_types.h | 1 +
2 files changed, 23 insertions(+), 2 deletions(-)
diff --git a/block/bdev.c b/block/bdev.c
index cd8323083740..cc16f0d7d496 100644
--- a/block/bdev.c
+++ b/block/bdev.c
@@ -1167,10 +1167,30 @@ void bdev_release(struct file *bdev_file)
* of the world and we want to avoid long (could be several minute)
* syncs while holding the mutex.
*/
- if (atomic_read(&bdev->bd_openers) == 1)
+ mutex_lock(&disk->open_mutex);
+ if (atomic_read(&bdev->bd_openers) == 1 + bdev->bd_closers) {
+ struct block_device *whole = bdev_is_partition(bdev) ?
+ bdev_whole(bdev) : NULL;
+
+ bdev->bd_closers++;
+ if (whole)
+ whole->bd_closers++;
+ mutex_unlock(&disk->open_mutex);
sync_blockdev(bdev);
+ /*
+ * Always sync the whole disk when closing a partition despite
+ * we need to sync the whole disk only when we're also closing
+ * the whole disk, for we can't serialize concurrent closing of
+ * partitions using disk->open_mutex.
+ */
+ if (whole)
+ sync_blockdev(whole);
+ mutex_lock(&disk->open_mutex);
+ bdev->bd_closers--;
+ if (whole)
+ whole->bd_closers--;
+ }
- mutex_lock(&disk->open_mutex);
bdev_yield_write_access(bdev_file);
if (holder)
diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h
index 98e21b4cbf32..04d378818c76 100644
--- a/include/linux/blk_types.h
+++ b/include/linux/blk_types.h
@@ -74,6 +74,7 @@ struct block_device {
#ifdef CONFIG_SECURITY
void *bd_security;
#endif
+ int bd_closers;
/*
* keep this out-of-line as it's both big and not needed in the fast
* path
--
2.56.0
^ permalink raw reply [flat|nested] 8+ messages in thread* [PATCH v7] block: avoid long sync_blockdev() under disk->open_mutex during parallel close
2026-10-15 11:18 ` [PATCH v6] " Tetsuo Handa
@ 2026-10-16 15:40 ` Tetsuo Handa
2026-10-19 2:29 ` kernel test robot
0 siblings, 1 reply; 8+ messages in thread
From: Tetsuo Handa @ 2026-10-16 15:40 UTC (permalink / raw)
To: LKML
Commit b849dd84b6cc ("bdev: Reduce time holding bd_mutex in sync in
blkdev_close()") introduced a sync_blockdev() call immediately before
holding disk->open_mutex. But this check was racy and best-effort basis.
If more than one thread concurrently called bdev_release() and saw
atomic_read(&bdev->bd_openers) > 1, the thread which actually hit
the atomic_dec_and_test(&bdev->bd_openers) condition will call
sync_blockdev() from blkdev_flush_mapping() (which could take several
minutes) with disk->open_mutex held.
Kill this race window and make sync_blockdev() always be called before
holding disk->open_mutex, by using a counter that tracks how many threads
are calling sync_blockdev() from bdev_release() without disk->open_mutex
held.
Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
---
block/bdev.c | 18 +++++++++++++++---
include/linux/blk_types.h | 1 +
2 files changed, 16 insertions(+), 3 deletions(-)
diff --git a/block/bdev.c b/block/bdev.c
index cd8323083740..cc9f66fd9d6b 100644
--- a/block/bdev.c
+++ b/block/bdev.c
@@ -1150,6 +1150,17 @@ static inline void bd_yield_claim(struct file *bdev_file)
bd_end_claim(bdev, holder);
}
+static inline void bd_early_sync(struct gendisk *disk, struct block_device *bdev)
+{
+ if (atomic_read(&bdev->bd_openers) == 1 + bdev->bd_closers) {
+ bdev->bd_closers++;
+ mutex_unlock(&disk->open_mutex);
+ sync_blockdev(bdev);
+ mutex_lock(&disk->open_mutex);
+ bdev->bd_closers--;
+ }
+}
+
void bdev_release(struct file *bdev_file)
{
struct block_device *bdev = file_bdev(bdev_file);
@@ -1167,10 +1178,11 @@ void bdev_release(struct file *bdev_file)
* of the world and we want to avoid long (could be several minute)
* syncs while holding the mutex.
*/
- if (atomic_read(&bdev->bd_openers) == 1)
- sync_blockdev(bdev);
-
mutex_lock(&disk->open_mutex);
+ bd_early_sync(disk, bdev);
+ if (bdev_is_partition(bdev))
+ bd_early_sync(disk, bdev_whole(bdev));
+
bdev_yield_write_access(bdev_file);
if (holder)
diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h
index 98e21b4cbf32..04d378818c76 100644
--- a/include/linux/blk_types.h
+++ b/include/linux/blk_types.h
@@ -74,6 +74,7 @@ struct block_device {
#ifdef CONFIG_SECURITY
void *bd_security;
#endif
+ int bd_closers;
/*
* keep this out-of-line as it's both big and not needed in the fast
* path
--
2.56.0
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2026-10-19 2:30 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-14 12:02 [PATCH] block: avoid long sync_blockdev() under disk->open_mutex during parallel close Tetsuo Handa
2026-10-14 13:07 ` [PATCH v2] " Tetsuo Handa
2026-10-14 14:12 ` [PATCH v3] " Tetsuo Handa
2026-10-14 16:21 ` [PATCH v4] " Tetsuo Handa
2026-10-15 10:25 ` [PATCH v5] " Tetsuo Handa
2026-10-15 11:18 ` [PATCH v6] " Tetsuo Handa
2026-10-16 15:40 ` [PATCH v7] " Tetsuo Handa
2026-10-19 2:29 ` kernel test robot
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®