/*
* linux/mm/swap.c
*
* Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds
*/
/*
* This file contains the default values for the operation of the
* Linux VM subsystem. Fine-tuning documentation can be found in
* Documentation/sysctl/vm.txt.
* Started 18.12.91
* Swap aging added 23.2.95, Stephen Tweedie.
* Buffermem limits added 12.3.98, Rik van Riel.
*/
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/kernel_stat.h>
#include <linux/swap.h>
#include <linux/mman.h>
#include <linux/pagemap.h>
#include <linux/pagevec.h>
#include <linux/init.h>
#include <linux/export.h>
#include <linux/mm_inline.h>
#include <linux/percpu_counter.h>
#include <linux/memremap.h>
#include <linux/percpu.h>
#include <linux/cpu.h>
#include <linux/notifier.h>
#include <linux/backing-dev.h>
#include <linux/memcontrol.h>
#include <linux/gfp.h>
#include <linux/uio.h>
#include <linux/hugetlb.h>
#include <linux/page_idle.h>
#include "internal.h"
#define CREATE_TRACE_POINTS
#include <trace/events/pagemap.h>
/* How many pages do we try to swap or page in/out together? */
int page_cluster;
static DEFINE_PER_CPU(struct pagevec, lru_add_pvec);
static DEFINE_PER_CPU(struct pagevec, lru_rotate_pvecs);
static DEFINE_PER_CPU(struct pagevec, lru_deactivate_file_pvecs);
static DEFINE_PER_CPU(struct pagevec, lru_lazyfree_pvecs);
#ifdef CONFIG_SMP
static DEFINE_PER_CPU(struct pagevec, activate_page_pvecs);
#endif
/*
* This path almost never happens for VM activity - pages are normally
* freed via pagevecs. But it gets used by networking.
*/
static void __page_cache_release(struct page *page)
{
if (PageLRU(page)) {
struct zone *zone = page_zone(page);
struct lruvec *lruvec;
unsigned long flags;
spin_lock_irqsave(zone_lru_lock(zone), flags);
lruvec = mem_cgroup_page_lruvec(page, zone->zone_pgdat);
VM_BUG_ON_PAGE(!PageLRU(page), page);
__ClearPageLRU(page);
del_page_from_lru_list(page, lruvec, page_off_lru(page));
spin_unlock_irqrestore(zone_lru_lock(zone), flags);
}
__ClearPageWaiters(page);
mem_cgroup_uncharge(page);
}
static void __put_single_page(struct page *page)
{
__page_cache_release(page);
free_unref_page(page);
}
static void __put_compound_page(struct page *page)
{
compound_page_dtor *dtor;
/*
* __page_cache_release() is supposed to be called for thp, not for
* hugetlb. This is because hugetlb page does never have PageLRU set
* (it's never listed to any LRU lists) and no memcg routines should
* be called for hugetlb (it has a separate hugetlb_cgroup.)
*/
if (!PageHuge(page))
__page_cache_release(page);
dtor = get_compound_page_dtor(page);
(*dtor)(page);
}
void __put_page(struct page *page)
{
if (is_zone_device_page(page)) {
put_dev_pagemap(page->pgmap);
/*
* The page belongs to the device that created pgmap. Do
* not return it to page allocator.
*/
return;
}
if (unlikely(PageCompound(page)))
__put_compound_page(page);
else
__put_single_page(page);
}
EXPORT_SYMBOL(__put_page);
/**
* put_pages_list() - release a list of pages
* @pages: list of pages threaded on page->lru
*
* Release a list of pages which are strung together on page.lru. Currently
* used by read_cache_pages() and related error recovery code.
*/
void put_pages_list(struct list_head *pages)
{
while (!list_empty(pages)) {
struct page *victim;
victim = list_entry(pages->prev, struct page, lru);
list_del(&victim->lru);
put_page(victim);
}
}
EXPORT_SYMBOL(put_pages_list);
/*
* get_kernel_pages() - pin kernel pages in memory
* @kiov: An array of struct kvec structures
* @nr_segs: number of segments to pin
* @write: pinning for read/write, currently ignored
* @pages: array that receives pointers to the pages pinned.
* Should be at least nr_segs long.
*
* Returns number of pages pinned. This may be fewer than the number
* requested. If nr_pages is 0 or negative, returns 0. If no pages
* were pinned, returns -errno. Each page returned must be released
* with a put_page() call when it is finished with.
*/
int get_kernel_pages(const struct kvec *kiov, int nr_segs, int write,
struct page **pages)
{
int seg;
for (seg = 0; seg < nr_segs; seg++) {
if (WARN_ON(kiov[seg].iov_len != PAGE_SIZE))
return seg;
pages[seg] = kmap_to_page(kiov[seg].iov_base);
get_page(pages[seg]);
}
return seg;
}
EXPORT_SYMBOL_GPL(get_kernel_pages);
/*
* get_kernel_page() - pin a kernel page in memory
* @start: starting kernel address
* @write: pinning for read/write, currently ignored
* @pages: array that receives pointer to the page pinned.
* Must be at least nr_segs long.
*
* Returns 1 if page is pinned. If the page was not pinned, returns
* -errno. The page returned must be released with a put_page() call
* when it is finished with.
*/
int get_kernel_page(unsigned long start, int write, struct page **pages)
{
const struct kvec kiov = {
.iov_base = (void *)start,
.iov_len = PAGE_SIZE
};
return get_kernel_pages(&kiov, 1, write, pages);
}
EXPORT_SYMBOL_GPL(