diff options
author | Joerg Roedel <jroedel@suse.de> | 2014-11-04 08:53:51 -0500 |
---|---|---|
committer | Joerg Roedel <jroedel@suse.de> | 2014-11-04 08:53:51 -0500 |
commit | 38ec010d9b04ed94845f8ff6f10d33eb6bbfe180 (patch) | |
tree | 7e54787fbc0961a02707f38e5b39bfa2f22605c4 | |
parent | 315786ebbf4ad6552b6fd8e0e7b2ea220fcbfdbd (diff) |
iommu: Do more input validation in iommu_map_sg()
The IOMMU-API works on page boundarys, unlike the DMA-API
which can work with sub-page buffers. The sg->offset
field does not make sense on the IOMMU level, so force it to
be 0. Do some error-path consolidation while at it.
Signed-off-by: Joerg Roedel <jroedel@suse.de>
-rw-r--r-- | drivers/iommu/iommu.c | 29 |
1 files changed, 18 insertions, 11 deletions
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 46727ce9280d..08c53c5a046f 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c | |||
@@ -1127,26 +1127,33 @@ EXPORT_SYMBOL_GPL(iommu_unmap); | |||
1127 | size_t default_iommu_map_sg(struct iommu_domain *domain, unsigned long iova, | 1127 | size_t default_iommu_map_sg(struct iommu_domain *domain, unsigned long iova, |
1128 | struct scatterlist *sg, unsigned int nents, int prot) | 1128 | struct scatterlist *sg, unsigned int nents, int prot) |
1129 | { | 1129 | { |
1130 | int ret; | 1130 | struct scatterlist *s; |
1131 | size_t mapped = 0; | 1131 | size_t mapped = 0; |
1132 | unsigned int i; | 1132 | unsigned int i; |
1133 | struct scatterlist *s; | 1133 | int ret; |
1134 | 1134 | ||
1135 | for_each_sg(sg, s, nents, i) { | 1135 | for_each_sg(sg, s, nents, i) { |
1136 | phys_addr_t phys = page_to_phys(sg_page(s)); | 1136 | phys_addr_t phys = page_to_phys(sg_page(s)); |
1137 | size_t page_len = s->offset + s->length; | ||
1138 | 1137 | ||
1139 | ret = iommu_map(domain, iova + mapped, phys, page_len, prot); | 1138 | /* We are mapping on page boundarys, so offset must be 0 */ |
1140 | if (ret) { | 1139 | if (s->offset) |
1141 | /* undo mappings already done */ | 1140 | goto out_err; |
1142 | iommu_unmap(domain, iova, mapped); | 1141 | |
1143 | mapped = 0; | 1142 | ret = iommu_map(domain, iova + mapped, phys, s->length, prot); |
1144 | break; | 1143 | if (ret) |
1145 | } | 1144 | goto out_err; |
1146 | mapped += page_len; | 1145 | |
1146 | mapped += s->length; | ||
1147 | } | 1147 | } |
1148 | 1148 | ||
1149 | return mapped; | 1149 | return mapped; |
1150 | |||
1151 | out_err: | ||
1152 | /* undo mappings already done */ | ||
1153 | iommu_unmap(domain, iova, mapped); | ||
1154 | |||
1155 | return 0; | ||
1156 | |||
1150 | } | 1157 | } |
1151 | EXPORT_SYMBOL_GPL(default_iommu_map_sg); | 1158 | EXPORT_SYMBOL_GPL(default_iommu_map_sg); |
1152 | 1159 | ||