From: Sasha Levin <sashal@kernel.org>
To: runyu.xiao@seu.edu.cn, axboe@kernel.dk
Cc: stable@vger.kernel.org
Subject: FAILED: patch "[PATCH] block: amiflop: synchronize flush timer before track flush" failed to apply to 5.15-stable tree
Date: Sat, 7 Nov 2026 06:01:27 -0500 [thread overview]
Message-ID: <20261107060127-failed-5.15-9690943353ce@kernel.org> (raw)
The patch below does not apply to the 5.15-stable tree.
If someone wants it applied there, or to any other stable or longterm
tree, then please email the backport, including the original git commit
id to <stable@vger.kernel.org>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-5.15.y
git checkout FETCH_HEAD
git cherry-pick -x 9690943353cec1690a715e000ba6a74e5139f530
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<stable@vger.kernel.org>' --in-reply-to '20261107060127-failed-5.15-9690943353ce@kernel.org' --subject-prefix 'PATCH 5.15.y' 'HEAD^..'
Thanks,
Sasha
------------------ original commit in Linus's tree ------------------
From 9690943353cec1690a715e000ba6a74e5139f530 Mon Sep 17 00:00:00 2001
From: Runyu Xiao <runyu.xiao@seu.edu.cn>
Date: Wed, 30 Sep 2026 14:59:51 +0800
Subject: [PATCH] block: amiflop: synchronize flush timer before track flush
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>
---
drivers/block/amiflop.c | 71 ++++++++++++++++++++++++++++++++++++-----
1 file changed, 63 insertions(+), 8 deletions(-)
diff --git a/drivers/block/amiflop.c b/drivers/block/amiflop.c
index 2932b6653b6f0..a477ada6b1ef5 100644
--- a/drivers/block/amiflop.c
+++ b/drivers/block/amiflop.c
@@ -265,6 +265,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;
@@ -1370,11 +1372,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);
@@ -1421,6 +1434,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;
@@ -1435,8 +1477,7 @@ static int get_track(int drive, int track)
}
if (unit[drive].dirty == 1) {
- timer_delete(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, blk_mode_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, blk_mode_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, blk_mode_t mode,
case FDDEFPRM:
return -EINVAL;
case FDFLUSH: /* unconditionally, even if not needed */
- timer_delete(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,15 @@ static int fd_ioctl(struct block_device *bdev, blk_mode_t mode,
unsigned int cmd, unsigned long param)
{
int ret;
+ unsigned int memflags = 0;
+ bool freeze_queue = cmd == FDFMTTRK || cmd == FDFLUSH;
mutex_lock(&amiflop_mutex);
+ if (freeze_queue)
+ memflags = 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, memflags);
mutex_unlock(&amiflop_mutex);
return ret;
@@ -1711,11 +1764,12 @@ static void floppy_release(struct gendisk *disk)
{
struct amiga_floppy_struct *p = disk->private_data;
int drive = p - unit;
+ unsigned int memflags;
mutex_lock(&amiflop_mutex);
+ memflags = blk_mq_freeze_queue(disk->queue);
if (unit[drive].dirty == 1) {
- timer_delete(flush_track_timer + drive);
- non_int_flush_track (drive);
+ flush_track_timer_sync(drive);
}
if (!fd_ref[drive]--) {
@@ -1725,6 +1779,7 @@ static void floppy_release(struct gendisk *disk)
#ifdef MODULE
floppy_off (drive);
#endif
+ blk_mq_unfreeze_queue(disk->queue, memflags);
mutex_unlock(&amiflop_mutex);
}
--
2.53.0
next reply other threads:[~2026-11-07 11:01 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-07 11:01 Sasha Levin [this message]
2026-11-10 23:10 ` [PATCH 5.15.y] block: amiflop: synchronize flush timer before track flush Sasha Levin
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=20261107060127-failed-5.15-9690943353ce@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.