Skip to content

Commit 9a6d548

Browse files
committed
ide: ensure atapi sense request aren't preempted
There's an issue with how sense requests are handled in IDE. If ide-cd encounters an error, it queues a sense request. With how IDE request handling is done, this is the next request we need to handle. But it's impossible to guarantee this, as another request could come in between the sense being queued, and ->queue_rq() being run and handling it. If that request ALSO fails, then we attempt to doubly queue the single sense request we have. Since we only support one active request at the time, defer request processing when a sense request is queued. Fixes: 6003352 "ide: convert to blk-mq" Reported-by: He Zhe <zhe.he@windriver.com> Tested-by: He Zhe <zhe.he@windriver.com> Signed-off-by: Jens Axboe <axboe@kernel.dk>
1 parent 85bd6e6 commit 9a6d548

File tree

5 files changed

+59
-38
lines changed

5 files changed

+59
-38
lines changed

drivers/ide/ide-atapi.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -235,21 +235,28 @@ EXPORT_SYMBOL_GPL(ide_prep_sense);
235235

236236
int ide_queue_sense_rq(ide_drive_t *drive, void *special)
237237
{
238-
struct request *sense_rq = drive->sense_rq;
238+
ide_hwif_t *hwif = drive->hwif;
239+
struct request *sense_rq;
240+
unsigned long flags;
241+
242+
spin_lock_irqsave(&hwif->lock, flags);
239243

240244
/* deferred failure from ide_prep_sense() */
241245
if (!drive->sense_rq_armed) {
242246
printk(KERN_WARNING PFX "%s: error queuing a sense request\n",
243247
drive->name);
248+
spin_unlock_irqrestore(&hwif->lock, flags);
244249
return -ENOMEM;
245250
}
246251

252+
sense_rq = drive->sense_rq;
247253
ide_req(sense_rq)->special = special;
248254
drive->sense_rq_armed = false;
249255

250256
drive->hwif->rq = NULL;
251257

252258
ide_insert_request_head(drive, sense_rq);
259+
spin_unlock_irqrestore(&hwif->lock, flags);
253260
return 0;
254261
}
255262
EXPORT_SYMBOL_GPL(ide_queue_sense_rq);

drivers/ide/ide-io.c

Lines changed: 31 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,10 @@ int ide_end_rq(ide_drive_t *drive, struct request *rq, blk_status_t error,
6868
}
6969

7070
if (!blk_update_request(rq, error, nr_bytes)) {
71-
if (rq == drive->sense_rq)
71+
if (rq == drive->sense_rq) {
7272
drive->sense_rq = NULL;
73+
drive->sense_rq_active = false;
74+
}
7375

7476
__blk_mq_end_request(rq, error);
7577
return 0;
@@ -451,16 +453,11 @@ void ide_requeue_and_plug(ide_drive_t *drive, struct request *rq)
451453
blk_mq_delay_run_hw_queue(q->queue_hw_ctx[0], 3);
452454
}
453455

