make log a bit verbose for some useful information
[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/api.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     inode->itype = VFS_IFFILE;
68
69     if ((flags & RAMF_DIR)) {
70         inode->itype |= VFS_IFDIR;
71     }
72
73     if ((flags & RAMF_SYMLINK)) {
74         inode->itype |= VFS_IFSYMLINK;
75     }
76
77     if (nod_out) {
78         *nod_out = inode;
79     }
80
81     vfs_i_addhash(inode);
82     vfs_assign_inode(dnode, inode);
83
84     return 0;
85 }
86
87 int
88 ramfs_readdir(struct v_file* file, struct dir_context* dctx)
89 {
90     unsigned int i = 2;
91     struct v_dnode *pos, *n;
92
93     if (fsapi_handle_pseudo_dirent(file, dctx)) {
94         return 1;
95     }
96
97     llist_for_each(pos, n, &file->dnode->children, siblings)
98     {
99         if (i++ >= file->f_pos) {
100             dctx->read_complete_callback(dctx,
101                                          pos->name.value,
102                                          pos->name.len,
103                                          vfs_get_dtype(pos->inode->itype));
104             return 1;
105         }
106     }
107     return 0;
108 }
109
110 int
111 ramfs_mkdir(struct v_inode* this, struct v_dnode* dnode)
112 {
113     return __ramfs_mknod(dnode, NULL, RAMF_DIR);
114 }
115
116 int
117 ramfs_create(struct v_inode* this, struct v_dnode* dnode, unsigned int itype)
118 {
119     return __ramfs_mknod(dnode, NULL, RAMF_FILE);
120 }
121
122 void
123 ramfs_inode_init(struct v_superblock* vsb, struct v_inode* inode)
124 {
125     inode->id = ino++;
126     inode->ops = (struct v_inode_ops*)&ramfs_inode_ops;
127     inode->default_fops = (struct v_file_ops*)&ramfs_file_ops;
128 }
129
130 int
131 ramfs_mount(struct v_superblock* vsb, struct v_dnode* mount_point)
132 {
133     vsb->ops.init_inode = ramfs_inode_init;
134
135     return __ramfs_mknod(mount_point, NULL, RAMF_DIR);
136 }
137
138 int
139 ramfs_unmount(struct v_superblock* vsb)
140 {
141     return 0;
142 }
143
144 int
145 ramfs_mksymlink(struct v_inode* this, const char* target)
146 {
147     struct ram_inode* rinode = RAM_INODE(this->data);
148
149     assert(!(rinode->flags & RAMF_SYMLINK));
150
151     size_t len = strlen(target) + 1;
152     char* symlink = valloc(len);
153
154     if (!symlink) {
155         return ENOMEM;
156     }
157
158     memcpy(symlink, target, len);
159
160     this->itype = VFS_IFSYMLINK;
161     rinode->flags |= RAMF_SYMLINK;
162     rinode->symlink = symlink;
163     rinode->size = len;
164
165     return 0;
166 }
167
168 int
169 ramfs_read_symlink(struct v_inode* this, const char** path_out)
170 {
171     struct ram_inode* rinode = RAM_INODE(this->data);
172
173     if (!(rinode->flags & RAMF_SYMLINK)) {
174         return EINVAL;
175     }
176
177     *path_out = rinode->symlink;
178
179     return rinode->size;
180 }
181
182 int
183 ramfs_unlink(struct v_inode* this, struct v_dnode* name)
184 {
185     struct ram_inode* rinode = RAM_INODE(this->data);
186
187     if ((rinode->flags & RAMF_SYMLINK)) {
188         rinode->flags &= ~RAMF_SYMLINK;
189         this->itype &= ~F_SYMLINK;
190
191         vfree(rinode->symlink);
192
193         return 0;
194     }
195
196     // TODO
197
198     return 0;
199 }
200
201 static void
202 ramfs_init()
203 {
204     struct filesystem* fs;
205     fs = fsapi_fs_declare("ramfs", FSTYPE_PSEUDO);
206     
207     fsapi_fs_set_mntops(fs, ramfs_mount, ramfs_unmount);
208     fsapi_fs_finalise(fs);
209 }
210 EXPORT_FILE_SYSTEM(ramfs, ramfs_init);
211
212 const struct v_inode_ops ramfs_inode_ops = { .mkdir = ramfs_mkdir,
213                                              .rmdir = default_inode_rmdir,
214                                              .dir_lookup =
215                                                default_inode_dirlookup,
216                                              .create = ramfs_create,
217                                              .open = default_inode_open,
218                                              .unlink = ramfs_unlink,
219                                              .set_symlink = ramfs_mksymlink,
220                                              .read_symlink = ramfs_read_symlink,
221                                              .rename = default_inode_rename };
222
223 const struct v_file_ops ramfs_file_ops = { .readdir = ramfs_readdir,
224                                            .close = default_file_close,
225                                            .read = default_file_read,
226                                            .read_page = default_file_read_page,
227                                            .write = default_file_write,
228                                            .write_page =
229                                              default_file_write_page,
230                                            .seek = default_file_seek };