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:
Bart Van Assche
2014-02-18 08:31:44 +00:00
parent 65945b45bb
commit 13e22542d1
4 changed files with 39 additions and 9 deletions

View File

@@ -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 *

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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;
}