Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9c0dc3d9 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "lowmemorykiller: sysfs node and notifications"

parents 963758c9 f195968d
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -42,6 +42,17 @@ config ANDROID_VSOC
	  a 'cuttlefish' Android image inside QEmu. The driver interacts with
	  a QEmu ivshmem device. If built as a module, it will be called vsoc.

config ANDROID_LMK_NOTIFY_TRIGGER
	bool "Android Low Memory Killer Notify Trigger"
	depends on ANDROID_LOW_MEMORY_KILLER
	default n
	---help---
	Create node "/sys/kernel/mm/lowmemkiller/notify_trigger_active",
	on which an userspace application can poll for notification when
	the number of free physical memory pages in the system falls below
	a set threshold. The threshold is set by the new module parameter
	"/sys/module/lowmemorykiller/parameters/notify_trigger".

source "drivers/staging/android/ion/Kconfig"

endif # if ANDROID
+110 −1
Original line number Diff line number Diff line
@@ -92,6 +92,12 @@ static int lmk_fast_run = 1;

static unsigned long lowmem_deathpending_timeout;

#ifdef CONFIG_ANDROID_LMK_NOTIFY_TRIGGER
static struct shrink_control lowmem_notif_sc = {GFP_KERNEL, 0};
static int lowmem_minfree_notif_trigger;
static struct kobject *lowmem_notify_kobj;
#endif

#define lowmem_print(level, x...)			\
	do {						\
		if (lowmem_debug_level >= (level))	\
@@ -582,6 +588,34 @@ static void mark_lmk_victim(struct task_struct *tsk)
	}
}

#ifdef CONFIG_ANDROID_LMK_NOTIFY_TRIGGER
static void lowmem_notify_killzone_approach(void);

static int get_free_ram(int *other_free, int *other_file,
			struct shrink_control *sc)
{
	*other_free = global_page_state(NR_FREE_PAGES) - totalreserve_pages;

	if (global_node_page_state(NR_SHMEM) + total_swapcache_pages() +
			global_node_page_state(NR_UNEVICTABLE) <
			global_node_page_state(NR_FILE_PAGES))
		*other_file = global_node_page_state(NR_FILE_PAGES) -
					global_node_page_state(NR_SHMEM) -
					global_node_page_state(NR_UNEVICTABLE) -
					total_swapcache_pages();
	else
		*other_file = 0;

	tune_lmk_param(other_free, other_file, sc);

	if (*other_free < lowmem_minfree_notif_trigger &&
	    *other_file < lowmem_minfree_notif_trigger)
		return 1;
	else
		return 0;
}
#endif

static unsigned long lowmem_scan(struct shrinker *s, struct shrink_control *sc)
{
	struct task_struct *tsk;
@@ -601,6 +635,12 @@ static unsigned long lowmem_scan(struct shrinker *s, struct shrink_control *sc)
	if (!mutex_trylock(&scan_mutex))
		return 0;

#ifdef CONFIG_ANDROID_LMK_NOTIFY_TRIGGER
	lowmem_notif_sc.gfp_mask = sc->gfp_mask;

	if (get_free_ram(&other_free, &other_file, sc))
		lowmem_notify_killzone_approach();
#else
	other_free = global_page_state(NR_FREE_PAGES) - totalreserve_pages;

	if (global_node_page_state(NR_SHMEM) + total_swapcache_pages() +
@@ -614,6 +654,7 @@ static unsigned long lowmem_scan(struct shrinker *s, struct shrink_control *sc)
		other_file = 0;

	tune_lmk_param(&other_free, &other_file, sc);
#endif

	if (lowmem_adj_size < array_size)
		array_size = lowmem_adj_size;
@@ -801,8 +842,74 @@ static struct shrinker lowmem_shrinker = {
	.seeks = DEFAULT_SEEKS * 16
};

#ifdef CONFIG_ANDROID_LMK_NOTIFY_TRIGGER
static void lowmem_notify_killzone_approach(void)
{
	lowmem_print(3, "notification trigger activated\n");
	sysfs_notify(lowmem_notify_kobj, NULL,
		     "notify_trigger_active");
}

static ssize_t lowmem_notify_trigger_active_show(struct kobject *k,
						 struct kobj_attribute *attr,
						 char *buf)
{
	int other_free, other_file;

	if (get_free_ram(&other_free, &other_file, &lowmem_notif_sc))
		return snprintf(buf, 3, "1\n");
	else
		return snprintf(buf, 3, "0\n");
}

static struct kobj_attribute lowmem_notify_trigger_active_attr =
	__ATTR(notify_trigger_active, 0444,
	       lowmem_notify_trigger_active_show, NULL);

static struct attribute *lowmem_notify_default_attrs[] = {
	&lowmem_notify_trigger_active_attr.attr, NULL,
};

static ssize_t lowmem_show(struct kobject *k, struct attribute *attr, char *buf)
{
	struct kobj_attribute *kobj_attr;

	kobj_attr = container_of(attr, struct kobj_attribute, attr);
	return kobj_attr->show(k, kobj_attr, buf);
}

static const struct sysfs_ops lowmem_notify_ops = {
	.show = lowmem_show,
};

static void lowmem_notify_kobj_release(struct kobject *kobj)
{
	/* Nothing to be done here */
}

static struct kobj_type lowmem_notify_kobj_type = {
	.release = lowmem_notify_kobj_release,
	.sysfs_ops = &lowmem_notify_ops,
	.default_attrs = lowmem_notify_default_attrs,
};
#endif

static int __init lowmem_init(void)
{
#ifdef CONFIG_ANDROID_LMK_NOTIFY_TRIGGER
	int rc;

	lowmem_notify_kobj = kzalloc(sizeof(*lowmem_notify_kobj), GFP_KERNEL);
	if (!lowmem_notify_kobj)
		return -ENOMEM;

	rc = kobject_init_and_add(lowmem_notify_kobj, &lowmem_notify_kobj_type,
				  mm_kobj, "lowmemkiller");
	if (rc) {
		kfree(lowmem_notify_kobj);
		return rc;
	}
#endif
	register_shrinker(&lowmem_shrinker);
	vmpressure_notifier_register(&lmk_vmpr_nb);
	lmk_event_init();
@@ -904,4 +1011,6 @@ module_param_array_named(minfree, lowmem_minfree, uint, &lowmem_minfree_size,
			 S_IRUGO | S_IWUSR);
module_param_named(debug_level, lowmem_debug_level, uint, S_IRUGO | S_IWUSR);
module_param_named(lmk_fast_run, lmk_fast_run, int, S_IRUGO | S_IWUSR);
#ifdef CONFIG_ANDROID_LMK_NOTIFY_TRIGGER
module_param_named(notify_trigger, lowmem_minfree_notif_trigger, uint, 0644);
#endif