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