⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 iscsi_main.c

📁 这个linux源代码是很全面的~基本完整了~使用c编译的~由于时间问题我没有亲自测试~但就算用来做参考资料也是非常好的
💻 C
📖 第 1 页 / 共 5 页
字号:
# ifdef PROC_SCSI_ISCSI    PROC_SCSI_ISCSI,# else    PROC_SCSI_NOT_PRESENT,# endif    5,    "iscsi",    S_IFDIR|S_IRUGO|S_IXUGO,    2};#endif/* become a daemon kernel thread.  Some kernels provide this functionality * already, and some even do it correctly */void iscsi_daemonize(void){    /* use the kernel's daemonize */    daemonize();    /* Reparent to init */    reparent_to_init();    /* increase priority like the md driver does for it's kernel threads */    wmb();}/* drop an iscsi session */void iscsi_drop_session(iscsi_session_t *session){    pid_t pid;                  DEBUG_INIT4("iSCSI: iscsi_drop_session %p, rx %d, tx %d at %lu\n",                 session, session->rx_pid, session->tx_pid, jiffies);    clear_bit(SESSION_ESTABLISHED, &session->control_bits);    if ((pid = session->tx_pid))        kill_proc(pid, SIGHUP, 1);    if ((pid = session->rx_pid))        kill_proc(pid, SIGHUP, 1);}void iscsi_terminate_session(iscsi_session_t *session){    pid_t pid;                  DEBUG_INIT4("iSCSI: iscsi_terminate_session %p, rx %d, tx %d at %lu\n",                 session, session->rx_pid, session->tx_pid, jiffies);    set_bit(SESSION_TERMINATING, &session->control_bits);    clear_bit(SESSION_ESTABLISHED, &session->control_bits);    if ((pid = session->tx_pid))        kill_proc(pid, SIGKILL, 1);    if ((pid = session->rx_pid))        kill_proc(pid, SIGKILL, 1);}/* if a signal is pending, deal with it, and return 1. * Otherwise, return 0. */static int iscsi_handle_signals(iscsi_session_t *session){    pid_t pid;    int ret = 0;        /* if we got SIGHUP, try to establish a replacement session.     * if we got SIGKILL, terminate this session.     */    if (signal_pending(current)) {        spin_lock_irq(&current->sighand->siglock);        /* iscsi_drop_session and iscsi_terminate_session signal both         * threads, but someone logged in as root may not.  So, we         * make sure whichever process gets signalled first propagates         * the signal when it looks like only one thread got         * signalled.         */        /* on SIGKILL, terminate the session */        if (SIGNAL_IS_PENDING(SIGKILL)) {            if (!test_and_set_bit(SESSION_TERMINATING, &session->control_bits)) {                if ((pid = session->tx_pid) && (pid != current->pid)) {                    printk("iSCSI: rx thread %d received SIGKILL, killing tx thread %d\n", current->pid, pid);                    kill_proc(pid, SIGKILL, 1);                }                if ((pid = session->rx_pid) && (pid != current->pid)) {                    printk("iSCSI: tx thread %d received SIGKILL, killing rx thread %d\n", current->pid, pid);                    kill_proc(pid, SIGKILL, 1);                }            }            ret = 1;        }        /* on SIGHUP, drop the session, and try to establish a replacement session */        if (SIGNAL_IS_PENDING(SIGHUP)) {            if (test_and_clear_bit(SESSION_ESTABLISHED, &session->control_bits)) {                if ((pid = session->tx_pid) && (pid != current->pid)) {                    printk("iSCSI: rx thread %d received SIGHUP, signaling tx thread %d\n", current->pid, pid);                    kill_proc(pid, SIGHUP, 1);                }                if ((pid = session->rx_pid) && (pid != current->pid)) {                    printk("iSCSI: tx thread %d received SIGHUP, signaling rx thread %d\n", current->pid, pid);                    kill_proc(pid, SIGHUP, 1);                }            }            ret = 1;        }        /* we don't care about any other signals */        flush_signals(current);        spin_unlock_irq(&current->sighand->siglock);    }    return ret;}/* wake up the tx_thread without ever losing the wakeup event */static void wake_tx_thread(int control_bit, iscsi_session_t *session){    /* tell the tx thread what to do when it wakes up. */    set_bit(control_bit, &session->control_bits);        /* We make a condition variable out of a wait queue and atomic test&clear.     * May get spurious wake-ups, but no wakeups will be lost.     * this is cv_signal().  wait_event_interruptible is cv_wait().     */    set_bit(TX_WAKE, &session->control_bits);    wake_up(&session->tx_wait_q);}/* compare against 2^31 */#define SNA32_CHECK 2147483648UL/* Serial Number Arithmetic, 32 bits, less than, RFC1982 */static int sna_lt(uint32_t n1, uint32_t n2){    return ((n1 != n2) &&             (((n1 < n2) && ((n2 - n1) < SNA32_CHECK)) || ((n1 > n2) && ((n2 - n1) < SNA32_CHECK))));}/* Serial Number Arithmetic, 32 bits, less than, RFC1982 */static int sna_lte(uint32_t n1, uint32_t n2){    return ((n1 == n2) ||            (((n1 < n2) && ((n2 - n1) < SNA32_CHECK)) || ((n1 > n2) && ((n2 - n1) < SNA32_CHECK))));}/* difference isn't really a defined operation in SNA, but we'd like it so that * we can determine how many commands can be queued to a session. */static int cmdsn_window_size(uint32_t expected, uint32_t max){    if ((expected <= max) && ((max - expected) < SNA32_CHECK)) {        return (max - expected + 1);    }    else if ((expected > max) && ((expected - max) < SNA32_CHECK)) {        /* window wraps around */        return ((UINT32_MAX - expected) + 1 + max + 1);    }    else {        /* window closed, or numbers bogus */        return 0;    }}/* remember old peak cmdsn window size, and report the largest */static int max_tasks_for_session(iscsi_session_t *session){    if (session->ExpCmdSn == session->MaxCmdSn + 1)        /* if the window is closed, report nothing, regardless of what it was in the past */        return 0;    else if (session->last_peak_window_size < session->current_peak_window_size)        /* window increasing, so report the current peak size */        return MIN(session->current_peak_window_size, ISCSI_CMDS_PER_LUN * session->num_luns);    else        /* window decreasing.  report the previous peak size, in case it's         * a temporary decrease caused by the commands we're sending.         * we want to keep the right number of commands queued in the driver,         * ready to go as soon as they can.         */        return MIN(session->last_peak_window_size, ISCSI_CMDS_PER_LUN * session->num_luns);}/* possibly update the ExpCmdSN and MaxCmdSN, and peak window sizes */static void updateSN(iscsi_session_t *session, UINT32 expcmdsn, UINT32 maxcmdsn) {    int window_size;    /* standard specifies this check for when to update expected and max sequence numbers */    if (!sna_lt(maxcmdsn, expcmdsn - 1)) {        if ((expcmdsn != session->ExpCmdSn) && !sna_lt(expcmdsn, session->ExpCmdSn)) {            session->ExpCmdSn = expcmdsn;        }        if ((maxcmdsn != session->MaxCmdSn) && !sna_lt(maxcmdsn, session->MaxCmdSn)) {                        session->MaxCmdSn = maxcmdsn;            /* look for the peak window size */            window_size = cmdsn_window_size(expcmdsn, maxcmdsn);            if (window_size > session->current_peak_window_size)                session->current_peak_window_size = window_size;            /* age peak window size info */            if (time_before(session->window_peak_check + (15 * HZ), jiffies)) {                session->last_peak_window_size = session->current_peak_window_size;                session->current_peak_window_size = window_size;                session->window_peak_check = jiffies;            }            /* memory barrier for all of that */            mb();            /* wake the tx thread to try sending more commands */            wake_tx_thread(TX_SCSI_COMMAND, session);        }        /* record whether or not the command window for this session has closed,         * so that we can ping the target periodically to ensure we eventually         * find out that the window has re-opened.           */        if (maxcmdsn == expcmdsn - 1) {            session->current_peak_window_size = 0;            set_bit(SESSION_WINDOW_CLOSED, &session->control_bits);        }        else            clear_bit(SESSION_WINDOW_CLOSED, &session->control_bits);        DEBUG_FLOW3("iSCSI: session %p - ExpCmdSN %u, MaxCmdSN %u\n",                     session, session->ExpCmdSn, session->MaxCmdSn);    }}/* add a session from an HBA's collection of sessions. * caller must hold the HBA's session lock. */static int add_session(iscsi_hba_t *hba, iscsi_session_t *session){    iscsi_session_t *prior, *next;    prior = NULL;    next = hba->session_list_head;    while (next && (next->channel < session->channel)) {        prior = next;        next = prior->next;    }    while (next && (next->channel == session->channel) && (next->target_id < session->target_id)) {        prior = next;        next = prior->next;    }        /* same Linux SCSI address? */    if (next && (next->channel == session->channel) && (next->target_id == session->target_id)) {        if (strcmp(next->TargetName, session->TargetName) == 0) {            /* already have a session running to this target */            printk("iSCSI: session to %s already exists\n", session->TargetName);        }        else {            printk("iSCSI: error - TargetName %s cannot claim bus %d id %d, already in use by %s\n",                    session->TargetName, session->iscsi_bus, next->target_id, next->TargetName);        }        return 0;    }    else {        /* insert the session into the list */        if ((session->next = next))            next->prev = session;        else            hba->session_list_tail = session;        if ((session->prev = prior))            prior->next = session;        else            hba->session_list_head = session;        session->hba = hba;        mb();        DEBUG_INIT2("iSCSI: added session %p to hba %p\n", session, hba);                return 1;    }}/* remove a session from an HBA's collection of sessions. * caller must hold the HBA's session lock. */static int remove_session(iscsi_hba_t *hba, iscsi_session_t *session){    if (session->hba && (hba != session->hba)) {        printk("iSCSI: tried to remove session %p from hba %p, but session->hba is %p\n",               session, hba, session->hba);        return 0;    }    /* remove the session from the HBA */    if (session == hba->session_list_head) {        if ((hba->session_list_head = session->next))            hba->session_list_head->prev = NULL;        else            hba->session_list_tail = NULL;    }    else if (session == hba->session_list_tail) {        hba->session_list_tail = session->prev;        hba->session_list_tail->next = NULL;    }    else {        /* we should always be in the middle,          * but check pointers to make sure we don't crash the kernel          * if the function is called for a session not on the hba.         */        if (session->next && session->prev) {            session->next->prev = session->prev;            session->prev->next = session->next;        }        else {            DEBUG_ERR2("iSCSI: failed to remove session %p from hba %p\n",                       session, hba);            return 0;        }    }    session->prev = NULL;    session->next = NULL;    return 1;}static iscsi_session_t *find_session_for_cmnd(Scsi_Cmnd *sc){    iscsi_session_t *session = NULL;    iscsi_hba_t *hba;    DECLARE_NOQUEUE_FLAGS;    if (!sc->host)        return NULL;    if (!sc->host->hostdata)        return NULL;    hba = (iscsi_hba_t *)sc->host->hostdata;    /* find the session for this command */    SPIN_LOCK_NOQUEUE(&hba->session_lock);    session = hba->session_list_head;    while (session && (session->channel != sc->channel || session->target_id != sc->target))        session = session->next;    if (session)        atomic_inc(&session->refcount); /* caller must use drop_reference when it's done with the session */    SPIN_UNLOCK_NOQUEUE(&hba->session_lock);    return session;}/* decrement the session refcount, and remove it and free it if the refcount hit zero */static void drop_reference(iscsi_session_t *session){    iscsi_hba_t *hba = session->hba;    DECLARE_NOQUEUE_FLAGS;    SPIN_LOCK_NOQUEUE(&hba->session_lock);    if (atomic_dec_and_test(&session->refcount)) {        if (remove_session(hba, session)) {            DEBUG_INIT1("iSCSI: terminated and deleted session %p\n", session);            memset(session, 0, sizeof(*session));            kfree(session);        }        else {            printk("iSCSI: bug - failed to remove unreferenced session %p\n", session);        }    }    SPIN_UNLOCK_NOQUEUE(&hba->session_lock);}/* must hold the task_lock to call this */static iscsi_task_t *find_task(iscsi_task_collection_t *collection, uint32_t itt){    iscsi_task_t *task = collection->head;        while (task) {        if (task->itt == itt) {            DEBUG_FLOW3("iSCSI: found itt %u, task %p, refcount %d\n", itt, task, atomic_read(&task->refcount));            return task;        }        task = task->next;    }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -