History

Merge branch 'core-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull NUMA balancing memory corruption fixes from Ingo Molnar: "So these fixes are definitely not something I'd like to sit on, but as I said to Mel at the KS the timing is quite tight, with Linus planning v3.12-final within a week. Fedora-19 is affected: comet:~> grep NUMA_BALANCING /boot/config-3.11.3-201.fc19.x86_64 CONFIG_ARCH_SUPPORTS_NUMA_BALANCING=y CONFIG_NUMA_BALANCING_DEFAULT_ENABLED=y CONFIG_NUMA_BALANCING=y AFAICS Ubuntu will be affected as well, once it updates the kernel: hubble:~> grep NUMA_BALANCING /boot/config-3.8.0-32-generic CONFIG_ARCH_SUPPORTS_NUMA_BALANCING=y CONFIG_NUMA_BALANCING_DEFAULT_ENABLED=y CONFIG_NUMA_BALANCING=y These 6 commits are a minimalized set of cherry-picks needed to fix the memory corruption bugs. All commits are fixes, except "mm: numa: Sanitize task_numa_fault() callsites" which is a cleanup that made two followup fixes simpler. I've done targeted testing with just this SHA1 to try to make sure there are no cherry-picking artifacts. The original non-cherry-picked set of fixes were exposed to linux-next for a couple of weeks" * 'core-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: mm: Account for a THP NUMA hinting update as one PTE update mm: Close races between THP migration and PMD numa clearing mm: numa: Sanitize task_numa_fault() callsites mm: Prevent parallel splits during THP migration mm: Wait for THP migrations to complete during NUMA hinting faults mm: numa: Do not account for a hinting fault if we raced

Linus Torvalds committed 13 years ago

Commit 52469b42 parents 026f8f6 0255d494 files · +81 −63Browse files

Unified · Split

4 files
  1. mm/huge_memory.c +48 −22
  2. mm/memory.c +21 −32
  3. mm/migrate.c +11 −8
  4. mm/mprotect.c +1 −1
