📄 initiator_tx.c
字号:
total_sent += res; } sg++; } if (unlikely(padding > 0)) { __u32 pad_bytes = 0; struct iovec iov = {&pad_bytes, padding}; struct msghdr msg; memset(&msg, 0, sizeof(msg)); msg.msg_iov = &iov; msg.msg_iovlen = 1; oldfs = get_fs(); set_fs(get_ds()); res = sock_sendmsg(sock, &msg, padding); set_fs(oldfs); if (res != padding) { if (res > 0) { sent = total_sent; goto finish; } else { if (res == -EAGAIN) { sent = total_sent; goto eagain; } sent = res; goto finish; } } } sent = size; } else { oldfs = get_fs(); set_fs(get_ds()); sent = sock_sendmsg(current_connection->sock, ¤t_command->tx_msghdr, size); set_fs(oldfs); }finish:#else oldfs = get_fs(); set_fs(get_ds()); sent = sock_sendmsg(current_connection->sock, ¤t_command->tx_msghdr, size); set_fs(oldfs);#endif /* now get back exclusive access to this session iscsi structures */ UNH_LOCK(¤t_session->sess_lock,current_connection->tx_lock_flags); TRACE(TRACE_DEBUG, "--sent %d, ITT %u resume\n", sent, current_command->init_task_tag); if (unlikely(sent < size)) { /* did not send what we expected to send, why? */ if (current_connection->tx_thread == NULL || sent == -EINTR) { /* thread was killed as part of session shutdown */ retval = -ESRCH; /* No such process */ goto out; } TRACE(TRACE_DEBUG, "%s sock_sendmsg returned %d, expected %d\n", current->comm, sent, size); if (sent < 0) { if (sent != -EAGAIN) { /* hard error -- report it, then get out */ TRACE_ERROR("%s sock_sendmsg error %d\n", current->comm, -sent); retval = sent; goto out; } sent = 0; /* got nothing on this send */ }#ifdef K26eagain:#endif /* need to try again later */ current_command->tx_size -= sent; current_command->tx_sent_so_far += sent; current_command->tx_wait_to_send = jiffies + (HZ >> 6); current_connection->connection_flags |= NEED_TX_WAKEUP; /* couldn't send all of this command now */ TRACE(TRACE_ISCSI, "%s Part 0x%02x, ITT %u, " "%u bytes unsent\n", current->comm, opcode, current_command->init_task_tag, current_command->tx_size); /* do nothing more on this command or connection */ current_connection->short_command = current_command; retval = 0; goto out; } /* sent everything we wanted to send, this pdu is completely sent */ current_connection->short_command = NULL; if (unlikely(TRACE_TEST(TRACE_DEBUG) && opcode == ISCSI_INIT_SCSI_CMND)) { /* this was a SCSI Request */ TRACE(TRACE_DEBUG, "%s Sent SCSI %s ITT %u " "CmndSn %u exp_stat_sn %u length %d\n", current->comm, printable_scsi_op(current_command->iscsi_cmd.cdb[0], op_buf), ntohl(current_command->iscsi_cmd.init_task_tag), ntohl(current_command->iscsi_cmd.cmd_sn), ntohl(current_command->iscsi_cmd.exp_stat_sn), size); } /* Timestamp the command transmission time - SAI */ current_command->time_stamp = jiffies; /* Mark that current PDU has been completely sent. This allows * new transfers to be set up in this command's pdu slot. */ current_command->tx_sent_so_far += sent; current_command->tx_size = 0; if (!(current_command->header_flags & F_BIT)) { /* F bit is 0, more DataOut PDUs to be sent, keep loop going */ if (atomic_read(¤t_connection->tx_sem.count) <= 0) { up(¤t_connection->tx_sem); } } else if (opcode == ISCSI_INIT_SCSI_DATA_OUT) { /* this was the last DataOut PDU in an R2T sequence */ if (!list_empty(¤t_connection->r2t_list)) { /* first DataOut PDU of next R2T ready to be sent */ if (atomic_read(¤t_connection->tx_sem.count)<=0) { up(¤t_connection->tx_sem); } } } else if (opcode == ISCSI_INIT_NOP_OUT) { /* this was the last (only) NopOut PDU sent */ if (current_command->init_task_tag == ALL_ONES) { /* this was a ping response to target's NopIn * Free up the command itself since we will * get no further response from target. */ current_command->cmd_state |= CMD_STATE_TXDONE | CMD_STATE_RXDONE; } } else if (opcode == ISCSI_INIT_SNACK) { /* Free SNACK Request from pending commands list - SAI */ current_command->cmd_state |= CMD_STATE_TXDONE | CMD_STATE_RXDONE; }#ifdef ISCSI_STATS UPDATE_TX_SESS_STATS(opcode, current_command, current_session->sess_stats, current_connection);#endifout: return retval;}/* * executed only by tx thread. * when called, NO LOCKS SHOULD BE LOCKED! * Called only once by iscsi_initiator_tx_thread() to shutdown the tx thread, */static voidtx_shutdown_thread(struct connection *conn, struct session *sess){ TRACE(TRACE_DEBUG, "%s shutting down\n", current->comm); /* get exclusive access to this session iscsi structures */ UNH_LOCK(&sess->sess_lock, conn->tx_lock_flags); /* do not allow tx_timer to restart itself */ conn->connection_flags |= TX_TIMER_OFF; if (conn->tx_thread != NULL) { /* no other thread is already shutting this session down * indicate that this thread is shutting itself down */ conn->tx_thread = NULL; } /* tell anyone waiting that this tx thread is finished */ up(&conn->tx_done_sem); /* finally, release our exclusive access to the iscsi structures */ UNH_UNLOCK(&sess->sess_lock, conn->tx_lock_flags); printk("%s Exiting pid %d conn %p\n", current->comm, current->pid, conn);}/**************************************************************************** * The tx thread is woken up anytime someone has something * that needs to be sent. each time it is woken up it searches through the * command table for stuff that it needs to send. * There is only one tx thread for each session. ******************************************************************************/voidiscsi_initiator_tx_thread(void *arg){ struct connection *conn; struct session *sess; struct command *command; int delta; __u32 nop_timer_expired; struct list_head *lptr, *next; conn = (struct connection *) arg; sess = conn->my_session; /* Lock kernel to daemonize thread and update tx thread pointer */ lock_kernel(); /* NOTE: struct task_struct has declared char comm[16] *//* Ming Zhang, mingz@ele.uri.edu */#ifdef K26 daemonize(#else daemonize(); snprintf(current->comm, sizeof(current->comm),#endif "tx-%u-%02u", sess->scsi_target_id, conn->connection_id);#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 4, 18) /* * Arne Redlich, agr1@users.sourceforge.net: * This prevents the tx_thread from becoming a zombie after it exits. */ reparent_to_init();#endif siginitsetinv(¤t->blocked, ISCSI_SHUTDOWN_SIGBITS); /* mark that this tx thread is alive */ conn->tx_thread = current; unlock_kernel(); printk("%s Starting pid %d conn %p\n", current->comm, current->pid, conn); /* set up counter so NopOut pings can be sent to target periodically */ conn->nop_remaining = sess->nop_period; TRACE(TRACE_TIMERS, "%s nop_remaining %u\n", current->comm, conn->nop_remaining); /* Always start the tx timer now */ restart_tx_timer(conn); /* signal anyone waiting that the tx thread is up and running */ up(&conn->tx_done_sem); for (;;) { TRACE(TRACE_SEM, "%s blocked on tx_sem\n", current->comm); if (unlikely(down_interruptible(&conn->tx_sem) < 0)) { /* did not get the sem but got signalled */ TRACE(TRACE_ISCSI, "%s Killed by signal\n", current->comm); goto leave; } TRACE(TRACE_SEM, "%s unblocked on tx_sem\n", current->comm); /* now get exclusive access to the iscsi structures */ UNH_LOCK(&sess->sess_lock, conn->tx_lock_flags); /* tx thread just awakened, so no further wakeups needed yet */ conn->connection_flags &= ~NEED_TX_WAKEUP; /* Free Unused Connections - SAI */ /* clear_free_conn(sess); */ nop_timer_expired = 0; if (unlikely(atomic_read(&conn->tx_timer_went_off))) { /* periodic tx timer went off */ TRACE(TRACE_TIMERS, "%s tx_timer_went_off %u, " "nop_remaining %u\n", current->comm, atomic_read(&conn->tx_timer_went_off), conn->nop_remaining); atomic_dec(&conn->tx_timer_went_off); if (conn->nop_remaining) { /* sending periodic nop pings is enabled */ conn->nop_remaining--; if (conn->nop_remaining == 0) { /* time to send a periodic nop * on inactive connections */ nop_timer_expired = 1; conn->nop_remaining = sess->nop_period; } } } /* tx thread IS dependent on rx thread */ if (unlikely(conn->rx_thread == NULL)) { /* no rx thread, connection not up yet * or was brought down unexpectedly. * In either case, don't try to use it! */ printk("%s exiting, no rx thread!\n", current->comm); goto out; } /* See if this connection got logged out */ if (unlikely(conn->connection_state == CONNECTION_LOGGED_OUT)) { printk("%s logged out\n", current->comm); goto out; } /* if timer went off and this connection has had no * activity since the last timer then send a * NopOut ping to the target */ if (unlikely(nop_timer_expired && list_empty(&conn->pending_commands))) { /* timer went off and nothing pending * on this connection */ if (!(conn->connection_flags & GOT_ACTIVITY)) { /* no activity since * last timer timed out, * send nop ping */ drive_nopout(conn, sess, 0, 1); } else { /* had activity, turn off * the flag to start next period */ conn->connection_flags &= ~GOT_ACTIVITY; } } list_for_each_safe(lptr, next, &conn->pending_commands) { command = list_entry(lptr,struct command,link); /* bypass this command if target window closed to it */ if (beyond_window(sess, conn, command)) continue; if ( command->need_write_built) { /* A write request. * Need to construct the infrastructure */ TRACE(TRACE_DEBUG, "command %p marked for write\n", command); build_write_command(sess, conn, command); command->need_write_built = 0 ; } if (unlikely(TRACE_TEST(TRACE_DEBUG))) { delta = jiffies - command->time_stamp; TRACE(TRACE_DEBUG, "%s for command %p, tx_size %u, " "ITT %u, time_stamp %u, " "delta %d\n", current->comm, command, command->tx_size, command->init_task_tag, command->time_stamp, delta); } if (unlikely(conn->short_command != NULL)) { if (conn->short_command != command) { /* when we have a partial send * outstanding, don't look at any other * command until that is resumed */ break; } } if (unlikely(conn->sock == NULL)) goto out; /* Check if command re-transmission required * -- SAI */ if (unlikely(!command->tx_size && !check_for_retransmit(sess, conn, command))) { /* nothing works on rexmit, shut * this tx thread down */ printk("%s exiting, bad retransmit, ITT %u\n", current->comm, command->init_task_tag); goto out; } if ((delta = ready_to_xmit(sess, conn, command)) <= 0) { if (delta < 0) { /* do nothing more on * this command or connection */ break; } /* this command not ready to send */ continue; } /* have a command that needs to be * sent on this connection * and target window is open * enough to receive it */ delta = do_tx_send(sess, conn, command); if (unlikely(delta <= 0)) { if (delta == 0) { /* do nothing more on * this command or connection */ break; } /* fatal error */ printk("%s exiting due to error %d\n", current->comm, -delta); goto out; } /* in case this changed while we gave * up the lock */ next = lptr->next; if (command->still_to_send == 0) command->cmd_state |= CMD_STATE_TXDONE; free_pending_command(command, conn); } /* end of for command loop */ /* Check if a Connection Recovery Test needs * to be done - SAI */ if (unlikely(conn->rec_tests == 8)) { if (sess->nconnections <= 1) { UNH_UNLOCK(&sess->sess_lock, conn->tx_lock_flags); create_rec_conn(sess->connection_head); UNH_LOCK(&sess->sess_lock, conn->tx_lock_flags); } drive_logout(sess, conn, sess->oper_param-> ErrorRecoveryLevel); conn->rec_tests = 0; } /* release our exclusive access to the session * iscsi structures and resume infinite loop */ UNH_UNLOCK(&sess->sess_lock, conn->tx_lock_flags); } /* end of infinite loop */ /* NOT REACHED */out: /* release our exclusive access to the iscsi session structures */ UNH_UNLOCK(&sess->sess_lock, conn->tx_lock_flags);leave: tx_shutdown_thread(conn, sess);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -