Jens Axboe wrote: > @@ -323,13 +324,17 @@ static int __dma_map_cont(struct scatterlist *sg, int start, int stopat, > { > unsigned long iommu_start = alloc_iommu(pages); > unsigned long iommu_page = iommu_start; > - int i; > + struct scatterlist *s; > + int i, nelems; > > if (iommu_start == -1) > return -1; > + > + nelems = stopat - start; > + while (start--) > + sg = sg_next(sg); Ouch. This will suck if we merge many times in a long list. How about keeping and passing start as a struct scatterlist * rather than an index? (see attached example, (compiles, bu untested though) > > - for (i = start; i < stopat; i++) { > - struct scatterlist *s = &sg[i]; > + for_each_sg(sg, s, nelems, i) { > unsigned long pages, addr; > unsigned long phys_addr = s->dma_address; There seems to be a bug hiding here as now i is in [0, nelems) now, not [start, stopat) so "if (i == start)" below should turn into "if (i == 0)" this is fixed by comparing pointers instead way in the attached example. > > @@ -360,12 +365,14 @@ static inline int dma_map_cont(struct scatterlist *sg, int start, int stopat, > struct scatterlist *sout, > unsigned long pages, int need) > { > - if (!need) { > + if (!need) { > BUG_ON(stopat - start != 1); > - *sout = sg[start]; > - sout->dma_length = sg[start].length; > + while (--start) > + sg = sg_next(sg); same efficiency issue as above. > + *sout = *sg; > + sout->dma_length = sg->length; > return 0; > - } > + } > return __dma_map_cont(sg, start, stopat, sout, pages); > } >