[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