[linux-yocto] [PATCH] ide: Fix ide convert to blk-mq
zhe.he at windriver.com
zhe.he at windriver.com
Tue Jan 29 19:27:13 PST 2019
From: He Zhe <zhe.he at windriver.com>
This is written by Jens Axboe <axboe at kernel.dk>.
https://lore.kernel.org/lkml/a0fcb119-82e7-c9b2-ea76-6aa39bd33edb@windriver.com/
LTP case read_all_proc(read_all -d /proc -q -r 10) often, but not every time,
fails with the following call traces, since 600335205b8d
"ide: convert to blk-mq"(5.0-rc1) till now(5.0-rc3).
[ 47.085810] kernel BUG at block/blk-mq.c:767!
[ 47.086498] invalid opcode: 0000 [#1] PREEMPT SMP PTI
[ 47.087022] CPU: 5 PID: 146 Comm: kworker/5:1H Not tainted 5.0.0-rc3 #1
---- snip ----
[ 47.099650] Call Trace:
[ 47.099910] <IRQ>
[ 47.100128] blk_mq_requeue_request+0x58/0x60
[ 47.100576] ide_requeue_and_plug+0x20/0x50
[ 47.101014] ide_intr+0x21a/0x230
[ 47.101362] ? idecd_open+0xc0/0xc0
[ 47.101735] __handle_irq_event_percpu+0x43/0x1e0
[ 47.102214] handle_irq_event_percpu+0x32/0x80
[ 47.102668] handle_irq_event+0x39/0x60
[ 47.103074] handle_edge_irq+0xe8/0x1c0
[ 47.103470] handle_irq+0x20/0x30
[ 47.103819] do_IRQ+0x46/0xe0
[ 47.104128] common_interrupt+0xf/0xf
[ 47.104505] </IRQ>
---- snip ----
[ 47.111446] ide_transfer_pc+0x216/0x310
[ 47.111848] ? __const_udelay+0x3d/0x40
[ 47.112236] ? ide_execute_command+0x85/0xb0
[ 47.112668] ? ide_pc_intr+0x3f0/0x3f0
[ 47.113051] ? ide_check_atapi_device+0x110/0x110
[ 47.113524] ide_issue_pc+0x178/0x240
[ 47.113901] ide_cd_do_request+0x15c/0x350
[ 47.114314] ide_queue_rq+0x180/0x6b0
[ 47.114686] ? blk_mq_get_driver_tag+0xa1/0x110
[ 47.115153] blk_mq_dispatch_rq_list+0x90/0x550
[ 47.115606] ? __queue_delayed_work+0x63/0x90
[ 47.116054] ? deadline_fifo_request+0x41/0x90
[ 47.116506] blk_mq_do_dispatch_sched+0x80/0x100
[ 47.116976] blk_mq_sched_dispatch_requests+0xfc/0x170
[ 47.117491] __blk_mq_run_hw_queue+0x6f/0xd0
[ 47.117941] blk_mq_run_work_fn+0x1b/0x20
[ 47.118342] process_one_work+0x14c/0x450
[ 47.118747] worker_thread+0x4a/0x440
[ 47.119125] kthread+0x105/0x140
[ 47.119456] ? process_one_work+0x450/0x450
[ 47.119880] ? kthread_park+0x90/0x90
[ 47.120251] ret_from_fork+0x35/0x40
---- snip ----
[ 47.149543] Call Trace:
[ 47.149794] <IRQ>
[ 47.150004] try_to_wake_up+0x257/0x470
[ 47.150400] default_wake_function+0x12/0x20
[ 47.150831] autoremove_wake_function+0x12/0x40
[ 47.151296] __wake_up_common+0x8c/0x130
[ 47.151696] __wake_up_common_lock+0x80/0xc0
[ 47.152129] __wake_up+0x13/0x20
[ 47.152469] wake_up_klogd_work_func+0x40/0x70
[ 47.152924] irq_work_run_list+0x4e/0x80
[ 47.153324] irq_work_tick+0x40/0x50
[ 47.153687] update_process_times+0x42/0x60
[ 47.154108] tick_sched_handle.isra.6+0x34/0x40
[ 47.154564] tick_nohz_handler+0x5b/0x90
[ 47.154956] smp_apic_timer_interrupt+0x70/0x180
[ 47.155422] apic_timer_interrupt+0xf/0x20
---- snip ----
[ 47.162431] ? apic_timer_interrupt+0xa/0x20
[ 47.162861] ? panic+0x235/0x284
[ 47.163192] oops_end+0x8e/0xa0
[ 47.163520] die+0x42/0x50
[ 47.163795] do_trap+0xdd/0x110
[ 47.164119] do_error_trap+0x7b/0xa0
[ 47.164493] ? blk_mq_add_to_requeue_list+0xc1/0xd0
[ 47.164983] do_invalid_op+0x3b/0x50
[ 47.165345] ? blk_mq_add_to_requeue_list+0xc1/0xd0
[ 47.165835] invalid_op+0x14/0x20
[ 47.166173] RIP: 0010:blk_mq_add_to_requeue_list+0xc1/0xd0
[ 47.166727] Code: 48 8d 53 48 49 8b 8c 24 b8 04 00 00 48 89 51 08 48 89 4b 48 49 8d 8c 24 b8 04 00 00 48 89 4b 50 49 89 94 24 b8
[ 47.168581] RSP: 0018:ffff9e1ea4b43e40 EFLAGS: 00010002
[ 47.169109] RAX: ffff9e1ea13c0048 RBX: ffff9e1ea13c0000 RCX: 0000000000000006
[ 47.169823] RDX: 0000000000000000 RSI: 0000000000000001 RDI: ffff9e1ea13c0000
[ 47.170542] RBP: ffff9e1ea4b43e68 R08: ffffeb5bcf630680 R09: 0000000000000000
[ 47.171249] R10: 0000000000000001 R11: 0000000000000012 R12: ffff9e1ea1033a40
[ 47.171960] R13: ffff9e1ea13a8d00 R14: ffff9e1ea13a9000 R15: 0000000000000046
[ 47.172677] blk_mq_requeue_request+0x58/0x60
[ 47.173119] ide_requeue_and_plug+0x20/0x50
[ 47.173548] ide_intr+0x21a/0x230
[ 47.173887] ? idecd_open+0xc0/0xc0
[ 47.174241] __handle_irq_event_percpu+0x43/0x1e0
[ 47.174720] handle_irq_event_percpu+0x32/0x80
[ 47.175163] handle_irq_event+0x39/0x60
[ 47.175554] handle_edge_irq+0xe8/0x1c0
[ 47.175943] handle_irq+0x20/0x30
[ 47.176280] do_IRQ+0x46/0xe0
[ 47.176586] common_interrupt+0xf/0xf
[ 47.176956] </IRQ>
---- snip ----
[ 47.183838] ide_transfer_pc+0x216/0x310
[ 47.184231] ? __const_udelay+0x3d/0x40
[ 47.184625] ? ide_execute_command+0x85/0xb0
[ 47.185058] ? ide_pc_intr+0x3f0/0x3f0
[ 47.185440] ? ide_check_atapi_device+0x110/0x110
[ 47.185915] ide_issue_pc+0x178/0x240
[ 47.186284] ide_cd_do_request+0x15c/0x350
[ 47.186700] ide_queue_rq+0x180/0x6b0
[ 47.187070] ? blk_mq_get_driver_tag+0xa1/0x110
[ 47.187539] blk_mq_dispatch_rq_list+0x90/0x550
[ 47.187996] ? __queue_delayed_work+0x63/0x90
[ 47.188441] ? deadline_fifo_request+0x41/0x90
[ 47.188895] blk_mq_do_dispatch_sched+0x80/0x100
[ 47.189362] blk_mq_sched_dispatch_requests+0xfc/0x170
[ 47.189891] __blk_mq_run_hw_queue+0x6f/0xd0
[ 47.190320] blk_mq_run_work_fn+0x1b/0x20
[ 47.190727] process_one_work+0x14c/0x450
[ 47.191136] worker_thread+0x4a/0x440
[ 47.191509] kthread+0x105/0x140
[ 47.191845] ? process_one_work+0x450/0x450
[ 47.192273] ? kthread_park+0x90/0x90
[ 47.192649] ret_from_fork+0x35/0x40
---- snip ----
[ 47.208545] Call Trace:
[ 47.208797] <IRQ>
[ 47.209005] try_to_wake_up+0x257/0x470
[ 47.209392] default_wake_function+0x12/0x20
[ 47.209826] __wake_up_common+0x8c/0x130
[ 47.210220] __wake_up_locked+0x16/0x20
[ 47.210608] ep_poll_callback+0x1c1/0x310
[ 47.211012] __wake_up_common+0x8c/0x130
[ 47.211408] __wake_up_common_lock+0x80/0xc0
[ 47.211840] __wake_up+0x13/0x20
[ 47.212168] wake_up_klogd_work_func+0x40/0x70
[ 47.212622] irq_work_run_list+0x4e/0x80
[ 47.213022] irq_work_tick+0x40/0x50
[ 47.213382] update_process_times+0x42/0x60
[ 47.213806] tick_sched_handle.isra.6+0x34/0x40
[ 47.214261] tick_nohz_handler+0x5b/0x90
[ 47.214659] smp_apic_timer_interrupt+0x70/0x180
[ 47.215131] apic_timer_interrupt+0xf/0x20
---- snip ----
[ 47.222104] ? apic_timer_interrupt+0xa/0x20
[ 47.222536] ? panic+0x235/0x284
[ 47.222866] oops_end+0x8e/0xa0
[ 47.223185] die+0x42/0x50
[ 47.223462] do_trap+0xdd/0x110
[ 47.223786] do_error_trap+0x7b/0xa0
[ 47.224147] ? blk_mq_add_to_requeue_list+0xc1/0xd0
[ 47.224641] do_invalid_op+0x3b/0x50
[ 47.225004] ? blk_mq_add_to_requeue_list+0xc1/0xd0
[ 47.225494] invalid_op+0x14/0x20
---- snip ----
[ 47.232423] blk_mq_requeue_request+0x58/0x60
[ 47.232877] ide_requeue_and_plug+0x20/0x50
[ 47.233306] ide_intr+0x21a/0x230
[ 47.233648] ? idecd_open+0xc0/0xc0
[ 47.234022] __handle_irq_event_percpu+0x43/0x1e0
[ 47.234500] handle_irq_event_percpu+0x32/0x80
[ 47.234955] handle_irq_event+0x39/0x60
[ 47.235351] handle_edge_irq+0xe8/0x1c0
[ 47.235744] handle_irq+0x20/0x30
[ 47.236093] do_IRQ+0x46/0xe0
[ 47.236399] common_interrupt+0xf/0xf
[ 47.236779] </IRQ>
---- snip ----
[ 47.243758] ide_transfer_pc+0x216/0x310
[ 47.244166] ? __const_udelay+0x3d/0x40
[ 47.244570] ? ide_execute_command+0x85/0xb0
[ 47.245021] ? ide_pc_intr+0x3f0/0x3f0
[ 47.245409] ? ide_check_atapi_device+0x110/0x110
[ 47.245886] ide_issue_pc+0x178/0x240
[ 47.246267] ide_cd_do_request+0x15c/0x350
[ 47.246689] ide_queue_rq+0x180/0x6b0
[ 47.247072] ? blk_mq_get_driver_tag+0xa1/0x110
[ 47.247536] blk_mq_dispatch_rq_list+0x90/0x550
[ 47.247998] ? __queue_delayed_work+0x63/0x90
[ 47.248457] ? deadline_fifo_request+0x41/0x90
[ 47.248914] blk_mq_do_dispatch_sched+0x80/0x100
[ 47.249395] blk_mq_sched_dispatch_requests+0xfc/0x170
[ 47.249922] __blk_mq_run_hw_queue+0x6f/0xd0
[ 47.250365] blk_mq_run_work_fn+0x1b/0x20
[ 47.250782] process_one_work+0x14c/0x450
[ 47.251188] worker_thread+0x4a/0x440
[ 47.251566] kthread+0x105/0x140
[ 47.251900] ? process_one_work+0x450/0x450
[ 47.252335] ? kthread_park+0x90/0x90
[ 47.252715] ret_from_fork+0x35/0x40
[ 47.253090] ---[ end trace 4562f716e88fdf00 ]---
Signed-off-by: He Zhe <zhe.he at windriver.com>
---
Since it causes serious call traces that make the system die. It's worth adding
this to linux-yocto before the formal patch appears in mainline.
drivers/ide/ide-atapi.c | 9 +++++++-
drivers/ide/ide-io.c | 61 +++++++++++++++++++++++++------------------------
drivers/ide/ide-park.c | 2 ++
drivers/ide/ide-probe.c | 23 +++++++++++++------
include/linux/ide.h | 2 ++
5 files changed, 59 insertions(+), 38 deletions(-)
diff --git a/drivers/ide/ide-atapi.c b/drivers/ide/ide-atapi.c
index da58020..33a28cd 100644
--- a/drivers/ide/ide-atapi.c
+++ b/drivers/ide/ide-atapi.c
@@ -235,21 +235,28 @@ EXPORT_SYMBOL_GPL(ide_prep_sense);
int ide_queue_sense_rq(ide_drive_t *drive, void *special)
{
- struct request *sense_rq = drive->sense_rq;
+ ide_hwif_t *hwif = drive->hwif;
+ struct request *sense_rq;
+ unsigned long flags;
+
+ spin_lock_irqsave(&hwif->lock, flags);
/* deferred failure from ide_prep_sense() */
if (!drive->sense_rq_armed) {
printk(KERN_WARNING PFX "%s: error queuing a sense request\n",
drive->name);
+ spin_unlock_irqrestore(&hwif->lock, flags);
return -ENOMEM;
}
+ sense_rq = drive->sense_rq;
ide_req(sense_rq)->special = special;
drive->sense_rq_armed = false;
drive->hwif->rq = NULL;
ide_insert_request_head(drive, sense_rq);
+ spin_unlock_irqrestore(&hwif->lock, flags);
return 0;
}
EXPORT_SYMBOL_GPL(ide_queue_sense_rq);
diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c
index 8445b48..b137f27 100644
--- a/drivers/ide/ide-io.c
+++ b/drivers/ide/ide-io.c
@@ -68,8 +68,10 @@ int ide_end_rq(ide_drive_t *drive, struct request *rq, blk_status_t error,
}
if (!blk_update_request(rq, error, nr_bytes)) {
- if (rq == drive->sense_rq)
+ if (rq == drive->sense_rq) {
drive->sense_rq = NULL;
+ drive->sense_rq_active = false;
+ }
__blk_mq_end_request(rq, error);
return 0;
@@ -451,16 +453,11 @@ void ide_requeue_and_plug(ide_drive_t *drive, struct request *rq)
blk_mq_delay_run_hw_queue(q->queue_hw_ctx[0], 3);
}
-/*
- * Issue a new request to a device.
- */
-blk_status_t ide_queue_rq(struct blk_mq_hw_ctx *hctx,
- const struct blk_mq_queue_data *bd)
+blk_status_t ide_issue_rq(ide_drive_t *drive, struct request *rq,
+ bool local_requeue)
{
- ide_drive_t *drive = hctx->queue->queuedata;
- ide_hwif_t *hwif = drive->hwif;
+ ide_hwif_t *hwif = drive->hwif;
struct ide_host *host = hwif->host;
- struct request *rq = bd->rq;
ide_startstop_t startstop;
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,
if (ide_lock_host(host, hwif))
return BLK_STS_DEV_RESOURCE;
- blk_mq_start_request(rq);
-
spin_lock_irq(&hwif->lock);
if (!ide_lock_port(hwif)) {
@@ -511,18 +506,6 @@ blk_status_t ide_queue_rq(struct blk_mq_hw_ctx *hctx,
drive->dev_flags &= ~(IDE_DFLAG_SLEEPING | IDE_DFLAG_PARKED);
/*
- * we know that the queue isn't empty, but this can happen
- * if ->prep_rq() decides to kill a request
- */
- if (!rq) {
- rq = bd->rq;
- if (!rq) {
- ide_unlock_port(hwif);
- goto out;
- }
- }
-
- /*
* Sanity: don't accept a request that isn't a PM request
* if we are currently power managed. This is very important as
* blk_stop_queue() doesn't prevent the blk_fetch_request()
@@ -560,9 +543,12 @@ blk_status_t ide_queue_rq(struct blk_mq_hw_ctx *hctx,
}
} else {
plug_device:
+ if (local_requeue)
+ list_add(&rq->queuelist, &drive->rq_list);
spin_unlock_irq(&hwif->lock);
ide_unlock_host(host);
- ide_requeue_and_plug(drive, rq);
+ if (!local_requeue)
+ ide_requeue_and_plug(drive, rq);
return BLK_STS_OK;
}
@@ -573,6 +559,26 @@ blk_status_t ide_queue_rq(struct blk_mq_hw_ctx *hctx,
return BLK_STS_OK;
}
+/*
+ * Issue a new request to a device.
+ */
+blk_status_t ide_queue_rq(struct blk_mq_hw_ctx *hctx,
+ const struct blk_mq_queue_data *bd)
+{
+ ide_drive_t *drive = hctx->queue->queuedata;
+ ide_hwif_t *hwif = drive->hwif;
+
+ spin_lock_irq(&hwif->lock);
+ if (drive->sense_rq_active) {
+ spin_unlock_irq(&hwif->lock);
+ return BLK_STS_DEV_RESOURCE;
+ }
+ spin_unlock_irq(&hwif->lock);
+
+ blk_mq_start_request(bd->rq);
+ return ide_issue_rq(drive, bd->rq, false);
+}
+
static int drive_is_ready(ide_drive_t *drive)
{
ide_hwif_t *hwif = drive->hwif;
@@ -893,13 +899,8 @@ EXPORT_SYMBOL_GPL(ide_pad_transfer);
void ide_insert_request_head(ide_drive_t *drive, struct request *rq)
{
- ide_hwif_t *hwif = drive->hwif;
- unsigned long flags;
-
- spin_lock_irqsave(&hwif->lock, flags);
+ drive->sense_rq_active = true;
list_add_tail(&rq->queuelist, &drive->rq_list);
- spin_unlock_irqrestore(&hwif->lock, flags);
-
kblockd_schedule_work(&drive->rq_work);
}
EXPORT_SYMBOL_GPL(ide_insert_request_head);
diff --git a/drivers/ide/ide-park.c b/drivers/ide/ide-park.c
index 102aa3b..8af7af6 100644
--- a/drivers/ide/ide-park.c
+++ b/drivers/ide/ide-park.c
@@ -54,7 +54,9 @@ static void issue_park_cmd(ide_drive_t *drive, unsigned long timeout)
scsi_req(rq)->cmd[0] = REQ_UNPARK_HEADS;
scsi_req(rq)->cmd_len = 1;
ide_req(rq)->type = ATA_PRIV_MISC;
+ spin_lock_irq(&hwif->lock);
ide_insert_request_head(drive, rq);
+ spin_unlock_irq(&hwif->lock);
out:
return;
diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c
index 63627be..5aeaca2 100644
--- a/drivers/ide/ide-probe.c
+++ b/drivers/ide/ide-probe.c
@@ -1159,18 +1159,27 @@ static void drive_rq_insert_work(struct work_struct *work)
ide_drive_t *drive = container_of(work, ide_drive_t, rq_work);
ide_hwif_t *hwif = drive->hwif;
struct request *rq;
+ blk_status_t ret;
LIST_HEAD(list);
- spin_lock_irq(&hwif->lock);
- if (!list_empty(&drive->rq_list))
- list_splice_init(&drive->rq_list, &list);
- spin_unlock_irq(&hwif->lock);
+ blk_mq_quiesce_queue(drive->queue);
- while (!list_empty(&list)) {
- rq = list_first_entry(&list, struct request, queuelist);
+ ret = BLK_STS_OK;
+ spin_lock_irq(&hwif->lock);
+ while (!list_empty(&drive->rq_list)) {
+ rq = list_first_entry(&drive->rq_list, struct request, queuelist);
list_del_init(&rq->queuelist);
- blk_execute_rq_nowait(drive->queue, rq->rq_disk, rq, true, NULL);
+
+ spin_unlock_irq(&hwif->lock);
+ ret = ide_issue_rq(drive, rq, true);
+ spin_lock_irq(&hwif->lock);
}
+ spin_unlock_irq(&hwif->lock);
+
+ blk_mq_unquiesce_queue(drive->queue);
+
+ if (ret != BLK_STS_OK)
+ kblockd_schedule_work(&drive->rq_work);
}
static const u8 ide_hwif_to_major[] =
diff --git a/include/linux/ide.h b/include/linux/ide.h
index e7d29ae..971cf76 100644
--- a/include/linux/ide.h
+++ b/include/linux/ide.h
@@ -615,6 +615,7 @@ struct ide_drive_s {
/* current sense rq and buffer */
bool sense_rq_armed;
+ bool sense_rq_active;
struct request *sense_rq;
struct request_sense sense_data;
@@ -1219,6 +1220,7 @@ extern void ide_stall_queue(ide_drive_t *drive, unsigned long timeout);
extern void ide_timer_expiry(struct timer_list *t);
extern irqreturn_t ide_intr(int irq, void *dev_id);
extern blk_status_t ide_queue_rq(struct blk_mq_hw_ctx *, const struct blk_mq_queue_data *);
+extern blk_status_t ide_issue_rq(ide_drive_t *, struct request *, bool);
extern void ide_requeue_and_plug(ide_drive_t *drive, struct request *rq);
void ide_init_disk(struct gendisk *, ide_drive_t *);
--
2.7.4
More information about the linux-yocto
mailing list