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