MOS Source Code
Loading...
Searching...
No Matches
userfs.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-3.0-or-later
2// userspace filesystems
3
5
10#include "mos/syslog/printk.hpp"
11#include "proto/filesystem.pb.h"
13
14#include <algorithm>
15#include <librpc/macro_magic.h>
16#include <librpc/rpc.h>
17#include <librpc/rpc_client.h>
18#include <librpc/rpc_server.h>
20#include <mos_stdio.hpp>
21#include <mos_stdlib.hpp>
22#include <mos_string.hpp>
23#include <pb.h>
24#include <pb_decode.h>
25#include <pb_encode.h>
26
27MOS_RPC_USERFS_CLIENT(fs_client)
28
29extern const inode_ops_t userfs_iops;
30extern const file_ops_t userfs_fops;
33
34#define userfs_get(_fs, _fmt, ...) \
35 statement_expr(userfs_t *, { \
36 retval = container_of(_fs, userfs_t, fs); \
37 userfs_ensure_connected(retval); \
38 pr_dinfo2(userfs, "calling '%s' (rpc_server '%s'): " _fmt, _fs->name.c_str(), retval->rpc_server_name.c_str() __VA_OPT__(, __VA_ARGS__)); \
39 })
40
42{
43 const pb_msgdesc_t *const fields;
44 void *data;
45
46 void skip()
47 {
48 data = nullptr;
49 }
50
51 explicit AutoCleanup(const pb_msgdesc_t *fields, void *data) : fields(fields), data(data) {};
53 {
54 if (fields && data)
56 }
57};
58
60{
61 // enum pb_file_type_t -> enum file_type_t is safe here because they have the same values
62 inode_t *i = inode_create(sb, stat->ino, (file_type_t) stat->type);
63 i->created = stat->created;
64 i->modified = stat->modified;
65 i->accessed = stat->accessed;
66 i->size = stat->size;
67 i->uid = stat->uid;
68 i->gid = stat->gid;
69 i->perm = stat->perm;
70 i->nlinks = stat->nlinks;
71 i->suid = stat->suid;
72 i->sgid = stat->sgid;
73 i->sticky = stat->sticky;
74 i->private_data = private_data;
75 i->ops = &userfs_iops;
77 return i;
78}
79
81{
82 pbi->ino = i->ino;
83 pbi->type = i->type;
84 pbi->created = i->created;
85 pbi->modified = i->modified;
86 pbi->accessed = i->accessed;
87 pbi->size = i->size;
88 pbi->uid = i->uid;
89 pbi->gid = i->gid;
90 pbi->perm = i->perm;
91 pbi->nlinks = i->nlinks;
92 pbi->suid = i->suid;
93 pbi->sgid = i->sgid;
94 pbi->sticky = i->sticky;
95 // pbi->private_data = (ptr_t) i->private;
96 return pbi;
97}
98
100{
101 mosrpc_fs_inode_ref ref = { .data = (ptr_t) i->private_data }; // for userfs, private_data is the inode reference used by the server
102 return ref;
103}
104
106{
107 if (likely(userfs->rpc_server))
108 return;
109
111 if (unlikely(!userfs->rpc_server))
112 {
113 pr_warn("userfs_ensure_connected: failed to connect to %s", userfs->rpc_server_name.c_str());
114 return;
115 }
116}
117
118static bool userfs_iop_hardlink(dentry_t *d, inode_t *i, dentry_t *new_d)
119{
120 MOS_UNUSED(i);
121 MOS_UNUSED(new_d);
122
123 const auto name = dentry_name(d);
124 userfs_t *userfs = userfs_get(d->superblock->fs, "hardlink: %s", name.c_str());
125 MOS_UNUSED(userfs);
126
127 return false;
128}
129
131{
132 const auto name = dentry_name(dentry);
133 userfs_t *userfs = userfs_get(dentry->superblock->fs, "iterate_dir: %s", name.c_str());
134
135 mosrpc_fs_readdir_request req = { .i_ref = i_to_pb_ref(dentry->inode) };
137
138 const pf_point_t ev = profile_enter();
139 const int result = fs_client_readdir(userfs->rpc_server, &req, &resp);
140 profile_leave(ev, "userfs.'%s'.readdir", userfs->rpc_server_name);
141
143
144 if (result != RPC_RESULT_OK)
145 {
146 pr_warn("userfs_iop_iterate_dir: failed to readdir %s: %d", name.c_str(), result);
147 return;
148 }
149
150 if (!resp.entries_count)
151 {
152 pr_dwarn(userfs, "userfs_iop_iterate_dir: failed to readdir %s: %s", name.c_str(), resp.result.error);
153 return;
154 }
155
156 for (size_t i = 0; i < resp.entries_count; i++)
157 {
158 const mosrpc_fs_pb_dirent *pbde = &resp.entries[i];
159 MOS_ASSERT(pbde->name);
160 add_record(state, pbde->ino, pbde->name, (file_type_t) pbde->type);
161 }
162}
163
164static bool userfs_iop_lookup(inode_t *dir, dentry_t *dentry)
165{
166 const auto name = dentry_name(dentry);
167 userfs_t *userfs = userfs_get(dir->superblock->fs, "lookup: %s", name.c_str());
168
170 .i_ref = i_to_pb_ref(dir),
171 .name = (char *) name.c_str(),
172 };
173
175 const pf_point_t ev = profile_enter();
176 const int result = fs_client_lookup(userfs->rpc_server, &req, &resp);
177 profile_leave(ev, "userfs.'%s'.lookup", userfs->rpc_server_name);
178
180
181 if (result != RPC_RESULT_OK)
182 {
183 pr_warn("userfs_iop_lookup: failed to lookup %s: %d", name.c_str(), result);
184 return false;
185 }
186
187 if (!resp.result.success)
188 {
189 return false; // ENOENT is not a big deal
190 }
191
192 inode_t *i = i_from_pbfull(&resp.i_info, dir->superblock, (void *) resp.i_ref.data);
193 dentry_attach(dentry, i);
194 dentry->superblock = i->superblock = dir->superblock;
195 i->ops = &userfs_iops;
197 i->file_ops = &userfs_fops;
198 return true;
199}
200
201static bool userfs_iop_mkdir(inode_t *dir, dentry_t *dentry, file_perm_t perm)
202{
203 const auto name = dentry_name(dentry);
204 userfs_t *userfs = userfs_get(dir->superblock->fs, "mkdir: %s", name.c_str());
205
207 .i_ref = i_to_pb_ref(dir),
208 .name = (char *) name.c_str(),
209 .perm = perm,
210 };
212
213 const pf_point_t pp = profile_enter();
214 const int result = fs_client_make_dir(userfs->rpc_server, &req, &resp);
215 profile_leave(pp, "userfs.'%s'.make_dir", userfs->rpc_server_name);
216
218
219 if (result != RPC_RESULT_OK)
220 {
221 pr_warn("userfs_iop_mkdir: failed to mkdir %s: %d", name.c_str(), result);
222 return false;
223 }
224
225 if (!resp.result.success)
226 {
227 pr_dwarn(userfs, "userfs_iop_mkdir: failed to mkdir %s: %s", name.c_str(), resp.result.error);
228 return false;
229 }
230
231 inode_t *i = i_from_pbfull(&resp.i_info, dir->superblock, (void *) resp.i_ref.data);
232 dentry_attach(dentry, i);
233 dentry->superblock = i->superblock = dir->superblock;
234 i->ops = &userfs_iops;
236 i->file_ops = &userfs_fops;
237 return true;
238}
239
240static bool userfs_iop_mknode(inode_t *dir, dentry_t *dentry, file_type_t type, file_perm_t perm, dev_t dev)
241{
242 MOS_UNUSED(dir);
243 MOS_UNUSED(dentry);
244 MOS_UNUSED(type);
245 MOS_UNUSED(perm);
246 MOS_UNUSED(dev);
247
248 const auto name = dentry_name(dentry);
249 userfs_t *userfs = userfs_get(dir->superblock->fs, "mknode: %s", name.c_str());
250 MOS_UNUSED(userfs);
251
252 return false;
253}
254
255static bool userfs_iop_newfile(inode_t *dir, dentry_t *dentry, file_type_t type, file_perm_t perm)
256{
257 const auto name = dentry_name(dentry);
258 userfs_t *userfs = userfs_get(dir->superblock->fs, "newfile: %s", name.c_str());
259
261 .i_ref = i_to_pb_ref(dir),
262 .name = (char *) name.c_str(),
263 .type = type,
264 .perm = perm,
265 };
267
268 const pf_point_t pp = profile_enter();
269 const int result = fs_client_create_file(userfs->rpc_server, &req, &resp);
270 profile_leave(pp, "userfs.'%s'.create_file", userfs->rpc_server_name);
271
273
274 if (result != RPC_RESULT_OK)
275 {
276 pr_warn("userfs_iop_newfile: failed to create file %s: %d", name.c_str(), result);
277 return false;
278 }
279
280 if (!resp.result.success)
281 {
282 pr_dwarn(userfs, "userfs_iop_newfile: failed to create file %s: %s", name.c_str(), resp.result.error);
283 return false;
284 }
285
286 inode_t *i = i_from_pbfull(&resp.i_info, dir->superblock, (void *) resp.i_ref.data);
287 dentry_attach(dentry, i);
288 dentry->superblock = i->superblock = dir->superblock;
289 i->ops = &userfs_iops;
291 i->file_ops = &userfs_fops;
292 return true;
293}
294
295static size_t userfs_iop_readlink(dentry_t *dentry, char *buffer, size_t buflen)
296{
297 const auto name = dentry_name(dentry);
298 userfs_t *userfs = userfs_get(dentry->superblock->fs, "readlink: %s", name.c_str());
299
300 const mosrpc_fs_readlink_request req = {
301 .i_ref = i_to_pb_ref(dentry->inode),
302 };
304
305 const pf_point_t pp = profile_enter();
306 const int result = fs_client_readlink(userfs->rpc_server, &req, &resp);
307 profile_leave(pp, "userfs.'%s'.readlink", userfs->rpc_server_name);
308
310
311 if (result != RPC_RESULT_OK)
312 {
313 pr_warn("userfs_iop_readlink: failed to readlink %s: %d", name.c_str(), result);
314 return -EIO;
315 }
316
317 if (!resp.result.success)
318 {
319 pr_dwarn(userfs, "userfs_iop_readlink: failed to readlink %s: %s", name.c_str(), resp.result.error);
320 return -EIO;
321 }
322
323 size_t len = strlen(resp.target);
324 if (len > buflen)
325 len = buflen;
326
327 memcpy(buffer, resp.target, len);
328 return len;
329}
330
331static bool userfs_iop_rename(inode_t *old_dir, dentry_t *old_dentry, inode_t *new_dir, dentry_t *new_dentry)
332{
333 MOS_UNUSED(old_dir);
334 MOS_UNUSED(old_dentry);
335 MOS_UNUSED(new_dir);
336 MOS_UNUSED(new_dentry);
337
338 const auto old_name = dentry_name(old_dentry);
339 const auto new_name = dentry_name(new_dentry);
340 userfs_t *userfs = userfs_get(old_dir->superblock->fs, "rename: %s -> %s", old_name.c_str(), new_name.c_str());
341 MOS_UNUSED(userfs);
342
343 return false;
344}
345
346static bool userfs_iop_rmdir(inode_t *dir, dentry_t *dentry)
347{
348 MOS_UNUSED(dir);
349 MOS_UNUSED(dentry);
350
351 const auto name = dentry_name(dentry);
352 userfs_t *userfs = userfs_get(dir->superblock->fs, "rmdir: %s", name.c_str());
353 MOS_UNUSED(userfs);
354
355 return false;
356}
357
358static bool userfs_iop_symlink(inode_t *dir, dentry_t *dentry, const char *symname)
359{
360 MOS_UNUSED(dir);
361 MOS_UNUSED(dentry);
362 MOS_UNUSED(symname);
363
364 const auto name = dentry_name(dentry);
365 userfs_t *userfs = userfs_get(dir->superblock->fs, "symlink: %s", name.c_str());
366 MOS_UNUSED(userfs);
367
368 return false;
369}
370
371static bool userfs_iop_unlink(inode_t *dir, dentry_t *dentry)
372{
373 const auto name = dentry_name(dentry);
374 userfs_t *userfs = userfs_get(dir->superblock->fs, "unlink: %s", name.c_str());
375
376 const mosrpc_fs_unlink_request req = {
377 .i_ref = i_to_pb_ref(dir),
378 .dentry = { .inode_id = dentry->inode->ino, .name = (char *) name.c_str() },
379 };
381
382 const pf_point_t pp = profile_enter();
383 const int result = fs_client_unlink(userfs->rpc_server, &req, &resp);
384 profile_leave(pp, "userfs.'%s'.unlink", userfs->rpc_server_name);
385
387
388 if (result != RPC_RESULT_OK)
389 {
390 pr_warn("userfs_iop_unlink: failed to unlink %s: %d", name.c_str(), result);
391 return false;
392 }
393
394 if (!resp.result.success)
395 {
396 pr_dwarn(userfs, "userfs_iop_unlink: failed to unlink %s: %s", name.c_str(), resp.result.error);
397 return false;
398 }
399
400 return true;
401}
402
404 .hardlink = userfs_iop_hardlink,
405 .iterate_dir = userfs_iop_iterate_dir,
406 .lookup = userfs_iop_lookup,
407 .mkdir = userfs_iop_mkdir,
408 .mknode = userfs_iop_mknode,
409 .newfile = userfs_iop_newfile,
410 .readlink = userfs_iop_readlink,
411 .rename = userfs_iop_rename,
412 .rmdir = userfs_iop_rmdir,
413 .symlink = userfs_iop_symlink,
414 .unlink = userfs_iop_unlink,
415};
416
417static bool userfs_fop_open(inode_t *inode, file_t *file, bool created)
418{
419 MOS_UNUSED(inode);
420 MOS_UNUSED(file);
421 MOS_UNUSED(created);
422
423 return true;
424}
425
427 .open = userfs_fop_open,
428 .read = vfs_generic_read,
429 .write = vfs_generic_write,
430 .release = NULL,
431 .seek = NULL,
432 .mmap = NULL,
433 .munmap = NULL,
434};
435
437{
438 userfs_t *userfs = userfs_get(cache->owner->superblock->fs, "fill_cache", );
439
440 const mosrpc_fs_getpage_request req = {
441 .i_ref = i_to_pb_ref(cache->owner),
442 .pgoff = pgoff,
443 };
444
446
447 const pf_point_t pp = profile_enter();
448 const int result = fs_client_get_page(userfs->rpc_server, &req, &resp);
449 profile_leave(pp, "userfs.'%s'.getpage", userfs->rpc_server_name);
450
452
453 if (result != RPC_RESULT_OK)
454 {
455 pr_warn("userfs_inode_cache_fill_cache: failed to getpage: %d", result);
456 return -EIO;
457 }
458
459 if (!resp.result.success)
460 {
461 pr_dwarn(userfs, "userfs_inode_cache_fill_cache: failed to getpage: %s", resp.result.error);
462 return -EIO;
463 }
464
465 // allocate a page
467 if (!page)
468 {
469 pr_warn("userfs_inode_cache_fill_cache: failed to allocate page");
470 return -ENOMEM;
471 }
472
473 // copy the data from the server
474 memcpy((void *) phyframe_va(page), resp.data->bytes, std::min(resp.data->size, (pb_size_t) MOS_PAGE_SIZE));
475 return page;
476}
477
479{
480 userfs_t *userfs = userfs_get(cache->owner->superblock->fs, "flush_page", );
481
483 .i_ref = i_to_pb_ref(cache->owner),
484 .pgoff = pgoff,
485 .data = nullptr,
486 };
487 req.data = (pb_bytes_array_t *) kcalloc<char>(PB_BYTES_ARRAY_T_ALLOCSIZE(MOS_PAGE_SIZE));
488 req.data->size = MOS_PAGE_SIZE;
489 memcpy(req.data->bytes, (void *) phyframe_va(page), MOS_PAGE_SIZE);
490
492
493 const pf_point_t pp = profile_enter();
494 const int result = fs_client_put_page(userfs->rpc_server, &req, &resp);
495 profile_leave(pp, "userfs.'%s'.putpage", userfs->rpc_server_name);
496
499
500 if (result != RPC_RESULT_OK)
501 {
502 pr_warn("userfs_inode_cache_flush_page: failed to putpage: %d", result);
503 return -EIO;
504 }
505
506 if (!resp.result.success)
507 {
508 pr_dwarn(userfs, "userfs_inode_cache_flush_page: failed to putpage: %s", resp.result.error);
509 return -EIO;
510 }
511
512 return 0;
513}
514
516 .fill_cache = userfs_inode_cache_fill_cache,
517 .page_write_begin = simple_page_write_begin,
518 .page_write_end = simple_page_write_end,
519 .flush_page = userfs_inode_cache_flush_page,
520};
521
523{
524 userfs_t *userfs = userfs_get(inode->superblock->fs, "sync_inode: %llu", inode->ino);
525
527 req.i_ref = i_to_pb_ref(inode);
528 req.i_info = *i_to_pb_full(inode, &req.i_info);
529
531 const pf_point_t pp = profile_enter();
532 const int result = fs_client_sync_inode(userfs->rpc_server, &req, &resp);
533 profile_leave(pp, "userfs.'%s'.sync_inode", userfs->rpc_server_name);
534
535 if (result != RPC_RESULT_OK)
536 {
537 pr_warn("userfs_sync_inode: failed to sync inode %llu: %d", inode->ino, result);
538 return -EIO;
539 }
540
541 if (!resp.result.success)
542 {
543 pr_dwarn(userfs, "userfs_sync_inode: failed to sync inode %llu: %s", inode->ino, resp.result.error);
544 return -EIO;
545 }
546
547 return 0;
548}
549
551 .drop_inode = NULL,
552 .sync_inode = userfs_sync_inode,
553};
554
555PtrResult<dentry_t> userfs_fsop_mount(filesystem_t *fs, const char *device, const char *options)
556{
557 userfs_t *userfs = userfs_get(fs, "mount: %s", fs->name.c_str());
558
559 const mosrpc_fs_mount_request req = {
560 .fs_name = (char *) fs->name.c_str(),
561 .device = (char *) device,
562 .options = (char *) options,
563 };
564
565 mosrpc_fs_mount_response resp = {};
566
567 const pf_point_t pp = profile_enter();
568 const int result = fs_client_mount(userfs->rpc_server, &req, &resp);
569 profile_leave(pp, "userfs.'%s'.mount", userfs->rpc_server_name);
570
572
573 if (result != RPC_RESULT_OK)
574 {
575 pr_warn("userfs_fsop_mount: failed to mount %s: %d", fs->name.c_str(), result);
576 return -EIO;
577 }
578
579 if (!resp.result.success)
580 {
581 pr_warn("userfs_fsop_mount: failed to mount %s: %s", fs->name.c_str(), resp.result.error);
582 return -EIO;
583 }
584
586 sb->ops = &userfs_sb_ops;
587
588 inode_t *i = i_from_pbfull(&resp.root_info, sb, (void *) resp.root_ref.data);
589
590 sb->fs = fs;
592 sb->root->superblock = i->superblock = sb;
593 dentry_attach(sb->root, i);
594 return sb->root;
595}
#define MOS_ASSERT(cond)
Definition assert.hpp:14
#define MOS_PAGE_SIZE
Definition autoconf.h:6
const Char * c_str() const
Definition string.hpp:215
#define mosrpc_fs_create_file_response_fields
#define mosrpc_fs_readlink_response_fields
#define mosrpc_fs_putpage_response_fields
#define mosrpc_fs_putpage_request_fields
#define mosrpc_fs_unlink_response_fields
#define mosrpc_fs_mount_response_fields
#define mosrpc_fs_getpage_response_fields
#define mosrpc_fs_lookup_response_fields
#define mosrpc_fs_make_dir_response_fields
#define mosrpc_fs_readdir_response_fields
u16 file_perm_t
Definition fs_types.h:52
file_type_t
Definition fs_types.h:14
void dentry_attach(dentry_t *d, inode_t *inode)
Attach an inode to a dentry.
Definition dentry.cpp:306
#define phyframe_va(frame)
Definition mm.hpp:80
phyframe_t * mm_get_free_page(void)
Definition mm.cpp:39
#define pmm_ref_one(thing)
Definition pmm.hpp:159
inode_t * inode_create(superblock_t *sb, u64 ino, file_type_t type)
Definition inode.cpp:59
static vmap_global_mstat_t stat[_MEM_MAX_TYPES]
Definition mmstat.cpp:22
#define likely(x)
Definition mos_global.h:39
#define MOS_UNUSED(x)
Definition mos_global.h:65
#define unlikely(x)
Definition mos_global.h:40
T * create(Args &&...args)
Definition allocator.hpp:10
#define uint64_t
uint_least16_t pb_size_t
Definition pb.h:330
#define PB_BYTES_ARRAY_T_ALLOCSIZE(n)
Definition pb.h:397
void pb_release(const pb_msgdesc_t *fields, void *dest_struct)
Definition pb_decode.c:1355
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_warn(fmt,...)
Definition printk.hpp:38
#define pr_dwarn(feat, fmt,...)
Definition printk.hpp:30
#define profile_enter()
Definition profiling.hpp:33
u64 pf_point_t
Definition profiling.hpp:8
#define profile_leave(p,...)
Definition profiling.hpp:35
@ RPC_RESULT_OK
Definition rpc.h:26
MOSAPI rpc_server_stub_t * rpc_client_create(const char *server_name)
Create a new RPC client stub for the given server.
const char * name
Definition slab.cpp:35
void skip()
Definition userfs.cpp:46
const pb_msgdesc_t *const fields
Definition userfs.cpp:43
void * data
Definition userfs.cpp:44
AutoCleanup(const pb_msgdesc_t *fields, void *data)
Definition userfs.cpp:51
superblock_t * superblock
inode_t * inode
mos::string name
inode_t * owner
const inode_cache_ops_t * ops
superblock_t * superblock
uid_t uid
u64 modified
u64 accessed
u64 created
file_perm_t perm
const inode_ops_t * ops
bool sgid
size_t size
file_type_t type
const file_ops_t * file_ops
bool suid
inode_cache_t cache
bool sticky
gid_t gid
void * private_data
ssize_t nlinks
mosrpc_fs_inode_info i_info
pb_bytes_array_t * data
mosrpc_fs_inode_info i_info
mosrpc_fs_inode_ref i_ref
mosrpc_fs_inode_info i_info
mosrpc_fs_inode_ref i_ref
mosrpc_fs_inode_info root_info
mosrpc_fs_inode_ref root_ref
pb_bytes_array_t * data
struct _mosrpc_fs_pb_dirent * entries
mosrpc_fs_inode_info i_info
mosrpc_fs_inode_ref i_ref
char * error
Definition mosrpc.pb.h:15
dentry_t * root
const superblock_ops_t * ops
filesystem_t * fs
mos::string rpc_server_name
The name of the RPC server.
Definition userfs.hpp:14
rpc_server_stub_t * rpc_server
The RPC server stub, if connected.
Definition userfs.hpp:15
static char buffer[2048]
unsigned long ptr_t
Definition types.h:21
long userfs_inode_cache_flush_page(inode_cache_t *cache, uint64_t pgoff, phyframe_t *page)
Definition userfs.cpp:478
static bool userfs_iop_symlink(inode_t *dir, dentry_t *dentry, const char *symname)
Definition userfs.cpp:358
static bool userfs_iop_rename(inode_t *old_dir, dentry_t *old_dentry, inode_t *new_dir, dentry_t *new_dentry)
Definition userfs.cpp:331
const superblock_ops_t userfs_sb_ops
Definition userfs.cpp:550
void userfs_ensure_connected(userfs_t *userfs)
Ensure that the userfs is connected to the server.
Definition userfs.cpp:105
mosrpc_fs_inode_info * i_to_pb_full(const inode_t *i, mosrpc_fs_inode_info *pbi)
Convert a kernel inode to a protobuf inode.
Definition userfs.cpp:80
const inode_ops_t userfs_iops
Definition userfs.cpp:403
mosrpc_fs_inode_ref i_to_pb_ref(const inode_t *i)
Definition userfs.cpp:99
static bool userfs_iop_mkdir(inode_t *dir, dentry_t *dentry, file_perm_t perm)
Definition userfs.cpp:201
static bool userfs_iop_rmdir(inode_t *dir, dentry_t *dentry)
Definition userfs.cpp:346
static size_t userfs_iop_readlink(dentry_t *dentry, char *buffer, size_t buflen)
Definition userfs.cpp:295
static bool userfs_iop_mknode(inode_t *dir, dentry_t *dentry, file_type_t type, file_perm_t perm, dev_t dev)
Definition userfs.cpp:240
const inode_cache_ops_t userfs_inode_cache_ops
Definition userfs.cpp:515
#define userfs_get(_fs, _fmt,...)
Definition userfs.cpp:34
long userfs_sync_inode(inode_t *inode)
Definition userfs.cpp:522
const file_ops_t userfs_fops
Definition userfs.cpp:426
static void userfs_iop_iterate_dir(dentry_t *dentry, vfs_listdir_state_t *state, dentry_iterator_op add_record)
Definition userfs.cpp:130
static PtrResult< phyframe_t > userfs_inode_cache_fill_cache(inode_cache_t *cache, uint64_t pgoff)
Definition userfs.cpp:436
static bool userfs_iop_unlink(inode_t *dir, dentry_t *dentry)
Definition userfs.cpp:371
static bool userfs_iop_newfile(inode_t *dir, dentry_t *dentry, file_type_t type, file_perm_t perm)
Definition userfs.cpp:255
static bool userfs_iop_lookup(inode_t *dir, dentry_t *dentry)
Definition userfs.cpp:164
PtrResult< dentry_t > userfs_fsop_mount(filesystem_t *fs, const char *device, const char *options)
Definition userfs.cpp:555
inode_t * i_from_pbfull(const mosrpc_fs_inode_info *stat, superblock_t *sb, void *private_data)
Convert a protobuf inode to a kernel inode.
Definition userfs.cpp:59
static bool userfs_fop_open(inode_t *inode, file_t *file, bool created)
Definition userfs.cpp:417
static bool userfs_iop_hardlink(dentry_t *d, inode_t *i, dentry_t *new_d)
Definition userfs.cpp:118
mos::string dentry_name(const dentry_t *dentry)
void dentry_iterator_op(vfs_listdir_state_t *state, u64 ino, mos::string_view name, file_type_t type)
Definition vfs_types.hpp:61
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