diff options
-rw-r--r-- | drivers/infiniband/core/umem.c | 20 | ||||
-rw-r--r-- | include/rdma/ib_umem.h | 1 |
2 files changed, 20 insertions, 1 deletions
diff --git a/drivers/infiniband/core/umem.c b/drivers/infiniband/core/umem.c index 664d2faa9e74..2f54e29dc7a6 100644 --- a/drivers/infiniband/core/umem.c +++ b/drivers/infiniband/core/umem.c | |||
@@ -37,6 +37,7 @@ | |||
37 | #include <linux/mm.h> | 37 | #include <linux/mm.h> |
38 | #include <linux/dma-mapping.h> | 38 | #include <linux/dma-mapping.h> |
39 | #include <linux/sched.h> | 39 | #include <linux/sched.h> |
40 | #include <linux/hugetlb.h> | ||
40 | 41 | ||
41 | #include "uverbs.h" | 42 | #include "uverbs.h" |
42 | 43 | ||
@@ -75,6 +76,7 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr, | |||
75 | { | 76 | { |
76 | struct ib_umem *umem; | 77 | struct ib_umem *umem; |
77 | struct page **page_list; | 78 | struct page **page_list; |
79 | struct vm_area_struct **vma_list; | ||
78 | struct ib_umem_chunk *chunk; | 80 | struct ib_umem_chunk *chunk; |
79 | unsigned long locked; | 81 | unsigned long locked; |
80 | unsigned long lock_limit; | 82 | unsigned long lock_limit; |
@@ -104,6 +106,9 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr, | |||
104 | */ | 106 | */ |
105 | umem->writable = !!(access & ~IB_ACCESS_REMOTE_READ); | 107 | umem->writable = !!(access & ~IB_ACCESS_REMOTE_READ); |
106 | 108 | ||
109 | /* We assume the memory is from hugetlb until proved otherwise */ | ||
110 | umem->hugetlb = 1; | ||
111 | |||
107 | INIT_LIST_HEAD(&umem->chunk_list); | 112 | INIT_LIST_HEAD(&umem->chunk_list); |
108 | 113 | ||
109 | page_list = (struct page **) __get_free_page(GFP_KERNEL); | 114 | page_list = (struct page **) __get_free_page(GFP_KERNEL); |
@@ -112,6 +117,14 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr, | |||
112 | return ERR_PTR(-ENOMEM); | 117 | return ERR_PTR(-ENOMEM); |
113 | } | 118 | } |
114 | 119 | ||
120 | /* | ||
121 | * if we can't alloc the vma_list, it's not so bad; | ||
122 | * just assume the memory is not hugetlb memory | ||
123 | */ | ||
124 | vma_list = (struct vm_area_struct **) __get_free_page(GFP_KERNEL); | ||
125 | if (!vma_list) | ||
126 | umem->hugetlb = 0; | ||
127 | |||
115 | npages = PAGE_ALIGN(size + umem->offset) >> PAGE_SHIFT; | 128 | npages = PAGE_ALIGN(size + umem->offset) >> PAGE_SHIFT; |
116 | 129 | ||
117 | down_write(¤t->mm->mmap_sem); | 130 | down_write(¤t->mm->mmap_sem); |
@@ -131,7 +144,7 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr, | |||
131 | ret = get_user_pages(current, current->mm, cur_base, | 144 | ret = get_user_pages(current, current->mm, cur_base, |
132 | min_t(int, npages, | 145 | min_t(int, npages, |
133 | PAGE_SIZE / sizeof (struct page *)), | 146 | PAGE_SIZE / sizeof (struct page *)), |
134 | 1, !umem->writable, page_list, NULL); | 147 | 1, !umem->writable, page_list, vma_list); |
135 | 148 | ||
136 | if (ret < 0) | 149 | if (ret < 0) |
137 | goto out; | 150 | goto out; |
@@ -152,6 +165,9 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr, | |||
152 | 165 | ||
153 | chunk->nents = min_t(int, ret, IB_UMEM_MAX_PAGE_CHUNK); | 166 | chunk->nents = min_t(int, ret, IB_UMEM_MAX_PAGE_CHUNK); |
154 | for (i = 0; i < chunk->nents; ++i) { | 167 | for (i = 0; i < chunk->nents; ++i) { |
168 | if (vma_list && | ||
169 | !is_vm_hugetlb_page(vma_list[i + off])) | ||
170 | umem->hugetlb = 0; | ||
155 | chunk->page_list[i].page = page_list[i + off]; | 171 | chunk->page_list[i].page = page_list[i + off]; |
156 | chunk->page_list[i].offset = 0; | 172 | chunk->page_list[i].offset = 0; |
157 | chunk->page_list[i].length = PAGE_SIZE; | 173 | chunk->page_list[i].length = PAGE_SIZE; |
@@ -186,6 +202,8 @@ out: | |||
186 | current->mm->locked_vm = locked; | 202 | current->mm->locked_vm = locked; |
187 | 203 | ||
188 | up_write(¤t->mm->mmap_sem); | 204 | up_write(¤t->mm->mmap_sem); |
205 | if (vma_list) | ||
206 | free_page((unsigned long) vma_list); | ||
189 | free_page((unsigned long) page_list); | 207 | free_page((unsigned long) page_list); |
190 | 208 | ||
191 | return ret < 0 ? ERR_PTR(ret) : umem; | 209 | return ret < 0 ? ERR_PTR(ret) : umem; |
diff --git a/include/rdma/ib_umem.h b/include/rdma/ib_umem.h index c533d6c7903f..22298423cf0b 100644 --- a/include/rdma/ib_umem.h +++ b/include/rdma/ib_umem.h | |||
@@ -45,6 +45,7 @@ struct ib_umem { | |||
45 | int offset; | 45 | int offset; |
46 | int page_size; | 46 | int page_size; |
47 | int writable; | 47 | int writable; |
48 | int hugetlb; | ||
48 | struct list_head chunk_list; | 49 | struct list_head chunk_list; |
49 | struct work_struct work; | 50 | struct work_struct work; |
50 | struct mm_struct *mm; | 51 | struct mm_struct *mm; |