[PATCH 1/2] target: Recalculate pad size inside is_ring_space_avail()

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



If more than one thread is waiting for command ring space that includes
a PAD, then if the first one finishes (inserts a PAD and a CMD at the
start of the cmd ring) then the second one will incorrectly think it still
needs to insert a PAD (i.e. cmdr_space_needed is now wrong.) This will
lead to it asking for more space than it actually needs, and then inserting
a PAD somewhere else than at the end -- not what we want.

This patch moves the pad calculation inside is_ring_space_available() so
in the above scenario the second thread would then ask for space not
including a PAD. The patch also inserts a PAD op based upon an up-to-date
cmd_head, instead of the potentially stale value.

Signed-off-by: Andy Grover <agrover@xxxxxxxxxx>
---
 drivers/target/target_core_user.c | 31 ++++++++++++++++---------------
 1 file changed, 16 insertions(+), 15 deletions(-)

diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c
index c52b592..f798e80 100644
--- a/drivers/target/target_core_user.c
+++ b/drivers/target/target_core_user.c
@@ -236,16 +236,26 @@ static inline size_t head_to_end(size_t head, size_t size)
  *
  * Called with ring lock held.
  */
-static bool is_ring_space_avail(struct tcmu_dev *udev, size_t cmd_needed, size_t data_needed)
+static bool is_ring_space_avail(struct tcmu_dev *udev, size_t cmd_size, size_t data_needed)
 {
 	struct tcmu_mailbox *mb = udev->mb_addr;
 	size_t space;
 	u32 cmd_head;
+	size_t cmd_needed;
 
 	tcmu_flush_dcache_range(mb, sizeof(*mb));
 
 	cmd_head = mb->cmd_head % udev->cmdr_size; /* UAM */
 
+	/*
+	 * If cmd end-of-ring space is too small then we need space for a NOP plus
+	 * original cmd - cmds are internally contiguous.
+	 */
+	if (head_to_end(cmd_head, udev->cmdr_size) >= cmd_size)
+		cmd_needed = cmd_size;
+	else
+		cmd_needed = cmd_size + head_to_end(cmd_head, udev->cmdr_size);
+
 	space = spc_free(cmd_head, udev->cmdr_last_cleaned, udev->cmdr_size);
 	if (space < cmd_needed) {
 		pr_debug("no cmd space: %u %u %u\n", cmd_head,
@@ -268,9 +278,7 @@ static int tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd)
 	struct tcmu_dev *udev = tcmu_cmd->tcmu_dev;
 	struct se_cmd *se_cmd = tcmu_cmd->se_cmd;
 	size_t base_command_size, command_size;
-	size_t cmdr_space_needed;
 	struct tcmu_mailbox *mb;
-	size_t pad_size;
 	struct tcmu_cmd_entry *entry;
 	int i;
 	struct scatterlist *sg;
@@ -307,17 +315,7 @@ static int tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd)
 			"cmd/data ring buffers\n", command_size, tcmu_cmd->data_length,
 			udev->cmdr_size, udev->data_size);
 
-	/*
-	 * Cmd end-of-ring space is too small so we need space for a NOP plus
-	 * original cmd - cmds are internally contiguous.
-	 */
-	if (head_to_end(cmd_head, udev->cmdr_size) >= command_size)
-		pad_size = 0;
-	else
-		pad_size = head_to_end(cmd_head, udev->cmdr_size);
-	cmdr_space_needed = command_size + pad_size;
-
-	while (!is_ring_space_avail(udev, cmdr_space_needed, tcmu_cmd->data_length)) {
+	while (!is_ring_space_avail(udev, command_size, tcmu_cmd->data_length)) {
 		int ret;
 		DEFINE_WAIT(__wait);
 
@@ -338,7 +336,10 @@ static int tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd)
 		cmd_head = mb->cmd_head % udev->cmdr_size; /* UAM */
 	}
 
-	if (pad_size) {
+	/* Insert a PAD if end-of-ring space is too small */
+	if (head_to_end(cmd_head, udev->cmdr_size) < command_size) {
+		size_t pad_size = head_to_end(cmd_head, udev->cmdr_size);
+
 		entry = (void *) mb + CMDR_OFF + cmd_head;
 		tcmu_flush_dcache_range(entry, sizeof(*entry));
 		tcmu_hdr_set_op(&entry->hdr, TCMU_OP_PAD);
-- 
1.9.3

--
To unsubscribe from this list: send the line "unsubscribe target-devel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux SCSI]     [Kernel Newbies]     [Linux SCSI Target Infrastructure]     [Share Photos]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Linux IIO]     [Device Mapper]

  Powered by Linux