diff options
Diffstat (limited to 'mm/z3fold.c')
-rw-r--r-- | mm/z3fold.c | 29 |
1 files changed, 19 insertions, 10 deletions
diff --git a/mm/z3fold.c b/mm/z3fold.c index dfcd69d08c1e..6c72b18d8b9c 100644 --- a/mm/z3fold.c +++ b/mm/z3fold.c | |||
@@ -101,6 +101,7 @@ struct z3fold_buddy_slots { | |||
101 | * @refcount: reference count for the z3fold page | 101 | * @refcount: reference count for the z3fold page |
102 | * @work: work_struct for page layout optimization | 102 | * @work: work_struct for page layout optimization |
103 | * @slots: pointer to the structure holding buddy slots | 103 | * @slots: pointer to the structure holding buddy slots |
104 | * @pool: pointer to the containing pool | ||
104 | * @cpu: CPU which this page "belongs" to | 105 | * @cpu: CPU which this page "belongs" to |
105 | * @first_chunks: the size of the first buddy in chunks, 0 if free | 106 | * @first_chunks: the size of the first buddy in chunks, 0 if free |
106 | * @middle_chunks: the size of the middle buddy in chunks, 0 if free | 107 | * @middle_chunks: the size of the middle buddy in chunks, 0 if free |
@@ -114,6 +115,7 @@ struct z3fold_header { | |||
114 | struct kref refcount; | 115 | struct kref refcount; |
115 | struct work_struct work; | 116 | struct work_struct work; |
116 | struct z3fold_buddy_slots *slots; | 117 | struct z3fold_buddy_slots *slots; |
118 | struct z3fold_pool *pool; | ||
117 | short cpu; | 119 | short cpu; |
118 | unsigned short first_chunks; | 120 | unsigned short first_chunks; |
119 | unsigned short middle_chunks; | 121 | unsigned short middle_chunks; |
@@ -193,8 +195,10 @@ static void compact_page_work(struct work_struct *w); | |||
193 | static inline struct z3fold_buddy_slots *alloc_slots(struct z3fold_pool *pool, | 195 | static inline struct z3fold_buddy_slots *alloc_slots(struct z3fold_pool *pool, |
194 | gfp_t gfp) | 196 | gfp_t gfp) |
195 | { | 197 | { |
196 | struct z3fold_buddy_slots *slots = kmem_cache_alloc(pool->c_handle, | 198 | struct z3fold_buddy_slots *slots; |
197 | gfp); | 199 | |
200 | slots = kmem_cache_alloc(pool->c_handle, | ||
201 | (gfp & ~(__GFP_HIGHMEM | __GFP_MOVABLE))); | ||
198 | 202 | ||
199 | if (slots) { | 203 | if (slots) { |
200 | memset(slots->slot, 0, sizeof(slots->slot)); | 204 | memset(slots->slot, 0, sizeof(slots->slot)); |
@@ -320,6 +324,7 @@ static struct z3fold_header *init_z3fold_page(struct page *page, | |||
320 | zhdr->start_middle = 0; | 324 | zhdr->start_middle = 0; |
321 | zhdr->cpu = -1; | 325 | zhdr->cpu = -1; |
322 | zhdr->slots = slots; | 326 | zhdr->slots = slots; |
327 | zhdr->pool = pool; | ||
323 | INIT_LIST_HEAD(&zhdr->buddy); | 328 | INIT_LIST_HEAD(&zhdr->buddy); |
324 | INIT_WORK(&zhdr->work, compact_page_work); | 329 | INIT_WORK(&zhdr->work, compact_page_work); |
325 | return zhdr; | 330 | return zhdr; |
@@ -426,7 +431,7 @@ static enum buddy handle_to_buddy(unsigned long handle) | |||
426 | 431 | ||
427 | static inline struct z3fold_pool *zhdr_to_pool(struct z3fold_header *zhdr) | 432 | static inline struct z3fold_pool *zhdr_to_pool(struct z3fold_header *zhdr) |
428 | { | 433 | { |
429 | return slots_to_pool(zhdr->slots); | 434 | return zhdr->pool; |
430 | } | 435 | } |
431 | 436 | ||
432 | static void __release_z3fold_page(struct z3fold_header *zhdr, bool locked) | 437 | static void __release_z3fold_page(struct z3fold_header *zhdr, bool locked) |
@@ -850,7 +855,7 @@ static int z3fold_alloc(struct z3fold_pool *pool, size_t size, gfp_t gfp, | |||
850 | enum buddy bud; | 855 | enum buddy bud; |
851 | bool can_sleep = gfpflags_allow_blocking(gfp); | 856 | bool can_sleep = gfpflags_allow_blocking(gfp); |
852 | 857 | ||
853 | if (!size || (gfp & __GFP_HIGHMEM)) | 858 | if (!size) |
854 | return -EINVAL; | 859 | return -EINVAL; |
855 | 860 | ||
856 | if (size > PAGE_SIZE) | 861 | if (size > PAGE_SIZE) |
@@ -1345,24 +1350,29 @@ static int z3fold_page_migrate(struct address_space *mapping, struct page *newpa | |||
1345 | zhdr = page_address(page); | 1350 | zhdr = page_address(page); |
1346 | pool = zhdr_to_pool(zhdr); | 1351 | pool = zhdr_to_pool(zhdr); |
1347 | 1352 | ||
1348 | if (!trylock_page(page)) | ||
1349 | return -EAGAIN; | ||
1350 | |||
1351 | if (!z3fold_page_trylock(zhdr)) { | 1353 | if (!z3fold_page_trylock(zhdr)) { |
1352 | unlock_page(page); | ||
1353 | return -EAGAIN; | 1354 | return -EAGAIN; |
1354 | } | 1355 | } |
1355 | if (zhdr->mapped_count != 0) { | 1356 | if (zhdr->mapped_count != 0) { |
1356 | z3fold_page_unlock(zhdr); | 1357 | z3fold_page_unlock(zhdr); |
1357 | unlock_page(page); | ||
1358 | return -EBUSY; | 1358 | return -EBUSY; |
1359 | } | 1359 | } |
1360 | if (work_pending(&zhdr->work)) { | ||
1361 | z3fold_page_unlock(zhdr); | ||
1362 | return -EAGAIN; | ||
1363 | } | ||
1360 | new_zhdr = page_address(newpage); | 1364 | new_zhdr = page_address(newpage); |
1361 | memcpy(new_zhdr, zhdr, PAGE_SIZE); | 1365 | memcpy(new_zhdr, zhdr, PAGE_SIZE); |
1362 | newpage->private = page->private; | 1366 | newpage->private = page->private; |
1363 | page->private = 0; | 1367 | page->private = 0; |
1364 | z3fold_page_unlock(zhdr); | 1368 | z3fold_page_unlock(zhdr); |
1365 | spin_lock_init(&new_zhdr->page_lock); | 1369 | spin_lock_init(&new_zhdr->page_lock); |
1370 | INIT_WORK(&new_zhdr->work, compact_page_work); | ||
1371 | /* | ||
1372 | * z3fold_page_isolate() ensures that new_zhdr->buddy is empty, | ||
1373 | * so we only have to reinitialize it. | ||
1374 | */ | ||
1375 | INIT_LIST_HEAD(&new_zhdr->buddy); | ||
1366 | new_mapping = page_mapping(page); | 1376 | new_mapping = page_mapping(page); |
1367 | __ClearPageMovable(page); | 1377 | __ClearPageMovable(page); |
1368 | ClearPagePrivate(page); | 1378 | ClearPagePrivate(page); |
@@ -1386,7 +1396,6 @@ static int z3fold_page_migrate(struct address_space *mapping, struct page *newpa | |||
1386 | queue_work_on(new_zhdr->cpu, pool->compact_wq, &new_zhdr->work); | 1396 | queue_work_on(new_zhdr->cpu, pool->compact_wq, &new_zhdr->work); |
1387 | 1397 | ||
1388 | page_mapcount_reset(page); | 1398 | page_mapcount_reset(page); |
1389 | unlock_page(page); | ||
1390 | put_page(page); | 1399 | put_page(page); |
1391 | return 0; | 1400 | return 0; |
1392 | } | 1401 | } |