• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 DECLARE_FEATURE_FLAG(bugfix_throttling);
37 DECLARE_FEATURE_FLAG(bugfix_inode_eviction);
38 
39 static 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 
48 static const struct attribute_group attr_group = {
49 	.attrs = attributes,
50 };
51 
incfs_init_sysfs(void)52 int __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 
76 err_put_features:
77 	kobject_put(features_node);
78 err_put_instances:
79 	kobject_put(instances_node);
80 err_put_root:
81 	kobject_put(sysfs_root);
82 
83 	return res;
84 }
85 
incfs_cleanup_sysfs(void)86 void 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)					\
101 static 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 									\
110 static struct kobj_attribute name##_attr = __ATTR_RO(name)
111 
112 #define __DECLARE_STATUS_FLAG64(name)					\
113 static 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 									\
122 static 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 
132 static 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 
incfs_sysfs_release(struct kobject * kobj)143 static 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 
151 static const struct attribute_group mount_attr_group = {
152 	.attrs = mount_attributes,
153 };
154 
155 static struct kobj_type incfs_kobj_node_ktype = {
156 	.sysfs_ops	= &kobj_sysfs_ops,
157 	.release	= &incfs_sysfs_release,
158 };
159 
incfs_add_sysfs_node(const char * name,struct mount_info * mi)160 struct 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 
187 err:
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 
incfs_free_sysfs_node(struct incfs_sysfs_node * node)196 void 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 }
206