MOS Source Code
Loading...
Searching...
No Matches
tmpfs.c
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-3.0-or-later
2
5#include "mos/mm/mm.h"
8
11#include <mos/filesystem/vfs.h>
13#include <mos/misc/setup.h>
14#include <mos/mos_global.h>
15#include <mos/syslog/printk.h>
16#include <mos/types.h>
17#include <mos_stdlib.h>
18#include <mos_string.h>
19
20typedef struct
21{
23
24 union
25 {
27 dev_t dev;
28 };
30
31typedef struct
32{
34 atomic_t ino;
36
37#define TMPFS_INODE(inode) container_of(inode, tmpfs_inode_t, real_inode)
38#define TMPFS_SB(var) container_of(var, tmpfs_sb_t, sb)
39
40static const file_ops_t tmpfs_noop_file_ops = { 0 };
41
47
50
53
54static dentry_t *tmpfs_fsop_mount(filesystem_t *fs, const char *dev, const char *options); // forward declaration
57
59{
60 tmpfs_inode_t *inode = kmalloc(tmpfs_inode_cache);
61
62 inode_init(&inode->real_inode, &sb->sb, ++sb->ino, type);
63 inode->real_inode.perm = perm;
65
66 switch (type)
67 {
69 // directories
70 pr_dinfo2(tmpfs, "tmpfs: creating a directory inode");
73 break;
74
76 // symbolic links
77 pr_dinfo2(tmpfs, "tmpfs: creating a symlink inode");
80 break;
81
83 // regular files, char devices, block devices, named pipes and sockets
84 pr_dinfo2(tmpfs, "tmpfs: creating a file inode");
86 break;
87
92 mos_warn("TODO: tmpfs: create inode for file type %d", type);
93 mos_panic("tmpfs: unsupported file type");
94 break;
95
97 // unknown file type
98 mos_panic("tmpfs: unknown file type");
99 break;
100 }
101
102 return &inode->real_inode;
103}
104
106
107static dentry_t *tmpfs_fsop_mount(filesystem_t *fs, const char *dev, const char *options)
108{
109 MOS_ASSERT(fs == &fs_tmpfs);
110 if (strcmp(dev, "none") != 0)
111 {
112 mos_warn("tmpfs: device not supported");
113 return NULL;
114 }
115
116 if (options && strlen(options) != 0 && strcmp(options, "defaults") != 0)
117 {
118 mos_warn("tmpfs: options '%s' not supported", options);
119 return NULL;
120 }
121
122 tmpfs_sb_t *tmpfs_sb = kmalloc(tmpfs_superblock_cache);
123 tmpfs_sb->sb.fs = fs;
124 tmpfs_sb->sb.ops = &tmpfs_sb_op;
125 tmpfs_sb->sb.root = dentry_get_from_parent(&tmpfs_sb->sb, NULL, NULL);
127 return tmpfs_sb->sb.root;
128}
129
130// create a new node in the directory
131static bool tmpfs_mknod_impl(inode_t *dir, dentry_t *dentry, file_type_t type, file_perm_t perm, dev_t dev)
132{
133 inode_t *inode = tmpfs_create_inode(TMPFS_SB(dir->superblock), type, perm);
134 TMPFS_INODE(inode)->dev = dev;
135 dentry_attach(dentry, inode);
136 return true;
137}
138
139static bool tmpfs_i_create(inode_t *dir, dentry_t *dentry, file_type_t type, file_perm_t perm)
140{
141 return tmpfs_mknod_impl(dir, dentry, type, perm, 0);
142}
143
144static bool tmpfs_i_hardlink(dentry_t *old_dentry, inode_t *dir, dentry_t *new_dentry)
145{
146 MOS_UNUSED(dir);
147 MOS_ASSERT_X(old_dentry->inode->type != FILE_TYPE_DIRECTORY, "hard links to directories are insane");
148 old_dentry->inode->nlinks++;
149 dentry_attach(new_dentry, old_dentry->inode);
150 return true;
151}
152
153static bool tmpfs_i_symlink(inode_t *dir, dentry_t *dentry, const char *symname)
154{
155 bool created = tmpfs_mknod_impl(dir, dentry, FILE_TYPE_SYMLINK, tmpfs_default_mode, 0);
156 if (created)
157 {
158 tmpfs_inode_t *inode = TMPFS_INODE(dentry->inode);
159 inode->symlink_target = strdup(symname);
160 }
161
162 return created;
163}
164
165static bool tmpfs_i_unlink(inode_t *dir, dentry_t *dentry)
166{
167 MOS_UNUSED(dir);
168 MOS_UNUSED(dentry);
169 return true;
170}
171
172static bool tmpfs_i_mkdir(inode_t *dir, dentry_t *dentry, file_perm_t perm)
173{
174 return tmpfs_mknod_impl(dir, dentry, FILE_TYPE_DIRECTORY, perm, 0);
175}
176
177static bool tmpfs_i_rmdir(inode_t *dir, dentry_t *subdir_to_remove)
178{
179 // VFS will ensure that the directory is empty
180 MOS_UNUSED(dir);
181 MOS_ASSERT(subdir_to_remove->inode->type == FILE_TYPE_DIRECTORY);
182 MOS_ASSERT(subdir_to_remove->inode->nlinks == 1); // should be the only link to the directory
183
184 dentry_detach(subdir_to_remove);
185
186 tmpfs_inode_t *inode = TMPFS_INODE(subdir_to_remove->inode);
187 kfree(inode);
188 return true;
189}
190
191static bool tmpfs_i_mknod(inode_t *dir, dentry_t *dentry, file_type_t type, file_perm_t perm, dev_t dev)
192{
193 return tmpfs_mknod_impl(dir, dentry, type, perm, dev);
194}
195
196static bool tmpfs_i_rename(inode_t *old_dir, dentry_t *old_dentry, inode_t *new_dir, dentry_t *new_dentry)
197{
198 MOS_UNUSED(old_dir);
199 MOS_UNUSED(new_dir);
200 dentry_attach(new_dentry, old_dentry->inode);
201 dentry_detach(old_dentry);
202 return true;
203}
204
205static const inode_ops_t tmpfs_inode_dir_ops = {
206 .lookup = NULL, // use kernel's default in-memory lookup
207 .newfile = tmpfs_i_create,
208 .hardlink = tmpfs_i_hardlink,
209 .symlink = tmpfs_i_symlink,
210 .unlink = tmpfs_i_unlink,
211 .mkdir = tmpfs_i_mkdir,
212 .rmdir = tmpfs_i_rmdir,
213 .mknode = tmpfs_i_mknod,
214 .rename = tmpfs_i_rename,
215};
216
217static size_t tmpfs_i_readlink(dentry_t *dentry, char *buffer, size_t buflen)
218{
219 tmpfs_inode_t *inode = TMPFS_INODE(dentry->inode);
220 const size_t bytes_to_copy = MIN(buflen, strlen(inode->symlink_target));
221 memcpy(buffer, inode->symlink_target, bytes_to_copy);
222 return bytes_to_copy;
223}
224
226{
227 // if VFS ever calls this function, it means that a file has been
228 // written to a new page, but that page has not been allocated yet
229 // (i.e. the file has been extended)
230 // we don't need to do anything but allocate the page
231 MOS_UNUSED(cache);
232 MOS_UNUSED(pgoff);
233
235}
236
237static bool tmpfs_sb_drop_inode(inode_t *inode)
238{
239 tmpfs_inode_t *tmpfs_inode = TMPFS_INODE(inode);
240 if (inode->nlinks == 0)
241 {
242 if (inode->type == FILE_TYPE_DIRECTORY)
243 return false;
244
245 if (inode->type == FILE_TYPE_SYMLINK)
246 if (tmpfs_inode->symlink_target != NULL)
247 kfree(tmpfs_inode->symlink_target);
248 kfree(tmpfs_inode);
249 }
250
251 return true;
252}
253
255 .readlink = tmpfs_i_readlink,
256};
257
258static const file_ops_t tmpfs_file_ops = {
259 .read = vfs_generic_read,
260 .write = vfs_generic_write,
261};
262
264 .fill_cache = tmpfs_fill_cache,
265 .page_write_begin = simple_page_write_begin,
266 .page_write_end = simple_page_write_end,
267};
268
269static const superblock_ops_t tmpfs_sb_op = {
270 .drop_inode = tmpfs_sb_drop_inode,
271};
#define MOS_ASSERT_X(cond, msg,...)
Definition assert.h:15
#define MOS_ASSERT(cond)
Definition assert.h:14
#define mos_warn(fmt,...)
Definition assert.h:23
#define PERM_WRITE
Definition fs_types.h:58
#define PERM_READ
Definition fs_types.h:57
u16 file_perm_t
Definition fs_types.h:52
#define PERM_EXEC
Definition fs_types.h:59
file_type_t
Definition fs_types.h:14
@ FILE_TYPE_UNKNOWN
Definition fs_types.h:22
@ FILE_TYPE_CHAR_DEVICE
Definition fs_types.h:18
@ FILE_TYPE_NAMED_PIPE
Definition fs_types.h:20
@ FILE_TYPE_REGULAR
Definition fs_types.h:15
@ FILE_TYPE_BLOCK_DEVICE
Definition fs_types.h:19
@ FILE_TYPE_SYMLINK
Definition fs_types.h:17
@ FILE_TYPE_DIRECTORY
Definition fs_types.h:16
@ FILE_TYPE_SOCKET
Definition fs_types.h:21
void dentry_attach(dentry_t *d, inode_t *inode)
Attach an inode to a dentry.
Definition dentry.c:305
void dentry_detach(dentry_t *d)
Detach the inode from a dentry.
Definition dentry.c:318
MOSAPI char * strdup(const char *src)
MOSAPI s32 strcmp(const char *str1, const char *str2)
Definition mos_string.c:24
#define MIN(a, b)
Definition mos_stdlib.h:30
__BEGIN_DECLS phyframe_t * mm_get_free_page(void)
Definition mm.c:46
#define pmm_ref_one(thing)
Definition pmm.h:146
void inode_init(inode_t *inode, superblock_t *sb, u64 ino, file_type_t type)
Definition inode.c:49
filesystem_t fs_tmpfs
#define MOS_UNUSED(x)
Definition mos_global.h:64
#define mos_panic(fmt,...)
Definition panic.h:55
static void * memcpy(void *s1, const void *s2, size_t n)
Definition pb_syshdr.h:90
#define NULL
Definition pb_syshdr.h:46
static size_t strlen(const char *s)
Definition pb_syshdr.h:80
#define pr_dinfo2(feat, fmt,...)
Definition printk.h:27
#define SLAB_AUTOINIT(name, var, type)
inode_t * inode
Definition vfs_types.h:117
const inode_cache_ops_t * ops
Definition vfs_types.h:152
superblock_t * superblock
Definition vfs_types.h:171
file_perm_t perm
Definition vfs_types.h:159
const inode_ops_t * ops
Definition vfs_types.h:172
file_type_t type
Definition vfs_types.h:158
const file_ops_t * file_ops
Definition vfs_types.h:173
inode_cache_t cache
Definition vfs_types.h:175
ssize_t nlinks
Definition vfs_types.h:166
Definition slab.h:45
dentry_t * root
Definition vfs_types.h:107
const superblock_ops_t * ops
Definition vfs_types.h:109
filesystem_t * fs
Definition vfs_types.h:108
char * symlink_target
Definition tmpfs.c:26
dev_t dev
Definition tmpfs.c:27
inode_t real_inode
Definition tmpfs.c:22
superblock_t sb
Definition tmpfs.c:33
atomic_t ino
Definition tmpfs.c:34
static char buffer[2048]
Definition test_printf.c:7
static const inode_cache_ops_t tmpfs_inode_cache_ops
Definition tmpfs.c:44
static slab_t * tmpfs_superblock_cache
Definition tmpfs.c:51
static bool tmpfs_i_mknod(inode_t *dir, dentry_t *dentry, file_type_t type, file_perm_t perm, dev_t dev)
Definition tmpfs.c:191
static const inode_ops_t tmpfs_inode_symlink_ops
Definition tmpfs.c:43
static bool tmpfs_i_symlink(inode_t *dir, dentry_t *dentry, const char *symname)
Definition tmpfs.c:153
static bool tmpfs_i_hardlink(dentry_t *old_dentry, inode_t *dir, dentry_t *new_dentry)
Definition tmpfs.c:144
static const file_perm_t tmpfs_default_mode
Definition tmpfs.c:105
static dentry_t * tmpfs_fsop_mount(filesystem_t *fs, const char *dev, const char *options)
Definition tmpfs.c:107
static bool tmpfs_sb_drop_inode(inode_t *inode)
Definition tmpfs.c:237
static const superblock_ops_t tmpfs_sb_op
Definition tmpfs.c:46
static bool tmpfs_mknod_impl(inode_t *dir, dentry_t *dentry, file_type_t type, file_perm_t perm, dev_t dev)
Definition tmpfs.c:131
#define TMPFS_INODE(inode)
Definition tmpfs.c:37
static bool tmpfs_i_create(inode_t *dir, dentry_t *dentry, file_type_t type, file_perm_t perm)
Definition tmpfs.c:139
static const file_ops_t tmpfs_noop_file_ops
Definition tmpfs.c:40
static const inode_ops_t tmpfs_inode_dir_ops
Definition tmpfs.c:42
static const file_ops_t tmpfs_file_ops
Definition tmpfs.c:45
static bool tmpfs_i_unlink(inode_t *dir, dentry_t *dentry)
Definition tmpfs.c:165
inode_t * tmpfs_create_inode(tmpfs_sb_t *sb, file_type_t type, file_perm_t perm)
Definition tmpfs.c:58
static bool tmpfs_i_rmdir(inode_t *dir, dentry_t *subdir_to_remove)
Definition tmpfs.c:177
static phyframe_t * tmpfs_fill_cache(inode_cache_t *cache, off_t pgoff)
Definition tmpfs.c:225
static slab_t * tmpfs_inode_cache
Definition tmpfs.c:48
#define TMPFS_SB(var)
Definition tmpfs.c:38
static size_t tmpfs_i_readlink(dentry_t *dentry, char *buffer, size_t buflen)
Definition tmpfs.c:217
static bool tmpfs_i_rename(inode_t *old_dir, dentry_t *old_dentry, inode_t *new_dir, dentry_t *new_dentry)
Definition tmpfs.c:196
static bool tmpfs_i_mkdir(inode_t *dir, dentry_t *dentry, file_perm_t perm)
Definition tmpfs.c:172
ssize_t off_t
Definition types.h:84
#define FILESYSTEM_DEFINE(var, fsname, mountfn, unmountfn)
Definition vfs_types.h:21
#define FILESYSTEM_AUTOREGISTER(fs)
Definition vfs_types.h:29
bool simple_page_write_begin(inode_cache_t *icache, off_t offset, size_t size, phyframe_t **page, void **private)
Definition vfs_utils.c:65
ssize_t vfs_generic_write(const file_t *file, const void *buf, size_t size, off_t offset)
Definition vfs_utils.c:105
dentry_t * dentry_get_from_parent(superblock_t *sb, dentry_t *parent, const char *name)
Create a new dentry with the given name and parent.
Definition vfs_utils.c:40
void simple_page_write_end(inode_cache_t *icache, off_t offset, size_t size, phyframe_t *page, void *private)
Definition vfs_utils.c:76
ssize_t vfs_generic_read(const file_t *file, void *buf, size_t size, off_t offset)
Definition vfs_utils.c:95