summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--mm/z3fold.c49
1 files changed, 34 insertions, 15 deletions
diff --git a/mm/z3fold.c b/mm/z3fold.c
index ed19d98c9dcd..d637d9ee005c 100644
--- a/mm/z3fold.c
+++ b/mm/z3fold.c
@@ -366,9 +366,10 @@ static inline int __idx(struct z3fold_header *zhdr, enum buddy bud)
366 * Encodes the handle of a particular buddy within a z3fold page 366 * Encodes the handle of a particular buddy within a z3fold page
367 * Pool lock should be held as this function accesses first_num 367 * Pool lock should be held as this function accesses first_num
368 */ 368 */
369static unsigned long encode_handle(struct z3fold_header *zhdr, enum buddy bud) 369static unsigned long __encode_handle(struct z3fold_header *zhdr,
370 struct z3fold_buddy_slots *slots,
371 enum buddy bud)
370{ 372{
371 struct z3fold_buddy_slots *slots;
372 unsigned long h = (unsigned long)zhdr; 373 unsigned long h = (unsigned long)zhdr;
373 int idx = 0; 374 int idx = 0;
374 375
@@ -385,11 +386,15 @@ static unsigned long encode_handle(struct z3fold_header *zhdr, enum buddy bud)
385 if (bud == LAST) 386 if (bud == LAST)
386 h |= (zhdr->last_chunks << BUDDY_SHIFT); 387 h |= (zhdr->last_chunks << BUDDY_SHIFT);
387 388
388 slots = zhdr->slots;
389 slots->slot[idx] = h; 389 slots->slot[idx] = h;
390 return (unsigned long)&slots->slot[idx]; 390 return (unsigned long)&slots->slot[idx];
391} 391}
392 392
393static unsigned long encode_handle(struct z3fold_header *zhdr, enum buddy bud)
394{
395 return __encode_handle(zhdr, zhdr->slots, bud);
396}
397
393/* Returns the z3fold page where a given handle is stored */ 398/* Returns the z3fold page where a given handle is stored */
394static inline struct z3fold_header *handle_to_z3fold_header(unsigned long h) 399static inline struct z3fold_header *handle_to_z3fold_header(unsigned long h)
395{ 400{
@@ -624,6 +629,7 @@ static void do_compact_page(struct z3fold_header *zhdr, bool locked)
624 } 629 }
625 630
626 if (unlikely(PageIsolated(page) || 631 if (unlikely(PageIsolated(page) ||
632 test_bit(PAGE_CLAIMED, &page->private) ||
627 test_bit(PAGE_STALE, &page->private))) { 633 test_bit(PAGE_STALE, &page->private))) {
628 z3fold_page_unlock(zhdr); 634 z3fold_page_unlock(zhdr);
629 return; 635 return;
@@ -1100,6 +1106,7 @@ static int z3fold_reclaim_page(struct z3fold_pool *pool, unsigned int retries)
1100 struct z3fold_header *zhdr = NULL; 1106 struct z3fold_header *zhdr = NULL;
1101 struct page *page = NULL; 1107 struct page *page = NULL;
1102 struct list_head *pos; 1108 struct list_head *pos;
1109 struct z3fold_buddy_slots slots;
1103 unsigned long first_handle = 0, middle_handle = 0, last_handle = 0; 1110 unsigned long first_handle = 0, middle_handle = 0, last_handle = 0;
1104 1111
1105 spin_lock(&pool->lock); 1112 spin_lock(&pool->lock);
@@ -1118,16 +1125,22 @@ static int z3fold_reclaim_page(struct z3fold_pool *pool, unsigned int retries)
1118 /* this bit could have been set by free, in which case 1125 /* this bit could have been set by free, in which case
1119 * we pass over to the next page in the pool. 1126 * we pass over to the next page in the pool.
1120 */ 1127 */
1121 if (test_and_set_bit(PAGE_CLAIMED, &page->private)) 1128 if (test_and_set_bit(PAGE_CLAIMED, &page->private)) {
1129 page = NULL;
1122 continue; 1130 continue;
1131 }
1123 1132
1124 if (unlikely(PageIsolated(page))) 1133 if (unlikely(PageIsolated(page))) {
1134 clear_bit(PAGE_CLAIMED, &page->private);
1135 page = NULL;
1125 continue; 1136 continue;
1137 }
1138 zhdr = page_address(page);
1126 if (test_bit(PAGE_HEADLESS, &page->private)) 1139 if (test_bit(PAGE_HEADLESS, &page->private))
1127 break; 1140 break;
1128 1141
1129 zhdr = page_address(page);
1130 if (!z3fold_page_trylock(zhdr)) { 1142 if (!z3fold_page_trylock(zhdr)) {
1143 clear_bit(PAGE_CLAIMED, &page->private);
1131 zhdr = NULL; 1144 zhdr = NULL;
1132 continue; /* can't evict at this point */ 1145 continue; /* can't evict at this point */
1133 } 1146 }
@@ -1145,26 +1158,30 @@ static int z3fold_reclaim_page(struct z3fold_pool *pool, unsigned int retries)
1145 1158
1146 if (!test_bit(PAGE_HEADLESS, &page->private)) { 1159 if (!test_bit(PAGE_HEADLESS, &page->private)) {
1147 /* 1160 /*
1148 * We need encode the handles before unlocking, since 1161 * We need encode the handles before unlocking, and
1149 * we can race with free that will set 1162 * use our local slots structure because z3fold_free
1150 * (first|last)_chunks to 0 1163 * can zero out zhdr->slots and we can't do much
1164 * about that
1151 */ 1165 */
1152 first_handle = 0; 1166 first_handle = 0;
1153 last_handle = 0; 1167 last_handle = 0;
1154 middle_handle = 0; 1168 middle_handle = 0;
1155 if (zhdr->first_chunks) 1169 if (zhdr->first_chunks)
1156 first_handle = encode_handle(zhdr, FIRST); 1170 first_handle = __encode_handle(zhdr, &slots,
1171 FIRST);
1157 if (zhdr->middle_chunks) 1172 if (zhdr->middle_chunks)
1158 middle_handle = encode_handle(zhdr, MIDDLE); 1173 middle_handle = __encode_handle(zhdr, &slots,
1174 MIDDLE);
1159 if (zhdr->last_chunks) 1175 if (zhdr->last_chunks)
1160 last_handle = encode_handle(zhdr, LAST); 1176 last_handle = __encode_handle(zhdr, &slots,
1177 LAST);
1161 /* 1178 /*
1162 * it's safe to unlock here because we hold a 1179 * it's safe to unlock here because we hold a
1163 * reference to this page 1180 * reference to this page
1164 */ 1181 */
1165 z3fold_page_unlock(zhdr); 1182 z3fold_page_unlock(zhdr);
1166 } else { 1183 } else {
1167 first_handle = encode_handle(zhdr, HEADLESS); 1184 first_handle = __encode_handle(zhdr, &slots, HEADLESS);
1168 last_handle = middle_handle = 0; 1185 last_handle = middle_handle = 0;
1169 } 1186 }
1170 1187
@@ -1194,9 +1211,9 @@ next:
1194 spin_lock(&pool->lock); 1211 spin_lock(&pool->lock);
1195 list_add(&page->lru, &pool->lru); 1212 list_add(&page->lru, &pool->lru);
1196 spin_unlock(&pool->lock); 1213 spin_unlock(&pool->lock);
1214 clear_bit(PAGE_CLAIMED, &page->private);
1197 } else { 1215 } else {
1198 z3fold_page_lock(zhdr); 1216 z3fold_page_lock(zhdr);
1199 clear_bit(PAGE_CLAIMED, &page->private);
1200 if (kref_put(&zhdr->refcount, 1217 if (kref_put(&zhdr->refcount,
1201 release_z3fold_page_locked)) { 1218 release_z3fold_page_locked)) {
1202 atomic64_dec(&pool->pages_nr); 1219 atomic64_dec(&pool->pages_nr);
@@ -1211,6 +1228,7 @@ next:
1211 list_add(&page->lru, &pool->lru); 1228 list_add(&page->lru, &pool->lru);
1212 spin_unlock(&pool->lock); 1229 spin_unlock(&pool->lock);
1213 z3fold_page_unlock(zhdr); 1230 z3fold_page_unlock(zhdr);
1231 clear_bit(PAGE_CLAIMED, &page->private);
1214 } 1232 }
1215 1233
1216 /* We started off locked to we need to lock the pool back */ 1234 /* We started off locked to we need to lock the pool back */
@@ -1315,7 +1333,8 @@ static bool z3fold_page_isolate(struct page *page, isolate_mode_t mode)
1315 VM_BUG_ON_PAGE(!PageMovable(page), page); 1333 VM_BUG_ON_PAGE(!PageMovable(page), page);
1316 VM_BUG_ON_PAGE(PageIsolated(page), page); 1334 VM_BUG_ON_PAGE(PageIsolated(page), page);
1317 1335
1318 if (test_bit(PAGE_HEADLESS, &page->private)) 1336 if (test_bit(PAGE_HEADLESS, &page->private) ||
1337 test_bit(PAGE_CLAIMED, &page->private))
1319 return false; 1338 return false;
1320 1339
1321 zhdr = page_address(page); 1340 zhdr = page_address(page);