From: Sasha Levin <sashal@kernel.org>
To: stable@vger.kernel.org
Cc: Runyu Xiao <runyu.xiao@seu.edu.cn>, Jens Axboe <axboe@kernel.dk>,
Sasha Levin <sashal@kernel.org>
Subject: [PATCH 5.10.y] block: amiflop: synchronize flush timer before track flush
Date: Tue, 10 Nov 2026 19:13:20 -0500 [thread overview]
Message-ID: <20261111001129.97308-1-sashal@kernel.org> (raw)
In-Reply-To: <20261107061811-failed-5.10-9690943353ce@kernel.org>
From: Runyu Xiao <runyu.xiao@seu.edu.cn>
[ Upstream commit 9690943353cec1690a715e000ba6a74e5139f530 ]
The amiflop track buffer is shared with the timer callback. timer_delete()
does not wait for an in-flight callback, and that callback can rearm itself
when it cannot acquire the floppy controller. A synchronous track flush can
therefore race with the callback.
Stop the timer before synchronous track writes and use timer_delete_sync()
to wait for any callback already running. Keep callback rearming disabled
until the write is complete. Apply this to the FDFMTTRK path as well.
FDFLUSH, FDFMTTRK and close-time flushes run outside the blk-mq
request callback. Freeze their queues so an in-flight request cannot
change the shared track buffer while it is encoded and written. Restart
the timer if a track remains dirty after a failed flush.
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Cc: stable@vger.kernel.org
Assisted-by: LLM
Signed-off-by: Runyu Xiao <runyu.xiao@seu.edu.cn>
Link: https://patch.msgid.link/20260930065951.2932739-1-runyu.xiao@seu.edu.cn
Signed-off-by: Jens Axboe <axboe@kernel.dk>
[ sashal: adapted queue freeze/unfreeze calls to the older API without saving or passing memflags ]
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/block/amiflop.c | 69 ++++++++++++++++++++++++++++++++++++-----
1 file changed, 61 insertions(+), 8 deletions(-)
diff --git a/drivers/block/amiflop.c b/drivers/block/amiflop.c
index 71c2b15645586..544d8dc8208d4 100644
--- a/drivers/block/amiflop.c
+++ b/drivers/block/amiflop.c
@@ -264,6 +264,8 @@ static struct fd_data_type data_types[] = {
static struct amiga_floppy_struct unit[FD_MAX_UNITS];
static struct timer_list flush_track_timer[FD_MAX_UNITS];
+static DEFINE_SPINLOCK(flush_track_timer_lock);
+static bool flush_track_timer_stopped[FD_MAX_UNITS];
static struct timer_list post_write_timer;
static unsigned long post_write_timer_drive;
static struct timer_list motor_on_timer;
@@ -1369,11 +1371,22 @@ static void flush_track_callback(struct timer_list *timer)
sizeof(flush_track_timer[0]);
nr&=3;
+ spin_lock(&flush_track_timer_lock);
+ if (flush_track_timer_stopped[nr]) {
+ spin_unlock(&flush_track_timer_lock);
+ return;
+ }
+ spin_unlock(&flush_track_timer_lock);
+
writefromint = 1;
if (!try_fdc(nr)) {
/* we might block in an interrupt, so try again later */
- flush_track_timer[nr].expires = jiffies + 1;
- add_timer(flush_track_timer + nr);
+ spin_lock(&flush_track_timer_lock);
+ if (!flush_track_timer_stopped[nr]) {
+ flush_track_timer[nr].expires = jiffies + 1;
+ add_timer(flush_track_timer + nr);
+ }
+ spin_unlock(&flush_track_timer_lock);
return;
}
get_fdc(nr);
@@ -1420,6 +1433,35 @@ static int non_int_flush_track (unsigned long nr)
return 1;
}
+static void flush_track_timer_stop(unsigned int drive)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&flush_track_timer_lock, flags);
+ flush_track_timer_stopped[drive] = true;
+ spin_unlock_irqrestore(&flush_track_timer_lock, flags);
+
+ timer_delete_sync(flush_track_timer + drive);
+}
+
+static void flush_track_timer_start(unsigned int drive)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&flush_track_timer_lock, flags);
+ flush_track_timer_stopped[drive] = false;
+ if (unit[drive].dirty)
+ mod_timer(flush_track_timer + drive, jiffies + 1);
+ spin_unlock_irqrestore(&flush_track_timer_lock, flags);
+}
+
+static void flush_track_timer_sync(unsigned int drive)
+{
+ flush_track_timer_stop(drive);
+ non_int_flush_track(drive);
+ flush_track_timer_start(drive);
+}
+
static int get_track(int drive, int track)
{
int error, errcnt;
@@ -1434,8 +1476,7 @@ static int get_track(int drive, int track)
}
if (unit[drive].dirty == 1) {
- del_timer (flush_track_timer + drive);
- non_int_flush_track (drive);
+ flush_track_timer_sync(drive);
}
errcnt = 0;
while (errcnt < MAX_ERRORS) {
@@ -1562,6 +1603,12 @@ static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode,
case FDFMTTRK:
if (param < p->type->tracks * p->type->heads)
{
+ flush_track_timer_stop(drive);
+ if (unit[drive].dirty == 1 &&
+ !non_int_flush_track(drive)) {
+ flush_track_timer_start(drive);
+ return -EIO;
+ }
get_fdc(drive);
if (fd_seek(drive,param) != 0){
memset(p->trackbuf, FD_FILL_BYTE,
@@ -1570,6 +1617,7 @@ static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode,
}
floppy_off(drive);
rel_fdc();
+ flush_track_timer_start(drive);
}
else
return -EINVAL;
@@ -1591,8 +1639,7 @@ static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode,
case FDDEFPRM:
return -EINVAL;
case FDFLUSH: /* unconditionally, even if not needed */
- del_timer (flush_track_timer + drive);
- non_int_flush_track(drive);
+ flush_track_timer_sync(drive);
break;
#ifdef RAW_IOCTL
case IOCTL_RAW_TRACK:
@@ -1611,9 +1658,14 @@ static int fd_ioctl(struct block_device *bdev, fmode_t mode,
unsigned int cmd, unsigned long param)
{
int ret;
+ bool freeze_queue = cmd == FDFMTTRK || cmd == FDFLUSH;
mutex_lock(&amiflop_mutex);
+ if (freeze_queue)
+ blk_mq_freeze_queue(bdev->bd_disk->queue);
ret = fd_locked_ioctl(bdev, mode, cmd, param);
+ if (freeze_queue)
+ blk_mq_unfreeze_queue(bdev->bd_disk->queue);
mutex_unlock(&amiflop_mutex);
return ret;
@@ -1710,9 +1762,9 @@ static void floppy_release(struct gendisk *disk, fmode_t mode)
int drive = p - unit;
mutex_lock(&amiflop_mutex);
+ blk_mq_freeze_queue(disk->queue);
if (unit[drive].dirty == 1) {
- del_timer (flush_track_timer + drive);
- non_int_flush_track (drive);
+ flush_track_timer_sync(drive);
}
if (!fd_ref[drive]--) {
@@ -1722,6 +1774,7 @@ static void floppy_release(struct gendisk *disk, fmode_t mode)
#ifdef MODULE
floppy_off (drive);
#endif
+ blk_mq_unfreeze_queue(disk->queue);
mutex_unlock(&amiflop_mutex);
}
--
2.53.0
prev parent reply other threads:[~2026-11-11 0:13 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-07 11:18 FAILED: patch "[PATCH] block: amiflop: synchronize flush timer before track flush" failed to apply to 5.10-stable tree Sasha Levin
2026-11-11 0:13 ` Sasha Levin [this message]
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=20261111001129.97308-1-sashal@kernel.org \
--to=sashal@kernel.org \
--cc=axboe@kernel.dk \
--cc=runyu.xiao@seu.edu.cn \
--cc=stable@vger.kernel.org \
/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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.