xref: /OK3568_Linux_fs/kernel/fs/incfs/sysfs.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Copyright 2021 Google LLC
4*4882a593Smuzhiyun  */
5*4882a593Smuzhiyun #include <linux/fs.h>
6*4882a593Smuzhiyun #include <linux/kobject.h>
7*4882a593Smuzhiyun 
8*4882a593Smuzhiyun #include <uapi/linux/incrementalfs.h>
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun #include "sysfs.h"
11*4882a593Smuzhiyun #include "data_mgmt.h"
12*4882a593Smuzhiyun #include "vfs.h"
13*4882a593Smuzhiyun 
14*4882a593Smuzhiyun /******************************************************************************
15*4882a593Smuzhiyun  * Define sys/fs/incrementalfs & sys/fs/incrementalfs/features
16*4882a593Smuzhiyun  *****************************************************************************/
17*4882a593Smuzhiyun #define INCFS_NODE_FEATURES "features"
18*4882a593Smuzhiyun #define INCFS_NODE_INSTANCES "instances"
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun static struct kobject *sysfs_root;
21*4882a593Smuzhiyun static struct kobject *features_node;
22*4882a593Smuzhiyun static struct kobject *instances_node;
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun #define DECLARE_FEATURE_FLAG(name)					\
25*4882a593Smuzhiyun 	static ssize_t name##_show(struct kobject *kobj,		\
26*4882a593Smuzhiyun 			 struct kobj_attribute *attr, char *buff)	\
27*4882a593Smuzhiyun {									\
28*4882a593Smuzhiyun 	return sysfs_emit(buff, "supported\n");				\
29*4882a593Smuzhiyun }									\
30*4882a593Smuzhiyun 									\
31*4882a593Smuzhiyun static struct kobj_attribute name##_attr = __ATTR_RO(name)
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun DECLARE_FEATURE_FLAG(corefs);
34*4882a593Smuzhiyun DECLARE_FEATURE_FLAG(zstd);
35*4882a593Smuzhiyun DECLARE_FEATURE_FLAG(v2);
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun static struct attribute *attributes[] = {
38*4882a593Smuzhiyun 	&corefs_attr.attr,
39*4882a593Smuzhiyun 	&zstd_attr.attr,
40*4882a593Smuzhiyun 	&v2_attr.attr,
41*4882a593Smuzhiyun 	NULL,
42*4882a593Smuzhiyun };
43*4882a593Smuzhiyun 
44*4882a593Smuzhiyun static const struct attribute_group attr_group = {
45*4882a593Smuzhiyun 	.attrs = attributes,
46*4882a593Smuzhiyun };
47*4882a593Smuzhiyun 
incfs_init_sysfs(void)48*4882a593Smuzhiyun int __init incfs_init_sysfs(void)
49*4882a593Smuzhiyun {
50*4882a593Smuzhiyun 	int res = -ENOMEM;
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun 	sysfs_root = kobject_create_and_add(INCFS_NAME, fs_kobj);
53*4882a593Smuzhiyun 	if (!sysfs_root)
54*4882a593Smuzhiyun 		return -ENOMEM;
55*4882a593Smuzhiyun 
56*4882a593Smuzhiyun 	instances_node = kobject_create_and_add(INCFS_NODE_INSTANCES,
57*4882a593Smuzhiyun 						sysfs_root);
58*4882a593Smuzhiyun 	if (!instances_node)
59*4882a593Smuzhiyun 		goto err_put_root;
60*4882a593Smuzhiyun 
61*4882a593Smuzhiyun 	features_node = kobject_create_and_add(INCFS_NODE_FEATURES,
62*4882a593Smuzhiyun 						sysfs_root);
63*4882a593Smuzhiyun 	if (!features_node)
64*4882a593Smuzhiyun 		goto err_put_instances;
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun 	res = sysfs_create_group(features_node, &attr_group);
67*4882a593Smuzhiyun 	if (res)
68*4882a593Smuzhiyun 		goto err_put_features;
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun 	return 0;
71*4882a593Smuzhiyun 
72*4882a593Smuzhiyun err_put_features:
73*4882a593Smuzhiyun 	kobject_put(features_node);
74*4882a593Smuzhiyun err_put_instances:
75*4882a593Smuzhiyun 	kobject_put(instances_node);
76*4882a593Smuzhiyun err_put_root:
77*4882a593Smuzhiyun 	kobject_put(sysfs_root);
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun 	return res;
80*4882a593Smuzhiyun }
81*4882a593Smuzhiyun 
incfs_cleanup_sysfs(void)82*4882a593Smuzhiyun void incfs_cleanup_sysfs(void)
83*4882a593Smuzhiyun {
84*4882a593Smuzhiyun 	if (features_node) {
85*4882a593Smuzhiyun 		sysfs_remove_group(features_node, &attr_group);
86*4882a593Smuzhiyun 		kobject_put(features_node);
87*4882a593Smuzhiyun 	}
88*4882a593Smuzhiyun 
89*4882a593Smuzhiyun 	kobject_put(instances_node);
90*4882a593Smuzhiyun 	kobject_put(sysfs_root);
91*4882a593Smuzhiyun }
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun /******************************************************************************
94*4882a593Smuzhiyun  * Define sys/fs/incrementalfs/instances/<name>/
95*4882a593Smuzhiyun  *****************************************************************************/
96*4882a593Smuzhiyun #define __DECLARE_STATUS_FLAG(name)					\
97*4882a593Smuzhiyun static ssize_t name##_show(struct kobject *kobj,			\
98*4882a593Smuzhiyun 			 struct kobj_attribute *attr, char *buff)	\
99*4882a593Smuzhiyun {									\
100*4882a593Smuzhiyun 	struct incfs_sysfs_node *node = container_of(kobj,		\
101*4882a593Smuzhiyun 			struct incfs_sysfs_node, isn_sysfs_node);	\
102*4882a593Smuzhiyun 									\
103*4882a593Smuzhiyun 	return sysfs_emit(buff, "%d\n", node->isn_mi->mi_##name);	\
104*4882a593Smuzhiyun }									\
105*4882a593Smuzhiyun 									\
106*4882a593Smuzhiyun static struct kobj_attribute name##_attr = __ATTR_RO(name)
107*4882a593Smuzhiyun 
108*4882a593Smuzhiyun #define __DECLARE_STATUS_FLAG64(name)					\
109*4882a593Smuzhiyun static ssize_t name##_show(struct kobject *kobj,			\
110*4882a593Smuzhiyun 			 struct kobj_attribute *attr, char *buff)	\
111*4882a593Smuzhiyun {									\
112*4882a593Smuzhiyun 	struct incfs_sysfs_node *node = container_of(kobj,		\
113*4882a593Smuzhiyun 			struct incfs_sysfs_node, isn_sysfs_node);	\
114*4882a593Smuzhiyun 									\
115*4882a593Smuzhiyun 	return sysfs_emit(buff, "%lld\n", node->isn_mi->mi_##name);	\
116*4882a593Smuzhiyun }									\
117*4882a593Smuzhiyun 									\
118*4882a593Smuzhiyun static struct kobj_attribute name##_attr = __ATTR_RO(name)
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun __DECLARE_STATUS_FLAG(reads_failed_timed_out);
121*4882a593Smuzhiyun __DECLARE_STATUS_FLAG(reads_failed_hash_verification);
122*4882a593Smuzhiyun __DECLARE_STATUS_FLAG(reads_failed_other);
123*4882a593Smuzhiyun __DECLARE_STATUS_FLAG(reads_delayed_pending);
124*4882a593Smuzhiyun __DECLARE_STATUS_FLAG64(reads_delayed_pending_us);
125*4882a593Smuzhiyun __DECLARE_STATUS_FLAG(reads_delayed_min);
126*4882a593Smuzhiyun __DECLARE_STATUS_FLAG64(reads_delayed_min_us);
127*4882a593Smuzhiyun 
128*4882a593Smuzhiyun static struct attribute *mount_attributes[] = {
129*4882a593Smuzhiyun 	&reads_failed_timed_out_attr.attr,
130*4882a593Smuzhiyun 	&reads_failed_hash_verification_attr.attr,
131*4882a593Smuzhiyun 	&reads_failed_other_attr.attr,
132*4882a593Smuzhiyun 	&reads_delayed_pending_attr.attr,
133*4882a593Smuzhiyun 	&reads_delayed_pending_us_attr.attr,
134*4882a593Smuzhiyun 	&reads_delayed_min_attr.attr,
135*4882a593Smuzhiyun 	&reads_delayed_min_us_attr.attr,
136*4882a593Smuzhiyun 	NULL,
137*4882a593Smuzhiyun };
138*4882a593Smuzhiyun 
incfs_sysfs_release(struct kobject * kobj)139*4882a593Smuzhiyun static void incfs_sysfs_release(struct kobject *kobj)
140*4882a593Smuzhiyun {
141*4882a593Smuzhiyun 	struct incfs_sysfs_node *node = container_of(kobj,
142*4882a593Smuzhiyun 				struct incfs_sysfs_node, isn_sysfs_node);
143*4882a593Smuzhiyun 
144*4882a593Smuzhiyun 	complete(&node->isn_completion);
145*4882a593Smuzhiyun }
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun static const struct attribute_group mount_attr_group = {
148*4882a593Smuzhiyun 	.attrs = mount_attributes,
149*4882a593Smuzhiyun };
150*4882a593Smuzhiyun 
151*4882a593Smuzhiyun static struct kobj_type incfs_kobj_node_ktype = {
152*4882a593Smuzhiyun 	.sysfs_ops	= &kobj_sysfs_ops,
153*4882a593Smuzhiyun 	.release	= &incfs_sysfs_release,
154*4882a593Smuzhiyun };
155*4882a593Smuzhiyun 
incfs_add_sysfs_node(const char * name,struct mount_info * mi)156*4882a593Smuzhiyun struct incfs_sysfs_node *incfs_add_sysfs_node(const char *name,
157*4882a593Smuzhiyun 					      struct mount_info *mi)
158*4882a593Smuzhiyun {
159*4882a593Smuzhiyun 	struct incfs_sysfs_node *node = NULL;
160*4882a593Smuzhiyun 	int error;
161*4882a593Smuzhiyun 
162*4882a593Smuzhiyun 	if (!name)
163*4882a593Smuzhiyun 		return NULL;
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun 	node = kzalloc(sizeof(*node), GFP_NOFS);
166*4882a593Smuzhiyun 	if (!node)
167*4882a593Smuzhiyun 		return ERR_PTR(-ENOMEM);
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun 	node->isn_mi = mi;
170*4882a593Smuzhiyun 
171*4882a593Smuzhiyun 	init_completion(&node->isn_completion);
172*4882a593Smuzhiyun 	kobject_init(&node->isn_sysfs_node, &incfs_kobj_node_ktype);
173*4882a593Smuzhiyun 	error = kobject_add(&node->isn_sysfs_node, instances_node, "%s", name);
174*4882a593Smuzhiyun 	if (error)
175*4882a593Smuzhiyun 		goto err;
176*4882a593Smuzhiyun 
177*4882a593Smuzhiyun 	error = sysfs_create_group(&node->isn_sysfs_node, &mount_attr_group);
178*4882a593Smuzhiyun 	if (error)
179*4882a593Smuzhiyun 		goto err;
180*4882a593Smuzhiyun 
181*4882a593Smuzhiyun 	return node;
182*4882a593Smuzhiyun 
183*4882a593Smuzhiyun err:
184*4882a593Smuzhiyun 	/*
185*4882a593Smuzhiyun 	 * Note kobject_put always calls release, so incfs_sysfs_release will
186*4882a593Smuzhiyun 	 * free node
187*4882a593Smuzhiyun 	 */
188*4882a593Smuzhiyun 	kobject_put(&node->isn_sysfs_node);
189*4882a593Smuzhiyun 	return ERR_PTR(error);
190*4882a593Smuzhiyun }
191*4882a593Smuzhiyun 
incfs_free_sysfs_node(struct incfs_sysfs_node * node)192*4882a593Smuzhiyun void incfs_free_sysfs_node(struct incfs_sysfs_node *node)
193*4882a593Smuzhiyun {
194*4882a593Smuzhiyun 	if (!node)
195*4882a593Smuzhiyun 		return;
196*4882a593Smuzhiyun 
197*4882a593Smuzhiyun 	sysfs_remove_group(&node->isn_sysfs_node, &mount_attr_group);
198*4882a593Smuzhiyun 	kobject_put(&node->isn_sysfs_node);
199*4882a593Smuzhiyun 	wait_for_completion_interruptible(&node->isn_completion);
200*4882a593Smuzhiyun 	kfree(node);
201*4882a593Smuzhiyun }
202