454-
/*
455-
* Issue a new request to a device.
456-
*/
457-
blk_status_t ide_queue_rq(struct blk_mq_hw_ctx *hctx,
458-
const struct blk_mq_queue_data *bd)
456+
blk_status_t ide_issue_rq(ide_drive_t *drive, struct request *rq,
457+
bool local_requeue)
459458
{
460-
ide_drive_t *drive = hctx->queue->queuedata;
461-
ide_hwif_t *hwif = drive->hwif;
459+
ide_hwif_t *hwif = drive->hwif;
462460
struct ide_host *host = hwif->host;
463-
struct request *rq = bd->rq;
464461
ide_startstop_t startstop;
465462

466463
if (!blk_rq_is_passthrough(rq) && !(rq->rq_flags & RQF_DONTPREP)) {
@@ -474,8 +471,6 @@ blk_status_t ide_queue_rq(struct blk_mq_hw_ctx *hctx,
474471
if (ide_lock_host(host, hwif))
475472
return BLK_STS_DEV_RESOURCE;
476473

477-
blk_mq_start_request(rq);
478-
479474
spin_lock_irq(&hwif->lock);
480475

481476
if (!ide_lock_port(hwif)) {
@@ -510,18 +505,6 @@ blk_status_t ide_queue_rq(struct blk_mq_hw_ctx *hctx,
510505
hwif->cur_dev = drive;
511506
drive->dev_flags &= ~(IDE_DFLAG_SLEEPING | IDE_DFLAG_PARKED);
512507

513-
/*
514-
* we know that the queue isn't empty, but this can happen
515-
* if ->prep_rq() decides to kill a request
516-
*/
517-
if (!rq) {
518-
rq = bd->rq;
519-
if (!rq) {
520-
ide_unlock_port(hwif);
521-
goto out;
522-
}
523-
}
524-
525508
/*
526509
* Sanity: don't accept a request that isn't a PM request
527510
* if we are currently power managed. This is very important as
@@ -560,9 +543,12 @@ blk_status_t ide_queue_rq(struct blk_mq_hw_ctx *hctx,
560543
}
561544
} else {
562545
plug_device:
546+
if (local_requeue)
547+
list_add(&rq->queuelist, &drive->rq_list);
563548
spin_unlock_irq(&hwif->lock);
564549
ide_unlock_host(host);
565-
ide_requeue_and_plug(drive, rq);
550+
if (!local_requeue)
551+
ide_requeue_and_plug(drive, rq);
566552
return BLK_STS_OK;
567553
}
568554

@@ -573,6 +559,26 @@ blk_status_t ide_queue_rq(struct blk_mq_hw_ctx *hctx,
573559
return BLK_STS_OK;
574560
}
575561

562+
/*
563+
* Issue a new request to a device.
564+
*/
565+
blk_status_t ide_queue_rq(struct blk_mq_hw_ctx *hctx,
566+
const struct blk_mq_queue_data *bd)
567+
{
568+
ide_drive_t *drive = hctx->queue->queuedata;
569+
ide_hwif_t *hwif = drive->hwif;
570+
571+
spin_lock_irq(&hwif->lock);
572+
if (drive->sense_rq_active) {
573+
spin_unlock_irq(&hwif->lock);
574+
return BLK_STS_DEV_RESOURCE;
575+
}
576+
spin_unlock_irq(&hwif->lock);
577+
578+
blk_mq_start_request(bd->rq);
579+
return ide_issue_rq(drive, bd->rq, false);
580+
}
581+
576582
static int drive_is_ready(ide_drive_t *drive)
577583
{
578584
ide_hwif_t *hwif = drive->hwif;
@@ -893,13 +899,8 @@ EXPORT_SYMBOL_GPL(ide_pad_transfer);
893899

894900
void ide_insert_request_head(ide_drive_t *drive, struct request *rq)
895901
{
896-
ide_hwif_t *hwif = drive->hwif;
897-
unsigned long flags;
898-
899-
spin_lock_irqsave(&hwif->lock, flags);
902+
drive->sense_rq_active = true;
900903
list_add_tail(&rq->queuelist, &drive->rq_list);
901-
spin_unlock_irqrestore(&hwif->lock, flags);
902-
903904
kblockd_schedule_work(&drive->rq_work);
904905
}
905906
EXPORT_SYMBOL_GPL(ide_insert_request_head);

drivers/ide/ide-park.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,9 @@ static void issue_park_cmd(ide_drive_t *drive, unsigned long timeout)
5454
scsi_req(rq)->cmd[0] = REQ_UNPARK_HEADS;
5555
scsi_req(rq)->cmd_len = 1;
5656
ide_req(rq)->type = ATA_PRIV_MISC;
57+
spin_lock_irq(&hwif->lock);
5758
ide_insert_request_head(drive, rq);
59+
spin_unlock_irq(&hwif->lock);
5860

5961
out:
6062
return;

drivers/ide/ide-probe.c

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1159,18 +1159,27 @@ static void drive_rq_insert_work(struct work_struct *work)
11591159
ide_drive_t *drive = container_of(work, ide_drive_t, rq_work);
11601160
ide_hwif_t *hwif = drive->hwif;
11611161
struct request *rq;
1162+
blk_status_t ret;
11621163
LIST_HEAD(list);
11631164

1164-
spin_lock_irq(&hwif->lock);
1165-
if (!list_empty(&drive->rq_list))
1166-
list_splice_init(&drive->rq_list, &list);
1167-
spin_unlock_irq(&hwif->lock);
1165+
blk_mq_quiesce_queue(drive->queue);
11681166

1169-
while (!list_empty(&list)) {
1170-
rq = list_first_entry(&list, struct request, queuelist);
1167+
ret = BLK_STS_OK;
1168+
spin_lock_irq(&hwif->lock);
1169+
while (!list_empty(&drive->rq_list)) {
1170+
rq = list_first_entry(&drive->rq_list, struct request, queuelist);
11711171
list_del_init(&rq->queuelist);
1172-
blk_execute_rq_nowait(drive->queue, rq->rq_disk, rq, true, NULL);
1172+
1173+
spin_unlock_irq(&hwif->lock);
1174+
ret = ide_issue_rq(drive, rq, true);
1175+
spin_lock_irq(&hwif->lock);
11731176
}
1177+
spin_unlock_irq(&hwif->lock);
1178+
1179+
blk_mq_unquiesce_queue(drive->queue);
1180+
1181+
if (ret != BLK_STS_OK)
1182+
kblockd_schedule_work(&drive->rq_work);
11741183
}
11751184

11761185
static const u8 ide_hwif_to_major[] =

include/linux/ide.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -615,6 +615,7 @@ struct ide_drive_s {
615615

616616
/* current sense rq and buffer */
617617
bool sense_rq_armed;
618+
bool sense_rq_active;
618619
struct request *sense_rq;
619620
struct request_sense sense_data;
620621

@@ -1219,6 +1220,7 @@ extern void ide_stall_queue(ide_drive_t *drive, unsigned long timeout);
12191220
extern void ide_timer_expiry(struct timer_list *t);
12201221
extern irqreturn_t ide_intr(int irq, void *dev_id);
12211222
extern blk_status_t ide_queue_rq(struct blk_mq_hw_ctx *, const struct blk_mq_queue_data *);
1223+
extern blk_status_t ide_issue_rq(ide_drive_t *, struct request *, bool);
12221224
extern void ide_requeue_and_plug(ide_drive_t *drive, struct request *rq);
12231225

12241226
void ide_init_disk(struct gendisk *, ide_drive_t *);

0 commit comments

Comments
 (0)