summaryrefslogtreecommitdiffstats
path: root/mm/memcontrol.c
diff options
context:
space:
mode:
Diffstat (limited to 'mm/memcontrol.c')
-rw-r--r--mm/memcontrol.c43
1 files changed, 31 insertions, 12 deletions
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 3df3c04d73ab..e09741af816f 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -1611,9 +1611,13 @@ cleanup:
1611 * @page: the page 1611 * @page: the page
1612 * 1612 *
1613 * This function protects unlocked LRU pages from being moved to 1613 * This function protects unlocked LRU pages from being moved to
1614 * another cgroup and stabilizes their page->mem_cgroup binding. 1614 * another cgroup.
1615 *
1616 * It ensures lifetime of the returned memcg. Caller is responsible
1617 * for the lifetime of the page; __unlock_page_memcg() is available
1618 * when @page might get freed inside the locked section.
1615 */ 1619 */
1616void lock_page_memcg(struct page *page) 1620struct mem_cgroup *lock_page_memcg(struct page *page)
1617{ 1621{
1618 struct mem_cgroup *memcg; 1622 struct mem_cgroup *memcg;
1619 unsigned long flags; 1623 unsigned long flags;
@@ -1622,18 +1626,24 @@ void lock_page_memcg(struct page *page)
1622 * The RCU lock is held throughout the transaction. The fast 1626 * The RCU lock is held throughout the transaction. The fast
1623 * path can get away without acquiring the memcg->move_lock 1627 * path can get away without acquiring the memcg->move_lock
1624 * because page moving starts with an RCU grace period. 1628 * because page moving starts with an RCU grace period.
1625 */ 1629 *
1630 * The RCU lock also protects the memcg from being freed when
1631 * the page state that is going to change is the only thing
1632 * preventing the page itself from being freed. E.g. writeback
1633 * doesn't hold a page reference and relies on PG_writeback to
1634 * keep off truncation, migration and so forth.
1635 */
1626 rcu_read_lock(); 1636 rcu_read_lock();
1627 1637
1628 if (mem_cgroup_disabled()) 1638 if (mem_cgroup_disabled())
1629 return; 1639 return NULL;
1630again: 1640again:
1631 memcg = page->mem_cgroup; 1641 memcg = page->mem_cgroup;
1632 if (unlikely(!memcg)) 1642 if (unlikely(!memcg))
1633 return; 1643 return NULL;
1634 1644
1635 if (atomic_read(&memcg->moving_account) <= 0) 1645 if (atomic_read(&memcg->moving_account) <= 0)
1636 return; 1646 return memcg;
1637 1647
1638 spin_lock_irqsave(&memcg->move_lock, flags); 1648 spin_lock_irqsave(&memcg->move_lock, flags);
1639 if (memcg != page->mem_cgroup) { 1649 if (memcg != page->mem_cgroup) {
@@ -1649,18 +1659,18 @@ again:
1649 memcg->move_lock_task = current; 1659 memcg->move_lock_task = current;
1650 memcg->move_lock_flags = flags; 1660 memcg->move_lock_flags = flags;
1651 1661
1652 return; 1662 return memcg;
1653} 1663}
1654EXPORT_SYMBOL(lock_page_memcg); 1664EXPORT_SYMBOL(lock_page_memcg);
1655 1665
1656/** 1666/**
1657 * unlock_page_memcg - unlock a page->mem_cgroup binding 1667 * __unlock_page_memcg - unlock and unpin a memcg
1658 * @page: the page 1668 * @memcg: the memcg
1669 *
1670 * Unlock and unpin a memcg returned by lock_page_memcg().
1659 */ 1671 */
1660void unlock_page_memcg(struct page *page) 1672void __unlock_page_memcg(struct mem_cgroup *memcg)
1661{ 1673{
1662 struct mem_cgroup *memcg = page->mem_cgroup;
1663
1664 if (memcg && memcg->move_lock_task == current) { 1674 if (memcg && memcg->move_lock_task == current) {
1665 unsigned long flags = memcg->move_lock_flags; 1675 unsigned long flags = memcg->move_lock_flags;
1666 1676
@@ -1672,6 +1682,15 @@ void unlock_page_memcg(struct page *page)
1672 1682
1673 rcu_read_unlock(); 1683 rcu_read_unlock();
1674} 1684}
1685
1686/**
1687 * unlock_page_memcg - unlock a page->mem_cgroup binding
1688 * @page: the page
1689 */
1690void unlock_page_memcg(struct page *page)
1691{
1692 __unlock_page_memcg(page->mem_cgroup);
1693}
1675EXPORT_SYMBOL(unlock_page_memcg); 1694EXPORT_SYMBOL(unlock_page_memcg);
1676 1695
1677/* 1696/*