mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
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: 1da177e4c3 ("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>
This commit is contained in:
parent
e0f2224433
commit
9690943353
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user