Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Linux/drivers/target/iscsi/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 10 kB image not shown  

Quelle  iscsi_target_erl2.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0-or-later
/*******************************************************************************
 * This file contains error recovery level two functions used by
 * the iSCSI Target driver.
 *
 * (c) Copyright 2007-2013 Datera, Inc.
 *
 * Author: Nicholas A. Bellinger <nab@linux-iscsi.org>
 *
 ******************************************************************************/


#include <linux/slab.h>
#include <scsi/iscsi_proto.h>
#include <target/target_core_base.h>
#include <target/target_core_fabric.h>

#include <target/iscsi/iscsi_target_core.h>
#include "iscsi_target_datain_values.h"
#include "iscsi_target_util.h"
#include "iscsi_target_erl0.h"
#include "iscsi_target_erl1.h"
#include "iscsi_target_erl2.h"
#include "iscsi_target.h"

/*
 * FIXME: Does RData SNACK apply here as well?
 */

static int iscsit_attach_active_connection_recovery_entry(
 struct iscsit_session *sess,
 struct iscsi_conn_recovery *cr)
{
 spin_lock(&sess->cr_a_lock);
 list_add_tail(&cr->cr_list, &sess->cr_active_list);
 spin_unlock(&sess->cr_a_lock);

 return 0;
}

static int iscsit_attach_inactive_connection_recovery_entry(
 struct iscsit_session *sess,
 struct iscsi_conn_recovery *cr)
{
 spin_lock(&sess->cr_i_lock);
 list_add_tail(&cr->cr_list, &sess->cr_inactive_list);

 sess->conn_recovery_count++;
 pr_debug("Incremented connection recovery count to %u for"
  " SID: %u\n", sess->conn_recovery_count, sess->sid);
 spin_unlock(&sess->cr_i_lock);

 return 0;
}

struct iscsi_conn_recovery *iscsit_get_inactive_connection_recovery_entry(
 struct iscsit_session *sess,
 u16 cid)
{
 struct iscsi_conn_recovery *cr;

 spin_lock(&sess->cr_i_lock);
 list_for_each_entry(cr, &sess->cr_inactive_list, cr_list) {
  if (cr->cid == cid) {
   spin_unlock(&sess->cr_i_lock);
   return cr;
  }
 }
 spin_unlock(&sess->cr_i_lock);

 return NULL;
}

void iscsit_free_connection_recovery_entries(struct iscsit_session *sess)
{
 struct iscsit_cmd *cmd, *cmd_tmp;
 struct iscsi_conn_recovery *cr, *cr_tmp;

 spin_lock(&sess->cr_a_lock);
 list_for_each_entry_safe(cr, cr_tmp, &sess->cr_active_list, cr_list) {
  list_del(&cr->cr_list);
  spin_unlock(&sess->cr_a_lock);

  spin_lock(&cr->conn_recovery_cmd_lock);
  list_for_each_entry_safe(cmd, cmd_tmp,
    &cr->conn_recovery_cmd_list, i_conn_node) {

   list_del_init(&cmd->i_conn_node);
   cmd->conn = NULL;
   spin_unlock(&cr->conn_recovery_cmd_lock);
   iscsit_free_cmd(cmd, true);
   spin_lock(&cr->conn_recovery_cmd_lock);
  }
  spin_unlock(&cr->conn_recovery_cmd_lock);
  spin_lock(&sess->cr_a_lock);

  kfree(cr);
 }
 spin_unlock(&sess->cr_a_lock);

 spin_lock(&sess->cr_i_lock);
 list_for_each_entry_safe(cr, cr_tmp, &sess->cr_inactive_list, cr_list) {
  list_del(&cr->cr_list);
  spin_unlock(&sess->cr_i_lock);

  spin_lock(&cr->conn_recovery_cmd_lock);
  list_for_each_entry_safe(cmd, cmd_tmp,
    &cr->conn_recovery_cmd_list, i_conn_node) {

   list_del_init(&cmd->i_conn_node);
   cmd->conn = NULL;
   spin_unlock(&cr->conn_recovery_cmd_lock);
   iscsit_free_cmd(cmd, true);
   spin_lock(&cr->conn_recovery_cmd_lock);
  }
  spin_unlock(&cr->conn_recovery_cmd_lock);
  spin_lock(&sess->cr_i_lock);

  kfree(cr);
 }
 spin_unlock(&sess->cr_i_lock);
}

int iscsit_remove_active_connection_recovery_entry(
 struct iscsi_conn_recovery *cr,
 struct iscsit_session *sess)
{
 spin_lock(&sess->cr_a_lock);
 list_del(&cr->cr_list);

 sess->conn_recovery_count--;
 pr_debug("Decremented connection recovery count to %u for"
  " SID: %u\n", sess->conn_recovery_count, sess->sid);
 spin_unlock(&sess->cr_a_lock);

 kfree(cr);

 return 0;
}

