forked from Minki/linux
spi: use sg_next for walking through the allocated scatterlist table
A null dereference or Oops exception might occurs when reading at once the whole content of an spi-nor of big enough size that requires an scatterlist table that does not fit into one single page. The spi_map_buf function is ignoring the chained sg case by dereferenceing the scatterlist elements in an array fashion. This wrongly assumes that the allocation of the scatterlist elements are contiguous. This is true as long as the scatterlist table fits within a PAGE_SIZE. However, for allocation where the scatter table is bigger than that, the pages allocated by sg_alloc might not be contigous. The sg table can be properly walked by sg_next instead of using an array. Signed-off-by: Juan Gutierrez <juan.gutierrez@nxp.com> Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
parent
1001354ca3
commit
8dd4a0163e
@ -720,6 +720,7 @@ static int spi_map_buf(struct spi_master *master, struct device *dev,
|
|||||||
int desc_len;
|
int desc_len;
|
||||||
int sgs;
|
int sgs;
|
||||||
struct page *vm_page;
|
struct page *vm_page;
|
||||||
|
struct scatterlist *sg;
|
||||||
void *sg_buf;
|
void *sg_buf;
|
||||||
size_t min;
|
size_t min;
|
||||||
int i, ret;
|
int i, ret;
|
||||||
@ -738,6 +739,7 @@ static int spi_map_buf(struct spi_master *master, struct device *dev,
|
|||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
sg = &sgt->sgl[0];
|
||||||
for (i = 0; i < sgs; i++) {
|
for (i = 0; i < sgs; i++) {
|
||||||
|
|
||||||
if (vmalloced_buf || kmap_buf) {
|
if (vmalloced_buf || kmap_buf) {
|
||||||
@ -751,16 +753,17 @@ static int spi_map_buf(struct spi_master *master, struct device *dev,
|
|||||||
sg_free_table(sgt);
|
sg_free_table(sgt);
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
sg_set_page(&sgt->sgl[i], vm_page,
|
sg_set_page(sg, vm_page,
|
||||||
min, offset_in_page(buf));
|
min, offset_in_page(buf));
|
||||||
} else {
|
} else {
|
||||||
min = min_t(size_t, len, desc_len);
|
min = min_t(size_t, len, desc_len);
|
||||||
sg_buf = buf;
|
sg_buf = buf;
|
||||||
sg_set_buf(&sgt->sgl[i], sg_buf, min);
|
sg_set_buf(sg, sg_buf, min);
|
||||||
}
|
}
|
||||||
|
|
||||||
buf += min;
|
buf += min;
|
||||||
len -= min;
|
len -= min;
|
||||||
|
sg = sg_next(sg);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = dma_map_sg(dev, sgt->sgl, sgt->nents, dir);
|
ret = dma_map_sg(dev, sgt->sgl, sgt->nents, dir);
|
||||||
|
Loading…
Reference in New Issue
Block a user