@@ -48,6 +48,7 @@ enum scan_result {
48
48
SCAN_CGROUP_CHARGE_FAIL ,
49
49
SCAN_EXCEED_SWAP_PTE ,
50
50
SCAN_TRUNCATED ,
51
+ SCAN_PAGE_HAS_PRIVATE ,
51
52
};
52
53
53
54
#define CREATE_TRACE_POINTS
@@ -404,7 +405,11 @@ static bool hugepage_vma_check(struct vm_area_struct *vma,
404
405
(vm_flags & VM_NOHUGEPAGE ) ||
405
406
test_bit (MMF_DISABLE_THP , & vma -> vm_mm -> flags ))
406
407
return false;
407
- if (shmem_file (vma -> vm_file )) {
408
+
409
+ if (shmem_file (vma -> vm_file ) ||
410
+ (IS_ENABLED (CONFIG_READ_ONLY_THP_FOR_FS ) &&
411
+ vma -> vm_file &&
412
+ (vm_flags & VM_DENYWRITE ))) {
408
413
if (!IS_ENABLED (CONFIG_TRANSPARENT_HUGE_PAGECACHE ))
409
414
return false;
410
415
return IS_ALIGNED ((vma -> vm_start >> PAGE_SHIFT ) - vma -> vm_pgoff ,
@@ -456,8 +461,9 @@ int khugepaged_enter_vma_merge(struct vm_area_struct *vma,
456
461
unsigned long hstart , hend ;
457
462
458
463
/*
459
- * khugepaged does not yet work on non-shmem files or special
460
- * mappings. And file-private shmem THP is not supported.
464
+ * khugepaged only supports read-only files for non-shmem files.
465
+ * khugepaged does not yet work on special mappings. And
466
+ * file-private shmem THP is not supported.
461
467
*/
462
468
if (!hugepage_vma_check (vma , vm_flags ))
463
469
return 0 ;
@@ -1287,12 +1293,12 @@ static void retract_page_tables(struct address_space *mapping, pgoff_t pgoff)
1287
1293
}
1288
1294
1289
1295
/**
1290
- * collapse_file - collapse small tmpfs/shmem pages into huge one.
1296
+ * collapse_file - collapse filemap/ tmpfs/shmem pages into huge one.
1291
1297
*
1292
1298
* Basic scheme is simple, details are more complex:
1293
1299
* - allocate and lock a new huge page;
1294
1300
* - scan page cache replacing old pages with the new one
1295
- * + swap in pages if necessary;
1301
+ * + swap/gup in pages if necessary;
1296
1302
* + fill in gaps;
1297
1303
* + keep old pages around in case rollback is required;
1298
1304
* - if replacing succeeds:
@@ -1316,7 +1322,9 @@ static void collapse_file(struct mm_struct *mm,
1316
1322
LIST_HEAD (pagelist );
1317
1323
XA_STATE_ORDER (xas , & mapping -> i_pages , start , HPAGE_PMD_ORDER );
1318
1324
int nr_none = 0 , result = SCAN_SUCCEED ;
1325
+ bool is_shmem = shmem_file (file );
1319
1326
1327
+ VM_BUG_ON (!IS_ENABLED (CONFIG_READ_ONLY_THP_FOR_FS ) && !is_shmem );
1320
1328
VM_BUG_ON (start & (HPAGE_PMD_NR - 1 ));
1321
1329
1322
1330
/* Only allocate from the target node */
@@ -1348,7 +1356,8 @@ static void collapse_file(struct mm_struct *mm,
1348
1356
} while (1 );
1349
1357
1350
1358
__SetPageLocked (new_page );
1351
- __SetPageSwapBacked (new_page );
1359
+ if (is_shmem )
1360
+ __SetPageSwapBacked (new_page );
1352
1361
new_page -> index = start ;
1353
1362
new_page -> mapping = mapping ;
1354
1363
@@ -1363,41 +1372,75 @@ static void collapse_file(struct mm_struct *mm,
1363
1372
struct page * page = xas_next (& xas );
1364
1373
1365
1374
VM_BUG_ON (index != xas .xa_index );
1366
- if (!page ) {
1367
- /*
1368
- * Stop if extent has been truncated or hole-punched,
1369
- * and is now completely empty.
1370
- */
1371
- if (index == start ) {
1372
- if (!xas_next_entry (& xas , end - 1 )) {
1373
- result = SCAN_TRUNCATED ;
1375
+ if (is_shmem ) {
1376
+ if (!page ) {
1377
+ /*
1378
+ * Stop if extent has been truncated or
1379
+ * hole-punched, and is now completely
1380
+ * empty.
1381
+ */
1382
+ if (index == start ) {
1383
+ if (!xas_next_entry (& xas , end - 1 )) {
1384
+ result = SCAN_TRUNCATED ;
1385
+ goto xa_locked ;
1386
+ }
1387
+ xas_set (& xas , index );
1388
+ }
1389
+ if (!shmem_charge (mapping -> host , 1 )) {
1390
+ result = SCAN_FAIL ;
1374
1391
goto xa_locked ;
1375
1392
}
1376
- xas_set (& xas , index );
1393
+ xas_store (& xas , new_page );
1394
+ nr_none ++ ;
1395
+ continue ;
1377
1396
}
1378
- if (!shmem_charge (mapping -> host , 1 )) {
1379
- result = SCAN_FAIL ;
1397
+
1398
+ if (xa_is_value (page ) || !PageUptodate (page )) {
1399
+ xas_unlock_irq (& xas );
1400
+ /* swap in or instantiate fallocated page */
1401
+ if (shmem_getpage (mapping -> host , index , & page ,
1402
+ SGP_NOHUGE )) {
1403
+ result = SCAN_FAIL ;
1404
+ goto xa_unlocked ;
1405
+ }
1406
+ } else if (trylock_page (page )) {
1407
+ get_page (page );
1408
+ xas_unlock_irq (& xas );
1409
+ } else {
1410
+ result = SCAN_PAGE_LOCK ;
1380
1411
goto xa_locked ;
1381
1412
}
1382
- xas_store (& xas , new_page );
1383
- nr_none ++ ;
1384
- continue ;
1385
- }
1386
-
1387
- if (xa_is_value (page ) || !PageUptodate (page )) {
1388
- xas_unlock_irq (& xas );
1389
- /* swap in or instantiate fallocated page */
1390
- if (shmem_getpage (mapping -> host , index , & page ,
1391
- SGP_NOHUGE )) {
1413
+ } else { /* !is_shmem */
1414
+ if (!page || xa_is_value (page )) {
1415
+ xas_unlock_irq (& xas );
1416
+ page_cache_sync_readahead (mapping , & file -> f_ra ,
1417
+ file , index ,
1418
+ PAGE_SIZE );
1419
+ /* drain pagevecs to help isolate_lru_page() */
1420
+ lru_add_drain ();
1421
+ page = find_lock_page (mapping , index );
1422
+ if (unlikely (page == NULL )) {
1423
+ result = SCAN_FAIL ;
1424
+ goto xa_unlocked ;
1425
+ }
1426
+ } else if (!PageUptodate (page )) {
1427
+ xas_unlock_irq (& xas );
1428
+ wait_on_page_locked (page );
1429
+ if (!trylock_page (page )) {
1430
+ result = SCAN_PAGE_LOCK ;
1431
+ goto xa_unlocked ;
1432
+ }
1433
+ get_page (page );
1434
+ } else if (PageDirty (page )) {
1392
1435
result = SCAN_FAIL ;
1393
- goto xa_unlocked ;
1436
+ goto xa_locked ;
1437
+ } else if (trylock_page (page )) {
1438
+ get_page (page );
1439
+ xas_unlock_irq (& xas );
1440
+ } else {
1441
+ result = SCAN_PAGE_LOCK ;
1442
+ goto xa_locked ;
1394
1443
}
1395
- } else if (trylock_page (page )) {
1396
- get_page (page );
1397
- xas_unlock_irq (& xas );
1398
- } else {
1399
- result = SCAN_PAGE_LOCK ;
1400
- goto xa_locked ;
1401
1444
}
1402
1445
1403
1446
/*
@@ -1426,6 +1469,12 @@ static void collapse_file(struct mm_struct *mm,
1426
1469
goto out_unlock ;
1427
1470
}
1428
1471
1472
+ if (page_has_private (page ) &&
1473
+ !try_to_release_page (page , GFP_KERNEL )) {
1474
+ result = SCAN_PAGE_HAS_PRIVATE ;
1475
+ goto out_unlock ;
1476
+ }
1477
+
1429
1478
if (page_mapped (page ))
1430
1479
unmap_mapping_pages (mapping , index , 1 , false);
1431
1480
@@ -1463,12 +1512,18 @@ static void collapse_file(struct mm_struct *mm,
1463
1512
goto xa_unlocked ;
1464
1513
}
1465
1514
1466
- __inc_node_page_state (new_page , NR_SHMEM_THPS );
1515
+ if (is_shmem )
1516
+ __inc_node_page_state (new_page , NR_SHMEM_THPS );
1517
+ else
1518
+ __inc_node_page_state (new_page , NR_FILE_THPS );
1519
+
1467
1520
if (nr_none ) {
1468
1521
struct zone * zone = page_zone (new_page );
1469
1522
1470
1523
__mod_node_page_state (zone -> zone_pgdat , NR_FILE_PAGES , nr_none );
1471
- __mod_node_page_state (zone -> zone_pgdat , NR_SHMEM , nr_none );
1524
+ if (is_shmem )
1525
+ __mod_node_page_state (zone -> zone_pgdat ,
1526
+ NR_SHMEM , nr_none );
1472
1527
}
1473
1528
1474
1529
xa_locked :
@@ -1506,10 +1561,15 @@ static void collapse_file(struct mm_struct *mm,
1506
1561
1507
1562
SetPageUptodate (new_page );
1508
1563
page_ref_add (new_page , HPAGE_PMD_NR - 1 );
1509
- set_page_dirty (new_page );
1510
1564
mem_cgroup_commit_charge (new_page , memcg , false, true);
1565
+
1566
+ if (is_shmem ) {
1567
+ set_page_dirty (new_page );
1568
+ lru_cache_add_anon (new_page );
1569
+ } else {
1570
+ lru_cache_add_file (new_page );
1571
+ }
1511
1572
count_memcg_events (memcg , THP_COLLAPSE_ALLOC , 1 );
1512
- lru_cache_add_anon (new_page );
1513
1573
1514
1574
/*
1515
1575
* Remove pte page tables, so we can re-fault the page as huge.
@@ -1524,7 +1584,9 @@ static void collapse_file(struct mm_struct *mm,
1524
1584
/* Something went wrong: roll back page cache changes */
1525
1585
xas_lock_irq (& xas );
1526
1586
mapping -> nrpages -= nr_none ;
1527
- shmem_uncharge (mapping -> host , nr_none );
1587
+
1588
+ if (is_shmem )
1589
+ shmem_uncharge (mapping -> host , nr_none );
1528
1590
1529
1591
xas_set (& xas , start );
1530
1592
xas_for_each (& xas , page , end - 1 ) {
@@ -1607,7 +1669,8 @@ static void khugepaged_scan_file(struct mm_struct *mm,
1607
1669
break ;
1608
1670
}
1609
1671
1610
- if (page_count (page ) != 1 + page_mapcount (page )) {
1672
+ if (page_count (page ) !=
1673
+ 1 + page_mapcount (page ) + page_has_private (page )) {
1611
1674
result = SCAN_PAGE_COUNT ;
1612
1675
break ;
1613
1676
}
@@ -1713,11 +1776,13 @@ static unsigned int khugepaged_scan_mm_slot(unsigned int pages,
1713
1776
VM_BUG_ON (khugepaged_scan .address < hstart ||
1714
1777
khugepaged_scan .address + HPAGE_PMD_SIZE >
1715
1778
hend );
1716
- if (shmem_file ( vma -> vm_file ) ) {
1779
+ if (IS_ENABLED ( CONFIG_SHMEM ) && vma -> vm_file ) {
1717
1780
struct file * file ;
1718
1781
pgoff_t pgoff = linear_page_index (vma ,
1719
1782
khugepaged_scan .address );
1720
- if (!shmem_huge_enabled (vma ))
1783
+
1784
+ if (shmem_file (vma -> vm_file )
1785
+ && !shmem_huge_enabled (vma ))
1721
1786
goto skip ;
1722
1787
file = get_file (vma -> vm_file );
1723
1788
up_read (& mm -> mmap_sem );
0 commit comments