📄 iscsi_main.c
字号:
return NULL;}#if 0/* don't actually use this at the moment *//* must hold the task_lock to call this */static iscsi_task_t *find_mgmt_task(iscsi_task_collection_t *collection, uint32_t mgmt_itt){ iscsi_task_t *task = collection->head; while (task) { if (task->mgmt_itt == mgmt_itt) { DEBUG_FLOW2("iSCSI: found mgmt_itt %u, task %p\n", mgmt_itt, task); return task; } task = task->next; } return NULL;}#endif#if 0/* don't actually need this at the moment *//* must hold the task_lock to call this */static iscsi_task_t *find_task_for_cmnd(iscsi_task_collection_t *collection, Scsi_Cmnd *sc){ iscsi_task_t *task = collection->head; while (task) { if (task->scsi_cmnd == sc) { DEBUG_FLOW3("iSCSI: found itt %u, task %p for cmnd %p\n", task->itt, task, sc); return task; } task = task->next; } return NULL;}#endif/* add a task to the collection. Must hold the task_lock to do this. */static void add_task(iscsi_task_collection_t *collection, iscsi_task_t *task){ if (task->prev || task->next) printk("iSCSI: bug - adding task %p, prev %p, next %p, to collection %p\n", task, task->prev, task->next, collection); if (collection->head) { task->next = NULL; task->prev = collection->tail; collection->tail->next = task; collection->tail = task; } else { task->prev = task->next = NULL; collection->head = collection->tail = task; }}#define first_task(collection_ptr) ((collection_ptr)->head)#define next_task(collection_ptr, task_ptr) ((task_ptr)->next)#define order_next_task(collection_ptr, task_ptr) ((task_ptr)->order_next)/* must hold the task_lock when calling this */static iscsi_task_t *pop_task(iscsi_task_collection_t *collection){ iscsi_task_t *task = NULL; if ((task = collection->head)) { /* pop the head */ if ((collection->head = task->next)) collection->head->prev = NULL; else collection->tail = NULL; /* and return it */ task->prev = NULL; task->next = NULL; return task; } return NULL;}/* must hold the task_lock when calling this */static void push_task(iscsi_task_collection_t *collection, iscsi_task_t *task){ if (task) { task->prev = NULL; task->next = collection->head; if (collection->head) { collection->head->prev = task; collection->head = task; } else { collection->head = collection->tail = task; } }}static void unlink_task(iscsi_task_collection_t *collection, iscsi_task_t *task){ /* unlink the task from the collection */ if (task == collection->head) { if ((collection->head = task->next)) collection->head->prev = NULL; else collection->tail = NULL; } else if (task == collection->tail) { collection->tail = task->prev; collection->tail->next = NULL; } else { task->next->prev = task->prev; task->prev->next = task->next; } task->next = NULL; task->prev = NULL;}/* if the task for the itt is found in the collection, remove it, and return it. * otherwise, return NULL. Must hold the task_lock to call this. */static iscsi_task_t *remove_task(iscsi_task_collection_t *collection, uint32_t itt){ iscsi_task_t *task = NULL; iscsi_task_t *search = collection->head; while (search) { if (search->itt == itt) { task = search; unlink_task(collection, task); return task; } search = search->next; } return NULL;}/* if the task for the mgmt_itt is found in the collection, remove it, and return it. * otherwise, return NULL. Must hold the task_lock to call this. */static iscsi_task_t *remove_mgmt_task(iscsi_task_collection_t *collection, uint32_t mgmt_itt){ iscsi_task_t *task = NULL; iscsi_task_t *search = collection->head; while (search) { if (search->mgmt_itt == mgmt_itt) { task = search; unlink_task(collection, task); return task; } search = search->next; } return NULL;}/* if the task for the itt is found in the collection, remove it, and return it. * otherwise, return NULL. Must hold the task_lock to call this. */static iscsi_task_t *remove_task_for_cmnd(iscsi_task_collection_t *collection, Scsi_Cmnd *sc){ iscsi_task_t *task = NULL; iscsi_task_t *search = collection->head; while (search) { if (search->scsi_cmnd == sc) { task = search; unlink_task(collection, task); return task; } search = search->next; } return NULL;}/* * remove all tasks with the specified LUN. Must hold the task_lock to call this. */static void remove_tasks_for_lun(iscsi_task_collection_t *collection, int lun){ iscsi_task_t *search = collection->head; iscsi_task_t *next = NULL; while (search) { next = search->next; if (search->scsi_cmnd && search->scsi_cmnd->lun == lun) unlink_task(collection, search); search = next; }}/* must be called with no locks held, since it may sleep, and acquires * locks on it's own. */static iscsi_task_t *alloc_task(iscsi_session_t *session){ iscsi_task_t *task = NULL; iscsi_hba_t *hba = session->hba; if (!hba) { printk("iSCSI: alloc_task - session %p has NULL HBA\n", session); return NULL; } /* try to get one from the HBA's free task collection */ spin_lock(&hba->free_task_lock); if ((task = pop_task(&hba->free_tasks))) { atomic_dec(&hba->num_free_tasks); atomic_inc(&hba->num_used_tasks); hba->min_free_tasks = MIN(hba->min_free_tasks, atomic_read(&hba->num_free_tasks)); } else { hba->min_free_tasks = 0; } spin_unlock(&hba->free_task_lock); /* otherwise, try to dynamically allocate a task */ if (!task) { if ((task = kmalloc(sizeof(iscsi_task_t), GFP_ATOMIC))) { atomic_inc(&hba->num_used_tasks); DEBUG_ALLOC6("iSCSI: kmalloc task %p (active %u, used %u, free %u) for session %p to %s\n", task, atomic_read(&session->num_active_tasks), atomic_read(&hba->num_used_tasks), atomic_read(&hba->num_free_tasks), session, session->log_name); } } if (task) { memset(task, 0, sizeof(iscsi_task_t) ); task->itt = RSVD_TASK_TAG; task->ttt = RSVD_TASK_TAG; task->mgmt_itt = RSVD_TASK_TAG; task->next = task->prev = NULL; task->order_next = task->order_prev = NULL; task->session = session; wmb(); } else { set_bit(SESSION_TASK_ALLOC_FAILED, &session->control_bits); } return task;}static void free_task( iscsi_task_t *task ){ iscsi_session_t *session = task->session; iscsi_hba_t *hba; if (! task) { DEBUG_ERR0("iSCSI: free_task couldn't free NULL task\n"); return; } if (! session) { DEBUG_ERR1("iSCSI: free_task couldn't find session for task %p\n", task); return; } hba = session->hba; if (!hba) { DEBUG_ERR1("iSCSI: free_task couldn't find HBA for task %p\n", task); return; } if (task->next || task->prev || task->order_next || task->order_prev) { /* this is a memory leak, which is better than memory corruption */ printk("iSCSI: bug - tried to free task %p with prev %p, next %p, order_prev %p, order_next %p\n", task, task->prev, task->next, task->order_prev, task->order_next); return; } DEBUG_QUEUE4("iSCSI: free_task %p, itt %u, session %p, %u currently free\n", task, task->itt, task->session, atomic_read(&hba->num_free_tasks)); /* zero out the task settings */ task->scsi_cmnd = NULL; task->session = NULL; task->itt = RSVD_TASK_TAG; task->mgmt_itt = RSVD_TASK_TAG; task->next = task->prev = NULL; task->order_next = task->order_prev = NULL; atomic_set(&task->refcount, 0); /* put the task on the session's free list */ spin_lock(&hba->free_task_lock); atomic_inc(&hba->num_free_tasks); atomic_dec(&hba->num_used_tasks); add_task(&hba->free_tasks, task); spin_unlock(&hba->free_task_lock); /* If an alloc call has failed, we need to wake up the TX thread * now that a task is available, since there are no guarantees * that anything else will wake it up. */ if (test_and_clear_bit(SESSION_TASK_ALLOC_FAILED, &session->control_bits)) wake_tx_thread(TX_SCSI_COMMAND, session);}/* As long as the tx thread is the only caller, no locking * is required. If any other thread also needs to call this, * then all callers must be changed to agree on some locking * protocol. Currently, some but not all caller's are holding * the session->task_lock. */static inline uint32_t allocate_itt(iscsi_session_t *session){ uint32_t itt = 0; if (session) { itt = session->itt++; /* iSCSI reserves 0xFFFFFFFF, this driver reserves 0 */ if (session->itt == RSVD_TASK_TAG) session->itt = 1; } return itt;}/* Caller must hold the session's task_lock. Associating a task with * a session causes it to be completed on a session drop or target * reset, along with all other session tasks, in the order they were * added to the session. Preserving the ordering is required by the * Linux SCSI architecture. Tasks that should not be completed to the * Linux SCSI layer (because the eh_abort_handler has or will return * SUCCESS for it) get removed from the session, though they may still * be in various task collections so that PDUs relating to them can be * sent or received. */static void add_session_task(iscsi_session_t *session, iscsi_task_t *task){ if (atomic_read(&session->num_active_tasks) == 0) { /* session going from idle to active, pretend we just * received something, so that the idle period before this doesn't * cause an immediate timeout. */ session->last_rx = jiffies; } atomic_inc(&session->num_active_tasks); /* set task info */ task->session = session; task->itt = allocate_itt(session); DEBUG_QUEUE5("iSCSI: task %p allocated itt %u for command %p, session %p to %s\n", task, task->itt, task->scsi_cmnd, session, session->log_name); /* add it to the session task ordering list */ if (session->arrival_order.head) { task->order_prev = session->arrival_order.tail; task->order_next = NULL; session->arrival_order.tail->order_next = task; session->arrival_order.tail = task; } else { task->order_prev = NULL; task->order_next = NULL; session->arrival_order.head = session->arrival_order.tail = task; } DEBUG_FLOW4("iSCSI: task %p, itt %u, added to session %p to %s\n", task, task->itt, session, session->log_name);}static int remove_session_task(iscsi_session_t *session, iscsi_task_t *task){ /* remove the task from the session's arrival_order collection */ if (task == session->arrival_order.head) { if ((session->arrival_order.head = task->order_next)) session->arrival_order.head->order_prev = NULL; else session->arrival_order.tail = NULL; } else if (task == session->arrival_order.tail) { session->arrival_order.tail = task->order_prev; session->arrival_order.tail->order_next = NULL; } else { /* we should always be in the middle,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -