diff options
author | Yishai Hadas <yishaih@mellanox.com> | 2014-01-28 06:40:15 -0500 |
---|---|---|
committer | Roland Dreier <roland@purestorage.com> | 2014-03-04 13:34:28 -0500 |
commit | eeb8461e36c99fdf2d058751be924a2aab215005 (patch) | |
tree | c92498349f842be5985194c840e2dd12201df861 /drivers/infiniband/core | |
parent | cfbf8d4857c26a8a307fb7cd258074c9dcd8c691 (diff) |
IB: Refactor umem to use linear SG table
This patch refactors the IB core umem code and vendor drivers to use a
linear (chained) SG table instead of chunk list. With this change the
relevant code becomes clearer—no need for nested loops to build and
use umem.
Signed-off-by: Shachar Raindel <raindel@mellanox.com>
Signed-off-by: Yishai Hadas <yishaih@mellanox.com>
Signed-off-by: Roland Dreier <roland@purestorage.com>
Diffstat (limited to 'drivers/infiniband/core')
-rw-r--r-- | drivers/infiniband/core/umem.c | 120 |
1 files changed, 56 insertions, 64 deletions
diff --git a/drivers/infiniband/core/umem.c b/drivers/infiniband/core/umem.c index a84112322071..a3a2e9c1639b 100644 --- a/drivers/infiniband/core/umem.c +++ b/drivers/infiniband/core/umem.c | |||
@@ -42,29 +42,29 @@ | |||
42 | 42 | ||
43 | #include "uverbs.h" | 43 | #include "uverbs.h" |
44 | 44 | ||
45 | #define IB_UMEM_MAX_PAGE_CHUNK \ | ||
46 | ((PAGE_SIZE - offsetof(struct ib_umem_chunk, page_list)) / \ | ||
47 | ((void *) &((struct ib_umem_chunk *) 0)->page_list[1] - \ | ||
48 | (void *) &((struct ib_umem_chunk *) 0)->page_list[0])) | ||
49 | 45 | ||
50 | static void __ib_umem_release(struct ib_device *dev, struct ib_umem *umem, int dirty) | 46 | static void __ib_umem_release(struct ib_device *dev, struct ib_umem *umem, int dirty) |
51 | { | 47 | { |
52 | struct ib_umem_chunk *chunk, *tmp; | 48 | struct scatterlist *sg; |
49 | struct page *page; | ||
53 | int i; | 50 | int i; |
54 | 51 | ||
55 | list_for_each_entry_safe(chunk, tmp, &umem->chunk_list, list) { | 52 | if (umem->nmap > 0) |
56 | ib_dma_unmap_sg(dev, chunk->page_list, | 53 | ib_dma_unmap_sg(dev, umem->sg_head.sgl, |
57 | chunk->nents, DMA_BIDIRECTIONAL); | 54 | umem->nmap, |
58 | for (i = 0; i < chunk->nents; ++i) { | 55 | DMA_BIDIRECTIONAL); |
59 | struct page *page = sg_page(&chunk->page_list[i]); | ||
60 | 56 | ||
61 | if (umem->writable && dirty) | 57 | for_each_sg(umem->sg_head.sgl, sg, umem->npages, i) { |
62 | set_page_dirty_lock(page); | ||
63 | put_page(page); | ||
64 | } | ||
65 | 58 | ||
66 | kfree(chunk); | 59 | page = sg_page(sg); |
60 | if (umem->writable && dirty) | ||
61 | set_page_dirty_lock(page); | ||
62 | put_page(page); | ||
67 | } | 63 | } |
64 | |||
65 | sg_free_table(&umem->sg_head); | ||
66 | return; | ||
67 | |||
68 | } | 68 | } |
69 | 69 | ||
70 | /** | 70 | /** |
@@ -81,15 +81,15 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr, | |||
81 | struct ib_umem *umem; | 81 | struct ib_umem *umem; |
82 | struct page **page_list; | 82 | struct page **page_list; |
83 | struct vm_area_struct **vma_list; | 83 | struct vm_area_struct **vma_list; |
84 | struct ib_umem_chunk *chunk; | ||
85 | unsigned long locked; | 84 | unsigned long locked; |
86 | unsigned long lock_limit; | 85 | unsigned long lock_limit; |
87 | unsigned long cur_base; | 86 | unsigned long cur_base; |
88 | unsigned long npages; | 87 | unsigned long npages; |
89 | int ret; | 88 | int ret; |
90 | int off; | ||
91 | int i; | 89 | int i; |
92 | DEFINE_DMA_ATTRS(attrs); | 90 | DEFINE_DMA_ATTRS(attrs); |
91 | struct scatterlist *sg, *sg_list_start; | ||
92 | int need_release = 0; | ||
93 | 93 | ||
94 | if (dmasync) | 94 | if (dmasync) |
95 | dma_set_attr(DMA_ATTR_WRITE_BARRIER, &attrs); | 95 | dma_set_attr(DMA_ATTR_WRITE_BARRIER, &attrs); |
@@ -97,7 +97,7 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr, | |||
97 | if (!can_do_mlock()) | 97 | if (!can_do_mlock()) |
98 | return ERR_PTR(-EPERM); | 98 | return ERR_PTR(-EPERM); |
99 | 99 | ||
100 | umem = kmalloc(sizeof *umem, GFP_KERNEL); | 100 | umem = kzalloc(sizeof *umem, GFP_KERNEL); |
101 | if (!umem) | 101 | if (!umem) |
102 | return ERR_PTR(-ENOMEM); | 102 | return ERR_PTR(-ENOMEM); |
103 | 103 | ||
@@ -117,8 +117,6 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr, | |||
117 | /* We assume the memory is from hugetlb until proved otherwise */ | 117 | /* We assume the memory is from hugetlb until proved otherwise */ |
118 | umem->hugetlb = 1; | 118 | umem->hugetlb = 1; |
119 | 119 | ||
120 | INIT_LIST_HEAD(&umem->chunk_list); | ||
121 | |||
122 | page_list = (struct page **) __get_free_page(GFP_KERNEL); | 120 | page_list = (struct page **) __get_free_page(GFP_KERNEL); |
123 | if (!page_list) { | 121 | if (!page_list) { |
124 | kfree(umem); | 122 | kfree(umem); |
@@ -147,7 +145,18 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr, | |||
147 | 145 | ||
148 | cur_base = addr & PAGE_MASK; | 146 | cur_base = addr & PAGE_MASK; |
149 | 147 | ||
150 | ret = 0; | 148 | if (npages == 0) { |
149 | ret = -EINVAL; | ||
150 | goto out; | ||
151 | } | ||
152 | |||
153 | ret = sg_alloc_table(&umem->sg_head, npages, GFP_KERNEL); | ||
154 | if (ret) | ||
155 | goto out; | ||
156 | |||
157 | need_release = 1; | ||
158 | sg_list_start = umem->sg_head.sgl; | ||
159 | |||
151 | while (npages) { | 160 | while (npages) { |
152 | ret = get_user_pages(current, current->mm, cur_base, | 161 | ret = get_user_pages(current, current->mm, cur_base, |
153 | min_t(unsigned long, npages, | 162 | min_t(unsigned long, npages, |
@@ -157,54 +166,38 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr, | |||
157 | if (ret < 0) | 166 | if (ret < 0) |
158 | goto out; | 167 | goto out; |
159 | 168 | ||
169 | umem->npages += ret; | ||
160 | cur_base += ret * PAGE_SIZE; | 170 | cur_base += ret * PAGE_SIZE; |
161 | npages -= ret; | 171 | npages -= ret; |
162 | 172 | ||
163 | off = 0; | 173 | for_each_sg(sg_list_start, sg, ret, i) { |
164 | 174 | if (vma_list && !is_vm_hugetlb_page(vma_list[i])) | |
165 | while (ret) { | 175 | umem->hugetlb = 0; |
166 | chunk = kmalloc(sizeof *chunk + sizeof (struct scatterlist) * | 176 | |
167 | min_t(int, ret, IB_UMEM_MAX_PAGE_CHUNK), | 177 | sg_set_page(sg, page_list[i], PAGE_SIZE, 0); |
168 | GFP_KERNEL); | ||
169 | if (!chunk) { | ||
170 | ret = -ENOMEM; | ||
171 | goto out; | ||
172 | } | ||
173 | |||
174 | chunk->nents = min_t(int, ret, IB_UMEM_MAX_PAGE_CHUNK); | ||
175 | sg_init_table(chunk->page_list, chunk->nents); | ||
176 | for (i = 0; i < chunk->nents; ++i) { | ||
177 | if (vma_list && | ||
178 | !is_vm_hugetlb_page(vma_list[i + off])) | ||
179 | umem->hugetlb = 0; | ||
180 | sg_set_page(&chunk->page_list[i], page_list[i + off], PAGE_SIZE, 0); | ||
181 | } | ||
182 | |||
183 | chunk->nmap = ib_dma_map_sg_attrs(context->device, | ||
184 | &chunk->page_list[0], | ||
185 | chunk->nents, | ||
186 | DMA_BIDIRECTIONAL, | ||
187 | &attrs); | ||
188 | if (chunk->nmap <= 0) { | ||
189 | for (i = 0; i < chunk->nents; ++i) | ||
190 | put_page(sg_page(&chunk->page_list[i])); | ||
191 | kfree(chunk); | ||
192 | |||
193 | ret = -ENOMEM; | ||
194 | goto out; | ||
195 | } | ||
196 | |||
197 | ret -= chunk->nents; | ||
198 | off += chunk->nents; | ||
199 | list_add_tail(&chunk->list, &umem->chunk_list); | ||
200 | } | 178 | } |
201 | 179 | ||
202 | ret = 0; | 180 | /* preparing for next loop */ |
181 | sg_list_start = sg; | ||
203 | } | 182 | } |
204 | 183 | ||
184 | umem->nmap = ib_dma_map_sg_attrs(context->device, | ||
185 | umem->sg_head.sgl, | ||
186 | umem->npages, | ||
187 | DMA_BIDIRECTIONAL, | ||
188 | &attrs); | ||
189 | |||
190 | if (umem->nmap <= 0) { | ||
191 | ret = -ENOMEM; | ||
192 | goto out; | ||
193 | } | ||
194 | |||
195 | ret = 0; | ||
196 | |||
205 | out: | 197 | out: |
206 | if (ret < 0) { | 198 | if (ret < 0) { |
207 | __ib_umem_release(context->device, umem, 0); | 199 | if (need_release) |
200 | __ib_umem_release(context->device, umem, 0); | ||
208 | kfree(umem); | 201 | kfree(umem); |
209 | } else | 202 | } else |
210 | current->mm->pinned_vm = locked; | 203 | current->mm->pinned_vm = locked; |
@@ -278,17 +271,16 @@ EXPORT_SYMBOL(ib_umem_release); | |||
278 | 271 | ||
279 | int ib_umem_page_count(struct ib_umem *umem) | 272 | int ib_umem_page_count(struct ib_umem *umem) |
280 | { | 273 | { |
281 | struct ib_umem_chunk *chunk; | ||
282 | int shift; | 274 | int shift; |
283 | int i; | 275 | int i; |
284 | int n; | 276 | int n; |
277 | struct scatterlist *sg; | ||
285 | 278 | ||
286 | shift = ilog2(umem->page_size); | 279 | shift = ilog2(umem->page_size); |
287 | 280 | ||
288 | n = 0; | 281 | n = 0; |
289 | list_for_each_entry(chunk, &umem->chunk_list, list) | 282 | for_each_sg(umem->sg_head.sgl, sg, umem->nmap, i) |
290 | for (i = 0; i < chunk->nmap; ++i) | 283 | n += sg_dma_len(sg) >> shift; |
291 | n += sg_dma_len(&chunk->page_list[i]) >> shift; | ||
292 | 284 | ||
293 | return n; | 285 | return n; |
294 | } | 286 | } |