📄 iscsi_target.c
字号:
list_for_each_safe(list_ptr, list_temp, &devdata->session_list) { session = list_entry(list_ptr, struct iscsi_session, sess_link); iscsi_release_session(session); } list_for_each_safe(list_ptr, list_temp, &devdata->bad_session_list) { session = list_entry(list_ptr, struct iscsi_session, sess_link); TRACE(TRACE_DEBUG, "iscsi%d: release bad session %p, tsih %u\n", (int) devdata->device->id, session, session->tsih); iscsi_release_session(session); } up(&devdata->session_sem); } bring_down_portals();out: TRACE(TRACE_ENTER_LEAVE, "Leave iscsi_release, err %d\n", err); return err;}/* print socket connect/disconnect message */voidreport_peer_up_down(struct sockaddr *ip_address, char *message){ char ip_string[INET6_ADDRSTRLEN+2], port_string[8]; if (cnv_inet_to_string(ip_address, ip_string, port_string) > 0) { printk("%s %s %s:%s\n", current->comm, message, ip_string, port_string); }}/* * generate the next TTT in a session * must be called with session->cmnd_sem lock held */static inline __u32 __attribute__ ((no_instrument_function))generate_next_ttt(struct iscsi_session* session){ __u32 retval; retval = session->cmnd_id++; if (session->cmnd_id == 0) { /* just assigned -1 to retval, which is reserved * so do it again, since 0 is not reserved */ retval = session->cmnd_id++; } return retval;}/* * allocates all the structures necessary for a new connection and a * new session. If later we find out that this connection belongs to * an existing session, the session structure alloced here will be * freed. Its just easier to do everything here in one place, and it * makes it easier to recover from errors if everything is all set up * (i.e., there are no partial structures) * returns NULL if anything fails, in which case everything is freed * pointer to new iscsi_conn, which points to new iscsi_sess, if all ok */static struct iscsi_conn *build_conn_sess(struct socket *sock, struct portal_group *ptr){ struct iscsi_conn *conn; struct iscsi_session *session; int addr_len; conn = (struct iscsi_conn *)my_kmalloc(sizeof(struct iscsi_conn), "iscsi_conn"); if (!conn) { goto out1; } TRACE(TRACE_DEBUG, "new conn %p for sock %p\n", conn, sock); memset(conn, 0, sizeof(struct iscsi_conn)); INIT_LIST_HEAD(&conn->conn_link); INIT_LIST_HEAD(&conn->reject_list); init_MUTEX(&conn->reject_sem); conn->active = 1; conn->conn_id = ++devdata->conn_id; conn->conn_socket = sock; conn->dev = devdata; conn->max_send_length = 8192; conn->max_recv_length = 8192; conn->portal_group_tag = ptr->tag; conn->connection_flags = devdata->force; conn->nop_period = devdata->nop_period; init_timer(&conn->nop_timer); init_MUTEX_LOCKED(&conn->tx_sem); init_MUTEX_LOCKED(&conn->kill_rx_sem); init_MUTEX_LOCKED(&conn->kill_tx_sem); init_MUTEX(&conn->text_in_progress_sem); /* get ip addressing info about both ends of this connection */ if ((conn->ip_address = my_kmalloc(sizeof(struct sockaddr), "ip address")) == NULL) { goto out2; } addr_len = ptr->ip_length; /* value-result parameter */ if (sock->ops->getname(sock, conn->ip_address, &addr_len, 1) < 0) { TRACE_ERROR("%s Could not get peer name for socket %p\n", current->comm, sock); goto out3; } if ((conn->local_ip_address = my_kmalloc(sizeof(struct sockaddr), "local ip address")) == NULL) { goto out3; } addr_len = ptr->ip_length; /* value-result parameter */ if (sock->ops->getname(sock, conn->local_ip_address, &addr_len, 0) < 0) { TRACE_ERROR("%s Could not get local name for socket %p\n", current->comm, sock); goto out4; } session = (struct iscsi_session *)my_kmalloc(sizeof(struct iscsi_session), "session"); if (!session) { goto out4; } memset(session, 0, sizeof(struct iscsi_session)); INIT_LIST_HEAD(&session->sess_link); INIT_LIST_HEAD(&session->conn_list); list_add_tail(&conn->conn_link, &session->conn_list); conn->session = session; session->nconn = 1; session->devdata = devdata; session->portal_group_tag = ptr->tag; session->version_max = ISCSI_MAX_VERSION; session->version_min = ISCSI_MIN_VERSION; if ((session->r2t_timer = (struct timer_list *) my_kmalloc(sizeof(struct timer_list), "r2t timer")) == NULL) { goto out5; } init_timer(session->r2t_timer); TRACE(TRACE_DEBUG, "Allocated R2T timer %p for session %p\n", session->r2t_timer, session); if (!(session->session_params = my_kmalloc(MAX_CONFIG_PARAMS * sizeof(struct parameter_type), "session_params"))) { goto out6; } if (!(session->oper_param = my_kmalloc(MAX_CONFIG_PARAMS * sizeof(struct session_operational_parameters), "oper_param"))) { goto out7; } /* copy the parameters information from the global structure */ param_tbl_cpy(*session->session_params, *devdata->param_tbl); session->r2t_period = devdata->r2t_period; /* Store SNACK flags as part of Session - SAI */ session->targ_snack_flg = devdata->targ_snack_flg; init_MUTEX(&session->cmnd_sem); init_MUTEX_LOCKED(&session->retran_sem); init_MUTEX_LOCKED(&session->thr_kill_sem); /* all ok */ goto out;out7: my_kfree((void**)&session->session_params, "session_params");out6: TRACE(TRACE_DEBUG, "Releasing R2T timer %p for session %p\n", session->r2t_timer, session); my_kfree((void**)&session->r2t_timer, "r2t timer");out5: my_kfree((void**)&session, "session");out4: my_kfree((void**)&conn->local_ip_address, "local ip address"); out3: my_kfree((void**)&conn->ip_address, "ip address");out2: my_kfree((void**)&conn, "iscsi_conn"); out1: sock_release(sock);out: return conn;}/* * iscsi_server_thread: This thread is responsible for accepting * connections */intiscsi_server_thread(void *param){ struct iscsi_conn *new_conn; struct socket *newsock, *sock; struct portal_group *ptr = param; long i; i = ptr - iscsi_portal_groups; lock_kernel();/* Ming Zhang, mingz@ele.uri.edu */#ifdef K26 daemonize(#else daemonize(); snprintf(current->comm, sizeof(current->comm),#endif "iscsi_thr_%ld", i);#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 4, 18) /* * Arne Redlich, agr1@users.sourceforge.net: * This prevents the server thread from becoming a zombie after it exits. */ reparent_to_init();#endif siginitsetinv(¤t->blocked, ISCSI_SHUTDOWN_SIGBITS); /* mark that this server thread is alive */ devdata->server_thr[i] = current; unlock_kernel(); printk("%s Starting pid %d\n", current->comm, current->pid); sock = devdata->server_socket[i]; printk("%s Listening on %s:%s\n", current->comm, ptr->ip_string, ptr->port_string); /* notify our parent that this thread is up */ up(&devdata->server_sem); /* loop forever accepting new connections from initiators */ for ( ; ; ) { /* fix for 2.6.10 contributed by Charles Coffing, ccoffing@novell.com */#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 9) newsock = sock_alloc(); if (!newsock)#else int ret; ret = sock_create_kern(sock->sk->sk_family, sock->type, sock->sk->sk_protocol, &newsock); if (ret)#endif { TRACE_ERROR("%s Could not allocate socket for accept\n", current->comm); goto iscsi_server_thread_out; } newsock->type = sock->type; newsock->ops = sock->ops; TRACE(TRACE_NET, "before accept: sock %p newsock %p\n", sock, newsock); if (sock->ops->accept(sock, newsock, 0) < 0) { goto out1; } TRACE(TRACE_NET, "after accept: sock %p newsock %p\n", sock, newsock); /* turn off the Nagle Algorithm on this socket */ tcp_nagle_off(newsock); /* clear bad sessions and connections here */ clean_bad_stuff(); /* allocate and fill in connection details */ if ((new_conn = build_conn_sess(newsock, ptr)) == NULL) goto iscsi_server_thread_out; TRACE(TRACE_ISCSI, "Connect socket %p on conn %p, cid %d, session %p\n", newsock, new_conn, new_conn->conn_id, new_conn->session); /* * NOTE THAT WE CANNOT DO MUCH OF ANYTHING WITH THIS * CONNECTION AS WE DO NOT KNOW WHAT SESSION IT BELONGS * TO. THIS WILL HAVE TO BE A PART OF THE RX_THREAD */ /* start the tx thread */ if (kernel_thread(iscsi_tx_thread, (void *)new_conn, 0) < 0) { TRACE_ERROR("%s unable to create tx_thread\n", current->comm); goto out1; } /* start the rx thread */ if (kernel_thread(iscsi_rx_thread, (void *)new_conn, 0) < 0) { TRACE_ERROR("%s unable to create rx_thread\n", current->comm); if (new_conn->tx_thread) { /* Mike Christie mikenc@us.ibm.com */ send_sig(ISCSI_SHUTDOWN_SIGNAL, new_conn->tx_thread, 1); } goto out1; } }out1: sock_release(newsock);iscsi_server_thread_out: /* mark that this server thread is no longer alive */ devdata->server_thr[i] = NULL; printk("%s closed %s:%s\n", current->comm, ptr->ip_string, ptr->port_string); /* exit this thread after notifying whoever might be waiting */ up(&devdata->server_sem); printk("%s Exiting pid %d\n", current->comm, current->pid); return 0;}/* * for each session on the list, * release inactive connections and the session itself if no conns remain. * devdata->session_sem MUST be locked before this routine is called. */static void __attribute__ ((no_instrument_function))clean_session_list(struct list_head *list){ struct iscsi_session *session; struct iscsi_conn *conn; struct list_head *list_ptr1, *list_temp1; struct list_head *list_ptr2, *list_temp2; list_for_each_safe(list_ptr1, list_temp1, list) { session = list_entry(list_ptr1, struct iscsi_session, sess_link); list_for_each_safe(list_ptr2, list_temp2, &session->conn_list) { conn = list_entry(list_ptr2, struct iscsi_conn, conn_link); if (conn->active == 0) { if (iscsi_release_connection(conn) < 0) { TRACE_ERROR("%s Error releasing connection\n", current->comm); } } } if (list_empty(&session->conn_list)) { iscsi_release_session(session); } }}static void __attribute__ ((no_instrument_function))clean_bad_stuff(void){ /* destructive access to session lists */ if (!down_interruptible(&devdata->session_sem)) { clean_session_list(&devdata->bad_session_list); clean_session_list(&devdata->session_list); up(&devdata->session_sem); }}/* * iscsi_release_session: This function is responsible for closing out * a session and removing it from whatever list it is on. * host->session_sem MUST be locked before this routine is called. * INPUT: session to be released * OUTPUT: 0 if success, < 0 if there is trouble */intiscsi_release_session(struct iscsi_session *session){ struct iscsi_cmnd *cmnd; struct iscsi_conn *conn; struct list_head *list_ptr, *list_temp; if (!session) { TRACE_ERROR("%s Cannot release a NULL session\n", current->comm); return -1; } if (TRACE_TEST(TRACE_ISCSI)) { print_isid_tsih_message(session, "Release session with "); } TRACE(TRACE_DEBUG, "Releasing R2T timer %p for session %p\n", session->r2t_timer, session); /* Delete r2t timer - SAI */ if (session->r2t_timer) { TRACE(TRACE_DEBUG, "Deleting r2t timer %p\n", session->r2t_timer); del_timer_sync(session->r2t_timer); TRACE(TRACE_DEBUG, "Deleted r2t timer\n"); my_kfree((void**)&session->r2t_timer, "r2t timer"); } /* free commands */ while ((cmnd = session->cmnd_list)) { session->cmnd_list = cmnd->next; if (cmnd->cmnd != NULL) { if (scsi_release(cmnd->cmnd) < 0) { TRACE_ERROR("%s Trouble releasing command, opcode 0x%02x, " "ITT %u, state 0x%x\n", current->comm, cmnd->opcode_byte, cmnd->init_task_tag, cmnd->state); } } /* free data_list if any, cdeng */ free_data_list(cmnd); my_kfree((void**)&cmnd->ping_data, "data_buf"); my_kfree((void**)&cmnd, "iscsi_cmnd"); } /* free connections */ list_for_each_safe(list_ptr, list_temp, &session->conn_list) { conn = list_entry(list_ptr, struct iscsi_conn, conn_link); TRACE(TRACE_ISCSI, "iscsi%d: releasing connection %d\n", (int) session->devdata->device->id, conn->conn_id); if (iscsi_release_connection(conn) < 0) { TRACE_ERROR("%s Trouble releasing connection\n", current->comm); } } /* dequeue session if it is linked into some list */ if (!list_empty(&session->sess_link)) { list_del(&session->sess_link); /* error recovery ver new 18_04 - SAI */ if (session->retran_thread) { /* Mike Christie mikenc@us.ibm.com */ send_sig(ISCSI_SHUTDOWN_SIGNAL, session->retran_thread, 1); down_interruptible(&session->thr_kill_sem); } } /* free session structures */ my_kfree((void**)&session->session_params, "session_params"); my_kfree((void**)&session->oper_param, "oper_param"); my_kfree((void**)&session, "session"); return 0;}/* * called by both rx and tx threads, but only after the rx thread has been * started on a connection (so the connected message has been given). * if socket for this conn has not already been released, do it now and * print a message that says we disconnected. * Also NULL out the conn's socket so we don't try to do this again later. */static voidiscsi_release_socket(struct iscsi_conn *conn){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -