xref: /kernel/linux/linux-6.6/fs/ubifs/sysfs.c (revision 62306a36)
162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * This file is part of UBIFS.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2021 Cisco Systems
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Author: Stefan Schaeckeler
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/fs.h>
1262306a36Sopenharmony_ci#include "ubifs.h"
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_cienum attr_id_t {
1562306a36Sopenharmony_ci	attr_errors_magic,
1662306a36Sopenharmony_ci	attr_errors_node,
1762306a36Sopenharmony_ci	attr_errors_crc,
1862306a36Sopenharmony_ci};
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_cistruct ubifs_attr {
2162306a36Sopenharmony_ci	struct attribute attr;
2262306a36Sopenharmony_ci	enum attr_id_t attr_id;
2362306a36Sopenharmony_ci};
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#define UBIFS_ATTR(_name, _mode, _id)					\
2662306a36Sopenharmony_cistatic struct ubifs_attr ubifs_attr_##_name = {				\
2762306a36Sopenharmony_ci	.attr = {.name = __stringify(_name), .mode = _mode },		\
2862306a36Sopenharmony_ci	.attr_id = attr_##_id,						\
2962306a36Sopenharmony_ci}
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci#define UBIFS_ATTR_FUNC(_name, _mode) UBIFS_ATTR(_name, _mode, _name)
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ciUBIFS_ATTR_FUNC(errors_magic, 0444);
3462306a36Sopenharmony_ciUBIFS_ATTR_FUNC(errors_crc, 0444);
3562306a36Sopenharmony_ciUBIFS_ATTR_FUNC(errors_node, 0444);
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci#define ATTR_LIST(name) (&ubifs_attr_##name.attr)
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_cistatic struct attribute *ubifs_attrs[] = {
4062306a36Sopenharmony_ci	ATTR_LIST(errors_magic),
4162306a36Sopenharmony_ci	ATTR_LIST(errors_node),
4262306a36Sopenharmony_ci	ATTR_LIST(errors_crc),
4362306a36Sopenharmony_ci	NULL,
4462306a36Sopenharmony_ci};
4562306a36Sopenharmony_ciATTRIBUTE_GROUPS(ubifs);
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_cistatic ssize_t ubifs_attr_show(struct kobject *kobj,
4862306a36Sopenharmony_ci			       struct attribute *attr, char *buf)
4962306a36Sopenharmony_ci{
5062306a36Sopenharmony_ci	struct ubifs_info *sbi = container_of(kobj, struct ubifs_info,
5162306a36Sopenharmony_ci					      kobj);
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	struct ubifs_attr *a = container_of(attr, struct ubifs_attr, attr);
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	switch (a->attr_id) {
5662306a36Sopenharmony_ci	case attr_errors_magic:
5762306a36Sopenharmony_ci		return sysfs_emit(buf, "%u\n", sbi->stats->magic_errors);
5862306a36Sopenharmony_ci	case attr_errors_node:
5962306a36Sopenharmony_ci		return sysfs_emit(buf, "%u\n", sbi->stats->node_errors);
6062306a36Sopenharmony_ci	case attr_errors_crc:
6162306a36Sopenharmony_ci		return sysfs_emit(buf, "%u\n", sbi->stats->crc_errors);
6262306a36Sopenharmony_ci	}
6362306a36Sopenharmony_ci	return 0;
6462306a36Sopenharmony_ci};
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_cistatic void ubifs_sb_release(struct kobject *kobj)
6762306a36Sopenharmony_ci{
6862306a36Sopenharmony_ci	struct ubifs_info *c = container_of(kobj, struct ubifs_info, kobj);
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	complete(&c->kobj_unregister);
7162306a36Sopenharmony_ci}
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_cistatic const struct sysfs_ops ubifs_attr_ops = {
7462306a36Sopenharmony_ci	.show	= ubifs_attr_show,
7562306a36Sopenharmony_ci};
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_cistatic const struct kobj_type ubifs_sb_ktype = {
7862306a36Sopenharmony_ci	.default_groups	= ubifs_groups,
7962306a36Sopenharmony_ci	.sysfs_ops	= &ubifs_attr_ops,
8062306a36Sopenharmony_ci	.release	= ubifs_sb_release,
8162306a36Sopenharmony_ci};
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_cistatic const struct kobj_type ubifs_ktype = {
8462306a36Sopenharmony_ci	.sysfs_ops	= &ubifs_attr_ops,
8562306a36Sopenharmony_ci};
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_cistatic struct kset ubifs_kset = {
8862306a36Sopenharmony_ci	.kobj	= {.ktype = &ubifs_ktype},
8962306a36Sopenharmony_ci};
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ciint ubifs_sysfs_register(struct ubifs_info *c)
9262306a36Sopenharmony_ci{
9362306a36Sopenharmony_ci	int ret, n;
9462306a36Sopenharmony_ci	char dfs_dir_name[UBIFS_DFS_DIR_LEN+1];
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	c->stats = kzalloc(sizeof(struct ubifs_stats_info), GFP_KERNEL);
9762306a36Sopenharmony_ci	if (!c->stats) {
9862306a36Sopenharmony_ci		ret = -ENOMEM;
9962306a36Sopenharmony_ci		goto out_last;
10062306a36Sopenharmony_ci	}
10162306a36Sopenharmony_ci	n = snprintf(dfs_dir_name, UBIFS_DFS_DIR_LEN + 1, UBIFS_DFS_DIR_NAME,
10262306a36Sopenharmony_ci		     c->vi.ubi_num, c->vi.vol_id);
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	if (n > UBIFS_DFS_DIR_LEN) {
10562306a36Sopenharmony_ci		/* The array size is too small */
10662306a36Sopenharmony_ci		ret = -EINVAL;
10762306a36Sopenharmony_ci		goto out_free;
10862306a36Sopenharmony_ci	}
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	c->kobj.kset = &ubifs_kset;
11162306a36Sopenharmony_ci	init_completion(&c->kobj_unregister);
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	ret = kobject_init_and_add(&c->kobj, &ubifs_sb_ktype, NULL,
11462306a36Sopenharmony_ci				   "%s", dfs_dir_name);
11562306a36Sopenharmony_ci	if (ret)
11662306a36Sopenharmony_ci		goto out_put;
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	return 0;
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ciout_put:
12162306a36Sopenharmony_ci	kobject_put(&c->kobj);
12262306a36Sopenharmony_ci	wait_for_completion(&c->kobj_unregister);
12362306a36Sopenharmony_ciout_free:
12462306a36Sopenharmony_ci	kfree(c->stats);
12562306a36Sopenharmony_ciout_last:
12662306a36Sopenharmony_ci	ubifs_err(c, "cannot create sysfs entry for ubifs%d_%d, error %d\n",
12762306a36Sopenharmony_ci		  c->vi.ubi_num, c->vi.vol_id, ret);
12862306a36Sopenharmony_ci	return ret;
12962306a36Sopenharmony_ci}
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_civoid ubifs_sysfs_unregister(struct ubifs_info *c)
13262306a36Sopenharmony_ci{
13362306a36Sopenharmony_ci	kobject_del(&c->kobj);
13462306a36Sopenharmony_ci	kobject_put(&c->kobj);
13562306a36Sopenharmony_ci	wait_for_completion(&c->kobj_unregister);
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	kfree(c->stats);
13862306a36Sopenharmony_ci}
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ciint __init ubifs_sysfs_init(void)
14162306a36Sopenharmony_ci{
14262306a36Sopenharmony_ci	int ret;
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	kobject_set_name(&ubifs_kset.kobj, "ubifs");
14562306a36Sopenharmony_ci	ubifs_kset.kobj.parent = fs_kobj;
14662306a36Sopenharmony_ci	ret = kset_register(&ubifs_kset);
14762306a36Sopenharmony_ci	if (ret)
14862306a36Sopenharmony_ci		kset_put(&ubifs_kset);
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	return ret;
15162306a36Sopenharmony_ci}
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_civoid ubifs_sysfs_exit(void)
15462306a36Sopenharmony_ci{
15562306a36Sopenharmony_ci	kset_unregister(&ubifs_kset);
15662306a36Sopenharmony_ci}
157