summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan McDonald <danmcd@nexenta.com>2013-06-27 13:54:16 -0400
committerDan McDonald <danmcd@nexenta.com>2013-07-02 13:20:45 -0400
commitef3b9e2fd29bbac9dc0e750d67355287620587a5 (patch)
tree6f267a4b8a27dd50e94f8cb679e15cd64ccb79e0
parent13c8743e4d3cc6d9653687512c0d48d2b653513d (diff)
downloadillumos-joyent-ef3b9e2fd29bbac9dc0e750d67355287620587a5.tar.gz
3775 Upstreaming of ALUA use-after-free fixes from Nexenta
Reviewed by: Saso Kiselkov <skiselkov.ml@gmail.com> Reviewed by: T Nguyen <truongqnguien@gmail.com> Approved by: Richard Lowe <richlowe@richlowe.net>
-rw-r--r--usr/src/uts/common/io/comstar/port/pppt/pppt.c24
-rw-r--r--usr/src/uts/common/io/comstar/port/pppt/pppt.h4
-rw-r--r--usr/src/uts/common/io/comstar/port/pppt/pppt_msg.c5
3 files changed, 23 insertions, 10 deletions
diff --git a/usr/src/uts/common/io/comstar/port/pppt/pppt.c b/usr/src/uts/common/io/comstar/port/pppt/pppt.c
index feec2f97e4..6c59db9004 100644
--- a/usr/src/uts/common/io/comstar/port/pppt/pppt.c
+++ b/usr/src/uts/common/io/comstar/port/pppt/pppt.c
@@ -20,6 +20,7 @@
*/
/*
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2013, Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/cpuvar.h>
@@ -131,8 +132,6 @@ static void pppt_task_sent_status(pppt_task_t *ptask);
static pppt_status_t pppt_task_try_abort(pppt_task_t *ptask);
-static pppt_status_t pppt_task_hold(pppt_task_t *ptask);
-
static void pppt_task_rele(pppt_task_t *ptask);
static void pppt_task_update_state(pppt_task_t *ptask,
@@ -801,7 +800,7 @@ pppt_lport_task_free(scsi_task_t *task)
pppt_task_t *ptask = task->task_port_private;
pppt_sess_t *ps = ptask->pt_sess;
- pppt_task_free(ptask);
+ pppt_task_rele(ptask);
pppt_sess_rele(ps);
}
@@ -1209,7 +1208,7 @@ pppt_task_alloc(void)
ptask->pt_state = PTS_INIT;
ptask->pt_read_buf = NULL;
ptask->pt_read_xfer_msgid = 0;
- cv_init(&ptask->pt_cv, NULL, CV_DRIVER, NULL);
+ ptask->pt_refcnt = 0;
mutex_init(&ptask->pt_mutex, NULL, MUTEX_DRIVER, NULL);
immed_pbuf = (pppt_buf_t *)(ptask + 1);
bzero(immed_pbuf, sizeof (*immed_pbuf));
@@ -1232,8 +1231,8 @@ void
pppt_task_free(pppt_task_t *ptask)
{
mutex_enter(&ptask->pt_mutex);
+ ASSERT(ptask->pt_refcnt == 0);
mutex_destroy(&ptask->pt_mutex);
- cv_destroy(&ptask->pt_cv);
kmem_free(ptask, sizeof (pppt_task_t) + sizeof (pppt_buf_t) +
sizeof (stmf_data_buf_t));
}
@@ -1249,6 +1248,8 @@ pppt_task_start(pppt_task_t *ptask)
mutex_enter(&ptask->pt_mutex);
if (avl_find(&ptask->pt_sess->ps_task_list, ptask, &where) == NULL) {
pppt_task_update_state(ptask, PTS_ACTIVE);
+ /* Manually increment refcnt, sincd we hold the mutex... */
+ ptask->pt_refcnt++;
avl_insert(&ptask->pt_sess->ps_task_list, ptask, where);
mutex_exit(&ptask->pt_mutex);
mutex_exit(&ptask->pt_sess->ps_mutex);
@@ -1289,6 +1290,8 @@ pppt_task_done(pppt_task_t *ptask)
mutex_enter(&ptask->pt_sess->ps_mutex);
avl_remove(&ptask->pt_sess->ps_task_list, ptask);
mutex_exit(&ptask->pt_sess->ps_mutex);
+ /* Out of the AVL tree, so drop a reference. */
+ pppt_task_rele(ptask);
}
return (pppt_status);
@@ -1401,12 +1404,14 @@ pppt_task_try_abort(pppt_task_t *ptask)
mutex_enter(&ptask->pt_sess->ps_mutex);
avl_remove(&ptask->pt_sess->ps_task_list, ptask);
mutex_exit(&ptask->pt_sess->ps_mutex);
+ /* Out of the AVL tree, so drop a reference. */
+ pppt_task_rele(ptask);
}
return (pppt_status);
}
-static pppt_status_t
+pppt_status_t
pppt_task_hold(pppt_task_t *ptask)
{
pppt_status_t pppt_status = PPPT_STATUS_SUCCESS;
@@ -1425,10 +1430,14 @@ pppt_task_hold(pppt_task_t *ptask)
static void
pppt_task_rele(pppt_task_t *ptask)
{
+ boolean_t freeit;
+
mutex_enter(&ptask->pt_mutex);
ptask->pt_refcnt--;
- cv_signal(&ptask->pt_cv);
+ freeit = (ptask->pt_refcnt == 0);
mutex_exit(&ptask->pt_mutex);
+ if (freeit)
+ pppt_task_free(ptask);
}
static void
@@ -1440,5 +1449,4 @@ pppt_task_update_state(pppt_task_t *ptask,
ASSERT(mutex_owned(&ptask->pt_mutex));
ptask->pt_state = new_state;
- cv_signal(&ptask->pt_cv);
}
diff --git a/usr/src/uts/common/io/comstar/port/pppt/pppt.h b/usr/src/uts/common/io/comstar/port/pppt/pppt.h
index 9b9bc87dd1..260eb94a8c 100644
--- a/usr/src/uts/common/io/comstar/port/pppt/pppt.h
+++ b/usr/src/uts/common/io/comstar/port/pppt/pppt.h
@@ -20,6 +20,7 @@
*/
/*
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2013, Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _PPPT_H
#define _PPPT_H
@@ -168,7 +169,6 @@ typedef struct {
avl_node_t pt_sess_ln;
int pt_refcnt;
kmutex_t pt_mutex;
- kcondvar_t pt_cv;
stmf_ic_msgid_t pt_task_id;
uint8_t pt_lun_id[16];
pppt_task_state_t pt_state;
@@ -296,6 +296,8 @@ int pppt_tgt_avl_compare(const void *void_tgt1, const void *void_tgt2);
void pppt_tgt_sm_ctl(stmf_local_port_t *lport, int cmd, void *arg);
+pppt_status_t pppt_task_hold(pppt_task_t *);
+
#ifdef __cplusplus
}
#endif
diff --git a/usr/src/uts/common/io/comstar/port/pppt/pppt_msg.c b/usr/src/uts/common/io/comstar/port/pppt/pppt_msg.c
index f586ea54c0..7d7f571ec0 100644
--- a/usr/src/uts/common/io/comstar/port/pppt/pppt_msg.c
+++ b/usr/src/uts/common/io/comstar/port/pppt/pppt_msg.c
@@ -20,6 +20,7 @@
*/
/*
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2013, Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/cpuvar.h>
@@ -316,8 +317,8 @@ pppt_msg_scsi_cmd(stmf_ic_msg_t *msg)
scmd->icsc_task_lun_no,
scmd->icsc_task_cdb_length, 0);
if (ptask->pt_stmf_task == NULL) {
+ /* NOTE: pppt_task_done() will free ptask. */
(void) pppt_task_done(ptask);
- pppt_task_free(ptask);
pppt_sess_rele(pppt_sess);
pppt_msg_tx_status(msg, STMF_ALLOC_FAILURE);
stmf_ic_msg_free(msg);
@@ -326,6 +327,8 @@ pppt_msg_scsi_cmd(stmf_ic_msg_t *msg)
}
task = ptask->pt_stmf_task;
+ /* task_port_private reference is a real reference. */
+ (void) pppt_task_hold(ptask);
task->task_port_private = ptask;
task->task_flags = scmd->icsc_task_flags;
task->task_additional_flags = 0;