diff options
author | Andy Grover <agrover@redhat.com> | 2011-07-20 15:13:28 -0400 |
---|---|---|
committer | Nicholas Bellinger <nab@linux-iscsi.org> | 2011-07-22 05:37:48 -0400 |
commit | 05d1c7c0d0db4cc25548d9aadebb416888a82327 (patch) | |
tree | 290243526d188a7f6a683b0e13a63c7207471fa1 /drivers/target/tcm_fc | |
parent | e22a7f075226c51f3f71b922e9eeb4f99fac1475 (diff) |
target: Make all control CDBs scatter-gather
Previously, some control CDBs did not allocate memory in pages for their
data buffer, but just did a kmalloc. This patch makes all cdbs allocate
pages.
This has the benefit of streamlining some paths that had to behave
differently when we used two allocation methods. The downside is that
all accesses to the data buffer need to kmap it before use, and need to
handle data in page-sized chunks if more than a page is needed for a given
command's data buffer.
Finally, note that cdbs with no data buffers are handled a little
differently. Before, SCSI_NON_DATA_CDBs would not call get_mem at all
(they'd be in the final else in transport_allocate_resources) but now
these will make it into generic_get_mem, but just not allocate any
buffers.
Signed-off-by: Andy Grover <agrover@redhat.com>
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
Diffstat (limited to 'drivers/target/tcm_fc')
-rw-r--r-- | drivers/target/tcm_fc/tfc_cmd.c | 4 | ||||
-rw-r--r-- | drivers/target/tcm_fc/tfc_io.c | 61 |
2 files changed, 19 insertions, 46 deletions
diff --git a/drivers/target/tcm_fc/tfc_cmd.c b/drivers/target/tcm_fc/tfc_cmd.c index a00951c80324..1017f56bbbcc 100644 --- a/drivers/target/tcm_fc/tfc_cmd.c +++ b/drivers/target/tcm_fc/tfc_cmd.c | |||
@@ -71,9 +71,9 @@ void ft_dump_cmd(struct ft_cmd *cmd, const char *caller) | |||
71 | caller, cmd, cmd->cdb); | 71 | caller, cmd, cmd->cdb); |
72 | printk(KERN_INFO "%s: cmd %p lun %d\n", caller, cmd, cmd->lun); | 72 | printk(KERN_INFO "%s: cmd %p lun %d\n", caller, cmd, cmd->lun); |
73 | 73 | ||
74 | printk(KERN_INFO "%s: cmd %p se_num %u buf %p len %u se_cmd_flags <0x%x>\n", | 74 | printk(KERN_INFO "%s: cmd %p se_num %u len %u se_cmd_flags <0x%x>\n", |
75 | caller, cmd, se_cmd->t_tasks_se_num, | 75 | caller, cmd, se_cmd->t_tasks_se_num, |
76 | se_cmd->t_task_buf, se_cmd->data_length, se_cmd->se_cmd_flags); | 76 | se_cmd->data_length, se_cmd->se_cmd_flags); |
77 | 77 | ||
78 | list_for_each_entry(mem, &se_cmd->t_mem_list, se_list) | 78 | list_for_each_entry(mem, &se_cmd->t_mem_list, se_list) |
79 | printk(KERN_INFO "%s: cmd %p mem %p page %p " | 79 | printk(KERN_INFO "%s: cmd %p mem %p page %p " |
diff --git a/drivers/target/tcm_fc/tfc_io.c b/drivers/target/tcm_fc/tfc_io.c index 8560182f0dad..837660728563 100644 --- a/drivers/target/tcm_fc/tfc_io.c +++ b/drivers/target/tcm_fc/tfc_io.c | |||
@@ -92,19 +92,15 @@ int ft_queue_data_in(struct se_cmd *se_cmd) | |||
92 | remaining = se_cmd->data_length; | 92 | remaining = se_cmd->data_length; |
93 | 93 | ||
94 | /* | 94 | /* |
95 | * Setup to use first mem list entry if any. | 95 | * Setup to use first mem list entry, unless no data. |
96 | */ | 96 | */ |
97 | if (se_cmd->t_tasks_se_num) { | 97 | BUG_ON(remaining && list_empty(&se_cmd->t_mem_list)); |
98 | if (remaining) { | ||
98 | mem = list_first_entry(&se_cmd->t_mem_list, | 99 | mem = list_first_entry(&se_cmd->t_mem_list, |
99 | struct se_mem, se_list); | 100 | struct se_mem, se_list); |
100 | mem_len = mem->se_len; | 101 | mem_len = mem->se_len; |
101 | mem_off = mem->se_off; | 102 | mem_off = mem->se_off; |
102 | page = mem->se_page; | 103 | page = mem->se_page; |
103 | } else { | ||
104 | mem = NULL; | ||
105 | mem_len = remaining; | ||
106 | mem_off = 0; | ||
107 | page = NULL; | ||
108 | } | 104 | } |
109 | 105 | ||
110 | /* no scatter/gather in skb for odd word length due to fc_seq_send() */ | 106 | /* no scatter/gather in skb for odd word length due to fc_seq_send() */ |
@@ -145,18 +141,7 @@ int ft_queue_data_in(struct se_cmd *se_cmd) | |||
145 | tlen = min(mem_len, frame_len); | 141 | tlen = min(mem_len, frame_len); |
146 | 142 | ||
147 | if (use_sg) { | 143 | if (use_sg) { |
148 | if (!mem) { | 144 | off_in_page = mem_off; |
149 | BUG_ON(!se_cmd->t_task_buf); | ||
150 | page_addr = se_cmd->t_task_buf + mem_off; | ||
151 | /* | ||
152 | * In this case, offset is 'offset_in_page' of | ||
153 | * (t_task_buf + mem_off) instead of 'mem_off'. | ||
154 | */ | ||
155 | off_in_page = offset_in_page(page_addr); | ||
156 | page = virt_to_page(page_addr); | ||
157 | tlen = min(tlen, PAGE_SIZE - off_in_page); | ||
158 | } else | ||
159 | off_in_page = mem_off; | ||
160 | BUG_ON(!page); | 145 | BUG_ON(!page); |
161 | get_page(page); | 146 | get_page(page); |
162 | skb_fill_page_desc(fp_skb(fp), | 147 | skb_fill_page_desc(fp_skb(fp), |
@@ -166,7 +151,7 @@ int ft_queue_data_in(struct se_cmd *se_cmd) | |||
166 | fp_skb(fp)->data_len += tlen; | 151 | fp_skb(fp)->data_len += tlen; |
167 | fp_skb(fp)->truesize += | 152 | fp_skb(fp)->truesize += |
168 | PAGE_SIZE << compound_order(page); | 153 | PAGE_SIZE << compound_order(page); |
169 | } else if (mem) { | 154 | } else { |
170 | BUG_ON(!page); | 155 | BUG_ON(!page); |
171 | from = kmap_atomic(page + (mem_off >> PAGE_SHIFT), | 156 | from = kmap_atomic(page + (mem_off >> PAGE_SHIFT), |
172 | KM_SOFTIRQ0); | 157 | KM_SOFTIRQ0); |
@@ -177,10 +162,6 @@ int ft_queue_data_in(struct se_cmd *se_cmd) | |||
177 | memcpy(to, from, tlen); | 162 | memcpy(to, from, tlen); |
178 | kunmap_atomic(page_addr, KM_SOFTIRQ0); | 163 | kunmap_atomic(page_addr, KM_SOFTIRQ0); |
179 | to += tlen; | 164 | to += tlen; |
180 | } else { | ||
181 | from = se_cmd->t_task_buf + mem_off; | ||
182 | memcpy(to, from, tlen); | ||
183 | to += tlen; | ||
184 | } | 165 | } |
185 | 166 | ||
186 | mem_off += tlen; | 167 | mem_off += tlen; |
@@ -305,19 +286,15 @@ void ft_recv_write_data(struct ft_cmd *cmd, struct fc_frame *fp) | |||
305 | frame_len = se_cmd->data_length - rel_off; | 286 | frame_len = se_cmd->data_length - rel_off; |
306 | 287 | ||
307 | /* | 288 | /* |
308 | * Setup to use first mem list entry if any. | 289 | * Setup to use first mem list entry, unless no data. |
309 | */ | 290 | */ |
310 | if (se_cmd->t_tasks_se_num) { | 291 | BUG_ON(frame_len && list_empty(&se_cmd->t_mem_list)); |
292 | if (frame_len) { | ||
311 | mem = list_first_entry(&se_cmd->t_mem_list, | 293 | mem = list_first_entry(&se_cmd->t_mem_list, |
312 | struct se_mem, se_list); | 294 | struct se_mem, se_list); |
313 | mem_len = mem->se_len; | 295 | mem_len = mem->se_len; |
314 | mem_off = mem->se_off; | 296 | mem_off = mem->se_off; |
315 | page = mem->se_page; | 297 | page = mem->se_page; |
316 | } else { | ||
317 | mem = NULL; | ||
318 | page = NULL; | ||
319 | mem_off = 0; | ||
320 | mem_len = frame_len; | ||
321 | } | 298 | } |
322 | 299 | ||
323 | while (frame_len) { | 300 | while (frame_len) { |
@@ -340,19 +317,15 @@ void ft_recv_write_data(struct ft_cmd *cmd, struct fc_frame *fp) | |||
340 | 317 | ||
341 | tlen = min(mem_len, frame_len); | 318 | tlen = min(mem_len, frame_len); |
342 | 319 | ||
343 | if (mem) { | 320 | to = kmap_atomic(page + (mem_off >> PAGE_SHIFT), |
344 | to = kmap_atomic(page + (mem_off >> PAGE_SHIFT), | 321 | KM_SOFTIRQ0); |
345 | KM_SOFTIRQ0); | 322 | page_addr = to; |
346 | page_addr = to; | 323 | to += mem_off & ~PAGE_MASK; |
347 | to += mem_off & ~PAGE_MASK; | 324 | tlen = min(tlen, (size_t)(PAGE_SIZE - |
348 | tlen = min(tlen, (size_t)(PAGE_SIZE - | 325 | (mem_off & ~PAGE_MASK))); |
349 | (mem_off & ~PAGE_MASK))); | 326 | memcpy(to, from, tlen); |
350 | memcpy(to, from, tlen); | 327 | kunmap_atomic(page_addr, KM_SOFTIRQ0); |
351 | kunmap_atomic(page_addr, KM_SOFTIRQ0); | 328 | |
352 | } else { | ||
353 | to = se_cmd->t_task_buf + mem_off; | ||
354 | memcpy(to, from, tlen); | ||
355 | } | ||
356 | from += tlen; | 329 | from += tlen; |
357 | frame_len -= tlen; | 330 | frame_len -= tlen; |
358 | mem_off += tlen; | 331 | mem_off += tlen; |