Unifying the Lunaix's Physical Memory Model (#28)
[lunaix-os.git] / lunaix-os / kernel / fs / ramfs / ramfs.c
1 /**
2  * @file ramfs.c
3  * @author Lunaixsky
4  * @brief RamFS - a file system sit in RAM
5  * @version 0.1
6  * @date 2022-08-18
7  *
8  * @copyright Copyright (c) 2022
9  *
10  */
11 #include <klibc/string.h>
12 #include <lunaix/fs.h>
13 #include <lunaix/fs/ramfs.h>
14 #include <lunaix/mm/valloc.h>
15 #include <lunaix/spike.h>
16
17 /*
18     A RAM FS will play a role of being a root.
19
20     This is an temporary meaure as we don't have any concrete fs
21     yet. In the near future, we will have an ISO-9660 as our first
22     fs and mount our boot medium as root. And similar thing could
23     be done when we have installed our OS into hard disk, in that
24     case, our rootfs will be something like ext2.
25
26     RamFS vs. TwiFS: Indeed, they are both fs that lives in RAM so
27     there is no foundmental differences. However, TwiFS is designed
28     to be a 'virtual FIlesystem for KERnel space' (FIKER), so other
29     kernel sub-modules can just create node and attach their own
30     implementation of read/write, without brothering to create a
31     full featured concrete filesystem. This particularly useful for
32     kernel state exposure. In Lunaix, TwiFS is summation of procfs,
33     sysfs and kernfs in Linux world.
34
35     However, there is a smell of bad-design in the concept of TwiFS.
36     Since it tries to integrate too much responsibility. The TwiFS may
37     be replaced by more specific fs in the future.
38
39     On the other hand, RamFS is designed to be act like a dummy fs
40     that just ensure 'something there at least' and thus provide basic
41     'mountibility' for other fs.
42 */
43
44 static volatile inode_t ino = 0;
45
46 extern const struct v_inode_ops ramfs_inode_ops;
47 extern const struct v_file_ops ramfs_file_ops;
48
49 static int
50 __ramfs_mknod(struct v_dnode* dnode, struct v_inode** nod_out, u32_t flags)
51 {
52     struct v_inode* inode = vfs_i_alloc(dnode->super_block);
53
54     if (!inode) {
55         return ENOMEM;
56     }
57
58     struct ram_inode* rinode = valloc(sizeof(struct ram_inode));
59
60     if (!rinode) {
61         vfs_i_free(inode);
62         return ENOMEM;
63     }
64
65     rinode->flags = flags;
66     inode->data = rinode;
67
68     if (!(flags & RAMF_DIR)) {
69         inode->itype = VFS_IFFILE;
70     }
71
72     if ((flags & RAMF_SYMLINK)) {
73         inode->itype |= VFS_IFSYMLINK;
74     }
75
76     if (nod_out) {
77         *nod_out = inode;
78     }
79
80     vfs_i_addhash(inode);
81     vfs_assign_inode(dnode, inode);
82
83     return 0;
84 }
85
86 int
87 ramfs_readdir(struct v_file* file, struct dir_context* dctx)
88 {
89     int i = 0;
90     struct v_dnode *pos, *n;
91     llist_for_each(pos, n, &file->dnode->children, siblings)
92     {
93         if (i++ >= dctx->index) {
94             dctx->read_complete_callback(dctx,
95                                          pos->name.value,
96                                          pos->name.len,
97                                          vfs_get_dtype(pos->inode->itype));
98             return 1;
99         }
100     }
101     return 0;
102 }
103
104 int
105 ramfs_mkdir(struct v_inode* this, struct v_dnode* dnode)
106 {
107     return __ramfs_mknod(dnode, NULL, RAMF_DIR);
108 }
109
110 int
111 ramfs_create(struct v_inode* this, struct v_dnode* dnode)
112 {
113     return __ramfs_mknod(dnode, NULL, RAMF_FILE);
114 }
115
116 void
117 ramfs_inode_init(struct v_superblock* vsb, struct v_inode* inode)
118 {
119     inode->id = ino++;
120     inode->ops = (struct v_inode_ops*)&ramfs_inode_ops;
121     inode->default_fops = (struct v_file_ops*)&ramfs_file_ops;
122 }
123
124 int
125 ramfs_mount(struct v_superblock* vsb, struct v_dnode* mount_point)
126 {
127     vsb->ops.init_inode = ramfs_inode_init;
128
129     return __ramfs_mknod(mount_point, NULL, RAMF_DIR);
130 }
131
132 int
133 ramfs_unmount(struct v_superblock* vsb)
134 {
135     return 0;
136 }
137
138 void
139 ramfs_init()
140 {
141     struct filesystem* ramfs = fsm_new_fs("ramfs", -1);
142     ramfs->mount = ramfs_mount;
143     ramfs->unmount = ramfs_unmount;
144
145     fsm_register(ramfs);
146 }
147 EXPORT_FILE_SYSTEM(ramfs, ramfs_init);
148
149 int
150 ramfs_mksymlink(struct v_inode* this, const char* target)
151 {
152     struct ram_inode* rinode = RAM_INODE(this->data);
153
154     assert(!(rinode->flags & RAMF_SYMLINK));
155
156     size_t len = strlen(target) + 1;
157     char* symlink = valloc(len);
158
159     if (!symlink) {
160         return ENOMEM;
161     }
162
163     memcpy(symlink, target, len);
164
165     this->itype |= VFS_IFSYMLINK;
166     rinode->flags |= RAMF_SYMLINK;
167     rinode->symlink = symlink;
168
169     return 0;
170 }
171
172 int
173 ramfs_read_symlink(struct v_inode* this, const char** path_out)
174 {
175     struct ram_inode* rinode = RAM_INODE(this->data);
176
177     if (!(rinode->flags & RAMF_SYMLINK)) {
178         return EINVAL;
179     }
180
181     *path_out = rinode->symlink;
182
183     return 0;
184 }
185
186 int
187 ramfs_unlink(struct v_inode* this)
188 {
189     struct ram_inode* rinode = RAM_INODE(this->data);
190
191     if ((rinode->flags & RAMF_SYMLINK)) {
192         rinode->flags &= ~RAMF_SYMLINK;
193         this->itype &= ~VFS_IFSYMLINK;
194
195         vfree(rinode->symlink);
196
197         return 0;
198     }
199
200     // TODO
201
202     return 0;
203 }
204
205 const struct v_inode_ops ramfs_inode_ops = { .mkdir = ramfs_mkdir,
206                                              .rmdir = default_inode_rmdir,
207                                              .dir_lookup =
208                                                default_inode_dirlookup,
209                                              .create = ramfs_create,
210                                              .open = default_inode_open,
211                                              .unlink = ramfs_unlink,
212                                              .set_symlink = ramfs_mksymlink,
213                                              .read_symlink = ramfs_read_symlink,
214                                              .rename = default_inode_rename };
215
216 const struct v_file_ops ramfs_file_ops = { .readdir = ramfs_readdir,
217                                            .close = default_file_close,
218                                            .read = default_file_read,
219                                            .read_page = default_file_read_page,
220                                            .write = default_file_write,
221                                            .write_page =
222                                              default_file_write_page,
223                                            .seek = default_file_seek };