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