@@ -4082,6 +4082,24 @@ static void mem_cgroup_id_get(struct mem_cgroup *memcg)
40824082 atomic_inc (& memcg -> id .ref );
40834083}
40844084
4085+ static struct mem_cgroup * mem_cgroup_id_get_online (struct mem_cgroup * memcg )
4086+ {
4087+ while (!atomic_inc_not_zero (& memcg -> id .ref )) {
4088+ /*
4089+ * The root cgroup cannot be destroyed, so it's refcount must
4090+ * always be >= 1.
4091+ */
4092+ if (WARN_ON_ONCE (memcg == root_mem_cgroup )) {
4093+ VM_BUG_ON (1 );
4094+ break ;
4095+ }
4096+ memcg = parent_mem_cgroup (memcg );
4097+ if (!memcg )
4098+ memcg = root_mem_cgroup ;
4099+ }
4100+ return memcg ;
4101+ }
4102+
40854103static void mem_cgroup_id_put (struct mem_cgroup * memcg )
40864104{
40874105 if (atomic_dec_and_test (& memcg -> id .ref )) {
@@ -5800,7 +5818,7 @@ subsys_initcall(mem_cgroup_init);
58005818 */
58015819void mem_cgroup_swapout (struct page * page , swp_entry_t entry )
58025820{
5803- struct mem_cgroup * memcg ;
5821+ struct mem_cgroup * memcg , * swap_memcg ;
58045822 unsigned short oldid ;
58055823
58065824 VM_BUG_ON_PAGE (PageLRU (page ), page );
@@ -5815,16 +5833,27 @@ void mem_cgroup_swapout(struct page *page, swp_entry_t entry)
58155833 if (!memcg )
58165834 return ;
58175835
5818- mem_cgroup_id_get (memcg );
5819- oldid = swap_cgroup_record (entry , mem_cgroup_id (memcg ));
5836+ /*
5837+ * In case the memcg owning these pages has been offlined and doesn't
5838+ * have an ID allocated to it anymore, charge the closest online
5839+ * ancestor for the swap instead and transfer the memory+swap charge.
5840+ */
5841+ swap_memcg = mem_cgroup_id_get_online (memcg );
5842+ oldid = swap_cgroup_record (entry , mem_cgroup_id (swap_memcg ));
58205843 VM_BUG_ON_PAGE (oldid , page );
5821- mem_cgroup_swap_statistics (memcg , true);
5844+ mem_cgroup_swap_statistics (swap_memcg , true);
58225845
58235846 page -> mem_cgroup = NULL ;
58245847
58255848 if (!mem_cgroup_is_root (memcg ))
58265849 page_counter_uncharge (& memcg -> memory , 1 );
58275850
5851+ if (memcg != swap_memcg ) {
5852+ if (!mem_cgroup_is_root (swap_memcg ))
5853+ page_counter_charge (& swap_memcg -> memsw , 1 );
5854+ page_counter_uncharge (& memcg -> memsw , 1 );
5855+ }
5856+
58285857 /*
58295858 * Interrupts should be disabled here because the caller holds the
58305859 * mapping->tree_lock lock which is taken with interrupts-off. It is
@@ -5863,11 +5892,14 @@ int mem_cgroup_try_charge_swap(struct page *page, swp_entry_t entry)
58635892 if (!memcg )
58645893 return 0 ;
58655894
5895+ memcg = mem_cgroup_id_get_online (memcg );
5896+
58665897 if (!mem_cgroup_is_root (memcg ) &&
5867- !page_counter_try_charge (& memcg -> swap , 1 , & counter ))
5898+ !page_counter_try_charge (& memcg -> swap , 1 , & counter )) {
5899+ mem_cgroup_id_put (memcg );
58685900 return - ENOMEM ;
5901+ }
58695902
5870- mem_cgroup_id_get (memcg );
58715903 oldid = swap_cgroup_record (entry , mem_cgroup_id (memcg ));
58725904 VM_BUG_ON_PAGE (oldid , page );
58735905 mem_cgroup_swap_statistics (memcg , true);
0 commit comments