![Michal Hocko](/assets/img/avatar_default.png)
vmpressure is called synchronously from reclaim where the target_memcg is guaranteed to be alive but the eventfd is signaled from the work queue context. This means that memcg (along with vmpressure structure which is embedded into it) might go away while the work item is pending which would result in use-after-release bug. We have two possible ways how to fix this. Either vmpressure pins memcg before it schedules vmpr->work and unpin it in vmpressure_work_fn or explicitely flush the work item from the css_offline context (as suggested by Tejun). This patch implements the later one and it introduces vmpressure_cleanup which flushes the vmpressure work queue item item. It hooks into mem_cgroup_css_offline after the memcg itself is cleaned up. [akpm@linux-foundation.org: coding-style fixes] Signed-off-by: Michal Hocko <mhocko@suse.cz> Reported-by: Tejun Heo <tj@kernel.org> Cc: Anton Vorontsov <anton.vorontsov@linaro.org> Cc: Johannes Weiner <hannes@cmpxchg.org> Cc: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com> Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com> Cc: Li Zefan <lizefan@huawei.com> Acked-by: Tejun Heo <tj@kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
49 lines
1.7 KiB
C
49 lines
1.7 KiB
C
#ifndef __LINUX_VMPRESSURE_H
|
|
#define __LINUX_VMPRESSURE_H
|
|
|
|
#include <linux/mutex.h>
|
|
#include <linux/list.h>
|
|
#include <linux/workqueue.h>
|
|
#include <linux/gfp.h>
|
|
#include <linux/types.h>
|
|
#include <linux/cgroup.h>
|
|
|
|
struct vmpressure {
|
|
unsigned long scanned;
|
|
unsigned long reclaimed;
|
|
/* The lock is used to keep the scanned/reclaimed above in sync. */
|
|
struct spinlock sr_lock;
|
|
|
|
/* The list of vmpressure_event structs. */
|
|
struct list_head events;
|
|
/* Have to grab the lock on events traversal or modifications. */
|
|
struct mutex events_lock;
|
|
|
|
struct work_struct work;
|
|
};
|
|
|
|
struct mem_cgroup;
|
|
|
|
#ifdef CONFIG_MEMCG
|
|
extern void vmpressure(gfp_t gfp, struct mem_cgroup *memcg,
|
|
unsigned long scanned, unsigned long reclaimed);
|
|
extern void vmpressure_prio(gfp_t gfp, struct mem_cgroup *memcg, int prio);
|
|
|
|
extern void vmpressure_init(struct vmpressure *vmpr);
|
|
extern void vmpressure_cleanup(struct vmpressure *vmpr);
|
|
extern struct vmpressure *memcg_to_vmpressure(struct mem_cgroup *memcg);
|
|
extern struct cgroup_subsys_state *vmpressure_to_css(struct vmpressure *vmpr);
|
|
extern struct vmpressure *css_to_vmpressure(struct cgroup_subsys_state *css);
|
|
extern int vmpressure_register_event(struct cgroup *cg, struct cftype *cft,
|
|
struct eventfd_ctx *eventfd,
|
|
const char *args);
|
|
extern void vmpressure_unregister_event(struct cgroup *cg, struct cftype *cft,
|
|
struct eventfd_ctx *eventfd);
|
|
#else
|
|
static inline void vmpressure(gfp_t gfp, struct mem_cgroup *memcg,
|
|
unsigned long scanned, unsigned long reclaimed) {}
|
|
static inline void vmpressure_prio(gfp_t gfp, struct mem_cgroup *memcg,
|
|
int prio) {}
|
|
#endif /* CONFIG_MEMCG */
|
|
#endif /* __LINUX_VMPRESSURE_H */
|