diff options
author | Christoph Hellwig <hch@infradead.org> | 2011-10-18 14:57:03 +0400 |
---|---|---|
committer | Nicholas Bellinger <nab@linux-iscsi.org> | 2011-10-24 07:22:04 +0400 |
commit | af3f00c75949369d937f499f49118e879939724d (patch) | |
tree | 97be6b877cd80489eb055ccf1dd0bdb5e8c3f526 | |
parent | 9ac549873d35626cd6d7718691aaf4c55f2667a7 (diff) | |
download | linux-af3f00c75949369d937f499f49118e879939724d.tar.xz |
target: re-use the command S/G list for single-task commands
If we only have a single task per command (which at least in my testing
is the by far most common case) we do not have to allocate a new per-task
S/G list but can reuse the one from the command.
(nab: Fix BIDI handling in transport_free_dev_tasks)
Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
-rw-r--r-- | drivers/target/target_core_transport.c | 42 |
1 files changed, 31 insertions, 11 deletions
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index ab4e3083d968..ac048db21240 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -3551,7 +3551,9 @@ static void transport_free_dev_tasks(struct se_cmd *cmd) */ del_timer_sync(&task->task_timer); - kfree(task->task_sg); + if (task->task_sg != cmd->t_data_sg && + task->task_sg != cmd->t_bidi_data_sg) + kfree(task->task_sg); list_del(&task->t_list); @@ -3830,7 +3832,33 @@ transport_allocate_data_tasks(struct se_cmd *cmd, lba = cmd->t_task_lba; sectors = DIV_ROUND_UP(cmd->data_length, sector_size); task_count = DIV_ROUND_UP_SECTOR_T(sectors, dev_max_sectors); - + + /* + * If we need just a single task reuse the SG list in the command + * and avoid a lot of work. + */ + if (task_count == 1) { + struct se_task *task; + unsigned long flags; + + task = transport_generic_get_task(cmd, data_direction); + if (!task) + return -ENOMEM; + + task->task_sg = cmd_sg; + task->task_sg_nents = sgl_nents; + + task->task_lba = lba; + task->task_sectors = sectors; + task->task_size = task->task_sectors * sector_size; + + spin_lock_irqsave(&cmd->t_state_lock, flags); + list_add_tail(&task->t_list, &cmd->t_task_list); + spin_unlock_irqrestore(&cmd->t_state_lock, flags); + + return task_count; + } + for (i = 0; i < task_count; i++) { struct se_task *task; unsigned int task_size, task_sg_nents_padded; @@ -3906,15 +3934,7 @@ transport_allocate_control_task(struct se_cmd *cmd) if (!task) return -ENOMEM; - task->task_sg = kmalloc(sizeof(struct scatterlist) * cmd->t_data_nents, - GFP_KERNEL); - if (!task->task_sg) { - cmd->se_dev->transport->free_task(task); - return -ENOMEM; - } - - memcpy(task->task_sg, cmd->t_data_sg, - sizeof(struct scatterlist) * cmd->t_data_nents); + task->task_sg = cmd->t_data_sg; task->task_size = cmd->data_length; task->task_sg_nents = cmd->t_data_nents; |