aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSheng Yang <sheng@yasker.org>2016-02-26 17:59:57 -0500
committerNicholas Bellinger <nab@linux-iscsi.org>2016-03-11 00:49:02 -0500
commit26418649eead52619d8dd6cbc6760a1b144dbcd2 (patch)
tree89baa8edf0b0f25f1a2c19a113ce064848e1e72b
parent0c28481ffb4683ef21c6664d15dbd5ae5a6cd027 (diff)
target/user: Introduce data_bitmap, replace data_length/data_head/data_tail
The data_bitmap was introduced to support asynchornization accessing of data area. We divide mailbox data area into blocks, and use data_bitmap to track the usage of data area. All the new command's data would start with a new block, and may left unusable space after it end. But it's easy to track using data_bitmap. Now we can allocate data area for asynchronization accessing from userspace, since we can track the allocation using data_bitmap. The userspace part would be the same as Maxim's previous asynchronized implementation. Signed-off-by: Sheng Yang <sheng@yasker.org> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
-rw-r--r--drivers/target/target_core_user.c221
1 files changed, 121 insertions, 100 deletions
diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c
index baa8720ab24f..b1539f357429 100644
--- a/drivers/target/target_core_user.c
+++ b/drivers/target/target_core_user.c
@@ -26,6 +26,7 @@
26#include <linux/vmalloc.h> 26#include <linux/vmalloc.h>
27#include <linux/uio_driver.h> 27#include <linux/uio_driver.h>
28#include <linux/stringify.h> 28#include <linux/stringify.h>
29#include <linux/bitops.h>
29#include <net/genetlink.h> 30#include <net/genetlink.h>
30#include <scsi/scsi_common.h> 31#include <scsi/scsi_common.h>
31#include <scsi/scsi_proto.h> 32#include <scsi/scsi_proto.h>
@@ -63,8 +64,11 @@
63 64
64#define TCMU_TIME_OUT (30 * MSEC_PER_SEC) 65#define TCMU_TIME_OUT (30 * MSEC_PER_SEC)
65 66
67#define DATA_BLOCK_BITS 256
68#define DATA_BLOCK_SIZE 4096
69
66#define CMDR_SIZE (16 * 4096) 70#define CMDR_SIZE (16 * 4096)
67#define DATA_SIZE (257 * 4096) 71#define DATA_SIZE (DATA_BLOCK_BITS * DATA_BLOCK_SIZE)
68 72
69#define TCMU_RING_SIZE (CMDR_SIZE + DATA_SIZE) 73#define TCMU_RING_SIZE (CMDR_SIZE + DATA_SIZE)
70 74
@@ -93,12 +97,11 @@ struct tcmu_dev {
93 u32 cmdr_size; 97 u32 cmdr_size;
94 u32 cmdr_last_cleaned; 98 u32 cmdr_last_cleaned;
95 /* Offset of data ring from start of mb */ 99 /* Offset of data ring from start of mb */
100 /* Must add data_off and mb_addr to get the address */
96 size_t data_off; 101 size_t data_off;
97 size_t data_size; 102 size_t data_size;
98 /* Ring head + tail values. */ 103
99 /* Must add data_off and mb_addr to get the address */ 104 DECLARE_BITMAP(data_bitmap, DATA_BLOCK_BITS);
100 size_t data_head;
101 size_t data_tail;
102 105
103 wait_queue_head_t wait_cmdr; 106 wait_queue_head_t wait_cmdr;
104 /* TODO should this be a mutex? */ 107 /* TODO should this be a mutex? */
@@ -122,9 +125,9 @@ struct tcmu_cmd {
122 125
123 uint16_t cmd_id; 126 uint16_t cmd_id;
124 127
125 /* Can't use se_cmd->data_length when cleaning up expired cmds, because if 128 /* Can't use se_cmd when cleaning up expired cmds, because if
126 cmd has been completed then accessing se_cmd is off limits */ 129 cmd has been completed then accessing se_cmd is off limits */
127 size_t data_length; 130 DECLARE_BITMAP(data_bitmap, DATA_BLOCK_BITS);
128 131
129 unsigned long deadline; 132 unsigned long deadline;
130 133
@@ -168,13 +171,6 @@ static struct tcmu_cmd *tcmu_alloc_cmd(struct se_cmd *se_cmd)
168 171
169 tcmu_cmd->se_cmd = se_cmd; 172 tcmu_cmd->se_cmd = se_cmd;
170 tcmu_cmd->tcmu_dev = udev; 173 tcmu_cmd->tcmu_dev = udev;
171 tcmu_cmd->data_length = se_cmd->data_length;
172
173 if (se_cmd->se_cmd_flags & SCF_BIDI) {
174 BUG_ON(!(se_cmd->t_bidi_data_sg && se_cmd->t_bidi_data_nents));
175 tcmu_cmd->data_length += se_cmd->t_bidi_data_sg->length;
176 }
177
178 tcmu_cmd->deadline = jiffies + msecs_to_jiffies(TCMU_TIME_OUT); 174 tcmu_cmd->deadline = jiffies + msecs_to_jiffies(TCMU_TIME_OUT);
179 175
180 idr_preload(GFP_KERNEL); 176 idr_preload(GFP_KERNEL);
@@ -242,111 +238,115 @@ static inline void new_iov(struct iovec **iov, int *iov_cnt,
242 238
243 iovec = *iov; 239 iovec = *iov;
244 memset(iovec, 0, sizeof(struct iovec)); 240 memset(iovec, 0, sizeof(struct iovec));
245
246 /* Even iov_base is relative to mb_addr */
247 iovec->iov_base = (void __user *) udev->data_off +
248 udev->data_head;
249} 241}
250 242
251#define UPDATE_HEAD(head, used, size) smp_store_release(&head, ((head % size) + used) % size) 243#define UPDATE_HEAD(head, used, size) smp_store_release(&head, ((head % size) + used) % size)
252 244
245/* offset is relative to mb_addr */
246static inline size_t get_block_offset(struct tcmu_dev *dev,
247 int block, int remaining)
248{
249 return dev->data_off + block * DATA_BLOCK_SIZE +
250 DATA_BLOCK_SIZE - remaining;
251}
252
253static inline size_t iov_tail(struct tcmu_dev *udev, struct iovec *iov)
254{
255 return (size_t)iov->iov_base + iov->iov_len;
256}
257
253static void alloc_and_scatter_data_area(struct tcmu_dev *udev, 258static void alloc_and_scatter_data_area(struct tcmu_dev *udev,
254 struct scatterlist *data_sg, unsigned int data_nents, 259 struct scatterlist *data_sg, unsigned int data_nents,
255 struct iovec **iov, int *iov_cnt, bool copy_data) 260 struct iovec **iov, int *iov_cnt, bool copy_data)
256{ 261{
257 int i; 262 int i, block;
263 int block_remaining = 0;
258 void *from, *to; 264 void *from, *to;
259 size_t copy_bytes; 265 size_t copy_bytes, to_offset;
260 struct scatterlist *sg; 266 struct scatterlist *sg;
261 267
262 if (data_nents == 0)
263 return;
264
265 new_iov(iov, iov_cnt, udev);
266 for_each_sg(data_sg, sg, data_nents, i) { 268 for_each_sg(data_sg, sg, data_nents, i) {
267 copy_bytes = min_t(size_t, sg->length, 269 int sg_remaining = sg->length;
268 head_to_end(udev->data_head, udev->data_size));
269 from = kmap_atomic(sg_page(sg)) + sg->offset; 270 from = kmap_atomic(sg_page(sg)) + sg->offset;
270 to = (void *) udev->mb_addr + udev->data_off + udev->data_head; 271 while (sg_remaining > 0) {
271 272 if (block_remaining == 0) {
272 if (copy_data) { 273 block = find_first_zero_bit(udev->data_bitmap,
273 memcpy(to, from, copy_bytes); 274 DATA_BLOCK_BITS);
274 tcmu_flush_dcache_range(to, copy_bytes); 275 block_remaining = DATA_BLOCK_SIZE;
275 } 276 set_bit(block, udev->data_bitmap);
276 277 }
277 (*iov)->iov_len += copy_bytes; 278 copy_bytes = min_t(size_t, sg_remaining,
278 279 block_remaining);
279 UPDATE_HEAD(udev->data_head, copy_bytes, udev->data_size); 280 to_offset = get_block_offset(udev, block,
280 281 block_remaining);
281 /* Uh oh, we wrapped the buffer. Must split sg across 2 iovs. */ 282 to = (void *)udev->mb_addr + to_offset;
282 if (sg->length != copy_bytes) { 283 if (*iov_cnt != 0 &&
283 void *from_skip = from + copy_bytes; 284 to_offset == iov_tail(udev, *iov)) {
284 285 (*iov)->iov_len += copy_bytes;
285 copy_bytes = sg->length - copy_bytes; 286 } else {
286 287 new_iov(iov, iov_cnt, udev);
287 new_iov(iov, iov_cnt, udev); 288 (*iov)->iov_base = (void __user *) to_offset;
288 (*iov)->iov_len = copy_bytes; 289 (*iov)->iov_len = copy_bytes;
289 290 }
290 if (copy_data) { 291 if (copy_data) {
291 to = (void *) udev->mb_addr + 292 memcpy(to, from + sg->length - sg_remaining,
292 udev->data_off + udev->data_head; 293 copy_bytes);
293 memcpy(to, from_skip, copy_bytes);
294 tcmu_flush_dcache_range(to, copy_bytes); 294 tcmu_flush_dcache_range(to, copy_bytes);
295 } 295 }
296 296 sg_remaining -= copy_bytes;
297 297 block_remaining -= copy_bytes;
298 UPDATE_HEAD(udev->data_head,
299 copy_bytes, udev->data_size);
300 } 298 }
301
302 kunmap_atomic(from - sg->offset); 299 kunmap_atomic(from - sg->offset);
303 } 300 }
304} 301}
305 302
306static void free_data_area(struct tcmu_dev *udev, size_t length) 303static void free_data_area(struct tcmu_dev *udev, struct tcmu_cmd *cmd)
307{ 304{
308 UPDATE_HEAD(udev->data_tail, length, udev->data_size); 305 bitmap_xor(udev->data_bitmap, udev->data_bitmap, cmd->data_bitmap,
306 DATA_BLOCK_BITS);
309} 307}
310 308
311static void gather_and_free_data_area(struct tcmu_dev *udev, 309static void gather_data_area(struct tcmu_dev *udev, unsigned long *cmd_bitmap,
312 struct scatterlist *data_sg, unsigned int data_nents) 310 struct scatterlist *data_sg, unsigned int data_nents)
313{ 311{
314 int i; 312 int i, block;
313 int block_remaining = 0;
315 void *from, *to; 314 void *from, *to;
316 size_t copy_bytes; 315 size_t copy_bytes, from_offset;
317 struct scatterlist *sg; 316 struct scatterlist *sg;
318 317
319 /* It'd be easier to look at entry's iovec again, but UAM */
320 for_each_sg(data_sg, sg, data_nents, i) { 318 for_each_sg(data_sg, sg, data_nents, i) {
321 copy_bytes = min_t(size_t, sg->length, 319 int sg_remaining = sg->length;
322 head_to_end(udev->data_tail, udev->data_size));
323
324 to = kmap_atomic(sg_page(sg)) + sg->offset; 320 to = kmap_atomic(sg_page(sg)) + sg->offset;
325 WARN_ON(sg->length + sg->offset > PAGE_SIZE); 321 while (sg_remaining > 0) {
326 from = (void *) udev->mb_addr + 322 if (block_remaining == 0) {
327 udev->data_off + udev->data_tail; 323 block = find_first_bit(cmd_bitmap,
328 tcmu_flush_dcache_range(from, copy_bytes); 324 DATA_BLOCK_BITS);
329 memcpy(to, from, copy_bytes); 325 block_remaining = DATA_BLOCK_SIZE;
330 326 clear_bit(block, cmd_bitmap);
331 free_data_area(udev, copy_bytes); 327 }
332 328 copy_bytes = min_t(size_t, sg_remaining,
333 /* Uh oh, wrapped the data buffer for this sg's data */ 329 block_remaining);
334 if (sg->length != copy_bytes) { 330 from_offset = get_block_offset(udev, block,
335 void *to_skip = to + copy_bytes; 331 block_remaining);
336 332 from = (void *) udev->mb_addr + from_offset;
337 from = (void *) udev->mb_addr +
338 udev->data_off + udev->data_tail;
339 WARN_ON(udev->data_tail);
340 copy_bytes = sg->length - copy_bytes;
341 tcmu_flush_dcache_range(from, copy_bytes); 333 tcmu_flush_dcache_range(from, copy_bytes);
342 memcpy(to_skip, from, copy_bytes); 334 memcpy(to + sg->length - sg_remaining, from,
335 copy_bytes);
343 336
344 free_data_area(udev, copy_bytes); 337 sg_remaining -= copy_bytes;
338 block_remaining -= copy_bytes;
345 } 339 }
346 kunmap_atomic(to - sg->offset); 340 kunmap_atomic(to - sg->offset);
347 } 341 }
348} 342}
349 343
344static inline size_t spc_bitmap_free(unsigned long *bitmap)
345{
346 return DATA_BLOCK_SIZE * (DATA_BLOCK_BITS -
347 bitmap_weight(bitmap, DATA_BLOCK_BITS));
348}
349
350/* 350/*
351 * We can't queue a command until we have space available on the cmd ring *and* 351 * We can't queue a command until we have space available on the cmd ring *and*
352 * space available on the data ring. 352 * space available on the data ring.
@@ -380,10 +380,10 @@ static bool is_ring_space_avail(struct tcmu_dev *udev, size_t cmd_size, size_t d
380 return false; 380 return false;
381 } 381 }
382 382
383 space = spc_free(udev->data_head, udev->data_tail, udev->data_size); 383 space = spc_bitmap_free(udev->data_bitmap);
384 if (space < data_needed) { 384 if (space < data_needed) {
385 pr_debug("no data space: %zu %zu %zu\n", udev->data_head, 385 pr_debug("no data space: only %lu available, but ask for %lu\n",
386 udev->data_tail, udev->data_size); 386 space, data_needed);
387 return false; 387 return false;
388 } 388 }
389 389
@@ -402,6 +402,8 @@ static int tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd)
402 uint32_t cmd_head; 402 uint32_t cmd_head;
403 uint64_t cdb_off; 403 uint64_t cdb_off;
404 bool copy_to_data_area; 404 bool copy_to_data_area;
405 size_t data_length;
406 DECLARE_BITMAP(old_bitmap, DATA_BLOCK_BITS);
405 407
406 if (test_bit(TCMU_DEV_BIT_BROKEN, &udev->flags)) 408 if (test_bit(TCMU_DEV_BIT_BROKEN, &udev->flags))
407 return -EINVAL; 409 return -EINVAL;
@@ -410,10 +412,12 @@ static int tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd)
410 * Must be a certain minimum size for response sense info, but 412 * Must be a certain minimum size for response sense info, but
411 * also may be larger if the iov array is large. 413 * also may be larger if the iov array is large.
412 * 414 *
413 * 3 iovs since we can describe the whole continuous are using one 415 * We prepare way too many iovs for potential uses here, because it's
414 * for data, one for bidi and one more in the case of wrap. 416 * expensive to tell how many regions are freed in the bitmap
415 */ 417 */
416 base_command_size = max(offsetof(struct tcmu_cmd_entry, req.iov[3]), 418 base_command_size = max(offsetof(struct tcmu_cmd_entry,
419 req.iov[se_cmd->t_bidi_data_nents +
420 se_cmd->t_data_nents]),
417 sizeof(struct tcmu_cmd_entry)); 421 sizeof(struct tcmu_cmd_entry));
418 command_size = base_command_size 422 command_size = base_command_size
419 + round_up(scsi_command_size(se_cmd->t_task_cdb), TCMU_OP_ALIGN_SIZE); 423 + round_up(scsi_command_size(se_cmd->t_task_cdb), TCMU_OP_ALIGN_SIZE);
@@ -424,13 +428,18 @@ static int tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd)
424 428
425 mb = udev->mb_addr; 429 mb = udev->mb_addr;
426 cmd_head = mb->cmd_head % udev->cmdr_size; /* UAM */ 430 cmd_head = mb->cmd_head % udev->cmdr_size; /* UAM */
431 data_length = se_cmd->data_length;
432 if (se_cmd->se_cmd_flags & SCF_BIDI) {
433 BUG_ON(!(se_cmd->t_bidi_data_sg && se_cmd->t_bidi_data_nents));
434 data_length += se_cmd->t_bidi_data_sg->length;
435 }
427 if ((command_size > (udev->cmdr_size / 2)) 436 if ((command_size > (udev->cmdr_size / 2))
428 || tcmu_cmd->data_length > (udev->data_size - 1)) 437 || data_length > udev->data_size)
429 pr_warn("TCMU: Request of size %zu/%zu may be too big for %u/%zu " 438 pr_warn("TCMU: Request of size %zu/%zu may be too big for %u/%zu "
430 "cmd/data ring buffers\n", command_size, tcmu_cmd->data_length, 439 "cmd/data ring buffers\n", command_size, data_length,
431 udev->cmdr_size, udev->data_size); 440 udev->cmdr_size, udev->data_size);
432 441
433 while (!is_ring_space_avail(udev, command_size, tcmu_cmd->data_length)) { 442 while (!is_ring_space_avail(udev, command_size, data_length)) {
434 int ret; 443 int ret;
435 DEFINE_WAIT(__wait); 444 DEFINE_WAIT(__wait);
436 445
@@ -477,6 +486,8 @@ static int tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd)
477 entry->hdr.kflags = 0; 486 entry->hdr.kflags = 0;
478 entry->hdr.uflags = 0; 487 entry->hdr.uflags = 0;
479 488
489 bitmap_copy(old_bitmap, udev->data_bitmap, DATA_BLOCK_BITS);
490
480 /* 491 /*
481 * Fix up iovecs, and handle if allocation in data ring wrapped. 492 * Fix up iovecs, and handle if allocation in data ring wrapped.
482 */ 493 */
@@ -495,6 +506,10 @@ static int tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd)
495 se_cmd->t_bidi_data_nents, &iov, &iov_cnt, false); 506 se_cmd->t_bidi_data_nents, &iov, &iov_cnt, false);
496 entry->req.iov_bidi_cnt = iov_cnt; 507 entry->req.iov_bidi_cnt = iov_cnt;
497 508
509 /* cmd's data_bitmap is what changed in process */
510 bitmap_xor(tcmu_cmd->data_bitmap, old_bitmap, udev->data_bitmap,
511 DATA_BLOCK_BITS);
512
498 /* All offsets relative to mb_addr, not start of entry! */ 513 /* All offsets relative to mb_addr, not start of entry! */
499 cdb_off = CMDR_OFF + cmd_head + base_command_size; 514 cdb_off = CMDR_OFF + cmd_head + base_command_size;
500 memcpy((void *) mb + cdb_off, se_cmd->t_task_cdb, scsi_command_size(se_cmd->t_task_cdb)); 515 memcpy((void *) mb + cdb_off, se_cmd->t_task_cdb, scsi_command_size(se_cmd->t_task_cdb));
@@ -547,31 +562,36 @@ static void tcmu_handle_completion(struct tcmu_cmd *cmd, struct tcmu_cmd_entry *
547 if (test_bit(TCMU_CMD_BIT_EXPIRED, &cmd->flags)) { 562 if (test_bit(TCMU_CMD_BIT_EXPIRED, &cmd->flags)) {
548 /* cmd has been completed already from timeout, just reclaim data 563 /* cmd has been completed already from timeout, just reclaim data
549 ring space */ 564 ring space */
550 free_data_area(udev, cmd->data_length); 565 free_data_area(udev, cmd);
551 return; 566 return;
552 } 567 }
553 568
554 if (entry->hdr.uflags & TCMU_UFLAG_UNKNOWN_OP) { 569 if (entry->hdr.uflags & TCMU_UFLAG_UNKNOWN_OP) {
555 free_data_area(udev, cmd->data_length); 570 free_data_area(udev, cmd);
556 pr_warn("TCMU: Userspace set UNKNOWN_OP flag on se_cmd %p\n", 571 pr_warn("TCMU: Userspace set UNKNOWN_OP flag on se_cmd %p\n",
557 cmd->se_cmd); 572 cmd->se_cmd);
558 entry->rsp.scsi_status = SAM_STAT_CHECK_CONDITION; 573 entry->rsp.scsi_status = SAM_STAT_CHECK_CONDITION;
559 } else if (entry->rsp.scsi_status == SAM_STAT_CHECK_CONDITION) { 574 } else if (entry->rsp.scsi_status == SAM_STAT_CHECK_CONDITION) {
560 memcpy(se_cmd->sense_buffer, entry->rsp.sense_buffer, 575 memcpy(se_cmd->sense_buffer, entry->rsp.sense_buffer,
561 se_cmd->scsi_sense_length); 576 se_cmd->scsi_sense_length);
562 free_data_area(udev, cmd->data_length); 577 free_data_area(udev, cmd);
563 } else if (se_cmd->se_cmd_flags & SCF_BIDI) { 578 } else if (se_cmd->se_cmd_flags & SCF_BIDI) {
564 /* Discard data_out buffer */ 579 DECLARE_BITMAP(bitmap, DATA_BLOCK_BITS);
565 free_data_area(udev, (size_t)se_cmd->t_data_sg->length);
566 580
567 /* Get Data-In buffer */ 581 /* Get Data-In buffer before clean up */
568 gather_and_free_data_area(udev, 582 bitmap_copy(bitmap, cmd->data_bitmap, DATA_BLOCK_BITS);
583 gather_data_area(udev, bitmap,
569 se_cmd->t_bidi_data_sg, se_cmd->t_bidi_data_nents); 584 se_cmd->t_bidi_data_sg, se_cmd->t_bidi_data_nents);
585 free_data_area(udev, cmd);
570 } else if (se_cmd->data_direction == DMA_FROM_DEVICE) { 586 } else if (se_cmd->data_direction == DMA_FROM_DEVICE) {
571 gather_and_free_data_area(udev, 587 DECLARE_BITMAP(bitmap, DATA_BLOCK_BITS);
588
589 bitmap_copy(bitmap, cmd->data_bitmap, DATA_BLOCK_BITS);
590 gather_data_area(udev, bitmap,
572 se_cmd->t_data_sg, se_cmd->t_data_nents); 591 se_cmd->t_data_sg, se_cmd->t_data_nents);
592 free_data_area(udev, cmd);
573 } else if (se_cmd->data_direction == DMA_TO_DEVICE) { 593 } else if (se_cmd->data_direction == DMA_TO_DEVICE) {
574 free_data_area(udev, cmd->data_length); 594 free_data_area(udev, cmd);
575 } else if (se_cmd->data_direction != DMA_NONE) { 595 } else if (se_cmd->data_direction != DMA_NONE) {
576 pr_warn("TCMU: data direction was %d!\n", 596 pr_warn("TCMU: data direction was %d!\n",
577 se_cmd->data_direction); 597 se_cmd->data_direction);
@@ -912,6 +932,7 @@ static int tcmu_configure_device(struct se_device *dev)
912 932
913 WARN_ON(!PAGE_ALIGNED(udev->data_off)); 933 WARN_ON(!PAGE_ALIGNED(udev->data_off));
914 WARN_ON(udev->data_size % PAGE_SIZE); 934 WARN_ON(udev->data_size % PAGE_SIZE);
935 WARN_ON(udev->data_size % DATA_BLOCK_SIZE);
915 936
916 info->version = __stringify(TCMU_MAILBOX_VERSION); 937 info->version = __stringify(TCMU_MAILBOX_VERSION);
917 938