mm/huge_memory.c+48−22
@@ -1278,64 +1278,90 @@ out: · 1277 unmodified lines
12781278 int do_huge_pmd_numa_page(struct mm_struct *mm, struct vm_area_struct *vma,
12791279 unsigned long addr, pmd_t pmd, pmd_t *pmdp)
12801280 {
1281+ struct anon_vma *anon_vma = NULL;
12811282 struct page *page;
12821283 unsigned long haddr = addr & HPAGE_PMD_MASK;
1284+ int page_nid = -1, this_nid = numa_node_id();
12831285 int target_nid;
1284− int current_nid = -1;
1285− bool migrated;
1286+ bool page_locked;
1287+ bool migrated = false;
12861288
12871289 spin_lock(&mm->page_table_lock);
12881290 if (unlikely(!pmd_same(pmd, *pmdp)))
12891291 goto out_unlock;
12901292
12911293 page = pmd_page(pmd);
1292− get_page(page);
1293− current_nid = page_to_nid(page);
1294+ page_nid = page_to_nid(page);
12941295 count_vm_numa_event(NUMA_HINT_FAULTS);
1295− if (current_nid == numa_node_id())
1296+ if (page_nid == this_nid)
12961297 count_vm_numa_event(NUMA_HINT_FAULTS_LOCAL);
12971298
1299+ /*
1300+ * Acquire the page lock to serialise THP migrations but avoid dropping
1301+ * page_table_lock if at all possible
1302+ */
1303+ page_locked = trylock_page(page);
12981304 target_nid = mpol_misplaced(page, vma, haddr);
12991305 if (target_nid == -1) {
1300− put_page(page);
1301− goto clear_pmdnuma;
1306+ /* If the page was locked, there are no parallel migrations */
1307+ if (page_locked)
1308+ goto clear_pmdnuma;
1309+
1310+ /*
1311+ * Otherwise wait for potential migrations and retry. We do
1312+ * relock and check_same as the page may no longer be mapped.
1313+ * As the fault is being retried, do not account for it.
1314+ */
1315+ spin_unlock(&mm->page_table_lock);
1316+ wait_on_page_locked(page);
1317+ page_nid = -1;
1318+ goto out;
13021319 }
13031320
1304− /* Acquire the page lock to serialise THP migrations */
1321+ /* Page is misplaced, serialise migrations and parallel THP splits */
1322+ get_page(page);
13051323 spin_unlock(&mm->page_table_lock);
1306− lock_page(page);
1324+ if (!page_locked)
1325+ lock_page(page);
1326+ anon_vma = page_lock_anon_vma_read(page);
13071327
13081328 /* Confirm the PTE did not while locked */
13091329 spin_lock(&mm->page_table_lock);
13101330 if (unlikely(!pmd_same(pmd, *pmdp))) {
13111331 unlock_page(page);
13121332 put_page(page);
1333+ page_nid = -1;
13131334 goto out_unlock;
13141335 }
1315− spin_unlock(&mm->page_table_lock);
13161336
1317− /* Migrate the THP to the requested node */
1337+ /*
1338+ * Migrate the THP to the requested node, returns with page unlocked
1339+ * and pmd_numa cleared.
1340+ */
1341+ spin_unlock(&mm->page_table_lock);
13181342 migrated = migrate_misplaced_transhuge_page(mm, vma,
13191343 pmdp, pmd, addr, page, target_nid);
1320− if (!migrated)
1321− goto check_same;
1322−
1323− task_numa_fault(target_nid, HPAGE_PMD_NR, true);
1324− return 0;
1344+ if (migrated)
1345+ page_nid = target_nid;
13251346
1326−check_same:
1327− spin_lock(&mm->page_table_lock);
1328− if (unlikely(!pmd_same(pmd, *pmdp)))
1329− goto out_unlock;
1347+ goto out;
13301348 clear_pmdnuma:
1349+ BUG_ON(!PageLocked(page));
13311350 pmd = pmd_mknonnuma(pmd);
13321351 set_pmd_at(mm, haddr, pmdp, pmd);
13331352 VM_BUG_ON(pmd_numa(*pmdp));
13341353 update_mmu_cache_pmd(vma, addr, pmdp);
1354+ unlock_page(page);
13351355 out_unlock:
13361356 spin_unlock(&mm->page_table_lock);
1337− if (current_nid != -1)
1338− task_numa_fault(current_nid, HPAGE_PMD_NR, false);
1357+
1358+out:
1359+ if (anon_vma)
1360+ page_unlock_anon_vma_read(anon_vma);
1361+
1362+ if (page_nid != -1)
1363+ task_numa_fault(page_nid, HPAGE_PMD_NR, migrated);
1364+
13391365 return 0;
13401366 }
13411367
mm/memory.c+21−32
@@ -3521,12 +3521,12 @@ static int do_nonlinear_fault(struct mm_struct *mm, struct vm_area_struct *vma, · 3520 unmodified lines
35213521 }
35223522
35233523 int numa_migrate_prep(struct page *page, struct vm_area_struct *vma,
3524− unsigned long addr, int current_nid)
3524+ unsigned long addr, int page_nid)
35253525 {
35263526 get_page(page);
35273527
35283528 count_vm_numa_event(NUMA_HINT_FAULTS);
3529− if (current_nid == numa_node_id())
3529+ if (page_nid == numa_node_id())
35303530 count_vm_numa_event(NUMA_HINT_FAULTS_LOCAL);
35313531
35323532 return mpol_misplaced(page, vma, addr);
@@ -3537,7 +3537,7 @@ int do_numa_page(struct mm_struct *mm, struct vm_area_struct *vma, · 4 unmodified lines
35373537 {
35383538 struct page *page = NULL;
35393539 spinlock_t *ptl;
3540− int current_nid = -1;
3540+ int page_nid = -1;
35413541 int target_nid;
35423542 bool migrated = false;
35433543
@@ -3567,15 +3567,10 @@ int do_numa_page(struct mm_struct *mm, struct vm_area_struct *vma, · 23 unmodified lines
35673567 return 0;
35683568 }
35693569
3570− current_nid = page_to_nid(page);
3571− target_nid = numa_migrate_prep(page, vma, addr, current_nid);
3570+ page_nid = page_to_nid(page);
3571+ target_nid = numa_migrate_prep(page, vma, addr, page_nid);
35723572 pte_unmap_unlock(ptep, ptl);
35733573 if (target_nid == -1) {
3574− /*
3575− * Account for the fault against the current node if it not
3576− * being replaced regardless of where the page is located.
3577− */
3578− current_nid = numa_node_id();
35793574 put_page(page);
35803575 goto out;
35813576 }
@@ -3583,11 +3578,11 @@ int do_numa_page(struct mm_struct *mm, struct vm_area_struct *vma, · 1 unmodified line
35833578 /* Migrate to the requested node */
35843579 migrated = migrate_misplaced_page(page, target_nid);
35853580 if (migrated)
3586− current_nid = target_nid;
3581+ page_nid = target_nid;
35873582
35883583 out:
3589− if (current_nid != -1)
3590− task_numa_fault(current_nid, 1, migrated);
3584+ if (page_nid != -1)
3585+ task_numa_fault(page_nid, 1, migrated);
35913586 return 0;
35923587 }
35933588
@@ -3602,7 +3597,6 @@ static int do_pmd_numa_page(struct mm_struct *mm, struct vm_area_struct *vma, · 8 unmodified lines
36023597 unsigned long offset;
36033598 spinlock_t *ptl;
36043599 bool numa = false;
3605− int local_nid = numa_node_id();
36063600
36073601 spin_lock(&mm->page_table_lock);
36083602 pmd = *pmdp;
@@ -3625,9 +3619,10 @@ static int do_pmd_numa_page(struct mm_struct *mm, struct vm_area_struct *vma, · 16 unmodified lines
36253619 for (addr = _addr + offset; addr < _addr + PMD_SIZE; pte++, addr += PAGE_SIZE) {
36263620 pte_t pteval = *pte;
36273621 struct page *page;
3628− int curr_nid = local_nid;
3622+ int page_nid = -1;
36293623 int target_nid;
3630− bool migrated;
3624+ bool migrated = false;
3625+
36313626 if (!pte_present(pteval))
36323627 continue;
36333628 if (!pte_numa(pteval))
@@ -3649,25 +3644,19 @@ static int do_pmd_numa_page(struct mm_struct *mm, struct vm_area_struct *vma, · 15 unmodified lines
36493644 if (unlikely(page_mapcount(page) != 1))
36503645 continue;
36513646
3652− /*
3653− * Note that the NUMA fault is later accounted to either
3654− * the node that is currently running or where the page is
3655− * migrated to.
3656− */
3657− curr_nid = local_nid;
3658− target_nid = numa_migrate_prep(page, vma, addr,
3659− page_to_nid(page));
3660− if (target_nid == -1) {
3647+ page_nid = page_to_nid(page);
3648+ target_nid = numa_migrate_prep(page, vma, addr, page_nid);
3649+ pte_unmap_unlock(pte, ptl);
3650+ if (target_nid != -1) {
3651+ migrated = migrate_misplaced_page(page, target_nid);
3652+ if (migrated)
3653+ page_nid = target_nid;
3654+ } else {
36613655 put_page(page);
3662− continue;
36633656 }
36643657
3665− /* Migrate to the requested node */
3666− pte_unmap_unlock(pte, ptl);
3667− migrated = migrate_misplaced_page(page, target_nid);
3668− if (migrated)
3669− curr_nid = target_nid;
3670− task_numa_fault(curr_nid, 1, migrated);
3658+ if (page_nid != -1)
3659+ task_numa_fault(page_nid, 1, migrated);
36713660
36723661 pte = pte_offset_map_lock(mm, pmdp, addr, &ptl);
36733662 }
mm/migrate.c+11−8
@@ -1715,12 +1715,12 @@ int migrate_misplaced_transhuge_page(struct mm_struct *mm, · 1714 unmodified lines
17151715 unlock_page(new_page);
17161716 put_page(new_page); /* Free it */
17171717
1718− unlock_page(page);
1718+ /* Retake the callers reference and putback on LRU */
1719+ get_page(page);
17191720 putback_lru_page(page);
1720−
1721− count_vm_events(PGMIGRATE_FAIL, HPAGE_PMD_NR);
1722− isolated = 0;
1723− goto out;
1721+ mod_zone_page_state(page_zone(page),
1722+ NR_ISOLATED_ANON + page_lru, -HPAGE_PMD_NR);
1723+ goto out_fail;
17241724 }
17251725
17261726 /*
@@ -1737,9 +1737,9 @@ int migrate_misplaced_transhuge_page(struct mm_struct *mm, · 10 unmodified lines
17371737 entry = maybe_pmd_mkwrite(pmd_mkdirty(entry), vma);
17381738 entry = pmd_mkhuge(entry);
17391739
1740− page_add_new_anon_rmap(new_page, vma, haddr);
1741−
1740+ pmdp_clear_flush(vma, haddr, pmd);
17421741 set_pmd_at(mm, haddr, pmd, entry);
1742+ page_add_new_anon_rmap(new_page, vma, haddr);
17431743 update_mmu_cache_pmd(vma, address, &entry);
17441744 page_remove_rmap(page);
17451745 /*
@@ -1758,7 +1758,6 @@ int migrate_misplaced_transhuge_page(struct mm_struct *mm, · 12 unmodified lines
17581758 count_vm_events(PGMIGRATE_SUCCESS, HPAGE_PMD_NR);
17591759 count_vm_numa_events(NUMA_PAGE_MIGRATE, HPAGE_PMD_NR);
17601760
1761−out:
17621761 mod_zone_page_state(page_zone(page),
17631762 NR_ISOLATED_ANON + page_lru,
17641763 -HPAGE_PMD_NR);
@@ -1767,6 +1766,10 @@ out: · 2 unmodified lines
17671766 out_fail:
17681767 count_vm_events(PGMIGRATE_FAIL, HPAGE_PMD_NR);
17691768 out_dropref:
1769+ entry = pmd_mknonnuma(entry);
1770+ set_pmd_at(mm, haddr, pmd, entry);
1771+ update_mmu_cache_pmd(vma, address, &entry);
1772+
17701773 unlock_page(page);
17711774 put_page(page);
17721775 return 0;
mm/mprotect.c+1−1
@@ -148,7 +148,7 @@ static inline unsigned long change_pmd_range(struct vm_area_struct *vma, · 147 unmodified lines
148148 split_huge_page_pmd(vma, addr, pmd);
149149 else if (change_huge_pmd(vma, pmd, addr, newprot,
150150 prot_numa)) {
151− pages += HPAGE_PMD_NR;
151+ pages++;
152152 continue;
153153 }
154154 /* fall through */

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t