b9ad003af1
This adds the following new sysfs file tracking the number of successfully released pages from a given CMA heap area. This file will be available via CONFIG_CMA_SYSFS and help in determining active CMA pages available on the CMA heap area. This adds a new 'nr_pages_released' (CONFIG_CMA_SYSFS) into 'struct cma' which gets updated during cma_release(). /sys/kernel/mm/cma/<cma-heap-area>/release_pages_success After this change, an user will be able to find active CMA pages available in a given CMA heap area via the following method. Active pages = alloc_pages_success - release_pages_success That's valuable information for both software designers, and system admins as it allows them to tune the number of CMA pages available in the system. This increases user visibility for allocated CMA area and its utilization. Link: https://lkml.kernel.org/r/20240206045731.472759-1-anshuman.khandual@arm.com Signed-off-by: Anshuman Khandual <anshuman.khandual@arm.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
128 lines
2.9 KiB
C
128 lines
2.9 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* CMA SysFS Interface
|
|
*
|
|
* Copyright (c) 2021 Minchan Kim <minchan@kernel.org>
|
|
*/
|
|
|
|
#include <linux/cma.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/slab.h>
|
|
|
|
#include "cma.h"
|
|
|
|
#define CMA_ATTR_RO(_name) \
|
|
static struct kobj_attribute _name##_attr = __ATTR_RO(_name)
|
|
|
|
void cma_sysfs_account_success_pages(struct cma *cma, unsigned long nr_pages)
|
|
{
|
|
atomic64_add(nr_pages, &cma->nr_pages_succeeded);
|
|
}
|
|
|
|
void cma_sysfs_account_fail_pages(struct cma *cma, unsigned long nr_pages)
|
|
{
|
|
atomic64_add(nr_pages, &cma->nr_pages_failed);
|
|
}
|
|
|
|
void cma_sysfs_account_release_pages(struct cma *cma, unsigned long nr_pages)
|
|
{
|
|
atomic64_add(nr_pages, &cma->nr_pages_released);
|
|
}
|
|
|
|
static inline struct cma *cma_from_kobj(struct kobject *kobj)
|
|
{
|
|
return container_of(kobj, struct cma_kobject, kobj)->cma;
|
|
}
|
|
|
|
static ssize_t alloc_pages_success_show(struct kobject *kobj,
|
|
struct kobj_attribute *attr, char *buf)
|
|
{
|
|
struct cma *cma = cma_from_kobj(kobj);
|
|
|
|
return sysfs_emit(buf, "%llu\n",
|
|
atomic64_read(&cma->nr_pages_succeeded));
|
|
}
|
|
CMA_ATTR_RO(alloc_pages_success);
|
|
|
|
static ssize_t alloc_pages_fail_show(struct kobject *kobj,
|
|
struct kobj_attribute *attr, char *buf)
|
|
{
|
|
struct cma *cma = cma_from_kobj(kobj);
|
|
|
|
return sysfs_emit(buf, "%llu\n", atomic64_read(&cma->nr_pages_failed));
|
|
}
|
|
CMA_ATTR_RO(alloc_pages_fail);
|
|
|
|
static ssize_t release_pages_success_show(struct kobject *kobj,
|
|
struct kobj_attribute *attr, char *buf)
|
|
{
|
|
struct cma *cma = cma_from_kobj(kobj);
|
|
|
|
return sysfs_emit(buf, "%llu\n", atomic64_read(&cma->nr_pages_released));
|
|
}
|
|
CMA_ATTR_RO(release_pages_success);
|
|
|
|
static void cma_kobj_release(struct kobject *kobj)
|
|
{
|
|
struct cma *cma = cma_from_kobj(kobj);
|
|
struct cma_kobject *cma_kobj = cma->cma_kobj;
|
|
|
|
kfree(cma_kobj);
|
|
cma->cma_kobj = NULL;
|
|
}
|
|
|
|
static struct attribute *cma_attrs[] = {
|
|
&alloc_pages_success_attr.attr,
|
|
&alloc_pages_fail_attr.attr,
|
|
&release_pages_success_attr.attr,
|
|
NULL,
|
|
};
|
|
ATTRIBUTE_GROUPS(cma);
|
|
|
|
static const struct kobj_type cma_ktype = {
|
|
.release = cma_kobj_release,
|
|
.sysfs_ops = &kobj_sysfs_ops,
|
|
.default_groups = cma_groups,
|
|
};
|
|
|
|
static int __init cma_sysfs_init(void)
|
|
{
|
|
struct kobject *cma_kobj_root;
|
|
struct cma_kobject *cma_kobj;
|
|
struct cma *cma;
|
|
int i, err;
|
|
|
|
cma_kobj_root = kobject_create_and_add("cma", mm_kobj);
|
|
if (!cma_kobj_root)
|
|
return -ENOMEM;
|
|
|
|
for (i = 0; i < cma_area_count; i++) {
|
|
cma_kobj = kzalloc(sizeof(*cma_kobj), GFP_KERNEL);
|
|
if (!cma_kobj) {
|
|
err = -ENOMEM;
|
|
goto out;
|
|
}
|
|
|
|
cma = &cma_areas[i];
|
|
cma->cma_kobj = cma_kobj;
|
|
cma_kobj->cma = cma;
|
|
err = kobject_init_and_add(&cma_kobj->kobj, &cma_ktype,
|
|
cma_kobj_root, "%s", cma->name);
|
|
if (err) {
|
|
kobject_put(&cma_kobj->kobj);
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
out:
|
|
while (--i >= 0) {
|
|
cma = &cma_areas[i];
|
|
kobject_put(&cma->cma_kobj->kobj);
|
|
}
|
|
kobject_put(cma_kobj_root);
|
|
|
|
return err;
|
|
}
|
|
subsys_initcall(cma_sysfs_init);
|