1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
|
# The Hyra control filesystem (ctlfs)
Written by Ian M. Moffett
## Rationale
Historically, Operating Systems of the Unix family typically relied
on syscalls like ``ioctl()`` or similar to perform operations (e.g., making calls through a driver)
via some file descriptor. Let's say for example, one wanted to acquire the framebuffer
dimensions of a given framebuffer device. To start, they'd acquire a file descriptor
by calling ``open()`` or similar on it. Then they'd make their ``ioctl()`` call.
```c
int fd = ...;
ioctl(fd, IOCTL_FBINFO, &fb_info);
...
```
While this works fine and is relatively simple to use from the user's
perspective, it is very clunky when you pop the hood and peer into the
inner-workings of it within the kernel. The number of possible requests
that can be passed through a file descriptor can grow quite rapidly which
can require really large switch statements within the drivers that implement
an ``ioctl()`` interface.
## Replacing ``ioctl()``
Hyra provides ctlfs, an abstract in-memory filesystem designed for
setting/getting various kernel / driver parameters and state via
the filesystem API. The control filesystem consists of several
instances of two fundamentals: "control nodes" and "control entries".
### Control nodes
Control nodes are simply directories within the ``/ctl`` root. For example,
console specific control files are in the ``/ctl/console`` node.
### Control entries
Control entries are simply files within specific control nodes. For example
console features may be find in the ``consfeat`` entry of the ``console`` node
(i.e., ``/ctl/console/consfeat``).
See ``sys/include/sys/console.h`` and ``sys/fs/ctlfs.h`` for more
information.
## The ctlfs API
The Hyra kernel provides an API for subsystems and drivers
to create their own ctlfs entries and nodes. This may be found
in sys/include/fs/ctlfs.h
### Control operations
Each control entry must define their own set of
"control operations" described by the ``ctlops`` structure:
```c
struct ctlops {
int(*read)(struct ctlfs_dev *cdp, struct sio_txn *sio);
int(*write)(struct ctlfs_dev *cdp, struct sio_txn *sio);
...
};
```
NOTE: Callbacks defined as ``NULL`` will be
ignored and unused.
## "Meow World": Creating a ctlfs entry
```c
#include <sys/types.h>
#include <sys/sio.h>
#include <fs/ctlfs.h>
static const struct ctlops meow_ctl;
/*
* Ctlfs read callback - this will be called
* when "/ctl/meow/hii" is read.
*/
static int
ctl_meow_read(struct ctlfs_dev *cdp, struct sio_txn *sio)
{
char data[] = "Meow World!""
/* Clamp the input length */
if (sio->len > sizeof(data)) {
sio->len = sizeof(data)
}
/* End of the data? */
if ((sio->offset + sio->len) > sizeof(data)) {
return 0;
}
/* Copy the data and return the length */
memcpy(sio->buf, &data[sio->offset], sio->len);
return sio->len;
}
static int
foo_init(void)
{
char ctlname[] = "meow";
struct ctlfs_dev ctl;
/*
* Here we create the "/ctl/meow" node.
*/
ctl.mode = 0444;
ctl.devname = devname;
ctlfs_create_node(devname, &ctl);
ctl.ops = &fb_size_ctl;
ctlfs_create_entry("attr", &ctl);
return 0;
}
static const struct ctlops meow_ctl = {
.read = ctl_meow_read,
.write = NULL,
};
```
|