@@ -181,6 +181,13 @@ enum z3fold_page_flags {
181181 PAGE_CLAIMED , /* by either reclaim or free */
182182};
183183
184+ /*
185+ * handle flags, go under HANDLE_FLAG_MASK
186+ */
187+ enum z3fold_handle_flags {
188+ HANDLES_NOFREE = 0 ,
189+ };
190+
184191/*
185192 * Forward declarations
186193 */
@@ -311,6 +318,12 @@ static inline void free_handle(unsigned long handle, struct z3fold_header *zhdr)
311318 slots = handle_to_slots (handle );
312319 write_lock (& slots -> lock );
313320 * (unsigned long * )handle = 0 ;
321+
322+ if (test_bit (HANDLES_NOFREE , & slots -> pool )) {
323+ write_unlock (& slots -> lock );
324+ return ; /* simple case, nothing else to do */
325+ }
326+
314327 if (zhdr -> slots != slots )
315328 zhdr -> foreign_handles -- ;
316329
@@ -621,6 +634,28 @@ static inline void add_to_unbuddied(struct z3fold_pool *pool,
621634 }
622635}
623636
637+ static inline enum buddy get_free_buddy (struct z3fold_header * zhdr , int chunks )
638+ {
639+ enum buddy bud = HEADLESS ;
640+
641+ if (zhdr -> middle_chunks ) {
642+ if (!zhdr -> first_chunks &&
643+ chunks <= zhdr -> start_middle - ZHDR_CHUNKS )
644+ bud = FIRST ;
645+ else if (!zhdr -> last_chunks )
646+ bud = LAST ;
647+ } else {
648+ if (!zhdr -> first_chunks )
649+ bud = FIRST ;
650+ else if (!zhdr -> last_chunks )
651+ bud = LAST ;
652+ else
653+ bud = MIDDLE ;
654+ }
655+
656+ return bud ;
657+ }
658+
624659static inline void * mchunk_memmove (struct z3fold_header * zhdr ,
625660 unsigned short dst_chunk )
626661{
@@ -682,18 +717,7 @@ static struct z3fold_header *compact_single_buddy(struct z3fold_header *zhdr)
682717 if (WARN_ON (new_zhdr == zhdr ))
683718 goto out_fail ;
684719
685- if (new_zhdr -> first_chunks == 0 ) {
686- if (new_zhdr -> middle_chunks != 0 &&
687- chunks >= new_zhdr -> start_middle ) {
688- new_bud = LAST ;
689- } else {
690- new_bud = FIRST ;
691- }
692- } else if (new_zhdr -> last_chunks == 0 ) {
693- new_bud = LAST ;
694- } else if (new_zhdr -> middle_chunks == 0 ) {
695- new_bud = MIDDLE ;
696- }
720+ new_bud = get_free_buddy (new_zhdr , chunks );
697721 q = new_zhdr ;
698722 switch (new_bud ) {
699723 case FIRST :
@@ -815,9 +839,8 @@ static void do_compact_page(struct z3fold_header *zhdr, bool locked)
815839 return ;
816840 }
817841
818- if (unlikely (PageIsolated (page ) ||
819- test_bit (PAGE_CLAIMED , & page -> private ) ||
820- test_bit (PAGE_STALE , & page -> private ))) {
842+ if (test_bit (PAGE_STALE , & page -> private ) ||
843+ test_and_set_bit (PAGE_CLAIMED , & page -> private )) {
821844 z3fold_page_unlock (zhdr );
822845 return ;
823846 }
@@ -826,13 +849,16 @@ static void do_compact_page(struct z3fold_header *zhdr, bool locked)
826849 zhdr -> mapped_count == 0 && compact_single_buddy (zhdr )) {
827850 if (kref_put (& zhdr -> refcount , release_z3fold_page_locked ))
828851 atomic64_dec (& pool -> pages_nr );
829- else
852+ else {
853+ clear_bit (PAGE_CLAIMED , & page -> private );
830854 z3fold_page_unlock (zhdr );
855+ }
831856 return ;
832857 }
833858
834859 z3fold_compact_page (zhdr );
835860 add_to_unbuddied (pool , zhdr );
861+ clear_bit (PAGE_CLAIMED , & page -> private );
836862 z3fold_page_unlock (zhdr );
837863}
838864
@@ -1080,17 +1106,8 @@ static int z3fold_alloc(struct z3fold_pool *pool, size_t size, gfp_t gfp,
10801106retry :
10811107 zhdr = __z3fold_alloc (pool , size , can_sleep );
10821108 if (zhdr ) {
1083- if (zhdr -> first_chunks == 0 ) {
1084- if (zhdr -> middle_chunks != 0 &&
1085- chunks >= zhdr -> start_middle )
1086- bud = LAST ;
1087- else
1088- bud = FIRST ;
1089- } else if (zhdr -> last_chunks == 0 )
1090- bud = LAST ;
1091- else if (zhdr -> middle_chunks == 0 )
1092- bud = MIDDLE ;
1093- else {
1109+ bud = get_free_buddy (zhdr , chunks );
1110+ if (bud == HEADLESS ) {
10941111 if (kref_put (& zhdr -> refcount ,
10951112 release_z3fold_page_locked ))
10961113 atomic64_dec (& pool -> pages_nr );
@@ -1236,7 +1253,6 @@ static void z3fold_free(struct z3fold_pool *pool, unsigned long handle)
12361253 pr_err ("%s: unknown bud %d\n" , __func__ , bud );
12371254 WARN_ON (1 );
12381255 put_z3fold_header (zhdr );
1239- clear_bit (PAGE_CLAIMED , & page -> private );
12401256 return ;
12411257 }
12421258
@@ -1251,8 +1267,7 @@ static void z3fold_free(struct z3fold_pool *pool, unsigned long handle)
12511267 z3fold_page_unlock (zhdr );
12521268 return ;
12531269 }
1254- if (unlikely (PageIsolated (page )) ||
1255- test_and_set_bit (NEEDS_COMPACTING , & page -> private )) {
1270+ if (test_and_set_bit (NEEDS_COMPACTING , & page -> private )) {
12561271 put_z3fold_header (zhdr );
12571272 clear_bit (PAGE_CLAIMED , & page -> private );
12581273 return ;
@@ -1316,6 +1331,10 @@ static int z3fold_reclaim_page(struct z3fold_pool *pool, unsigned int retries)
13161331 struct page * page = NULL ;
13171332 struct list_head * pos ;
13181333 unsigned long first_handle = 0 , middle_handle = 0 , last_handle = 0 ;
1334+ struct z3fold_buddy_slots slots __attribute__((aligned (SLOTS_ALIGN )));
1335+
1336+ rwlock_init (& slots .lock );
1337+ slots .pool = (unsigned long )pool | (1 << HANDLES_NOFREE );
13191338
13201339 spin_lock (& pool -> lock );
13211340 if (!pool -> ops || !pool -> ops -> evict || retries == 0 ) {
@@ -1330,35 +1349,36 @@ static int z3fold_reclaim_page(struct z3fold_pool *pool, unsigned int retries)
13301349 list_for_each_prev (pos , & pool -> lru ) {
13311350 page = list_entry (pos , struct page , lru );
13321351
1333- /* this bit could have been set by free, in which case
1334- * we pass over to the next page in the pool.
1335- */
1336- if (test_and_set_bit (PAGE_CLAIMED , & page -> private )) {
1337- page = NULL ;
1338- continue ;
1339- }
1340-
1341- if (unlikely (PageIsolated (page ))) {
1342- clear_bit (PAGE_CLAIMED , & page -> private );
1343- page = NULL ;
1344- continue ;
1345- }
13461352 zhdr = page_address (page );
13471353 if (test_bit (PAGE_HEADLESS , & page -> private ))
13481354 break ;
13491355
1356+ if (kref_get_unless_zero (& zhdr -> refcount ) == 0 ) {
1357+ zhdr = NULL ;
1358+ break ;
1359+ }
13501360 if (!z3fold_page_trylock (zhdr )) {
1351- clear_bit (PAGE_CLAIMED , & page -> private );
1361+ if (kref_put (& zhdr -> refcount ,
1362+ release_z3fold_page ))
1363+ atomic64_dec (& pool -> pages_nr );
13521364 zhdr = NULL ;
13531365 continue ; /* can't evict at this point */
13541366 }
1355- if (zhdr -> foreign_handles ) {
1356- clear_bit (PAGE_CLAIMED , & page -> private );
1357- z3fold_page_unlock (zhdr );
1367+
1368+ /* test_and_set_bit is of course atomic, but we still
1369+ * need to do it under page lock, otherwise checking
1370+ * that bit in __z3fold_alloc wouldn't make sense
1371+ */
1372+ if (zhdr -> foreign_handles ||
1373+ test_and_set_bit (PAGE_CLAIMED , & page -> private )) {
1374+ if (kref_put (& zhdr -> refcount ,
1375+ release_z3fold_page ))
1376+ atomic64_dec (& pool -> pages_nr );
1377+ else
1378+ z3fold_page_unlock (zhdr );
13581379 zhdr = NULL ;
13591380 continue ; /* can't evict such page */
13601381 }
1361- kref_get (& zhdr -> refcount );
13621382 list_del_init (& zhdr -> buddy );
13631383 zhdr -> cpu = -1 ;
13641384 break ;
@@ -1380,12 +1400,16 @@ static int z3fold_reclaim_page(struct z3fold_pool *pool, unsigned int retries)
13801400 first_handle = 0 ;
13811401 last_handle = 0 ;
13821402 middle_handle = 0 ;
1403+ memset (slots .slot , 0 , sizeof (slots .slot ));
13831404 if (zhdr -> first_chunks )
1384- first_handle = encode_handle (zhdr , FIRST );
1405+ first_handle = __encode_handle (zhdr , & slots ,
1406+ FIRST );
13851407 if (zhdr -> middle_chunks )
1386- middle_handle = encode_handle (zhdr , MIDDLE );
1408+ middle_handle = __encode_handle (zhdr , & slots ,
1409+ MIDDLE );
13871410 if (zhdr -> last_chunks )
1388- last_handle = encode_handle (zhdr , LAST );
1411+ last_handle = __encode_handle (zhdr , & slots ,
1412+ LAST );
13891413 /*
13901414 * it's safe to unlock here because we hold a
13911415 * reference to this page
@@ -1400,19 +1424,16 @@ static int z3fold_reclaim_page(struct z3fold_pool *pool, unsigned int retries)
14001424 ret = pool -> ops -> evict (pool , middle_handle );
14011425 if (ret )
14021426 goto next ;
1403- free_handle (middle_handle , zhdr );
14041427 }
14051428 if (first_handle ) {
14061429 ret = pool -> ops -> evict (pool , first_handle );
14071430 if (ret )
14081431 goto next ;
1409- free_handle (first_handle , zhdr );
14101432 }
14111433 if (last_handle ) {
14121434 ret = pool -> ops -> evict (pool , last_handle );
14131435 if (ret )
14141436 goto next ;
1415- free_handle (last_handle , zhdr );
14161437 }
14171438next :
14181439 if (test_bit (PAGE_HEADLESS , & page -> private )) {
@@ -1426,9 +1447,11 @@ static int z3fold_reclaim_page(struct z3fold_pool *pool, unsigned int retries)
14261447 spin_unlock (& pool -> lock );
14271448 clear_bit (PAGE_CLAIMED , & page -> private );
14281449 } else {
1450+ struct z3fold_buddy_slots * slots = zhdr -> slots ;
14291451 z3fold_page_lock (zhdr );
14301452 if (kref_put (& zhdr -> refcount ,
14311453 release_z3fold_page_locked )) {
1454+ kmem_cache_free (pool -> c_handle , slots );
14321455 atomic64_dec (& pool -> pages_nr );
14331456 return 0 ;
14341457 }
@@ -1544,8 +1567,7 @@ static bool z3fold_page_isolate(struct page *page, isolate_mode_t mode)
15441567 VM_BUG_ON_PAGE (!PageMovable (page ), page );
15451568 VM_BUG_ON_PAGE (PageIsolated (page ), page );
15461569
1547- if (test_bit (PAGE_HEADLESS , & page -> private ) ||
1548- test_bit (PAGE_CLAIMED , & page -> private ))
1570+ if (test_bit (PAGE_HEADLESS , & page -> private ))
15491571 return false;
15501572
15511573 zhdr = page_address (page );
@@ -1557,6 +1579,8 @@ static bool z3fold_page_isolate(struct page *page, isolate_mode_t mode)
15571579 if (zhdr -> mapped_count != 0 || zhdr -> foreign_handles != 0 )
15581580 goto out ;
15591581
1582+ if (test_and_set_bit (PAGE_CLAIMED , & page -> private ))
1583+ goto out ;
15601584 pool = zhdr_to_pool (zhdr );
15611585 spin_lock (& pool -> lock );
15621586 if (!list_empty (& zhdr -> buddy ))
@@ -1583,16 +1607,17 @@ static int z3fold_page_migrate(struct address_space *mapping, struct page *newpa
15831607
15841608 VM_BUG_ON_PAGE (!PageMovable (page ), page );
15851609 VM_BUG_ON_PAGE (!PageIsolated (page ), page );
1610+ VM_BUG_ON_PAGE (!test_bit (PAGE_CLAIMED , & page -> private ), page );
15861611 VM_BUG_ON_PAGE (!PageLocked (newpage ), newpage );
15871612
15881613 zhdr = page_address (page );
15891614 pool = zhdr_to_pool (zhdr );
15901615
1591- if (!z3fold_page_trylock (zhdr )) {
1616+ if (!z3fold_page_trylock (zhdr ))
15921617 return - EAGAIN ;
1593- }
15941618 if (zhdr -> mapped_count != 0 || zhdr -> foreign_handles != 0 ) {
15951619 z3fold_page_unlock (zhdr );
1620+ clear_bit (PAGE_CLAIMED , & page -> private );
15961621 return - EBUSY ;
15971622 }
15981623 if (work_pending (& zhdr -> work )) {
@@ -1634,6 +1659,7 @@ static int z3fold_page_migrate(struct address_space *mapping, struct page *newpa
16341659 queue_work_on (new_zhdr -> cpu , pool -> compact_wq , & new_zhdr -> work );
16351660
16361661 page_mapcount_reset (page );
1662+ clear_bit (PAGE_CLAIMED , & page -> private );
16371663 put_page (page );
16381664 return 0 ;
16391665}
@@ -1657,6 +1683,7 @@ static void z3fold_page_putback(struct page *page)
16571683 spin_lock (& pool -> lock );
16581684 list_add (& page -> lru , & pool -> lru );
16591685 spin_unlock (& pool -> lock );
1686+ clear_bit (PAGE_CLAIMED , & page -> private );
16601687 z3fold_page_unlock (zhdr );
16611688}
16621689
0 commit comments