PatchworkOS  19e446b
A non-POSIX operating system.
Loading...
Searching...
No Matches
sysfs.c
Go to the documentation of this file.
1#include <kernel/fs/sysfs.h>
2
3#include <kernel/fs/dentry.h>
4#include <kernel/fs/file.h>
6#include <kernel/fs/mount.h>
8#include <kernel/fs/path.h>
10#include <kernel/fs/vfs.h>
11#include <kernel/fs/vnode.h>
12#include <kernel/log/log.h>
13#include <kernel/log/panic.h>
14#include <kernel/sched/sched.h>
15#include <kernel/sync/lock.h>
16
17#include <assert.h>
18#include <errno.h>
19#include <stdatomic.h>
20#include <stdlib.h>
21#include <string.h>
22#include <sys/fs.h>
23#include <sys/list.h>
24
25static dentry_t* root = NULL;
26
30
31static dentry_t* sysfs_mount(filesystem_t* fs, const char* options, void* data)
32{
33 UNUSED(fs);
34 UNUSED(data);
35
36 if (options != NULL)
37 {
38 errno = EINVAL;
39 return NULL;
40 }
41
42 return REF(root);
43}
44
47 .mount = sysfs_mount,
48};
49
50void sysfs_init(void)
51{
53 {
54 panic(NULL, "Failed to register sysfs");
55 }
56
58 if (superblock == NULL)
59 {
60 panic(NULL, "Failed to create sysfs superblock");
61 }
62 UNREF_DEFER(superblock);
63
64 vnode_t* vnode = vnode_new(superblock, VDIR, NULL, NULL);
65 if (vnode == NULL)
66 {
67 panic(NULL, "Failed to create sysfs root vnode");
68 }
69 UNREF_DEFER(vnode);
70
71 dentry_t* dentry = dentry_new(superblock, NULL, NULL);
72 if (dentry == NULL)
73 {
74 panic(NULL, "Failed to create sysfs root dentry");
75 }
76
77 dentry_make_positive(dentry, vnode);
78 superblock->root = dentry;
79 root = dentry;
80
81 process_t* process = process_current();
82 assert(process != NULL);
83
84 namespace_t* ns = process_get_ns(process);
85 if (ns == NULL)
86 {
87 panic(NULL, "Failed to get process namespace");
88 }
89 UNREF_DEFER(ns);
90
91 path_t target = cwd_get(&process->cwd, ns);
92 PATH_DEFER(&target);
93
94 pathname_t pathname;
95 if (pathname_init(&pathname, "/sys") == ERR)
96 {
97 panic(NULL, "Failed to init pathname for /sys");
98 }
99
100 if (path_walk(&target, &pathname, ns) == ERR)
101 {
102 panic(NULL, "Failed to walk to /sys");
103 }
104
106 if (temp == NULL)
107 {
108 panic(NULL, "Failed to mount sysfs");
109 }
110 UNREF(temp);
111 LOG_INFO("sysfs mounted to '/sys'\n");
112}
113
114dentry_t* sysfs_dir_new(dentry_t* parent, const char* name, const vnode_ops_t* vnodeOps, void* data)
115{
116 if (name == NULL)
117 {
118 errno = EINVAL;
119 return NULL;
120 }
121
122 if (parent == NULL)
123 {
124 parent = root;
125 }
126
127 if (parent->superblock->fs != &sysfs)
128 {
129 errno = EXDEV;
130 return NULL;
131 }
132
133 dentry_t* dir = dentry_new(parent->superblock, parent, name);
134 if (dir == NULL)
135 {
136 return NULL;
137 }
139
140 vnode_t* vnode = vnode_new(parent->superblock, VDIR, vnodeOps, NULL);
141 if (vnode == NULL)
142 {
143 return NULL;
144 }
145 UNREF_DEFER(vnode);
146 vnode->data = data;
147
149
150 return REF(dir);
151}
152
153dentry_t* sysfs_file_new(dentry_t* parent, const char* name, const vnode_ops_t* vnodeOps, const file_ops_t* fileOps,
154 void* data)
155{
156 if (name == NULL)
157 {
158 errno = EINVAL;
159 return NULL;
160 }
161
162 if (parent == NULL)
163 {
164 parent = root;
165 }
166
167 if (parent->superblock->fs != &sysfs)
168 {
169 errno = EXDEV;
170 return NULL;
171 }
172
173 dentry_t* dentry = dentry_new(parent->superblock, parent, name);
174 if (dentry == NULL)
175 {
176 return NULL;
177 }
178 UNREF_DEFER(dentry);
179
180 vnode_t* vnode = vnode_new(parent->superblock, VREG, vnodeOps, fileOps);
181 if (vnode == NULL)
182 {
183 return NULL;
184 }
185 UNREF_DEFER(vnode);
186 vnode->data = data;
187
188 dentry_make_positive(dentry, vnode);
189
190 return REF(dentry);
191}
192
193dentry_t* sysfs_symlink_new(dentry_t* parent, const char* name, const vnode_ops_t* vnodeOps, void* data)
194{
195 if (parent == NULL || name == NULL || vnodeOps == NULL)
196 {
197 errno = EINVAL;
198 return NULL;
199 }
200
201 if (parent->superblock->fs != &sysfs)
202 {
203 errno = EXDEV;
204 return NULL;
205 }
206
207 dentry_t* dentry = dentry_new(parent->superblock, parent, name);
208 if (dentry == NULL)
209 {
210 return NULL;
211 }
212 UNREF_DEFER(dentry);
213
214 vnode_t* vnode = vnode_new(parent->superblock, VSYMLINK, vnodeOps, NULL);
215 if (vnode == NULL)
216 {
217 return NULL;
218 }
219 UNREF_DEFER(vnode);
220 vnode->data = data;
221
222 dentry_make_positive(dentry, vnode);
223
224 return REF(dentry);
225}
226
228{
229 if (out == NULL || descs == NULL)
230 {
231 errno = EINVAL;
232 return ERR;
233 }
234
235 if (parent == NULL)
236 {
237 parent = root;
238 }
239
240 if (parent->superblock->fs != &sysfs)
241 {
242 errno = EXDEV;
243 return ERR;
244 }
245
246 list_t createdList = LIST_CREATE(createdList);
247
248 uint64_t count = 0;
249 for (const sysfs_file_desc_t* desc = descs; desc->name != NULL; desc++)
250 {
251 dentry_t* file = sysfs_file_new(parent, desc->name, desc->vnodeOps, desc->fileOps, desc->data);
252 if (file == NULL)
253 {
254 while (!list_is_empty(&createdList))
255 {
256 UNREF(CONTAINER_OF_SAFE(list_pop_front(&createdList), dentry_t, otherEntry));
257 }
258 return ERR;
259 }
260
261 list_push_back(&createdList, &file->otherEntry);
262 count++;
263 }
264
265 if (out == NULL)
266 {
267 while (!list_is_empty(&createdList))
268 {
269 UNREF(CONTAINER_OF_SAFE(list_pop_front(&createdList), dentry_t, otherEntry));
270 }
271 return count;
272 }
273
274 while (!list_is_empty(&createdList))
275 {
276 dentry_t* file = CONTAINER_OF_SAFE(list_pop_front(&createdList), dentry_t, otherEntry);
277 list_push_back(out, &file->otherEntry);
278 }
279 return count;
280}
281
283{
284 if (files == NULL)
285 {
286 return;
287 }
288
289 while (!list_is_empty(files))
290 {
292 }
293}
#define assert(expression)
Definition assert.h:29
static fd_t data
Definition dwm.c:21
static dentry_t * dir
Definition fb.c:16
path_t cwd_get(cwd_t *cwd, namespace_t *ns)
Get the current working directory.
Definition cwd.c:19
dentry_t * dentry_new(superblock_t *superblock, dentry_t *parent, const char *name)
Create a new dentry.
Definition dentry.c:134
uint64_t dentry_generic_iterate(dentry_t *dentry, dir_ctx_t *ctx)
Helper function for a basic iterate.
Definition dentry.c:325
void dentry_make_positive(dentry_t *dentry, vnode_t *vnode)
Make a dentry positive by associating it with an vnode.
Definition dentry.c:289
uint64_t filesystem_register(filesystem_t *fs)
Registers a filesystem.
Definition filesystem.c:233
mount_t * namespace_mount(namespace_t *ns, path_t *target, filesystem_t *fs, const char *options, mode_t mode, void *data)
Mount a filesystem in a namespace.
Definition namespace.c:387
#define PATH_DEFER(path)
Defer path put.
Definition path.h:106
uint64_t path_walk(path_t *path, const pathname_t *pathname, namespace_t *ns)
Walk a pathname to a path.
Definition path.c:593
uint64_t pathname_init(pathname_t *pathname, const char *string)
Initialize a pathname.
Definition path.c:116
@ MODE_ALL_PERMS
Definition path.h:96
@ MODE_PROPAGATE
Definition path.h:94
superblock_t * superblock_new(filesystem_t *fs, const superblock_ops_t *ops, const dentry_ops_t *dentryOps)
Create a new superblock.
Definition superblock.c:33
dentry_t * sysfs_symlink_new(dentry_t *parent, const char *name, const vnode_ops_t *vnodeOps, void *data)
Create a new symbolic link inside a mounted sysfs instance.
Definition sysfs.c:193
uint64_t sysfs_files_new(list_t *out, dentry_t *parent, const sysfs_file_desc_t *descs)
Create multiple files in a sysfs directory.
Definition sysfs.c:227
#define SYSFS_NAME
The name of the system filesystem.
Definition sysfs.h:26
void sysfs_files_free(list_t *files)
Free all files in a list created by sysfs_files_new().
Definition sysfs.c:282
void sysfs_init(void)
Initializes the sysfs and mount an instance at /sys.
Definition sysfs.c:50
dentry_t * sysfs_file_new(dentry_t *parent, const char *name, const vnode_ops_t *vnodeOps, const file_ops_t *fileOps, void *data)
Create a new file inside a mounted sysfs instance.
Definition sysfs.c:153
dentry_t * sysfs_dir_new(dentry_t *parent, const char *name, const vnode_ops_t *vnodeOps, void *data)
Create a new directory inside a mounted sysfs instance.
Definition sysfs.c:114
vnode_t * vnode_new(superblock_t *superblock, vtype_t type, const vnode_ops_t *ops, const file_ops_t *fileOps)
Create a new vnode.
Definition vnode.c:51
NORETURN void panic(const interrupt_frame_t *frame, const char *format,...)
Panic the kernel, printing a message and halting.
Definition panic.c:292
#define LOG_INFO(format,...)
Definition log.h:91
static process_t * process_current(void)
Retrieves the process of the currently running thread.
Definition process.h:131
namespace_t * process_get_ns(process_t *process)
Gets the namespace of a process.
Definition process.c:206
#define UNREF_DEFER(ptr)
RAII-style cleanup for scoped references.
Definition ref.h:122
#define REF(ptr)
Increment reference count.
Definition ref.h:82
#define UNREF(ptr)
Decrement reference count.
Definition ref.h:109
#define EINVAL
Invalid argument.
Definition errno.h:142
#define EXDEV
Cross-device link.
Definition errno.h:122
#define errno
Error number variable.
Definition errno.h:27
#define UNUSED(x)
Mark a variable as unused.
Definition defs.h:96
@ VSYMLINK
Is a symbolic link.
Definition fs.h:345
@ VREG
Is a regular file.
Definition fs.h:343
@ VDIR
Is a directory.
Definition fs.h:344
static void list_push_back(list_t *list, list_entry_t *entry)
Pushes an entry to the end of the list.
Definition list.h:322
#define LIST_CREATE(name)
Creates a list initializer.
Definition list.h:163
static bool list_is_empty(list_t *list)
Checks if a list is empty.
Definition list.h:210
static list_entry_t * list_pop_back(list_t *list)
Pops the last entry from the list.
Definition list.h:386
static list_entry_t * list_pop_front(list_t *list)
Pops the first entry from the list.
Definition list.h:366
#define NULL
Pointer error value.
Definition NULL.h:25
#define ERR
Integer error value.
Definition ERR.h:17
#define CONTAINER_OF_SAFE(ptr, type, member)
Safe container of macro.
static list_t files
Definition file.c:9
static atomic_long count
Definition main.c:11
__UINT64_TYPE__ uint64_t
Definition stdint.h:17
Dentry operations structure.
Definition dentry.h:122
uint64_t(* iterate)(dentry_t *dentry, dir_ctx_t *ctx)
Iterate over the entries in a directory dentry.
Definition dentry.h:138
Directory entry structure.
Definition dentry.h:155
char name[MAX_NAME]
The name of the dentry, immutable after creation.
Definition dentry.h:158
list_entry_t otherEntry
Made available for use by any other subsystems for convenience.
Definition dentry.h:169
superblock_t * superblock
Definition dentry.h:163
File operations structure.
Definition file.h:54
Filesystem structure, represents a filesystem type, e.g. fat32, tmpfs, devfs, etc.
Definition filesystem.h:53
const char * name
Definition filesystem.h:58
A doubly linked list.
Definition list.h:46
Mount structure.
Definition mount.h:48
Namespace structure.
Definition namespace.h:57
Path structure.
Definition path.h:127
Pathname structure.
Definition path.h:139
Process structure.
Definition process.h:76
cwd_t cwd
Definition process.h:87
Superblock structure.
Definition superblock.h:33
filesystem_t * fs
Definition superblock.h:44
dentry_t * root
Root dentry of the filesystem, should not take a reference.
Definition superblock.h:40
Descriptor for batch file creation.
Definition sysfs.h:78
const char * name
Name of the file, NULL marks end of array.
Definition sysfs.h:79
vnode operations structure.
Definition vnode.h:69
vnode structure.
Definition vnode.h:48
void * data
Filesystem defined data.
Definition vnode.h:52
static dentry_ops_t dentryOps
Definition sysfs.c:27
static filesystem_t sysfs
Definition sysfs.c:45
static dentry_t * root
Definition sysfs.c:25
static dentry_t * sysfs_mount(filesystem_t *fs, const char *options, void *data)
Definition sysfs.c:31
static vnode_ops_t vnodeOps
Definition tmpfs.c:195
static file_ops_t fileOps
Definition tmpfs.c:86