static void iscsit_remove_inactive_connection_recovery_entry(
 struct iscsi_conn_recovery *cr,
 struct iscsit_session *sess)
{
 spin_lock(&sess->cr_i_lock);
 list_del(&cr->cr_list);
 spin_unlock(&sess->cr_i_lock);
}

/*
 * Called with cr->conn_recovery_cmd_lock help.
 */

int iscsit_remove_cmd_from_connection_recovery(
 struct iscsit_cmd *cmd,
 struct iscsit_session *sess)
{
 struct iscsi_conn_recovery *cr;

 if (!cmd->cr) {
  pr_err("struct iscsi_conn_recovery pointer for ITT: 0x%08x"
   " is NULL!\n", cmd->init_task_tag);
  BUG();
 }
 cr = cmd->cr;

 list_del_init(&cmd->i_conn_node);
 return --cr->cmd_count;
}

void iscsit_discard_cr_cmds_by_expstatsn(
 struct iscsi_conn_recovery *cr,
 u32 exp_statsn)
{
 u32 dropped_count = 0;
 struct iscsit_cmd *cmd, *cmd_tmp;
 struct iscsit_session *sess = cr->sess;

 spin_lock(&cr->conn_recovery_cmd_lock);
 list_for_each_entry_safe(cmd, cmd_tmp,
   &cr->conn_recovery_cmd_list, i_conn_node) {

  if (((cmd->deferred_i_state != ISTATE_SENT_STATUS) &&
       (cmd->deferred_i_state != ISTATE_REMOVE)) ||
       (cmd->stat_sn >= exp_statsn)) {
   continue;
  }

  dropped_count++;
  pr_debug("Dropping Acknowledged ITT: 0x%08x, StatSN:"
   " 0x%08x, CID: %hu.\n", cmd->init_task_tag,
    cmd->stat_sn, cr->cid);

  iscsit_remove_cmd_from_connection_recovery(cmd, sess);

  spin_unlock(&cr->conn_recovery_cmd_lock);
  iscsit_free_cmd(cmd, true);
  spin_lock(&cr->conn_recovery_cmd_lock);
 }
 spin_unlock(&cr->conn_recovery_cmd_lock);

 pr_debug("Dropped %u total acknowledged commands on"
  " CID: %hu less than old ExpStatSN: 0x%08x\n",
   dropped_count, cr->cid, exp_statsn);

 if (!cr->cmd_count) {
  pr_debug("No commands to be reassigned for failed"
   " connection CID: %hu on SID: %u\n",
   cr->cid, sess->sid);
  iscsit_remove_inactive_connection_recovery_entry(cr, sess);
  iscsit_attach_active_connection_recovery_entry(sess, cr);
  pr_debug("iSCSI connection recovery successful for CID:"
   " %hu on SID: %u\n", cr->cid, sess->sid);
  iscsit_remove_active_connection_recovery_entry(cr, sess);
 } else {
  iscsit_remove_inactive_connection_recovery_entry(cr, sess);
  iscsit_attach_active_connection_recovery_entry(sess, cr);
 }
}

int iscsit_discard_unacknowledged_ooo_cmdsns_for_conn(struct iscsit_conn *conn)
{
 u32 dropped_count = 0;
 struct iscsit_cmd *cmd, *cmd_tmp;
 struct iscsi_ooo_cmdsn *ooo_cmdsn, *ooo_cmdsn_tmp;
 struct iscsit_session *sess = conn->sess;

 mutex_lock(&sess->cmdsn_mutex);
 list_for_each_entry_safe(ooo_cmdsn, ooo_cmdsn_tmp,
   &sess->sess_ooo_cmdsn_list, ooo_list) {

  if (ooo_cmdsn->cid != conn->cid)
   continue;

  dropped_count++;
  pr_debug("Dropping unacknowledged CmdSN:"
  " 0x%08x during connection recovery on CID: %hu\n",
   ooo_cmdsn->cmdsn, conn->cid);
  iscsit_remove_ooo_cmdsn(sess, ooo_cmdsn);
 }
 mutex_unlock(&sess->cmdsn_mutex);

 spin_lock_bh(&conn->cmd_lock);
 list_for_each_entry_safe(cmd, cmd_tmp, &conn->conn_cmd_list, i_conn_node) {
  if (!(cmd->cmd_flags & ICF_OOO_CMDSN))
   continue;

  list_del_init(&cmd->i_conn_node);

  spin_unlock_bh(&conn->cmd_lock);
  iscsit_free_cmd(cmd, true);
  spin_lock_bh(&conn->cmd_lock);
 }
 spin_unlock_bh(&conn->cmd_lock);

 pr_debug("Dropped %u total unacknowledged commands on CID:"
  " %hu for ExpCmdSN: 0x%08x.\n", dropped_count, conn->cid,
    sess->exp_cmd_sn);
 return 0;
}

