aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/target/target_core_device.c
diff options
context:
space:
mode:
authorNicholas Bellinger <nab@linux-iscsi.org>2011-08-13 05:11:38 -0400
committerNicholas Bellinger <nab@linux-iscsi.org>2011-08-22 15:26:27 -0400
commit525a48a21da259d00d6ebc5b60563b5bcf022c26 (patch)
tree79843b0aacbef9b130eec8f5352fe92b6422ab18 /drivers/target/target_core_device.c
parent01cde4d54327884a0b61ce8666092f5703557d4b (diff)
target: Fix task count > 1 handling breakage and use max_sector page alignment
This patch addresses recent breakage with multiple se_task (task_count > 1) operation following backend dev->se_sub_dev->se_dev_attrib.max_sectors in new transport_allocate_data_tasks() code. The initial bug here was a bogus task->task_sg_nents assignment in transport_allocate_data_tasks() based on the passed parameter, which now uses DIV_ROUND_UP(task_size, PAGE_SIZE) to determine the proper number of per task SGL entries for the (task_count > 1) case. This also means we now need to enforce a PAGE_SIZE aligned max_sector count value for this to work as expected without bringing back the pre v3.1 transport_map_mem_to_sg() logic to handle SGL offsets across multiple tasks. So this patch adds se_dev_align_max_sectors() to round down max_sectors as necessary to ensure this alignment via se_dev_set_default_attribs() and se_dev_align_max_sectors() and keeps it simple for (task_count > 1) operation. So far this bugfix has been tested with (task_count > 1) operation using iscsi-target and iblock backends. Reported-by: Chris Boot <bootc@bootc.net> Cc: Kiran Patil <kiran.patil@intel.com> Cc: Andy Grover <agrover@redhat.com> Cc: Christoph Hellwig <hch@lst.de> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
Diffstat (limited to 'drivers/target/target_core_device.c')
-rw-r--r--drivers/target/target_core_device.c28
1 files changed, 28 insertions, 0 deletions
diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c
index ec3fbcda3e3c..4b5237f500a5 100644
--- a/drivers/target/target_core_device.c
+++ b/drivers/target/target_core_device.c
@@ -839,6 +839,24 @@ int se_dev_check_shutdown(struct se_device *dev)
839 return ret; 839 return ret;
840} 840}
841 841
842u32 se_dev_align_max_sectors(u32 max_sectors, u32 block_size)
843{
844 u32 tmp, aligned_max_sectors;
845 /*
846 * Limit max_sectors to a PAGE_SIZE aligned value for modern
847 * transport_allocate_data_tasks() operation.
848 */
849 tmp = rounddown((max_sectors * block_size), PAGE_SIZE);
850 aligned_max_sectors = (tmp / block_size);
851 if (max_sectors != aligned_max_sectors) {
852 printk(KERN_INFO "Rounding down aligned max_sectors from %u"
853 " to %u\n", max_sectors, aligned_max_sectors);
854 return aligned_max_sectors;
855 }
856
857 return max_sectors;
858}
859
842void se_dev_set_default_attribs( 860void se_dev_set_default_attribs(
843 struct se_device *dev, 861 struct se_device *dev,
844 struct se_dev_limits *dev_limits) 862 struct se_dev_limits *dev_limits)
@@ -878,6 +896,11 @@ void se_dev_set_default_attribs(
878 * max_sectors is based on subsystem plugin dependent requirements. 896 * max_sectors is based on subsystem plugin dependent requirements.
879 */ 897 */
880 dev->se_sub_dev->se_dev_attrib.hw_max_sectors = limits->max_hw_sectors; 898 dev->se_sub_dev->se_dev_attrib.hw_max_sectors = limits->max_hw_sectors;
899 /*
900 * Align max_sectors down to PAGE_SIZE to follow transport_allocate_data_tasks()
901 */
902 limits->max_sectors = se_dev_align_max_sectors(limits->max_sectors,
903 limits->logical_block_size);
881 dev->se_sub_dev->se_dev_attrib.max_sectors = limits->max_sectors; 904 dev->se_sub_dev->se_dev_attrib.max_sectors = limits->max_sectors;
882 /* 905 /*
883 * Set optimal_sectors from max_sectors, which can be lowered via 906 * Set optimal_sectors from max_sectors, which can be lowered via
@@ -1242,6 +1265,11 @@ int se_dev_set_max_sectors(struct se_device *dev, u32 max_sectors)
1242 return -EINVAL; 1265 return -EINVAL;
1243 } 1266 }
1244 } 1267 }
1268 /*
1269 * Align max_sectors down to PAGE_SIZE to follow transport_allocate_data_tasks()
1270 */
1271 max_sectors = se_dev_align_max_sectors(max_sectors,
1272 dev->se_sub_dev->se_dev_attrib.block_size);
1245 1273
1246 dev->se_sub_dev->se_dev_attrib.max_sectors = max_sectors; 1274 dev->se_sub_dev->se_dev_attrib.max_sectors = max_sectors;
1247 pr_debug("dev[%p]: SE Device max_sectors changed to %u\n", 1275 pr_debug("dev[%p]: SE Device max_sectors changed to %u\n",