From 13e22542d1c125a5daab2578d0683cdabf4d358d Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 18 Feb 2014 08:31:44 +0000 Subject: [PATCH] scst, qla2x00t: Prevent inappropriate sleeping with a real-time kernel With a realtime kernel with full preemption (CONFIG_PREEMPT_RT_FULL), spinlocks can sleep, interrupt handlers run in thread context, and the standard local_irq functions manipulate preemptibility, not HW interruptibility. Under these conditions, most calls to local_irq functions should be replaced by no-ops. The CONFIG_PREEMPT_RT patch defines _nort versions of local_irq functions that compile away under CONFIG_PREEMPT_RT_FULL and compile to their "normal" equivalents otherwise. Define _nort equivalents to support compilation against both "normal" and RT-patched kernels, and use the _nort local_irq functons in cases where spinlocks are taken within a local_irq_save() or local_irq_disable() block. Without these changes, runtime warnings about "sleeping function called from invalid context" occur. Signed-off-by: Steven J. Magnani [bvanassche: Edited patch description and comment in scst_priv.h] git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@5288 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- qla2x00t/qla_inline.h | 10 ++++++++++ scst/src/scst_lib.c | 4 ++-- scst/src/scst_priv.h | 20 ++++++++++++++++++++ scst/src/scst_targ.c | 14 +++++++------- 4 files changed, 39 insertions(+), 9 deletions(-) diff --git a/qla2x00t/qla_inline.h b/qla2x00t/qla_inline.h index 19820a804..9b5e618ef 100644 --- a/qla2x00t/qla_inline.h +++ b/qla2x00t/qla_inline.h @@ -36,9 +36,19 @@ qla2x00_poll(scsi_qla_host_t *ha) { unsigned long flags; +#ifdef CONFIG_PREEMPT_RT_FULL + local_irq_save_nort(flags); +#else local_irq_save(flags); +#endif + ha->isp_ops->intr_handler(0, ha); + +#ifdef CONFIG_PREEMPT_RT_FULL + local_irq_restore_nort(flags); +#else local_irq_restore(flags); +#endif } static __inline__ scsi_qla_host_t * diff --git a/scst/src/scst_lib.c b/scst/src/scst_lib.c index 36280480d..6c86a813f 100644 --- a/scst/src/scst_lib.c +++ b/scst/src/scst_lib.c @@ -8267,7 +8267,7 @@ void scst_unblock_dev(struct scst_device *dev) struct scst_cmd *cmd, *tcmd; unsigned long flags; - local_irq_save(flags); + local_irq_save_nort(flags); list_for_each_entry_safe(cmd, tcmd, &dev->blocked_cmd_list, blocked_cmd_list_entry) { bool strictly_serialized; @@ -8287,7 +8287,7 @@ void scst_unblock_dev(struct scst_device *dev) if (dev->strictly_serialized_cmd_waiting && strictly_serialized) break; } - local_irq_restore(flags); + local_irq_restore_nort(flags); dev->strictly_serialized_cmd_waiting = 0; } diff --git a/scst/src/scst_priv.h b/scst/src/scst_priv.h index 74d041000..f56d185be 100644 --- a/scst/src/scst_priv.h +++ b/scst/src/scst_priv.h @@ -120,6 +120,26 @@ extern unsigned long scst_trace_flag; #define SCST_MAX_EACH_INTERNAL_IO_SIZE (128*1024) #define SCST_MAX_IN_FLIGHT_INTERNAL_COMMANDS 32 +/* + * Compatibility with real-time (CONFIG_PREEMPT_RT_FULL) kernels. + * In such kernels: + * - Interrupt handlers run in kernel thread context (see e.g. + * http://lwn.net/Articles/302043/). + * - spin_lock() calls can sleep (see e.g. http://lwn.net/Articles/271817/). + * - local_irq functions manipulate preemptibility, not HW interruptibility + * (see also http://lwn.net/Articles/146861). + * For the upstream kernels up to at least kernel 3.14 _nort functions are + * only defined if a CONFIG PREEMPT RT patch has been applied to the kernel. + * See https://rt.wiki.kernel.org/index.php/CONFIG_PREEMPT_RT_Patch. + */ +#ifndef local_irq_enable_nort +/* Kernel does not have CONFIG_PREEMPT_RT patch */ +#define local_irq_enable_nort() local_irq_enable() +#define local_irq_disable_nort() local_irq_disable() +#define local_irq_save_nort(flags) local_irq_save(flags) +#define local_irq_restore_nort(flags) local_irq_restore(flags) +#endif + typedef void (*scst_i_finish_fn_t) (struct scst_cmd *cmd); extern struct mutex scst_mutex2; diff --git a/scst/src/scst_targ.c b/scst/src/scst_targ.c index cc0d5a1b0..697083bf6 100644 --- a/scst/src/scst_targ.c +++ b/scst/src/scst_targ.c @@ -5160,7 +5160,7 @@ void scst_unblock_aborted_cmds(const struct scst_tgt *tgt, continue; spin_lock_bh(&dev->dev_lock); - local_irq_disable(); + local_irq_disable_nort(); list_for_each_entry_safe(cmd, tcmd, &dev->blocked_cmd_list, blocked_cmd_list_entry) { @@ -5174,10 +5174,10 @@ void scst_unblock_aborted_cmds(const struct scst_tgt *tgt, TRACE_MGMT_DBG("Unblock aborted blocked cmd %p", cmd); } } - local_irq_enable(); + local_irq_enable_nort(); spin_unlock_bh(&dev->dev_lock); - local_irq_disable(); + local_irq_disable_nort(); list_for_each_entry(tgt_dev, &dev->dev_tgt_dev_list, dev_tgt_dev_list_entry) { struct scst_order_data *order_data = tgt_dev->curr_order_data; @@ -5200,7 +5200,7 @@ void scst_unblock_aborted_cmds(const struct scst_tgt *tgt, } spin_unlock(&order_data->sn_lock); } - local_irq_enable(); + local_irq_enable_nort(); } if (!scst_mutex_held) @@ -6238,7 +6238,7 @@ static int scst_post_rx_mgmt_cmd(struct scst_session *sess, sBUG(); } - local_irq_save(flags); + local_irq_save_nort(flags); spin_lock(&sess->sess_list_lock); @@ -6267,7 +6267,7 @@ static int scst_post_rx_mgmt_cmd(struct scst_session *sess, list_add_tail(&mcmd->mgmt_cmd_list_entry, &scst_active_mgmt_cmd_list); spin_unlock(&scst_mcmd_lock); - local_irq_restore(flags); + local_irq_restore_nort(flags); wake_up(&scst_mgmt_cmd_list_waitQ); @@ -6277,7 +6277,7 @@ out: out_unlock: spin_unlock(&sess->sess_list_lock); - local_irq_restore(flags); + local_irq_restore_nort(flags); goto out; }