int iscsit_prepare_cmds_for_reallegiance(struct iscsit_conn *conn)
{
 u32 cmd_count = 0;
 struct iscsit_cmd *cmd, *cmd_tmp;
 struct iscsi_conn_recovery *cr;

 /*
 * Allocate an struct iscsi_conn_recovery for this connection.
 * Each struct iscsit_cmd contains an struct iscsi_conn_recovery pointer
 * (struct iscsit_cmd->cr) so we need to allocate this before preparing the
 * connection's command list for connection recovery.
 */

 cr = kzalloc(sizeof(struct iscsi_conn_recovery), GFP_KERNEL);
 if (!cr) {
  pr_err("Unable to allocate memory for"
   " struct iscsi_conn_recovery.\n");
  return -1;
 }
 INIT_LIST_HEAD(&cr->cr_list);
 INIT_LIST_HEAD(&cr->conn_recovery_cmd_list);
 spin_lock_init(&cr->conn_recovery_cmd_lock);
 /*
 * Only perform connection recovery on ISCSI_OP_SCSI_CMD or
 * ISCSI_OP_NOOP_OUT opcodes.  For all other opcodes call
 * list_del_init(&cmd->i_conn_node); to release the command to the
 * session pool and remove it from the connection's list.
 *
 * Also stop the DataOUT timer, which will be restarted after
 * sending the TMR response.
 */

 spin_lock_bh(&conn->cmd_lock);
 list_for_each_entry_safe(cmd, cmd_tmp, &conn->conn_cmd_list, i_conn_node) {

  if ((cmd->iscsi_opcode != ISCSI_OP_SCSI_CMD) &&
      (cmd->iscsi_opcode != ISCSI_OP_NOOP_OUT)) {
   pr_debug("Not performing reallegiance on"
    " Opcode: 0x%02x, ITT: 0x%08x, CmdSN: 0x%08x,"
    " CID: %hu\n", cmd->iscsi_opcode,
    cmd->init_task_tag, cmd->cmd_sn, conn->cid);

   list_del_init(&cmd->i_conn_node);
   spin_unlock_bh(&conn->cmd_lock);
   iscsit_free_cmd(cmd, true);
   spin_lock_bh(&conn->cmd_lock);
   continue;
  }

  /*
 * Special case where commands greater than or equal to
 * the session's ExpCmdSN are attached to the connection
 * list but not to the out of order CmdSN list.  The one
 * obvious case is when a command with immediate data
 * attached must only check the CmdSN against ExpCmdSN
 * after the data is received.  The special case below
 * is when the connection fails before data is received,
 * but also may apply to other PDUs, so it has been
 * made generic here.
 */

  if (!(cmd->cmd_flags & ICF_OOO_CMDSN) && !cmd->immediate_cmd &&
       iscsi_sna_gte(cmd->cmd_sn, conn->sess->exp_cmd_sn)) {
   list_del_init(&cmd->i_conn_node);
   spin_unlock_bh(&conn->cmd_lock);
   iscsit_free_cmd(cmd, true);
   spin_lock_bh(&conn->cmd_lock);
   continue;
  }

  cmd_count++;
  pr_debug("Preparing Opcode: 0x%02x, ITT: 0x%08x,"
   " CmdSN: 0x%08x, StatSN: 0x%08x, CID: %hu for"
   " reallegiance.\n", cmd->iscsi_opcode,
   cmd->init_task_tag, cmd->cmd_sn, cmd->stat_sn,
   conn->cid);

  cmd->deferred_i_state = cmd->i_state;
  cmd->i_state = ISTATE_IN_CONNECTION_RECOVERY;

  if (cmd->data_direction == DMA_TO_DEVICE)
   iscsit_stop_dataout_timer(cmd);

  cmd->sess = conn->sess;

  list_del_init(&cmd->i_conn_node);
  spin_unlock_bh(&conn->cmd_lock);

  iscsit_free_all_datain_reqs(cmd);

  transport_wait_for_tasks(&cmd->se_cmd);
  /*
 * Add the struct iscsit_cmd to the connection recovery cmd list
 */

  spin_lock(&cr->conn_recovery_cmd_lock);
  list_add_tail(&cmd->i_conn_node, &cr->conn_recovery_cmd_list);
  spin_unlock(&cr->conn_recovery_cmd_lock);

  spin_lock_bh(&conn->cmd_lock);
  cmd->cr = cr;
  cmd->conn = NULL;
 }
 spin_unlock_bh(&conn->cmd_lock);
 /*
 * Fill in the various values in the preallocated struct iscsi_conn_recovery.
 */

 cr->cid = conn->cid;
 cr->cmd_count = cmd_count;
 cr->maxrecvdatasegmentlength = conn->conn_ops->MaxRecvDataSegmentLength;
 cr->maxxmitdatasegmentlength = conn->conn_ops->MaxXmitDataSegmentLength;
 cr->sess = conn->sess;

 iscsit_attach_inactive_connection_recovery_entry(conn->sess, cr);

 return 0;
}

int iscsit_connection_recovery_transport_reset(struct iscsit_conn *conn)
{
 atomic_set(&conn->connection_recovery, 1);

 if (iscsit_close_connection(conn) < 0)
  return -1;

 return 0;
}

Messung V0.5
C=95 H=97 G=95

¤ Dauer der Verarbeitung: 0.3 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.