Commit 23e44302 authored by Linus Torvalds's avatar Linus Torvalds

Merge git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending

Pull more scsi target fixes from Nicholas Bellinger:
 "This series is a second round of target fixes for v3.7-rc4 that have
  come into target-devel over the last days, and are important enough to
  be applied ASAP.

  All are being CC'ed to stable.  The most important two are:

   - target: Re-add explict zeroing of INQUIRY bounce buffer memory to
     fix a regression for handling zero-length payloads, a bug that went
     during v3.7-rc1, and hit >= v3.6.3 stable.  (nab + paolo)

   - iscsi-target: Fix a long-standing missed R2T wakeup race in TX
     thread processing when using a single queue slot.  (Roland)

  Thanks to Roland & PureStorage team for helping to track down this
  long standing race with iscsi-target single queue slot operation.

  Also, the tcm_fc(FCoE) regression bug that was observed recently with
  -rc2 code has also been resolved with the cancel_delayed_work() return
  bugfix (commit c0158ca6: "workqueue: cancel_delayed_work() should
  return %false if work item is idle") now in -rc3.  Thanks again to Yi
  Zou, MDR, Robert Love @ Intel for helping to track this down."

* git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending:
  target: Fix incorrect usage of nested IRQ spinlocks in ABORT_TASK path
  iscsi-target: Fix missed wakeup race in TX thread
  target: Avoid integer overflow in se_dev_align_max_sectors()
  target: Don't return success from module_init() if setup fails
  target: Re-add explict zeroing of INQUIRY bounce buffer memory
parents ae41fce3 ab74b3d6
...@@ -3719,7 +3719,9 @@ int iscsi_target_tx_thread(void *arg) ...@@ -3719,7 +3719,9 @@ int iscsi_target_tx_thread(void *arg)
*/ */
iscsit_thread_check_cpumask(conn, current, 1); iscsit_thread_check_cpumask(conn, current, 1);
schedule_timeout_interruptible(MAX_SCHEDULE_TIMEOUT); wait_event_interruptible(conn->queues_wq,
!iscsit_conn_all_queues_empty(conn) ||
ts->status == ISCSI_THREAD_SET_RESET);
if ((ts->status == ISCSI_THREAD_SET_RESET) || if ((ts->status == ISCSI_THREAD_SET_RESET) ||
signal_pending(current)) signal_pending(current))
......
...@@ -486,6 +486,7 @@ struct iscsi_tmr_req { ...@@ -486,6 +486,7 @@ struct iscsi_tmr_req {
}; };
struct iscsi_conn { struct iscsi_conn {
wait_queue_head_t queues_wq;
/* Authentication Successful for this connection */ /* Authentication Successful for this connection */
u8 auth_complete; u8 auth_complete;
/* State connection is currently in */ /* State connection is currently in */
......
...@@ -41,6 +41,7 @@ ...@@ -41,6 +41,7 @@
static int iscsi_login_init_conn(struct iscsi_conn *conn) static int iscsi_login_init_conn(struct iscsi_conn *conn)
{ {
init_waitqueue_head(&conn->queues_wq);
INIT_LIST_HEAD(&conn->conn_list); INIT_LIST_HEAD(&conn->conn_list);
INIT_LIST_HEAD(&conn->conn_cmd_list); INIT_LIST_HEAD(&conn->conn_cmd_list);
INIT_LIST_HEAD(&conn->immed_queue_list); INIT_LIST_HEAD(&conn->immed_queue_list);
......
...@@ -488,7 +488,7 @@ void iscsit_add_cmd_to_immediate_queue( ...@@ -488,7 +488,7 @@ void iscsit_add_cmd_to_immediate_queue(
atomic_set(&conn->check_immediate_queue, 1); atomic_set(&conn->check_immediate_queue, 1);
spin_unlock_bh(&conn->immed_queue_lock); spin_unlock_bh(&conn->immed_queue_lock);
wake_up_process(conn->thread_set->tx_thread); wake_up(&conn->queues_wq);
} }
struct iscsi_queue_req *iscsit_get_cmd_from_immediate_queue(struct iscsi_conn *conn) struct iscsi_queue_req *iscsit_get_cmd_from_immediate_queue(struct iscsi_conn *conn)
...@@ -562,7 +562,7 @@ void iscsit_add_cmd_to_response_queue( ...@@ -562,7 +562,7 @@ void iscsit_add_cmd_to_response_queue(
atomic_inc(&cmd->response_queue_count); atomic_inc(&cmd->response_queue_count);
spin_unlock_bh(&conn->response_queue_lock); spin_unlock_bh(&conn->response_queue_lock);
wake_up_process(conn->thread_set->tx_thread); wake_up(&conn->queues_wq);
} }
struct iscsi_queue_req *iscsit_get_cmd_from_response_queue(struct iscsi_conn *conn) struct iscsi_queue_req *iscsit_get_cmd_from_response_queue(struct iscsi_conn *conn)
...@@ -616,6 +616,24 @@ static void iscsit_remove_cmd_from_response_queue( ...@@ -616,6 +616,24 @@ static void iscsit_remove_cmd_from_response_queue(
} }
} }
bool iscsit_conn_all_queues_empty(struct iscsi_conn *conn)
{
bool empty;
spin_lock_bh(&conn->immed_queue_lock);
empty = list_empty(&conn->immed_queue_list);
spin_unlock_bh(&conn->immed_queue_lock);
if (!empty)
return empty;
spin_lock_bh(&conn->response_queue_lock);
empty = list_empty(&conn->response_queue_list);
spin_unlock_bh(&conn->response_queue_lock);
return empty;
}
void iscsit_free_queue_reqs_for_conn(struct iscsi_conn *conn) void iscsit_free_queue_reqs_for_conn(struct iscsi_conn *conn)
{ {
struct iscsi_queue_req *qr, *qr_tmp; struct iscsi_queue_req *qr, *qr_tmp;
......
...@@ -25,6 +25,7 @@ extern struct iscsi_queue_req *iscsit_get_cmd_from_immediate_queue(struct iscsi_ ...@@ -25,6 +25,7 @@ extern struct iscsi_queue_req *iscsit_get_cmd_from_immediate_queue(struct iscsi_
extern void iscsit_add_cmd_to_response_queue(struct iscsi_cmd *, struct iscsi_conn *, u8); extern void iscsit_add_cmd_to_response_queue(struct iscsi_cmd *, struct iscsi_conn *, u8);
extern struct iscsi_queue_req *iscsit_get_cmd_from_response_queue(struct iscsi_conn *); extern struct iscsi_queue_req *iscsit_get_cmd_from_response_queue(struct iscsi_conn *);
extern void iscsit_remove_cmd_from_tx_queues(struct iscsi_cmd *, struct iscsi_conn *); extern void iscsit_remove_cmd_from_tx_queues(struct iscsi_cmd *, struct iscsi_conn *);
extern bool iscsit_conn_all_queues_empty(struct iscsi_conn *);
extern void iscsit_free_queue_reqs_for_conn(struct iscsi_conn *); extern void iscsit_free_queue_reqs_for_conn(struct iscsi_conn *);
extern void iscsit_release_cmd(struct iscsi_cmd *); extern void iscsit_release_cmd(struct iscsi_cmd *);
extern void iscsit_free_cmd(struct iscsi_cmd *); extern void iscsit_free_cmd(struct iscsi_cmd *);
......
...@@ -3206,7 +3206,8 @@ static int __init target_core_init_configfs(void) ...@@ -3206,7 +3206,8 @@ static int __init target_core_init_configfs(void)
if (ret < 0) if (ret < 0)
goto out; goto out;
if (core_dev_setup_virtual_lun0() < 0) ret = core_dev_setup_virtual_lun0();
if (ret < 0)
goto out; goto out;
return 0; return 0;
......
...@@ -850,20 +850,20 @@ int se_dev_check_shutdown(struct se_device *dev) ...@@ -850,20 +850,20 @@ int se_dev_check_shutdown(struct se_device *dev)
static u32 se_dev_align_max_sectors(u32 max_sectors, u32 block_size) static u32 se_dev_align_max_sectors(u32 max_sectors, u32 block_size)
{ {
u32 tmp, aligned_max_sectors; u32 aligned_max_sectors;
u32 alignment;
/* /*
* Limit max_sectors to a PAGE_SIZE aligned value for modern * Limit max_sectors to a PAGE_SIZE aligned value for modern
* transport_allocate_data_tasks() operation. * transport_allocate_data_tasks() operation.
*/ */
tmp = rounddown((max_sectors * block_size), PAGE_SIZE); alignment = max(1ul, PAGE_SIZE / block_size);
aligned_max_sectors = (tmp / block_size); aligned_max_sectors = rounddown(max_sectors, alignment);
if (max_sectors != aligned_max_sectors) {
printk(KERN_INFO "Rounding down aligned max_sectors from %u" if (max_sectors != aligned_max_sectors)
" to %u\n", max_sectors, aligned_max_sectors); pr_info("Rounding down aligned max_sectors from %u to %u\n",
return aligned_max_sectors; max_sectors, aligned_max_sectors);
}
return max_sectors; return aligned_max_sectors;
} }
void se_dev_set_default_attribs( void se_dev_set_default_attribs(
......
...@@ -605,6 +605,8 @@ static int spc_emulate_inquiry(struct se_cmd *cmd) ...@@ -605,6 +605,8 @@ static int spc_emulate_inquiry(struct se_cmd *cmd)
unsigned char buf[SE_INQUIRY_BUF]; unsigned char buf[SE_INQUIRY_BUF];
int p, ret; int p, ret;
memset(buf, 0, SE_INQUIRY_BUF);
if (dev == tpg->tpg_virt_lun0.lun_se_dev) if (dev == tpg->tpg_virt_lun0.lun_se_dev)
buf[0] = 0x3f; /* Not connected */ buf[0] = 0x3f; /* Not connected */
else else
......
...@@ -140,15 +140,15 @@ void core_tmr_abort_task( ...@@ -140,15 +140,15 @@ void core_tmr_abort_task(
printk("ABORT_TASK: Found referenced %s task_tag: %u\n", printk("ABORT_TASK: Found referenced %s task_tag: %u\n",
se_cmd->se_tfo->get_fabric_name(), ref_tag); se_cmd->se_tfo->get_fabric_name(), ref_tag);
spin_lock_irq(&se_cmd->t_state_lock); spin_lock(&se_cmd->t_state_lock);
if (se_cmd->transport_state & CMD_T_COMPLETE) { if (se_cmd->transport_state & CMD_T_COMPLETE) {
printk("ABORT_TASK: ref_tag: %u already complete, skipping\n", ref_tag); printk("ABORT_TASK: ref_tag: %u already complete, skipping\n", ref_tag);
spin_unlock_irq(&se_cmd->t_state_lock); spin_unlock(&se_cmd->t_state_lock);
spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
goto out; goto out;
} }
se_cmd->transport_state |= CMD_T_ABORTED; se_cmd->transport_state |= CMD_T_ABORTED;
spin_unlock_irq(&se_cmd->t_state_lock); spin_unlock(&se_cmd->t_state_lock);
list_del_init(&se_cmd->se_cmd_list); list_del_init(&se_cmd->se_cmd_list);
kref_get(&se_cmd->cmd_kref); kref_get(&se_cmd->cmd_kref);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment