39 pr_dinfo2(vfs,
"vfs: flushing page cache for file %pio", (
void *) &file->
io);
43 if (pgoff == 0 && npages == (
size_t) -1)
55 if (
ops &&
ops->sync_inode)
110 if (!file_ops || !file_ops->
read)
114 size_t ret = file_ops->
read(file, buf, count, file->
offset);
117 else if (ret != (
size_t) -1)
128 if (!file_ops || !file_ops->
write)
132 size_t ret = file_ops->
write(file, buf, count, file->
offset);
145 return ops->seek(file, offset, whence);
153 file->
offset = std::max(offset, 0l);
159 new_offset = std::max(new_offset, 0l);
160 file->
offset = new_offset;
166 new_offset = std::max(new_offset, 0l);
167 file->
offset = new_offset;
188 if (pagecache_page.isErr())
237 return file_ops->
mmap(file, vmap, offset);
248 return file_ops->
munmap(file, vmap, unmapped);
295 statbuf->
ino = inode->
ino;
299 statbuf->
uid = inode->
uid;
300 statbuf->
gid = inode->
gid;
315 if (fs->name ==
name)
349 const bool expect_dir = flags &
OPEN_DIR;
363 pr_dinfo2(vfs,
"failed to resolve '%s': create=%d, r=%d, x=%d, nofollow=%d, dir=%d, truncate=%d", path, may_create, read, exec, no_follow, expect_dir, truncate);
364 return entry.getErr();
367 bool created =
false;
369 if (may_create && entry->inode ==
NULL)
372 if (!parent->inode->ops->newfile)
378 if (!parent->inode->ops->newfile(parent->inode, entry.get(),
FILE_TYPE_REGULAR, 0666))
397 return file.getErr();
460long vfs_mount(
const char *device,
const char *path,
const char *fs,
const char *options)
465 mos_warn(
"filesystem '%s' not found", fs);
476 pr_warn(
"root filesystem is already mounted");
479 pr_dinfo2(vfs,
"mounting root filesystem '%s'...", fs);
480 const auto mountResult = real_fs->
mount(real_fs, device, options);
481 if (mountResult.isErr())
483 mos_warn(
"failed to mount root filesystem");
502 return base.getErr();
506 return mpRoot.getErr();
508 if (mpRoot->is_mountpoint)
511 mos_warn(
"mount point is already mounted");
519 auto mounted_root = real_fs->
mount(real_fs, device, options);
520 if (mounted_root.isErr())
522 mos_warn(
"failed to mount filesystem");
523 return mounted_root.getErr();
526 const bool mounted =
dentry_mount(mpRoot.get(), mounted_root.get(), real_fs);
529 mos_warn(
"failed to mount filesystem");
533 MOS_ASSERT_X(mpRoot->refcount == mounted_root->refcount,
"mountpoint refcount=%zu, mounted_root refcount=%zu", mpRoot->refcount.load(),
534 mounted_root->refcount.load());
535 pr_dinfo2(vfs,
"mounted filesystem '%s' on '%s'", fs, path);
542 if (mounted_root.isErr())
543 return mounted_root.getErr();
546 if (mounted_root->refcount != 2)
549 mos_warn(
"refcount is not as expected");
559 mos_warn(
"failed to unmount filesystem");
563 MOS_ASSERT(mounted_root->refcount == mountpoint->refcount && mountpoint->refcount == 1);
564 if (mounted_root->superblock->fs->unmount)
565 mounted_root->superblock->fs->unmount(mounted_root->superblock->fs, mounted_root.get());
568 MOS_ASSERT_X(mounted_root->refcount == 0,
"fs->umount should release the last reference to the mounted root");
572 pr_info2(
"unmounted root filesystem");
583 pr_dinfo2(vfs,
"vfs_openat(fd=%d, path='%s', flags=%x)", fd, path, flags);
586 return basedir.getErr();
588 auto file =
vfs_do_open(basedir.get(), path, flags);
596 pr_dinfo2(vfs,
"vfs_fstatat(fd=%d, path='%p', stat=%p, flags=%x)", fd, (
void *) path, (
void *) statbuf, flags);
609 pr_dinfo2(vfs,
"vfs_fstatat(fd=%d, path='%s', stat=%p, flags=%x)", fd, path, (
void *) statbuf, flags);
612 return basedir.getErr();
620 return dentry.getErr();
632 return base.getErr();
636 return dentry.getErr();
644 const size_t len = dentry->inode->ops->readlink(dentry.get(), buf,
size);
649 return -ENAMETOOLONG;
656 pr_dinfo2(vfs,
"vfs_symlink(path='%s', target='%s')", path, target);
659 return base.getErr();
663 return dentry.getErr();
669 mos_warn(
"failed to create symlink '%s'", path);
672 return created ? 0 : -EIO;
680 return base.getErr();
684 return dentry.getErr();
697 mos_warn(
"failed to create directory '%s'", path);
700 return created ? 0 : -EIO;
708 return base.getErr();
712 return dentry.getErr();
724 mos_warn(
"failed to remove directory '%s'", path);
727 return removed ? 0 : -EIO;
732 pr_dinfo2(vfs,
"vfs_list_dir(io=%p, buf=%p, size=%zu)", (
void *) io, (
void *) user_buf, user_size);
754 size_t bytes_copied = 0;
764 const size_t entry_size =
sizeof(ino_t) +
sizeof(
off_t) +
sizeof(short) +
sizeof(
char) + entry->name.size() + 1;
765 if (bytes_copied + entry_size > user_size)
768 struct dirent *dirent = (
struct dirent *) (((
char *) user_buf) + bytes_copied);
769 dirent->d_ino = entry->ino;
770 dirent->d_type = entry->type;
771 dirent->d_reclen = entry_size;
772 dirent->d_off = entry_size - 1;
773 memcpy(dirent->d_name, entry->name.data(), entry->name.size());
774 dirent->d_name[entry->name.size()] =
'\0';
775 bytes_copied += entry_size;
787 return base.getErr();
791 return dentry.getErr();
812 pr_dinfo2(vfs,
"vfs_fchmodat(fd=%d, path='%s', perm=%o, flags=%x)", fd, path, perm, flags);
815 return base.getErr();
819 return dentry.getErr();
822 dentry->inode->perm = perm;
829 pr_dinfo2(vfs,
"vfs_unlinkat(dirfd=%d, path='%s')", dirfd, path);
832 return base.getErr();
836 return dentry.getErr();
859 pr_dinfo2(vfs,
"vfs_fsync(io=%p, sync_metadata=%d, start=%ld, end=%ld)", (
void *) io, sync_metadata, start, end);
862 const off_t nbytes = end - start;
898 sysfs_printf(f,
"%-20s %-10s\n", pathbuf, mp->fs->name.c_str());
912 mountroot ?
" (mount root)" : (dentry->
is_mountpoint ?
" (mountpoint)" :
"")
#define MOS_ASSERT_X(cond, msg,...)
#define mos_warn(fmt,...)
#define MOS_PATH_MAX_LENGTH
const Char * c_str() const
void dentry_dump_refstat(const dentry_t *dentry, dump_refstat_receiver_t *receiver, void *receiver_data)
dentry_t * dentry_unmount(dentry_t *root)
Unmount a filesystem at the mountpoint.
PtrResult< dentry_t > dentry_from_fd(fd_t fd)
Get the dentry from a file descriptor.
bool dentry_mount(dentry_t *mountpoint, dentry_t *root, filesystem_t *fs)
Mount a filesystem at a mountpoint.
should_inline bool path_is_absolute(const char *path)
Check if a path is absolute.
void dentry_detach(dentry_t *d)
Detach the inode from a dentry.
void dentry_try_release(dentry_t *dentry)
ssize_t dentry_path(dentry_t *dentry, dentry_t *root, char *buf, size_t size)
Get the path of a dentry.
should_inline dentry_t * dentry_parent(const dentry_t &dentry)
void vfs_populate_listdir_buf(dentry_t *dir, vfs_listdir_state_t *state)
List the contents of a directory.
void dentry_check_refstat(const dentry_t *dentry)
Check the reference count of a dentry.
PtrResult< dentry_t > dentry_resolve(dentry_t *starting_dir, dentry_t *root_dir, const char *path, lastseg_resolve_flags_t flags)
Lookup a path in the filesystem.
void dentry_unref(dentry_t *dentry)
Decrement the reference count of a dentry.
__nodiscard bool dentry_unref_one_norelease(dentry_t *dentry)
Decrease the refcount of ONE SINGLE dentry, including (if it's a mountpoint) the mountpoint dentry.
@ RESOLVE_EXPECT_ANY_EXIST
@ RESOLVE_SYMLINK_NOFOLLOW
@ RESOLVE_EXPECT_ANY_TYPE
@ RESOLVE_EXPECT_NONEXIST
MOSAPI s32 strcmp(const char *str1, const char *str2)
MOSAPI void linked_list_init(list_node_t *head_node)
Initialise a circular double linked list.
MOSAPI void list_node_append(list_node_t *head, list_node_t *item)
#define list_foreach(t, v, h)
Iterate over a list.
#define list_node(element)
Get the ‘list_node’ of a list element. This is exactly the reverse of ‘list_entry’ above.
list_node_t list_head
A linked list head.
MOSAPI bool list_is_empty(const list_node_t *head)
#define list_remove(element)
vmfault_result_t mm_resolve_cow_fault(vmap_t *vmap, ptr_t fault_addr, pagefault_t *info)
Helper function to resolve a copy-on-write fault.
@ VMFAULT_COPY_BACKING_PAGE
the caller should copy the backing page into the faulting address
@ VMFAULT_MAP_BACKING_PAGE
the caller should map the backing page into the faulting address
@ VMFAULT_CANNOT_HANDLE
the handler cannot handle this fault
@ VMFAULT_MAP_BACKING_PAGE_RO
the caller should map the backing page into the faulting address, and mark it non-writable
long vfs_chdirat(fd_t dirfd, const char *path)
Change the current working directory.
size_t vfs_list_dir(io_t *io, void *user_buf, size_t user_size)
Get the content of a directory.
long vfs_symlink(const char *path, const char *target)
Create a symbolic link.
long vfs_unmount(const char *path)
Unmount a filesystem at a given path.
long vfs_rmdir(const char *path)
should_inline const file_ops_t * file_get_ops(file_t *file)
PtrResult< file_t > vfs_openat(int fd, const char *path, open_flags flags)
Open a file at a given path.
long vfs_fstatat(fd_t fd, const char *path, file_stat_t *__restrict statbuf, fstatat_flags flags)
Stat a file.
PtrResult< file_t > vfs_do_open_dentry(dentry_t *entry, bool created, bool read, bool write, bool exec, bool truncate)
Open an directory dentry.
ssize_t vfs_getcwd(char *buf, size_t size)
Get the current working directory.
long vfs_unlinkat(fd_t dirfd, const char *path)
Remove the name of a file, and possibly the file itself.
long vfs_mount(const char *device, const char *path, const char *fs, const char *options)
Mount a filesystem at a given existing path.
void vfs_register_filesystem(filesystem_t *fs)
long vfs_fsync(io_t *io, bool sync_metadata, off_t start, off_t end)
Synchronize a file with the filesystem.
long vfs_mkdir(const char *path)
Create a directory.
long vfs_fchmodat(fd_t fd, const char *path, int perm, int flags)
Change the permissions of a file.
size_t vfs_readlinkat(fd_t dirfd, const char *path, char *buf, size_t size)
Read a symbolic link.
bool inode_unlink(inode_t *dir, dentry_t *dentry)
Unlink a dentry from its parent inode.
void io_init(io_t *io, io_type_t type, io_flags_t flags, const io_op_t *ops)
__nodiscard bool io_valid(const io_t *io)
#define vmap_stat_inc(vmap, type)
#define vmap_stat_dec(vmap, type)
#define ALIGN_UP_TO_PAGE(addr)
#define ALIGN_DOWN_TO_PAGE(addr)
list_head vfs_mountpoint_list
basic_string_view< char > string_view
T * create(Args &&...args)
PtrResult< phyframe_t > pagecache_get_page_for_read(inode_cache_t *cache, off_t pgoff)
Get a page from the page cache.
long pagecache_flush_or_drop(inode_cache_t *icache, off_t pgoff, size_t npages, bool drop_page)
Flush or drop a range of pages from the page cache.
long pagecache_flush_or_drop_all(inode_cache_t *icache, bool drop_page)
Flush or drop all pages in the page cache.
#define mos_panic(fmt,...)
static void * memcpy(void *s1, const void *s2, size_t n)
#define pr_info2(fmt,...)
#define pr_dinfo2(feat, fmt,...)
io_t * process_get_fd(Process *process, fd_t fd)
#define mutex_acquire(mutex)
#define mutex_release(mutex)
#define MOS_INIT(_comp, _fn)
#define spinlock_acquire(lock)
#define spinlock_release(lock)
bool(* munmap)(file_t *file, vmap_t *vmap, bool *unmapped)
unmap the file from memory
void(* release)(file_t *file)
called when the last reference to the file is dropped
ssize_t(* read)(const file_t *file, void *buf, size_t size, off_t offset)
read from the file
ssize_t(* write)(const file_t *file, const void *buf, size_t size, off_t offset)
write to the file
bool(* mmap)(file_t *file, vmap_t *vmap, off_t offset)
map the file into memory
PtrResult< dentry_t >(* mount)(filesystem_t *fs, const char *dev_name, const char *mount_options)
bool(* mkdir)(inode_t *dir, dentry_t *dentry, file_perm_t perm)
create a new directory
bool(* unlink)(inode_t *dir, dentry_t *dentry)
remove a file name, this is called after nlinks is decremented
bool(* rmdir)(inode_t *dir, dentry_t *dentry)
remove a directory
bool(* symlink)(inode_t *dir, dentry_t *dentry, const char *symname)
create a symbolic link
superblock_t * superblock
phyframe_t * faulting_page
the frame that contains the copy-on-write data (if any)
const phyframe_t * backing_page
the frame that contains the data for this page, the on_fault handler should set this
const superblock_ops_t * ops
size_t read_offset
user has read up to this offset, start from this offset when reading more entries
size_t n_count
number of entries in the list
vmfault_handler_t on_fault
ssize_t sysfs_printf(sysfs_file_t *file, const char *fmt,...)
#define SYSFS_RO_ITEM(_name, _show_fn)
#define SYSFS_AUTOREGISTER(sysfs_name, sysfs_items)
long timer_msleep(u64 ms)
#define container_of(ptr, type, member)
static bool vfs_io_ops_mmap(io_t *io, vmap_t *vmap, off_t offset)
static bool vfs_verify_permissions(dentry_t &file_dentry, bool open, bool read, bool create, bool execute, bool write)
static size_t vfs_io_ops_read(io_t *io, void *buf, size_t count)
static vmfault_result_t vfs_fault_handler(vmap_t *vmap, ptr_t fault_addr, pagefault_t *info)
static void vfs_io_ops_close(io_t *io)
static bool vfs_sysfs_dentry_stats(sysfs_file_t *f)
static void vfs_sysfs_dentry_stats_stat_receiver(int depth, const dentry_t *dentry, bool mountroot, void *data)
static void vfs_flusher_init(void)
static list_head vfs_fs_list
static __used void vfs_flusher_entry(void *arg)
static void vfs_io_ops_close_dir(io_t *io)
static const io_op_t dir_io_ops
static PtrResult< file_t > vfs_do_open(dentry_t *base, const char *path, open_flags flags)
static sysfs_item_t vfs_sysfs_items[]
static const io_op_t file_io_ops
static off_t vfs_io_ops_seek(io_t *io, off_t offset, io_seek_whence_t whence)
static filesystem_t * vfs_find_filesystem(mos::string_view name)
static long do_sync_inode(file_t *file)
static bool vfs_io_ops_munmap(io_t *io, vmap_t *vmap, bool *unmapped)
static spinlock_t vfs_fs_list_lock
static size_t vfs_io_ops_write(io_t *io, const void *buf, size_t count)
static bool vfs_sysfs_filesystems(sysfs_file_t *f)
static void vfs_io_ops_getname(const io_t *io, char *buf, size_t size)
static long do_pagecache_flush(file_t *file, off_t pgoff, size_t npages)
static bool vfs_sysfs_mountpoints(sysfs_file_t *f)
static void vfs_copy_stat(file_stat_t *statbuf, inode_t *inode)
mos::string dentry_name(const dentry_t *dentry)