aboutsummaryrefslogtreecommitdiffstats
path: root/mm/z3fold.c
diff options
context:
space:
mode:
Diffstat (limited to 'mm/z3fold.c')
-rw-r--r--mm/z3fold.c101
1 files changed, 62 insertions, 39 deletions
diff --git a/mm/z3fold.c b/mm/z3fold.c
index 4b366d181f35..aee9b0b8d907 100644
--- a/mm/z3fold.c
+++ b/mm/z3fold.c
@@ -99,6 +99,7 @@ struct z3fold_header {
99#define NCHUNKS ((PAGE_SIZE - ZHDR_SIZE_ALIGNED) >> CHUNK_SHIFT) 99#define NCHUNKS ((PAGE_SIZE - ZHDR_SIZE_ALIGNED) >> CHUNK_SHIFT)
100 100
101#define BUDDY_MASK (0x3) 101#define BUDDY_MASK (0x3)
102#define BUDDY_SHIFT 2
102 103
103/** 104/**
104 * struct z3fold_pool - stores metadata for each z3fold pool 105 * struct z3fold_pool - stores metadata for each z3fold pool
@@ -145,7 +146,7 @@ enum z3fold_page_flags {
145 MIDDLE_CHUNK_MAPPED, 146 MIDDLE_CHUNK_MAPPED,
146 NEEDS_COMPACTING, 147 NEEDS_COMPACTING,
147 PAGE_STALE, 148 PAGE_STALE,
148 UNDER_RECLAIM 149 PAGE_CLAIMED, /* by either reclaim or free */
149}; 150};
150 151
151/***************** 152/*****************
@@ -174,7 +175,7 @@ static struct z3fold_header *init_z3fold_page(struct page *page,
174 clear_bit(MIDDLE_CHUNK_MAPPED, &page->private); 175 clear_bit(MIDDLE_CHUNK_MAPPED, &page->private);
175 clear_bit(NEEDS_COMPACTING, &page->private); 176 clear_bit(NEEDS_COMPACTING, &page->private);
176 clear_bit(PAGE_STALE, &page->private); 177 clear_bit(PAGE_STALE, &page->private);
177 clear_bit(UNDER_RECLAIM, &page->private); 178 clear_bit(PAGE_CLAIMED, &page->private);
178 179
179 spin_lock_init(&zhdr->page_lock); 180 spin_lock_init(&zhdr->page_lock);
180 kref_init(&zhdr->refcount); 181 kref_init(&zhdr->refcount);
@@ -223,8 +224,11 @@ static unsigned long encode_handle(struct z3fold_header *zhdr, enum buddy bud)
223 unsigned long handle; 224 unsigned long handle;
224 225
225 handle = (unsigned long)zhdr; 226 handle = (unsigned long)zhdr;
226 if (bud != HEADLESS) 227 if (bud != HEADLESS) {
227 handle += (bud + zhdr->first_num) & BUDDY_MASK; 228 handle |= (bud + zhdr->first_num) & BUDDY_MASK;
229 if (bud == LAST)
230 handle |= (zhdr->last_chunks << BUDDY_SHIFT);
231 }
228 return handle; 232 return handle;
229} 233}
230 234
@@ -234,6 +238,12 @@ static struct z3fold_header *handle_to_z3fold_header(unsigned long handle)
234 return (struct z3fold_header *)(handle & PAGE_MASK); 238 return (struct z3fold_header *)(handle & PAGE_MASK);
235} 239}
236 240
241/* only for LAST bud, returns zero otherwise */
242static unsigned short handle_to_chunks(unsigned long handle)
243{
244 return (handle & ~PAGE_MASK) >> BUDDY_SHIFT;
245}
246
237/* 247/*
238 * (handle & BUDDY_MASK) < zhdr->first_num is possible in encode_handle 248 * (handle & BUDDY_MASK) < zhdr->first_num is possible in encode_handle
239 * but that doesn't matter. because the masking will result in the 249 * but that doesn't matter. because the masking will result in the
@@ -720,37 +730,39 @@ static void z3fold_free(struct z3fold_pool *pool, unsigned long handle)
720 page = virt_to_page(zhdr); 730 page = virt_to_page(zhdr);
721 731
722 if (test_bit(PAGE_HEADLESS, &page->private)) { 732 if (test_bit(PAGE_HEADLESS, &page->private)) {
723 /* HEADLESS page stored */ 733 /* if a headless page is under reclaim, just leave.
724 bud = HEADLESS; 734 * NB: we use test_and_set_bit for a reason: if the bit
725 } else { 735 * has not been set before, we release this page
726 z3fold_page_lock(zhdr); 736 * immediately so we don't care about its value any more.
727 bud = handle_to_buddy(handle); 737 */
728 738 if (!test_and_set_bit(PAGE_CLAIMED, &page->private)) {
729 switch (bud) { 739 spin_lock(&pool->lock);
730 case FIRST: 740 list_del(&page->lru);
731 zhdr->first_chunks = 0; 741 spin_unlock(&pool->lock);
732 break; 742 free_z3fold_page(page);
733 case MIDDLE: 743 atomic64_dec(&pool->pages_nr);
734 zhdr->middle_chunks = 0;
735 zhdr->start_middle = 0;
736 break;
737 case LAST:
738 zhdr->last_chunks = 0;
739 break;
740 default:
741 pr_err("%s: unknown bud %d\n", __func__, bud);
742 WARN_ON(1);
743 z3fold_page_unlock(zhdr);
744 return;
745 } 744 }
745 return;
746 } 746 }
747 747
748 if (bud == HEADLESS) { 748 /* Non-headless case */
749 spin_lock(&pool->lock); 749 z3fold_page_lock(zhdr);
750 list_del(&page->lru); 750 bud = handle_to_buddy(handle);
751 spin_unlock(&pool->lock); 751
752 free_z3fold_page(page); 752 switch (bud) {
753 atomic64_dec(&pool->pages_nr); 753 case FIRST:
754 zhdr->first_chunks = 0;
755 break;
756 case MIDDLE:
757 zhdr->middle_chunks = 0;
758 break;
759 case LAST:
760 zhdr->last_chunks = 0;
761 break;
762 default:
763 pr_err("%s: unknown bud %d\n", __func__, bud);
764 WARN_ON(1);
765 z3fold_page_unlock(zhdr);
754 return; 766 return;
755 } 767 }
756 768
@@ -758,7 +770,7 @@ static void z3fold_free(struct z3fold_pool *pool, unsigned long handle)
758 atomic64_dec(&pool->pages_nr); 770 atomic64_dec(&pool->pages_nr);
759 return; 771 return;
760 } 772 }
761 if (test_bit(UNDER_RECLAIM, &page->private)) { 773 if (test_bit(PAGE_CLAIMED, &page->private)) {
762 z3fold_page_unlock(zhdr); 774 z3fold_page_unlock(zhdr);
763 return; 775 return;
764 } 776 }
@@ -836,20 +848,30 @@ static int z3fold_reclaim_page(struct z3fold_pool *pool, unsigned int retries)
836 } 848 }
837 list_for_each_prev(pos, &pool->lru) { 849 list_for_each_prev(pos, &pool->lru) {
838 page = list_entry(pos, struct page, lru); 850 page = list_entry(pos, struct page, lru);
851
852 /* this bit could have been set by free, in which case
853 * we pass over to the next page in the pool.
854 */
855 if (test_and_set_bit(PAGE_CLAIMED, &page->private))
856 continue;
857
858 zhdr = page_address(page);
839 if (test_bit(PAGE_HEADLESS, &page->private)) 859 if (test_bit(PAGE_HEADLESS, &page->private))
840 /* candidate found */
841 break; 860 break;
842 861
843 zhdr = page_address(page); 862 if (!z3fold_page_trylock(zhdr)) {
844 if (!z3fold_page_trylock(zhdr)) 863 zhdr = NULL;
845 continue; /* can't evict at this point */ 864 continue; /* can't evict at this point */
865 }
846 kref_get(&zhdr->refcount); 866 kref_get(&zhdr->refcount);
847 list_del_init(&zhdr->buddy); 867 list_del_init(&zhdr->buddy);
848 zhdr->cpu = -1; 868 zhdr->cpu = -1;
849 set_bit(UNDER_RECLAIM, &page->private);
850 break; 869 break;
851 } 870 }
852 871
872 if (!zhdr)
873 break;
874
853 list_del_init(&page->lru); 875 list_del_init(&page->lru);
854 spin_unlock(&pool->lock); 876 spin_unlock(&pool->lock);
855 877
@@ -898,6 +920,7 @@ next:
898 if (test_bit(PAGE_HEADLESS, &page->private)) { 920 if (test_bit(PAGE_HEADLESS, &page->private)) {
899 if (ret == 0) { 921 if (ret == 0) {
900 free_z3fold_page(page); 922 free_z3fold_page(page);
923 atomic64_dec(&pool->pages_nr);
901 return 0; 924 return 0;
902 } 925 }
903 spin_lock(&pool->lock); 926 spin_lock(&pool->lock);
@@ -905,7 +928,7 @@ next:
905 spin_unlock(&pool->lock); 928 spin_unlock(&pool->lock);
906 } else { 929 } else {
907 z3fold_page_lock(zhdr); 930 z3fold_page_lock(zhdr);
908 clear_bit(UNDER_RECLAIM, &page->private); 931 clear_bit(PAGE_CLAIMED, &page->private);
909 if (kref_put(&zhdr->refcount, 932 if (kref_put(&zhdr->refcount,
910 release_z3fold_page_locked)) { 933 release_z3fold_page_locked)) {
911 atomic64_dec(&pool->pages_nr); 934 atomic64_dec(&pool->pages_nr);
@@ -964,7 +987,7 @@ static void *z3fold_map(struct z3fold_pool *pool, unsigned long handle)
964 set_bit(MIDDLE_CHUNK_MAPPED, &page->private); 987 set_bit(MIDDLE_CHUNK_MAPPED, &page->private);
965 break; 988 break;
966 case LAST: 989 case LAST:
967 addr += PAGE_SIZE - (zhdr->last_chunks << CHUNK_SHIFT); 990 addr += PAGE_SIZE - (handle_to_chunks(handle) << CHUNK_SHIFT);
968 break; 991 break;
969 default: 992 default:
970 pr_err("unknown buddy id %d\n", buddy); 993 pr_err("unknown buddy id %d\n", buddy);