summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVitaly Wool <vitalywool@gmail.com>2019-09-23 18:33:02 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2019-09-24 18:54:06 -0400
commit3f9d2b5766aea06042630ac60b7316fd0cebf06f (patch)
tree297838e1dff9482bd655535ee918331a558c3038
parent710ec38b0f633ab3e2581f07a73442d809e28ab0 (diff)
z3fold: fix retry mechanism in page reclaim
z3fold_page_reclaim()'s retry mechanism is broken: on a second iteration it will have zhdr from the first one so that zhdr is no longer in line with struct page. That leads to crashes when the system is stressed. Fix that by moving zhdr assignment up. While at it, protect against using already freed handles by using own local slots structure in z3fold_page_reclaim(). Link: http://lkml.kernel.org/r/20190908162919.830388dc7404d1e2c80f4095@gmail.com Signed-off-by: Vitaly Wool <vitalywool@gmail.com> Reported-by: Markus Linnala <markus.linnala@gmail.com> Reported-by: Chris Murphy <bugzilla@colorremedies.com> Reported-by: Agustin Dall'Alba <agustin@dallalba.com.ar> Cc: "Maciej S. Szmigiero" <mail@maciej.szmigiero.name> Cc: Shakeel Butt <shakeelb@google.com> Cc: Henry Burns <henrywolfeburns@gmail.com> Cc: <stable@vger.kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-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);