memcg: implement mem_cgroup_css_from_page()
Implement mem_cgroup_css_from_page() which returns the
cgroup_subsys_state of the memcg associated with a given page on the
default hierarchy.  This will be used by cgroup writeback support.
This function assumes that page->mem_cgroup association doesn't change
until the page is released, which is true on the default hierarchy as
long as replace_page_cache_page() is not used.  As the only user of
replace_page_cache_page() is FUSE which won't support cgroup writeback
for the time being, this works for now, and replace_page_cache_page()
will soon be updated so that the invariant actually holds.
Note that the RCU protected page->mem_cgroup access is consistent with
other usages across memcg but ultimately incorrect.  These unlocked
accesses are missing required barriers.  page->mem_cgroup should be
made an RCU pointer and updated and accessed using RCU operations.
v4: Instead of triggering WARN, return the root css on the traditional
    hierarchies.  This makes the function a lot easier to deal with
    especially as there's no light way to synchronize against
    hierarchy rebinding.
v3: s/mem_cgroup_migrate()/mem_cgroup_css_from_page()/
v2: Trigger WARN if the function is used on the traditional
    hierarchies and add comment about the assumed invariant.
Signed-off-by: Tejun Heo <tj@kernel.org>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Michal Hocko <mhocko@suse.cz>
Signed-off-by: Jens Axboe <axboe@fb.com>
			
			
This commit is contained in:
		
							parent
							
								
									1d933cf096
								
							
						
					
					
						commit
						ad7fa852d3
					
				| @ -115,6 +115,7 @@ static inline bool mm_match_cgroup(struct mm_struct *mm, | ||||
| } | ||||
| 
 | ||||
| extern struct cgroup_subsys_state *mem_cgroup_css(struct mem_cgroup *memcg); | ||||
| extern struct cgroup_subsys_state *mem_cgroup_css_from_page(struct page *page); | ||||
| 
 | ||||
| struct mem_cgroup *mem_cgroup_iter(struct mem_cgroup *, | ||||
| 				   struct mem_cgroup *, | ||||
|  | ||||
| @ -598,6 +598,39 @@ struct cgroup_subsys_state *mem_cgroup_css(struct mem_cgroup *memcg) | ||||
| 	return &memcg->css; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * mem_cgroup_css_from_page - css of the memcg associated with a page | ||||
|  * @page: page of interest | ||||
|  * | ||||
|  * If memcg is bound to the default hierarchy, css of the memcg associated | ||||
|  * with @page is returned.  The returned css remains associated with @page | ||||
|  * until it is released. | ||||
|  * | ||||
|  * If memcg is bound to a traditional hierarchy, the css of root_mem_cgroup | ||||
|  * is returned. | ||||
|  * | ||||
|  * XXX: The above description of behavior on the default hierarchy isn't | ||||
|  * strictly true yet as replace_page_cache_page() can modify the | ||||
|  * association before @page is released even on the default hierarchy; | ||||
|  * however, the current and planned usages don't mix the the two functions | ||||
|  * and replace_page_cache_page() will soon be updated to make the invariant | ||||
|  * actually true. | ||||
|  */ | ||||
| struct cgroup_subsys_state *mem_cgroup_css_from_page(struct page *page) | ||||
| { | ||||
| 	struct mem_cgroup *memcg; | ||||
| 
 | ||||
| 	rcu_read_lock(); | ||||
| 
 | ||||
| 	memcg = page->mem_cgroup; | ||||
| 
 | ||||
| 	if (!memcg || !cgroup_on_dfl(memcg->css.cgroup)) | ||||
| 		memcg = root_mem_cgroup; | ||||
| 
 | ||||
| 	rcu_read_unlock(); | ||||
| 	return &memcg->css; | ||||
| } | ||||
| 
 | ||||
| static struct mem_cgroup_per_zone * | ||||
| mem_cgroup_page_zoneinfo(struct mem_cgroup *memcg, struct page *page) | ||||
| { | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user