mirror of
https://github.com/SCST-project/scst.git
synced 2026-05-24 06:01:28 +00:00
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 <steve@digidescorp.com> [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
This commit is contained in:
@@ -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 *
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user