838 lines · 21.3 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0/* *	linux/mm/mlock.c * *  (C) Copyright 1995 Linus Torvalds *  (C) Copyright 2002 Christoph Hellwig */ #include <linux/capability.h>#include <linux/mman.h>#include <linux/mm.h>#include <linux/sched/user.h>#include <linux/swap.h>#include <linux/swapops.h>#include <linux/pagemap.h>#include <linux/folio_batch.h>#include <linux/pagewalk.h>#include <linux/mempolicy.h>#include <linux/syscalls.h>#include <linux/sched.h>#include <linux/export.h>#include <linux/rmap.h>#include <linux/mmzone.h>#include <linux/hugetlb.h>#include <linux/memcontrol.h>#include <linux/mm_inline.h>#include <linux/secretmem.h> #include "internal.h" struct mlock_fbatch {	local_lock_t lock;	struct folio_batch fbatch;}; static DEFINE_PER_CPU(struct mlock_fbatch, mlock_fbatch) = {	.lock = INIT_LOCAL_LOCK(lock),}; bool can_do_mlock(void){	if (rlimit(RLIMIT_MEMLOCK) != 0)		return true;	if (capable(CAP_IPC_LOCK))		return true;	return false;}EXPORT_SYMBOL(can_do_mlock); /* * Mlocked folios are marked with the PG_mlocked flag for efficient testing * in vmscan and, possibly, the fault path; and to support semi-accurate * statistics. * * An mlocked folio [folio_test_mlocked(folio)] is unevictable.  As such, it * will be ostensibly placed on the LRU "unevictable" list (actually no such * list exists), rather than the [in]active lists. PG_unevictable is set to * indicate the unevictable state. */ static struct lruvec *__mlock_folio(struct folio *folio, struct lruvec *lruvec){	/* There is nothing more we can do while it's off LRU */	if (!folio_test_clear_lru(folio))		return lruvec; 	lruvec = folio_lruvec_relock_irq(folio, lruvec); 	if (unlikely(folio_evictable(folio))) {		/*		 * This is a little surprising, but quite possible: PG_mlocked		 * must have got cleared already by another CPU.  Could this		 * folio be unevictable?  I'm not sure, but move it now if so.		 */		if (folio_test_unevictable(folio)) {			lruvec_del_folio(lruvec, folio);			folio_clear_unevictable(folio);			lruvec_add_folio(lruvec, folio); 			__count_vm_events(UNEVICTABLE_PGRESCUED,					  folio_nr_pages(folio));		}		goto out;	} 	if (folio_test_unevictable(folio)) {		if (folio_test_mlocked(folio))			folio->mlock_count++;		goto out;	} 	lruvec_del_folio(lruvec, folio);	folio_clear_active(folio);	folio_set_unevictable(folio);	folio->mlock_count = !!folio_test_mlocked(folio);	lruvec_add_folio(lruvec, folio);	__count_vm_events(UNEVICTABLE_PGCULLED, folio_nr_pages(folio));out:	folio_set_lru(folio);	return lruvec;} static struct lruvec *__mlock_new_folio(struct folio *folio, struct lruvec *lruvec){	VM_BUG_ON_FOLIO(folio_test_lru(folio), folio); 	lruvec = folio_lruvec_relock_irq(folio, lruvec); 	/* As above, this is a little surprising, but possible */	if (unlikely(folio_evictable(folio)))		goto out; 	folio_set_unevictable(folio);	folio->mlock_count = !!folio_test_mlocked(folio);	__count_vm_events(UNEVICTABLE_PGCULLED, folio_nr_pages(folio));out:	lruvec_add_folio(lruvec, folio);	folio_set_lru(folio);	return lruvec;} static struct lruvec *__munlock_folio(struct folio *folio, struct lruvec *lruvec){	int nr_pages = folio_nr_pages(folio);	bool isolated = false; 	if (!folio_test_clear_lru(folio))		goto munlock; 	isolated = true;	lruvec = folio_lruvec_relock_irq(folio, lruvec); 	if (folio_test_unevictable(folio)) {		/* Then mlock_count is maintained, but might undercount */		if (folio->mlock_count)			folio->mlock_count--;		if (folio->mlock_count)			goto out;	}	/* else assume that was the last mlock: reclaim will fix it if not */ munlock:	if (folio_test_clear_mlocked(folio)) {		__zone_stat_mod_folio(folio, NR_MLOCK, -nr_pages);		if (isolated || !folio_test_unevictable(folio))			__count_vm_events(UNEVICTABLE_PGMUNLOCKED, nr_pages);		else			__count_vm_events(UNEVICTABLE_PGSTRANDED, nr_pages);	} 	/* folio_evictable() has to be checked *after* clearing Mlocked */	if (isolated && folio_test_unevictable(folio) && folio_evictable(folio)) {		lruvec_del_folio(lruvec, folio);		folio_clear_unevictable(folio);		lruvec_add_folio(lruvec, folio);		__count_vm_events(UNEVICTABLE_PGRESCUED, nr_pages);	}out:	if (isolated)		folio_set_lru(folio);	return lruvec;} /* * Flags held in the low bits of a struct folio pointer on the mlock_fbatch. */#define LRU_FOLIO 0x1#define NEW_FOLIO 0x2static inline struct folio *mlock_lru(struct folio *folio){	return (struct folio *)((unsigned long)folio + LRU_FOLIO);} static inline struct folio *mlock_new(struct folio *folio){	return (struct folio *)((unsigned long)folio + NEW_FOLIO);} /* * mlock_folio_batch() is derived from folio_batch_move_lru(): perhaps that can * make use of such folio pointer flags in future, but for now just keep it for * mlock.  We could use three separate folio batches instead, but one feels * better (munlocking a full folio batch does not need to drain mlocking folio * batches first). */static void mlock_folio_batch(struct folio_batch *fbatch){	struct lruvec *lruvec = NULL;	unsigned long mlock;	struct folio *folio;	int i; 	for (i = 0; i < folio_batch_count(fbatch); i++) {		folio = fbatch->folios[i];		mlock = (unsigned long)folio & (LRU_FOLIO | NEW_FOLIO);		folio = (struct folio *)((unsigned long)folio - mlock);		fbatch->folios[i] = folio; 		if (mlock & LRU_FOLIO)			lruvec = __mlock_folio(folio, lruvec);		else if (mlock & NEW_FOLIO)			lruvec = __mlock_new_folio(folio, lruvec);		else			lruvec = __munlock_folio(folio, lruvec);	} 	if (lruvec)		lruvec_unlock_irq(lruvec);	folios_put(fbatch);} void mlock_drain_local(void){	struct folio_batch *fbatch; 	local_lock(&mlock_fbatch.lock);	fbatch = this_cpu_ptr(&mlock_fbatch.fbatch);	if (folio_batch_count(fbatch))		mlock_folio_batch(fbatch);	local_unlock(&mlock_fbatch.lock);} void mlock_drain_remote(int cpu){	struct folio_batch *fbatch; 	WARN_ON_ONCE(cpu_online(cpu));	fbatch = &per_cpu(mlock_fbatch.fbatch, cpu);	if (folio_batch_count(fbatch))		mlock_folio_batch(fbatch);} bool need_mlock_drain(int cpu){	return folio_batch_count(&per_cpu(mlock_fbatch.fbatch, cpu));} /** * mlock_folio - mlock a folio already on (or temporarily off) LRU * @folio: folio to be mlocked. */void mlock_folio(struct folio *folio){	struct folio_batch *fbatch; 	local_lock(&mlock_fbatch.lock);	fbatch = this_cpu_ptr(&mlock_fbatch.fbatch); 	if (!folio_test_set_mlocked(folio)) {		int nr_pages = folio_nr_pages(folio); 		zone_stat_mod_folio(folio, NR_MLOCK, nr_pages);		__count_vm_events(UNEVICTABLE_PGMLOCKED, nr_pages);	} 	folio_get(folio);	if (!folio_batch_add(fbatch, mlock_lru(folio)) ||	    !folio_may_be_lru_cached(folio) || lru_cache_disabled())		mlock_folio_batch(fbatch);	local_unlock(&mlock_fbatch.lock);} /** * mlock_new_folio - mlock a newly allocated folio not yet on LRU * @folio: folio to be mlocked, either normal or a THP head. */void mlock_new_folio(struct folio *folio){	struct folio_batch *fbatch;	int nr_pages = folio_nr_pages(folio); 	local_lock(&mlock_fbatch.lock);	fbatch = this_cpu_ptr(&mlock_fbatch.fbatch);	folio_set_mlocked(folio); 	zone_stat_mod_folio(folio, NR_MLOCK, nr_pages);	__count_vm_events(UNEVICTABLE_PGMLOCKED, nr_pages); 	folio_get(folio);	if (!folio_batch_add(fbatch, mlock_new(folio)) ||	    !folio_may_be_lru_cached(folio) || lru_cache_disabled())		mlock_folio_batch(fbatch);	local_unlock(&mlock_fbatch.lock);} /** * munlock_folio - munlock a folio * @folio: folio to be munlocked, either normal or a THP head. */void munlock_folio(struct folio *folio){	struct folio_batch *fbatch; 	local_lock(&mlock_fbatch.lock);	fbatch = this_cpu_ptr(&mlock_fbatch.fbatch);	/*	 * folio_test_clear_mlocked(folio) must be left to __munlock_folio(),	 * which will check whether the folio is multiply mlocked.	 */	folio_get(folio);	if (!folio_batch_add(fbatch, folio) ||	    !folio_may_be_lru_cached(folio) || lru_cache_disabled())		mlock_folio_batch(fbatch);	local_unlock(&mlock_fbatch.lock);} static inline unsigned int folio_mlock_step(struct folio *folio,		pte_t *pte, unsigned long addr, unsigned long end){	unsigned int count = (end - addr) >> PAGE_SHIFT;	pte_t ptent = ptep_get(pte); 	if (!folio_test_large(folio))		return 1; 	return folio_pte_batch(folio, pte, ptent, count);} static inline bool allow_mlock_munlock(struct folio *folio,		struct vm_area_struct *vma, unsigned long start,		unsigned long end, unsigned int step){	/*	 * For unlock, allow munlock large folio which is partially	 * mapped to VMA. As it's possible that large folio is	 * mlocked and VMA is split later.	 *	 * During memory pressure, such kind of large folio can	 * be split. And the pages are not in VM_LOCKed VMA	 * can be reclaimed.	 */	if (!vma_test(vma, VMA_LOCKED_BIT))		return true; 	/* folio_within_range() cannot take KSM, but any small folio is OK */	if (!folio_test_large(folio))		return true; 	/* folio not in range [start, end), skip mlock */	if (!folio_within_range(folio, vma, start, end))		return false; 	/* folio is not fully mapped, skip mlock */	if (step != folio_nr_pages(folio))		return false; 	return true;} static int mlock_pte_range(pmd_t *pmd, unsigned long addr,			   unsigned long end, struct mm_walk *walk) {	struct vm_area_struct *vma = walk->vma;	spinlock_t *ptl;	pte_t *start_pte, *pte;	pte_t ptent;	struct folio *folio;	unsigned int step = 1;	unsigned long start = addr; 	ptl = pmd_trans_huge_lock(pmd, vma);	if (ptl) {		if (!pmd_present(*pmd))			goto out;		if (is_huge_zero_pmd(*pmd))			goto out;		folio = pmd_folio(*pmd);		if (folio_is_zone_device(folio))			goto out;		if (vma_test(vma, VMA_LOCKED_BIT))			mlock_folio(folio);		else			munlock_folio(folio);		goto out;	} 	start_pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl);	if (!start_pte) {		walk->action = ACTION_AGAIN;		return 0;	} 	for (pte = start_pte; addr != end; pte++, addr += PAGE_SIZE) {		ptent = ptep_get(pte);		if (!pte_present(ptent))			continue;		folio = vm_normal_folio(vma, addr, ptent);		if (!folio || folio_is_zone_device(folio))			continue; 		step = folio_mlock_step(folio, pte, addr, end);		if (!allow_mlock_munlock(folio, vma, start, end, step))			goto next_entry; 		if (vma_test(vma, VMA_LOCKED_BIT))			mlock_folio(folio);		else			munlock_folio(folio); next_entry:		pte += step - 1;		addr += (step - 1) << PAGE_SHIFT;	}	pte_unmap(start_pte);out:	spin_unlock(ptl);	cond_resched();	return 0;} /* * mlock_vma_pages_range() - mlock any pages already in the range, *                           or munlock all pages in the range. * @vma - vma containing range to be mlock()ed or munlock()ed * @start - start address in @vma of the range * @end - end of range in @vma * @new_vma_flags - the new set of flags for @vma. * * Called for mlock(), mlock2() and mlockall(), to set @vma VMA_LOCKED_BIT; * called for munlock() and munlockall(), to clear VMA_LOCKED_BIT from @vma. */static void mlock_vma_pages_range(struct vm_area_struct *vma,	unsigned long start, unsigned long end,	vma_flags_t *new_vma_flags){	static const struct mm_walk_ops mlock_walk_ops = {		.pmd_entry = mlock_pte_range,		.walk_lock = PGWALK_WRLOCK_VERIFY,	}; 	/*	 * There is a slight chance that concurrent page migration,	 * or page reclaim finding a page of this now-VMA_LOCKED_BIT vma,	 * will call mlock_vma_folio() and raise page's mlock_count:	 * double counting, leaving the page unevictable indefinitely.	 * Communicate this danger to mlock_vma_folio() with VMA_IO_BIT,	 * which is a VMA_SPECIAL_FLAGS flag not allowed on VMA_LOCKED_BIT vmas.	 * mmap_lock is held in write mode here, so this weird	 * combination should not be visible to other mmap_lock users;	 * but WRITE_ONCE so rmap walkers must see VMA_IO_BIT if VMA_LOCKED_BIT.	 */	if (vma_flags_test(new_vma_flags, VMA_LOCKED_BIT))		vma_flags_set(new_vma_flags, VMA_IO_BIT);	vma_start_write(vma);	vma_flags_reset_once(vma, new_vma_flags); 	lru_add_drain();	walk_page_range_vma(vma, start, end, &mlock_walk_ops, NULL);	lru_add_drain(); 	if (vma_flags_test(new_vma_flags, VMA_IO_BIT)) {		vma_flags_clear(new_vma_flags, VMA_IO_BIT);		vma_flags_reset_once(vma, new_vma_flags);	}} /* * mlock_fixup  - handle mlock[all]/munlock[all] requests. * * Filters out "special" vmas -- VMA_LOCKED_BIT never gets set for these, and * munlock is a no-op.  However, for some special vmas, we go ahead and * populate the ptes. * * For vmas that pass the filters, merge/split as appropriate. */static int mlock_fixup(struct vma_iterator *vmi, struct vm_area_struct *vma,	       struct vm_area_struct **prev, unsigned long start,	       unsigned long end, vma_flags_t *new_vma_flags){	const vma_flags_t old_vma_flags = vma->flags;	struct mm_struct *mm = vma->vm_mm;	int nr_pages;	int ret = 0; 	if (vma_flags_same_pair(&old_vma_flags, new_vma_flags) ||	    vma_is_secretmem(vma) || !vma_supports_mlock(vma)) {		/*		 * Don't set VMA_LOCKED_BIT or VMA_LOCKONFAULT_BIT and don't		 * count.  For secretmem, don't allow the memory to be unlocked.		 */		goto out;	} 	vma = vma_modify_flags(vmi, *prev, vma, start, end, new_vma_flags);	if (IS_ERR(vma)) {		ret = PTR_ERR(vma);		goto out;	} 	/*	 * Keep track of amount of locked VM.	 */	nr_pages = (end - start) >> PAGE_SHIFT;	if (!vma_flags_test(new_vma_flags, VMA_LOCKED_BIT))		nr_pages = -nr_pages;	else if (vma_flags_test(&old_vma_flags, VMA_LOCKED_BIT))		nr_pages = 0;	mm->locked_vm += nr_pages; 

Lines 1–500 of 838.