Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

memcg: do obj_cgroup_put inside drain_obj_stock

Previously we could not call obj_cgroup_put() inside the local lock
because on the put on the last reference, the release function
obj_cgroup_release() may try to re-acquire the local lock. However that
chain has been broken. Now simply do obj_cgroup_put() inside
drain_obj_stock() instead of returning the old objcg.

Link: https://lkml.kernel.org/r/20250404013913.1663035-7-shakeel.butt@linux.dev
Signed-off-by: Shakeel Butt <shakeel.butt@linux.dev>
Reviewed-by: Roman Gushchin <roman.gushchin@linux.dev>
Acked-by: Vlastimil Babka <vbabka@suse.cz>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Michal Hocko <mhocko@kernel.org>
Cc: Muchun Song <muchun.song@linux.dev>
Cc: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

authored by

Shakeel Butt and committed by
Andrew Morton
ae51c775 b6d04711

+11 -26
+11 -26
mm/memcontrol.c
··· 1785 1785 }; 1786 1786 static DEFINE_MUTEX(percpu_charge_mutex); 1787 1787 1788 - static struct obj_cgroup *drain_obj_stock(struct memcg_stock_pcp *stock); 1788 + static void drain_obj_stock(struct memcg_stock_pcp *stock); 1789 1789 static bool obj_stock_flush_required(struct memcg_stock_pcp *stock, 1790 1790 struct mem_cgroup *root_memcg); 1791 1791 ··· 1859 1859 static void drain_local_stock(struct work_struct *dummy) 1860 1860 { 1861 1861 struct memcg_stock_pcp *stock; 1862 - struct obj_cgroup *old = NULL; 1863 1862 unsigned long flags; 1864 1863 1865 1864 /* ··· 1869 1870 local_lock_irqsave(&memcg_stock.stock_lock, flags); 1870 1871 1871 1872 stock = this_cpu_ptr(&memcg_stock); 1872 - old = drain_obj_stock(stock); 1873 + drain_obj_stock(stock); 1873 1874 drain_stock(stock); 1874 1875 clear_bit(FLUSHING_CACHED_CHARGE, &stock->flags); 1875 1876 1876 1877 local_unlock_irqrestore(&memcg_stock.stock_lock, flags); 1877 - obj_cgroup_put(old); 1878 1878 } 1879 1879 1880 1880 static void refill_stock(struct mem_cgroup *memcg, unsigned int nr_pages) ··· 1956 1958 static int memcg_hotplug_cpu_dead(unsigned int cpu) 1957 1959 { 1958 1960 struct memcg_stock_pcp *stock; 1959 - struct obj_cgroup *old; 1960 1961 unsigned long flags; 1961 1962 1962 1963 stock = &per_cpu(memcg_stock, cpu); 1963 1964 1964 1965 /* drain_obj_stock requires stock_lock */ 1965 1966 local_lock_irqsave(&memcg_stock.stock_lock, flags); 1966 - old = drain_obj_stock(stock); 1967 + drain_obj_stock(stock); 1967 1968 local_unlock_irqrestore(&memcg_stock.stock_lock, flags); 1968 1969 1969 1970 drain_stock(stock); 1970 - obj_cgroup_put(old); 1971 1971 1972 1972 return 0; 1973 1973 } ··· 2762 2766 } 2763 2767 2764 2768 /* Replace the stock objcg with objcg, return the old objcg */ 2765 - static struct obj_cgroup *replace_stock_objcg(struct memcg_stock_pcp *stock, 2766 - struct obj_cgroup *objcg) 2769 + static void replace_stock_objcg(struct memcg_stock_pcp *stock, 2770 + struct obj_cgroup *objcg) 2767 2771 { 2768 - struct obj_cgroup *old = NULL; 2769 - 2770 - old = drain_obj_stock(stock); 2772 + drain_obj_stock(stock); 2771 2773 obj_cgroup_get(objcg); 2772 2774 stock->nr_bytes = atomic_read(&objcg->nr_charged_bytes) 2773 2775 ? atomic_xchg(&objcg->nr_charged_bytes, 0) : 0; 2774 2776 WRITE_ONCE(stock->cached_objcg, objcg); 2775 - return old; 2776 2777 } 2777 2778 2778 2779 static void mod_objcg_state(struct obj_cgroup *objcg, struct pglist_data *pgdat, 2779 2780 enum node_stat_item idx, int nr) 2780 2781 { 2781 2782 struct memcg_stock_pcp *stock; 2782 - struct obj_cgroup *old = NULL; 2783 2783 unsigned long flags; 2784 2784 int *bytes; 2785 2785 ··· 2788 2796 * changes. 2789 2797 */ 2790 2798 if (READ_ONCE(stock->cached_objcg) != objcg) { 2791 - old = replace_stock_objcg(stock, objcg); 2799 + replace_stock_objcg(stock, objcg); 2792 2800 stock->cached_pgdat = pgdat; 2793 2801 } else if (stock->cached_pgdat != pgdat) { 2794 2802 /* Flush the existing cached vmstat data */ ··· 2829 2837 __mod_objcg_mlstate(objcg, pgdat, idx, nr); 2830 2838 2831 2839 local_unlock_irqrestore(&memcg_stock.stock_lock, flags); 2832 - obj_cgroup_put(old); 2833 2840 } 2834 2841 2835 2842 static bool consume_obj_stock(struct obj_cgroup *objcg, unsigned int nr_bytes) ··· 2850 2859 return ret; 2851 2860 } 2852 2861 2853 - static struct obj_cgroup *drain_obj_stock(struct memcg_stock_pcp *stock) 2862 + static void drain_obj_stock(struct memcg_stock_pcp *stock) 2854 2863 { 2855 2864 struct obj_cgroup *old = READ_ONCE(stock->cached_objcg); 2856 2865 2857 2866 if (!old) 2858 - return NULL; 2867 + return; 2859 2868 2860 2869 if (stock->nr_bytes) { 2861 2870 unsigned int nr_pages = stock->nr_bytes >> PAGE_SHIFT; ··· 2908 2917 } 2909 2918 2910 2919 WRITE_ONCE(stock->cached_objcg, NULL); 2911 - /* 2912 - * The `old' objects needs to be released by the caller via 2913 - * obj_cgroup_put() outside of memcg_stock_pcp::stock_lock. 2914 - */ 2915 - return old; 2920 + obj_cgroup_put(old); 2916 2921 } 2917 2922 2918 2923 static bool obj_stock_flush_required(struct memcg_stock_pcp *stock, ··· 2930 2943 bool allow_uncharge) 2931 2944 { 2932 2945 struct memcg_stock_pcp *stock; 2933 - struct obj_cgroup *old = NULL; 2934 2946 unsigned long flags; 2935 2947 unsigned int nr_pages = 0; 2936 2948 ··· 2937 2951 2938 2952 stock = this_cpu_ptr(&memcg_stock); 2939 2953 if (READ_ONCE(stock->cached_objcg) != objcg) { /* reset if necessary */ 2940 - old = replace_stock_objcg(stock, objcg); 2954 + replace_stock_objcg(stock, objcg); 2941 2955 allow_uncharge = true; /* Allow uncharge when objcg changes */ 2942 2956 } 2943 2957 stock->nr_bytes += nr_bytes; ··· 2948 2962 } 2949 2963 2950 2964 local_unlock_irqrestore(&memcg_stock.stock_lock, flags); 2951 - obj_cgroup_put(old); 2952 2965 2953 2966 if (nr_pages) 2954 2967 obj_cgroup_uncharge_pages(objcg, nr_pages);