Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

staging: ion: Move shrinker out of heaps

Every heap that uses deferred frees is going to need a shrinker
to shrink the freelist under memory pressure. Rather than
requiring each heap to implement a shrinker, automatically
register a shrinker if the deferred free flag is set.
The system heap also needs to shrink its page pools, so add
a shrink function to the heap ops that will be called after
shrinking the freelists.

Cc: Colin Cross <ccross@android.com>
Cc: Android Kernel Team <kernel-team@android.com>
Signed-off-by: Colin Cross <ccross@android.com>
[jstultz: Resolved big conflicts with the shrinker api change.
Also minor commit subject tweak.]
Signed-off-by: John Stultz <john.stultz@linaro.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Colin Cross and committed by
Greg Kroah-Hartman
b9daf0b6 2803ac7b

+86 -78
+3
drivers/staging/android/ion/ion.c
··· 1502 1502 if (heap->flags & ION_HEAP_FLAG_DEFER_FREE) 1503 1503 ion_heap_init_deferred_free(heap); 1504 1504 1505 + if ((heap->flags & ION_HEAP_FLAG_DEFER_FREE) || heap->ops->shrink) 1506 + ion_heap_init_shrinker(heap); 1507 + 1505 1508 heap->dev = dev; 1506 1509 down_write(&dev->lock); 1507 1510 /* use negative heap->id to reverse the priority -- when traversing
+50
drivers/staging/android/ion/ion_heap.c
··· 252 252 return 0; 253 253 } 254 254 255 + static unsigned long ion_heap_shrink_count(struct shrinker *shrinker, 256 + struct shrink_control *sc) 257 + { 258 + struct ion_heap *heap = container_of(shrinker, struct ion_heap, 259 + shrinker); 260 + int total = 0; 261 + 262 + total = ion_heap_freelist_size(heap) / PAGE_SIZE; 263 + if (heap->ops->shrink) 264 + total += heap->ops->shrink(heap, sc->gfp_mask, 0); 265 + return total; 266 + } 267 + 268 + static unsigned long ion_heap_shrink_scan(struct shrinker *shrinker, 269 + struct shrink_control *sc) 270 + { 271 + struct ion_heap *heap = container_of(shrinker, struct ion_heap, 272 + shrinker); 273 + int freed = 0; 274 + int to_scan = sc->nr_to_scan; 275 + 276 + if (to_scan == 0) 277 + return 0; 278 + 279 + /* 280 + * shrink the free list first, no point in zeroing the memory if we're 281 + * just going to reclaim it 282 + */ 283 + if (heap->flags & ION_HEAP_FLAG_DEFER_FREE) 284 + freed = ion_heap_freelist_drain(heap, to_scan * PAGE_SIZE) / 285 + PAGE_SIZE; 286 + 287 + to_scan -= freed; 288 + if (to_scan <= 0) 289 + return freed; 290 + 291 + if (heap->ops->shrink) 292 + freed += heap->ops->shrink(heap, sc->gfp_mask, to_scan); 293 + return freed; 294 + } 295 + 296 + void ion_heap_init_shrinker(struct ion_heap *heap) 297 + { 298 + heap->shrinker.count_objects = ion_heap_shrink_count; 299 + heap->shrinker.scan_objects = ion_heap_shrink_scan; 300 + heap->shrinker.seeks = DEFAULT_SEEKS; 301 + heap->shrinker.batch = 0; 302 + register_shrinker(&heap->shrinker); 303 + } 304 + 255 305 struct ion_heap *ion_heap_create(struct ion_platform_heap *heap_data) 256 306 { 257 307 struct ion_heap *heap = NULL;
+3 -5
drivers/staging/android/ion/ion_page_pool.c
··· 130 130 int ion_page_pool_shrink(struct ion_page_pool *pool, gfp_t gfp_mask, 131 131 int nr_to_scan) 132 132 { 133 - int nr_freed = 0; 134 - int i; 133 + int freed; 135 134 bool high; 136 135 137 136 high = !!(gfp_mask & __GFP_HIGHMEM); ··· 138 139 if (nr_to_scan == 0) 139 140 return ion_page_pool_total(pool, high); 140 141 141 - for (i = 0; i < nr_to_scan; i++) { 142 + for (freed = 0; freed < nr_to_scan; freed++) { 142 143 struct page *page; 143 144 144 145 mutex_lock(&pool->mutex); ··· 152 153 } 153 154 mutex_unlock(&pool->mutex); 154 155 ion_page_pool_free_pages(pool, page); 155 - nr_freed += (1 << pool->order); 156 156 } 157 157 158 - return nr_freed; 158 + return freed; 159 159 } 160 160 161 161 struct ion_page_pool *ion_page_pool_create(gfp_t gfp_mask, unsigned int order)
+12 -9
drivers/staging/android/ion/ion_priv.h
··· 114 114 void (*unmap_kernel)(struct ion_heap *heap, struct ion_buffer *buffer); 115 115 int (*map_user)(struct ion_heap *mapper, struct ion_buffer *buffer, 116 116 struct vm_area_struct *vma); 117 + int (*shrink)(struct ion_heap *heap, gfp_t gfp_mask, int nr_to_scan); 117 118 }; 118 119 119 120 /** ··· 133 132 * allocating. These are specified by platform data and 134 133 * MUST be unique 135 134 * @name: used for debugging 136 - * @shrinker: a shrinker for the heap, if the heap caches system 137 - * memory, it must define a shrinker to return it on low 138 - * memory conditions, this includes system memory cached 139 - * in the deferred free lists for heaps that support it 135 + * @shrinker: a shrinker for the heap 140 136 * @free_list: free list head if deferred free is used 141 137 * @free_list_size size of the deferred free list in bytes 142 138 * @lock: protects the free list ··· 215 217 struct vm_area_struct *); 216 218 int ion_heap_buffer_zero(struct ion_buffer *buffer); 217 219 int ion_heap_pages_zero(struct page *page, size_t size, pgprot_t pgprot); 220 + 221 + /** 222 + * ion_heap_init_shrinker 223 + * @heap: the heap 224 + * 225 + * If a heap sets the ION_HEAP_FLAG_DEFER_FREE flag or defines the shrink op 226 + * this function will be called to setup a shrinker to shrink the freelists 227 + * and call the heap's shrink op. 228 + */ 229 + void ion_heap_init_shrinker(struct ion_heap *heap); 218 230 219 231 /** 220 232 * ion_heap_init_deferred_free -- initialize deferred free functionality ··· 313 305 * @low_count: number of lowmem items in the pool 314 306 * @high_items: list of highmem items 315 307 * @low_items: list of lowmem items 316 - * @shrinker: a shrinker for the items 317 308 * @mutex: lock protecting this struct and especially the count 318 309 * item list 319 - * @alloc: function to be used to allocate pageory when the pool 320 - * is empty 321 - * @free: function to be used to free pageory back to the system 322 - * when the shrinker fires 323 310 * @gfp_mask: gfp_mask to use from alloc 324 311 * @order: order of pages in the pool 325 312 * @list: plist node for list of pools
+18 -64
drivers/staging/android/ion/ion_system_heap.c
··· 231 231 return; 232 232 } 233 233 234 + static int ion_system_heap_shrink(struct ion_heap *heap, gfp_t gfp_mask, 235 + int nr_to_scan) 236 + { 237 + struct ion_system_heap *sys_heap; 238 + int nr_total = 0; 239 + int i; 240 + 241 + sys_heap = container_of(heap, struct ion_system_heap, heap); 242 + 243 + for (i = 0; i < num_orders; i++) { 244 + struct ion_page_pool *pool = sys_heap->pools[i]; 245 + nr_total += ion_page_pool_shrink(pool, gfp_mask, nr_to_scan); 246 + } 247 + 248 + return nr_total; 249 + } 250 + 234 251 static struct ion_heap_ops system_heap_ops = { 235 252 .allocate = ion_system_heap_allocate, 236 253 .free = ion_system_heap_free, ··· 256 239 .map_kernel = ion_heap_map_kernel, 257 240 .unmap_kernel = ion_heap_unmap_kernel, 258 241 .map_user = ion_heap_map_user, 242 + .shrink = ion_system_heap_shrink, 259 243 }; 260 - 261 - static unsigned long ion_system_heap_shrink_count(struct shrinker *shrinker, 262 - struct shrink_control *sc) 263 - { 264 - struct ion_heap *heap = container_of(shrinker, struct ion_heap, 265 - shrinker); 266 - struct ion_system_heap *sys_heap = container_of(heap, 267 - struct ion_system_heap, 268 - heap); 269 - int nr_total = 0; 270 - int i; 271 - 272 - /* total number of items is whatever the page pools are holding 273 - plus whatever's in the freelist */ 274 - for (i = 0; i < num_orders; i++) { 275 - struct ion_page_pool *pool = sys_heap->pools[i]; 276 - nr_total += ion_page_pool_shrink(pool, sc->gfp_mask, 0); 277 - } 278 - nr_total += ion_heap_freelist_size(heap) / PAGE_SIZE; 279 - return nr_total; 280 - 281 - } 282 - 283 - static unsigned long ion_system_heap_shrink_scan(struct shrinker *shrinker, 284 - struct shrink_control *sc) 285 - { 286 - 287 - struct ion_heap *heap = container_of(shrinker, struct ion_heap, 288 - shrinker); 289 - struct ion_system_heap *sys_heap = container_of(heap, 290 - struct ion_system_heap, 291 - heap); 292 - int nr_freed = 0; 293 - int i; 294 - 295 - if (sc->nr_to_scan == 0) 296 - goto end; 297 - 298 - /* shrink the free list first, no point in zeroing the memory if 299 - we're just going to reclaim it */ 300 - nr_freed += ion_heap_freelist_drain(heap, sc->nr_to_scan * PAGE_SIZE) / 301 - PAGE_SIZE; 302 - 303 - if (nr_freed >= sc->nr_to_scan) 304 - goto end; 305 - 306 - for (i = 0; i < num_orders; i++) { 307 - struct ion_page_pool *pool = sys_heap->pools[i]; 308 - 309 - nr_freed += ion_page_pool_shrink(pool, sc->gfp_mask, 310 - sc->nr_to_scan); 311 - if (nr_freed >= sc->nr_to_scan) 312 - break; 313 - } 314 - 315 - end: 316 - return nr_freed; 317 - 318 - } 319 244 320 245 static int ion_system_heap_debug_show(struct ion_heap *heap, struct seq_file *s, 321 246 void *unused) ··· 306 347 heap->pools[i] = pool; 307 348 } 308 349 309 - heap->heap.shrinker.scan_objects = ion_system_heap_shrink_scan; 310 - heap->heap.shrinker.count_objects = ion_system_heap_shrink_count; 311 - heap->heap.shrinker.seeks = DEFAULT_SEEKS; 312 - heap->heap.shrinker.batch = 0; 313 - register_shrinker(&heap->heap.shrinker); 314 350 heap->heap.debug_show = ion_system_heap_debug_show; 315 351 return &heap->heap; 316 352 err_create_pool: