diff options
-rw-r--r-- | mm/z3fold.c | 49 |
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 | */ |
369 | static unsigned long encode_handle(struct z3fold_header *zhdr, enum buddy bud) | 369 | static 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 | ||
393 | static 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 */ |
394 | static inline struct z3fold_header *handle_to_z3fold_header(unsigned long h) | 399 | static 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); |