diff options
Diffstat (limited to 'include/linux/memcontrol.h')
| -rw-r--r-- | include/linux/memcontrol.h | 198 | 
1 files changed, 69 insertions, 129 deletions
| diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h index a805474df4ab..5d8ca6e02e39 100644 --- a/include/linux/memcontrol.h +++ b/include/linux/memcontrol.h @@ -52,7 +52,7 @@ enum mem_cgroup_stat_index {  	MEM_CGROUP_STAT_SWAP,		/* # of pages, swapped out */  	MEM_CGROUP_STAT_NSTATS,  	/* default hierarchy stats */ -	MEMCG_KERNEL_STACK = MEM_CGROUP_STAT_NSTATS, +	MEMCG_KERNEL_STACK_KB = MEM_CGROUP_STAT_NSTATS,  	MEMCG_SLAB_RECLAIMABLE,  	MEMCG_SLAB_UNRECLAIMABLE,  	MEMCG_SOCK, @@ -60,7 +60,7 @@ enum mem_cgroup_stat_index {  };  struct mem_cgroup_reclaim_cookie { -	struct zone *zone; +	pg_data_t *pgdat;  	int priority;  	unsigned int generation;  }; @@ -97,6 +97,11 @@ enum mem_cgroup_events_target {  #define MEM_CGROUP_ID_SHIFT	16  #define MEM_CGROUP_ID_MAX	USHRT_MAX +struct mem_cgroup_id { +	int id; +	atomic_t ref; +}; +  struct mem_cgroup_stat_cpu {  	long count[MEMCG_NR_STAT];  	unsigned long events[MEMCG_NR_EVENTS]; @@ -113,7 +118,7 @@ struct mem_cgroup_reclaim_iter {  /*   * per-zone information in memory controller.   */ -struct mem_cgroup_per_zone { +struct mem_cgroup_per_node {  	struct lruvec		lruvec;  	unsigned long		lru_size[NR_LRU_LISTS]; @@ -127,10 +132,6 @@ struct mem_cgroup_per_zone {  						/* use container_of	   */  }; -struct mem_cgroup_per_node { -	struct mem_cgroup_per_zone zoneinfo[MAX_NR_ZONES]; -}; -  struct mem_cgroup_threshold {  	struct eventfd_ctx *eventfd;  	unsigned long threshold; @@ -172,6 +173,9 @@ enum memcg_kmem_state {  struct mem_cgroup {  	struct cgroup_subsys_state css; +	/* Private memcg ID. Used to ID objects that outlive the cgroup */ +	struct mem_cgroup_id id; +  	/* Accounted resources */  	struct page_counter memory;  	struct page_counter swap; @@ -306,8 +310,46 @@ void mem_cgroup_uncharge_list(struct list_head *page_list);  void mem_cgroup_migrate(struct page *oldpage, struct page *newpage); -struct lruvec *mem_cgroup_zone_lruvec(struct zone *, struct mem_cgroup *); -struct lruvec *mem_cgroup_page_lruvec(struct page *, struct zone *); +static struct mem_cgroup_per_node * +mem_cgroup_nodeinfo(struct mem_cgroup *memcg, int nid) +{ +	return memcg->nodeinfo[nid]; +} + +/** + * mem_cgroup_lruvec - get the lru list vector for a node or a memcg zone + * @node: node of the wanted lruvec + * @memcg: memcg of the wanted lruvec + * + * Returns the lru list vector holding pages for a given @node or a given + * @memcg and @zone. This can be the node lruvec, if the memory controller + * is disabled. + */ +static inline struct lruvec *mem_cgroup_lruvec(struct pglist_data *pgdat, +				struct mem_cgroup *memcg) +{ +	struct mem_cgroup_per_node *mz; +	struct lruvec *lruvec; + +	if (mem_cgroup_disabled()) { +		lruvec = node_lruvec(pgdat); +		goto out; +	} + +	mz = mem_cgroup_nodeinfo(memcg, pgdat->node_id); +	lruvec = &mz->lruvec; +out: +	/* +	 * Since a node can be onlined after the mem_cgroup was created, +	 * we have to be prepared to initialize lruvec->pgdat here; +	 * and if offlined then reonlined, we need to reinitialize it. +	 */ +	if (unlikely(lruvec->pgdat != pgdat)) +		lruvec->pgdat = pgdat; +	return lruvec; +} + +struct lruvec *mem_cgroup_page_lruvec(struct page *, struct pglist_data *);  bool task_in_mem_cgroup(struct task_struct *task, struct mem_cgroup *memcg);  struct mem_cgroup *mem_cgroup_from_task(struct task_struct *p); @@ -330,22 +372,9 @@ static inline unsigned short mem_cgroup_id(struct mem_cgroup *memcg)  	if (mem_cgroup_disabled())  		return 0; -	return memcg->css.id; -} - -/** - * mem_cgroup_from_id - look up a memcg from an id - * @id: the id to look up - * - * Caller must hold rcu_read_lock() and use css_tryget() as necessary. - */ -static inline struct mem_cgroup *mem_cgroup_from_id(unsigned short id) -{ -	struct cgroup_subsys_state *css; - -	css = css_from_id(id, &memory_cgrp_subsys); -	return mem_cgroup_from_css(css); +	return memcg->id.id;  } +struct mem_cgroup *mem_cgroup_from_id(unsigned short id);  /**   * parent_mem_cgroup - find the accounting parent of a memcg @@ -409,9 +438,9 @@ unsigned long mem_cgroup_node_nr_lru_pages(struct mem_cgroup *memcg,  static inline  unsigned long mem_cgroup_get_lru_size(struct lruvec *lruvec, enum lru_list lru)  { -	struct mem_cgroup_per_zone *mz; +	struct mem_cgroup_per_node *mz; -	mz = container_of(lruvec, struct mem_cgroup_per_zone, lruvec); +	mz = container_of(lruvec, struct mem_cgroup_per_node, lruvec);  	return mz->lru_size[lru];  } @@ -482,7 +511,7 @@ static inline void mem_cgroup_dec_page_stat(struct page *page,  	mem_cgroup_update_page_stat(page, idx, -1);  } -unsigned long mem_cgroup_soft_limit_reclaim(struct zone *zone, int order, +unsigned long mem_cgroup_soft_limit_reclaim(pg_data_t *pgdat, int order,  						gfp_t gfp_mask,  						unsigned long *total_scanned); @@ -573,16 +602,16 @@ static inline void mem_cgroup_migrate(struct page *old, struct page *new)  {  } -static inline struct lruvec *mem_cgroup_zone_lruvec(struct zone *zone, -						    struct mem_cgroup *memcg) +static inline struct lruvec *mem_cgroup_lruvec(struct pglist_data *pgdat, +				struct mem_cgroup *memcg)  { -	return &zone->lruvec; +	return node_lruvec(pgdat);  }  static inline struct lruvec *mem_cgroup_page_lruvec(struct page *page, -						    struct zone *zone) +						    struct pglist_data *pgdat)  { -	return &zone->lruvec; +	return &pgdat->lruvec;  }  static inline bool mm_match_cgroup(struct mm_struct *mm, @@ -686,7 +715,7 @@ static inline void mem_cgroup_dec_page_stat(struct page *page,  }  static inline -unsigned long mem_cgroup_soft_limit_reclaim(struct zone *zone, int order, +unsigned long mem_cgroup_soft_limit_reclaim(pg_data_t *pgdat, int order,  					    gfp_t gfp_mask,  					    unsigned long *total_scanned)  { @@ -754,6 +783,13 @@ static inline bool mem_cgroup_under_socket_pressure(struct mem_cgroup *memcg)  }  #endif +struct kmem_cache *memcg_kmem_get_cache(struct kmem_cache *cachep); +void memcg_kmem_put_cache(struct kmem_cache *cachep); +int memcg_kmem_charge_memcg(struct page *page, gfp_t gfp, int order, +			    struct mem_cgroup *memcg); +int memcg_kmem_charge(struct page *page, gfp_t gfp, int order); +void memcg_kmem_uncharge(struct page *page, int order); +  #if defined(CONFIG_MEMCG) && !defined(CONFIG_SLOB)  extern struct static_key_false memcg_kmem_enabled_key; @@ -775,22 +811,6 @@ static inline bool memcg_kmem_enabled(void)  }  /* - * In general, we'll do everything in our power to not incur in any overhead - * for non-memcg users for the kmem functions. Not even a function call, if we - * can avoid it. - * - * Therefore, we'll inline all those functions so that in the best case, we'll - * see that kmemcg is off for everybody and proceed quickly.  If it is on, - * we'll still do most of the flag checking inline. We check a lot of - * conditions, but because they are pretty simple, they are expected to be - * fast. - */ -int __memcg_kmem_charge_memcg(struct page *page, gfp_t gfp, int order, -			      struct mem_cgroup *memcg); -int __memcg_kmem_charge(struct page *page, gfp_t gfp, int order); -void __memcg_kmem_uncharge(struct page *page, int order); - -/*   * helper for accessing a memcg's index. It will be used as an index in the   * child cache array in kmem_cache, and also to derive its name. This function   * will return -1 when this is not a kmem-limited memcg. @@ -800,67 +820,6 @@ static inline int memcg_cache_id(struct mem_cgroup *memcg)  	return memcg ? memcg->kmemcg_id : -1;  } -struct kmem_cache *__memcg_kmem_get_cache(struct kmem_cache *cachep, gfp_t gfp); -void __memcg_kmem_put_cache(struct kmem_cache *cachep); - -static inline bool __memcg_kmem_bypass(void) -{ -	if (!memcg_kmem_enabled()) -		return true; -	if (in_interrupt() || (!current->mm) || (current->flags & PF_KTHREAD)) -		return true; -	return false; -} - -/** - * memcg_kmem_charge: charge a kmem page - * @page: page to charge - * @gfp: reclaim mode - * @order: allocation order - * - * Returns 0 on success, an error code on failure. - */ -static __always_inline int memcg_kmem_charge(struct page *page, -					     gfp_t gfp, int order) -{ -	if (__memcg_kmem_bypass()) -		return 0; -	if (!(gfp & __GFP_ACCOUNT)) -		return 0; -	return __memcg_kmem_charge(page, gfp, order); -} - -/** - * memcg_kmem_uncharge: uncharge a kmem page - * @page: page to uncharge - * @order: allocation order - */ -static __always_inline void memcg_kmem_uncharge(struct page *page, int order) -{ -	if (memcg_kmem_enabled()) -		__memcg_kmem_uncharge(page, order); -} - -/** - * memcg_kmem_get_cache: selects the correct per-memcg cache for allocation - * @cachep: the original global kmem cache - * - * All memory allocated from a per-memcg cache is charged to the owner memcg. - */ -static __always_inline struct kmem_cache * -memcg_kmem_get_cache(struct kmem_cache *cachep, gfp_t gfp) -{ -	if (__memcg_kmem_bypass()) -		return cachep; -	return __memcg_kmem_get_cache(cachep, gfp); -} - -static __always_inline void memcg_kmem_put_cache(struct kmem_cache *cachep) -{ -	if (memcg_kmem_enabled()) -		__memcg_kmem_put_cache(cachep); -} -  /**   * memcg_kmem_update_page_stat - update kmem page state statistics   * @page: the page @@ -883,15 +842,6 @@ static inline bool memcg_kmem_enabled(void)  	return false;  } -static inline int memcg_kmem_charge(struct page *page, gfp_t gfp, int order) -{ -	return 0; -} - -static inline void memcg_kmem_uncharge(struct page *page, int order) -{ -} -  static inline int memcg_cache_id(struct mem_cgroup *memcg)  {  	return -1; @@ -905,16 +855,6 @@ static inline void memcg_put_cache_ids(void)  {  } -static inline struct kmem_cache * -memcg_kmem_get_cache(struct kmem_cache *cachep, gfp_t gfp) -{ -	return cachep; -} - -static inline void memcg_kmem_put_cache(struct kmem_cache *cachep) -{ -} -  static inline void memcg_kmem_update_page_stat(struct page *page,  				enum mem_cgroup_stat_index idx, int val)  { |