target: Eliminate usage of struct se_mem
Both backstores and fabrics use arrays of struct scatterlist to describe data buffers. However TCM used struct se_mems, basically a linked list of scatterlist entries. We are able to simplify the code by eliminating this intermediate data structure and just using struct scatterlist[] throughout. Also, moved attachment of task to cmd out of transport_generic_get_task and into allocate_control_task and allocate_data_tasks. The reasoning is that it's nonintuitive that get_task should automatically add it to the cmd's task list -- it should just return an allocated, initialized task. That's all it should do, based on the function's name, so either the function shouldn't do it, or the name should change to encapsulate the entire essence of what it does. (nab: Fix compile warnings in tcm_fc, and make transport_kmap_first_data_page honor sg->offset for SGLs from contigious memory with TCM_Loop, and fix control se_cmd descriptor memory leak) Signed-off-by: Andy Grover <agrover@redhat.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
This commit is contained in:
parent
3a86720567
commit
ec98f7825c
@ -175,10 +175,7 @@ static int tcm_loop_new_cmd_map(struct se_cmd *se_cmd)
|
|||||||
sgl_bidi_count = sdb->table.nents;
|
sgl_bidi_count = sdb->table.nents;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* Tell the core about our preallocated memory */
|
||||||
* Map the SG memory into struct se_mem->page linked list using the same
|
|
||||||
* physical memory at sg->page_link.
|
|
||||||
*/
|
|
||||||
ret = transport_generic_map_mem_to_cmd(se_cmd, scsi_sglist(sc),
|
ret = transport_generic_map_mem_to_cmd(se_cmd, scsi_sglist(sc),
|
||||||
scsi_sg_count(sc), sgl_bidi, sgl_bidi_count);
|
scsi_sg_count(sc), sgl_bidi, sgl_bidi_count);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
|
@ -634,7 +634,7 @@ static int iblock_map_task_SG(struct se_task *task)
|
|||||||
hbio = tbio = bio;
|
hbio = tbio = bio;
|
||||||
/*
|
/*
|
||||||
* Use fs/bio.c:bio_add_pages() to setup the bio_vec maplist
|
* Use fs/bio.c:bio_add_pages() to setup the bio_vec maplist
|
||||||
* from TCM struct se_mem -> task->task_sg -> struct scatterlist memory.
|
* from task->task_sg -> struct scatterlist memory.
|
||||||
*/
|
*/
|
||||||
for_each_sg(task->task_sg, sg, task->task_sg_num, i) {
|
for_each_sg(task->task_sg, sg, task->task_sg_num, i) {
|
||||||
DEBUG_IBLOCK("task: %p bio: %p Calling bio_add_page(): page:"
|
DEBUG_IBLOCK("task: %p bio: %p Calling bio_add_page(): page:"
|
||||||
|
@ -1097,7 +1097,7 @@ static int __pscsi_map_task_SG(
|
|||||||
return 0;
|
return 0;
|
||||||
/*
|
/*
|
||||||
* For SCF_SCSI_DATA_SG_IO_CDB, Use fs/bio.c:bio_add_page() to setup
|
* For SCF_SCSI_DATA_SG_IO_CDB, Use fs/bio.c:bio_add_page() to setup
|
||||||
* the bio_vec maplist from TC< struct se_mem -> task->task_sg ->
|
* the bio_vec maplist from task->task_sg ->
|
||||||
* struct scatterlist memory. The struct se_task->task_sg[] currently needs
|
* struct scatterlist memory. The struct se_task->task_sg[] currently needs
|
||||||
* to be attached to struct bios for submission to Linux/SCSI using
|
* to be attached to struct bios for submission to Linux/SCSI using
|
||||||
* struct request to struct scsi_device->request_queue.
|
* struct request to struct scsi_device->request_queue.
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -59,7 +59,8 @@ void ft_dump_cmd(struct ft_cmd *cmd, const char *caller)
|
|||||||
struct fc_exch *ep;
|
struct fc_exch *ep;
|
||||||
struct fc_seq *sp;
|
struct fc_seq *sp;
|
||||||
struct se_cmd *se_cmd;
|
struct se_cmd *se_cmd;
|
||||||
struct se_mem *mem;
|
struct scatterlist *sg;
|
||||||
|
int count;
|
||||||
|
|
||||||
if (!(ft_debug_logging & FT_DEBUG_IO))
|
if (!(ft_debug_logging & FT_DEBUG_IO))
|
||||||
return;
|
return;
|
||||||
@ -71,15 +72,16 @@ void ft_dump_cmd(struct ft_cmd *cmd, const char *caller)
|
|||||||
caller, cmd, cmd->cdb);
|
caller, cmd, cmd->cdb);
|
||||||
printk(KERN_INFO "%s: cmd %p lun %d\n", caller, cmd, cmd->lun);
|
printk(KERN_INFO "%s: cmd %p lun %d\n", caller, cmd, cmd->lun);
|
||||||
|
|
||||||
printk(KERN_INFO "%s: cmd %p se_num %u len %u se_cmd_flags <0x%x>\n",
|
printk(KERN_INFO "%s: cmd %p data_nents %u len %u se_cmd_flags <0x%x>\n",
|
||||||
caller, cmd, se_cmd->t_tasks_se_num,
|
caller, cmd, se_cmd->t_data_nents,
|
||||||
se_cmd->data_length, se_cmd->se_cmd_flags);
|
se_cmd->data_length, se_cmd->se_cmd_flags);
|
||||||
|
|
||||||
list_for_each_entry(mem, &se_cmd->t_mem_list, se_list)
|
for_each_sg(se_cmd->t_data_sg, sg, se_cmd->t_data_nents, count)
|
||||||
printk(KERN_INFO "%s: cmd %p mem %p page %p "
|
printk(KERN_INFO "%s: cmd %p sg %p page %p "
|
||||||
"len 0x%x off 0x%x\n",
|
"len 0x%x off 0x%x\n",
|
||||||
caller, cmd, mem,
|
caller, cmd, sg,
|
||||||
mem->se_page, mem->se_len, mem->se_off);
|
sg_page(sg), sg->length, sg->offset);
|
||||||
|
|
||||||
sp = cmd->seq;
|
sp = cmd->seq;
|
||||||
if (sp) {
|
if (sp) {
|
||||||
ep = fc_seq_exch(sp);
|
ep = fc_seq_exch(sp);
|
||||||
@ -256,10 +258,9 @@ int ft_write_pending(struct se_cmd *se_cmd)
|
|||||||
(fh->fh_r_ctl == FC_RCTL_DD_DATA_DESC)) {
|
(fh->fh_r_ctl == FC_RCTL_DD_DATA_DESC)) {
|
||||||
if (se_cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB) {
|
if (se_cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB) {
|
||||||
/*
|
/*
|
||||||
* Map se_mem list to scatterlist, so that
|
* cmd may have been broken up into multiple
|
||||||
* DDP can be setup. DDP setup function require
|
* tasks. Link their sgs together so we can
|
||||||
* scatterlist. se_mem_list is internal to
|
* operate on them all at once.
|
||||||
* TCM/LIO target
|
|
||||||
*/
|
*/
|
||||||
transport_do_task_sg_chain(se_cmd);
|
transport_do_task_sg_chain(se_cmd);
|
||||||
cmd->sg = se_cmd->t_tasks_sg_chained;
|
cmd->sg = se_cmd->t_tasks_sg_chained;
|
||||||
|
@ -68,17 +68,17 @@ int ft_queue_data_in(struct se_cmd *se_cmd)
|
|||||||
struct fc_frame *fp = NULL;
|
struct fc_frame *fp = NULL;
|
||||||
struct fc_exch *ep;
|
struct fc_exch *ep;
|
||||||
struct fc_lport *lport;
|
struct fc_lport *lport;
|
||||||
struct se_mem *mem;
|
struct scatterlist *sg = NULL;
|
||||||
size_t remaining;
|
size_t remaining;
|
||||||
u32 f_ctl = FC_FC_EX_CTX | FC_FC_REL_OFF;
|
u32 f_ctl = FC_FC_EX_CTX | FC_FC_REL_OFF;
|
||||||
u32 mem_off;
|
u32 mem_off = 0;
|
||||||
u32 fh_off = 0;
|
u32 fh_off = 0;
|
||||||
u32 frame_off = 0;
|
u32 frame_off = 0;
|
||||||
size_t frame_len = 0;
|
size_t frame_len = 0;
|
||||||
size_t mem_len;
|
size_t mem_len = 0;
|
||||||
size_t tlen;
|
size_t tlen;
|
||||||
size_t off_in_page;
|
size_t off_in_page;
|
||||||
struct page *page;
|
struct page *page = NULL;
|
||||||
int use_sg;
|
int use_sg;
|
||||||
int error;
|
int error;
|
||||||
void *page_addr;
|
void *page_addr;
|
||||||
@ -94,13 +94,12 @@ int ft_queue_data_in(struct se_cmd *se_cmd)
|
|||||||
/*
|
/*
|
||||||
* Setup to use first mem list entry, unless no data.
|
* Setup to use first mem list entry, unless no data.
|
||||||
*/
|
*/
|
||||||
BUG_ON(remaining && list_empty(&se_cmd->t_mem_list));
|
BUG_ON(remaining && !se_cmd->t_data_sg);
|
||||||
if (remaining) {
|
if (remaining) {
|
||||||
mem = list_first_entry(&se_cmd->t_mem_list,
|
sg = se_cmd->t_data_sg;
|
||||||
struct se_mem, se_list);
|
mem_len = sg->length;
|
||||||
mem_len = mem->se_len;
|
mem_off = sg->offset;
|
||||||
mem_off = mem->se_off;
|
page = sg_page(sg);
|
||||||
page = mem->se_page;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* no scatter/gather in skb for odd word length due to fc_seq_send() */
|
/* no scatter/gather in skb for odd word length due to fc_seq_send() */
|
||||||
@ -108,12 +107,10 @@ int ft_queue_data_in(struct se_cmd *se_cmd)
|
|||||||
|
|
||||||
while (remaining) {
|
while (remaining) {
|
||||||
if (!mem_len) {
|
if (!mem_len) {
|
||||||
BUG_ON(!mem);
|
sg = sg_next(sg);
|
||||||
mem = list_entry(mem->se_list.next,
|
mem_len = min((size_t)sg->length, remaining);
|
||||||
struct se_mem, se_list);
|
mem_off = sg->offset;
|
||||||
mem_len = min((size_t)mem->se_len, remaining);
|
page = sg_page(sg);
|
||||||
mem_off = mem->se_off;
|
|
||||||
page = mem->se_page;
|
|
||||||
}
|
}
|
||||||
if (!frame_len) {
|
if (!frame_len) {
|
||||||
/*
|
/*
|
||||||
@ -200,13 +197,13 @@ void ft_recv_write_data(struct ft_cmd *cmd, struct fc_frame *fp)
|
|||||||
struct fc_exch *ep;
|
struct fc_exch *ep;
|
||||||
struct fc_lport *lport;
|
struct fc_lport *lport;
|
||||||
struct fc_frame_header *fh;
|
struct fc_frame_header *fh;
|
||||||
struct se_mem *mem;
|
struct scatterlist *sg = NULL;
|
||||||
u32 mem_off;
|
u32 mem_off = 0;
|
||||||
u32 rel_off;
|
u32 rel_off;
|
||||||
size_t frame_len;
|
size_t frame_len;
|
||||||
size_t mem_len;
|
size_t mem_len = 0;
|
||||||
size_t tlen;
|
size_t tlen;
|
||||||
struct page *page;
|
struct page *page = NULL;
|
||||||
void *page_addr;
|
void *page_addr;
|
||||||
void *from;
|
void *from;
|
||||||
void *to;
|
void *to;
|
||||||
@ -288,23 +285,20 @@ void ft_recv_write_data(struct ft_cmd *cmd, struct fc_frame *fp)
|
|||||||
/*
|
/*
|
||||||
* Setup to use first mem list entry, unless no data.
|
* Setup to use first mem list entry, unless no data.
|
||||||
*/
|
*/
|
||||||
BUG_ON(frame_len && list_empty(&se_cmd->t_mem_list));
|
BUG_ON(frame_len && !se_cmd->t_data_sg);
|
||||||
if (frame_len) {
|
if (frame_len) {
|
||||||
mem = list_first_entry(&se_cmd->t_mem_list,
|
sg = se_cmd->t_data_sg;
|
||||||
struct se_mem, se_list);
|
mem_len = sg->length;
|
||||||
mem_len = mem->se_len;
|
mem_off = sg->offset;
|
||||||
mem_off = mem->se_off;
|
page = sg_page(sg);
|
||||||
page = mem->se_page;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
while (frame_len) {
|
while (frame_len) {
|
||||||
if (!mem_len) {
|
if (!mem_len) {
|
||||||
BUG_ON(!mem);
|
sg = sg_next(sg);
|
||||||
mem = list_entry(mem->se_list.next,
|
mem_len = sg->length;
|
||||||
struct se_mem, se_list);
|
mem_off = sg->offset;
|
||||||
mem_len = mem->se_len;
|
page = sg_page(sg);
|
||||||
mem_off = mem->se_off;
|
|
||||||
page = mem->se_page;
|
|
||||||
}
|
}
|
||||||
if (rel_off >= mem_len) {
|
if (rel_off >= mem_len) {
|
||||||
rel_off -= mem_len;
|
rel_off -= mem_len;
|
||||||
|
@ -490,8 +490,6 @@ struct se_cmd {
|
|||||||
int t_tasks_failed;
|
int t_tasks_failed;
|
||||||
int t_tasks_fua;
|
int t_tasks_fua;
|
||||||
bool t_tasks_bidi;
|
bool t_tasks_bidi;
|
||||||
u32 t_tasks_se_num;
|
|
||||||
u32 t_tasks_se_bidi_num;
|
|
||||||
u32 t_tasks_sg_chained_no;
|
u32 t_tasks_sg_chained_no;
|
||||||
atomic_t t_fe_count;
|
atomic_t t_fe_count;
|
||||||
atomic_t t_se_count;
|
atomic_t t_se_count;
|
||||||
@ -523,9 +521,13 @@ struct se_cmd {
|
|||||||
*/
|
*/
|
||||||
struct scatterlist *t_task_pt_sgl;
|
struct scatterlist *t_task_pt_sgl;
|
||||||
u32 t_task_pt_sgl_num;
|
u32 t_task_pt_sgl_num;
|
||||||
struct list_head t_mem_list;
|
|
||||||
|
struct scatterlist *t_data_sg;
|
||||||
|
unsigned int t_data_nents;
|
||||||
|
struct scatterlist *t_bidi_data_sg;
|
||||||
|
unsigned int t_bidi_data_nents;
|
||||||
|
|
||||||
/* Used for BIDI READ */
|
/* Used for BIDI READ */
|
||||||
struct list_head t_mem_bidi_list;
|
|
||||||
struct list_head t_task_list;
|
struct list_head t_task_list;
|
||||||
u32 t_task_list_num;
|
u32 t_task_list_num;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user