46 pr_dinfo2(vfs,
"vfs: flushing page cache for file %pio", (
void *) &file->
io);
50 if (pgoff == 0 && npages == (
size_t) -1)
118 if (!file_ops || !file_ops->
read)
122 size_t ret = file_ops->
read(file, buf, count, file->
offset);
125 else if (ret != (
size_t) -1)
136 if (!file_ops || !file_ops->
write)
140 size_t ret = file_ops->
write(file, buf, count, file->
offset);
153 return ops->
seek(file, offset, whence);
167 new_offset =
MAX(new_offset, 0);
168 file->
offset = new_offset;
174 new_offset =
MAX(new_offset, 0);
175 file->
offset = new_offset;
196 if (IS_ERR(pagecache_page))
245 return file_ops->
mmap(file, vmap, offset);
256 return file_ops->
munmap(file, vmap, unmapped);
303 statbuf->
ino = inode->
ino;
307 statbuf->
uid = inode->
uid;
308 statbuf->
gid = inode->
gid;
361 const bool expect_dir = flags &
OPEN_DIR;
371 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);
375 bool created =
false;
383 return ERR_PTR(-EROFS);
389 return ERR_PTR(-EIO);
398 return ERR_PTR(-EACCES);
442 if (ops && ops->
open)
446 return ERR_PTR(-ENOTSUP);
466long vfs_mount(
const char *device,
const char *path,
const char *fs,
const char *options)
471 mos_warn(
"filesystem '%s' not found", fs);
482 pr_warn(
"root filesystem is already mounted");
485 pr_dinfo2(vfs,
"mounting root filesystem '%s'...", fs);
489 mos_warn(
"failed to mount root filesystem");
503 if (IS_ERR(mountpoint))
504 return PTR_ERR(mountpoint);
509 mos_warn(
"mount point is already mounted");
517 dentry_t *mounted_root = real_fs->
mount(real_fs, device, options);
518 if (IS_ERR(mounted_root))
520 mos_warn(
"failed to mount filesystem");
521 return PTR_ERR(mounted_root);
524 const bool mounted =
dentry_mount(mountpoint, mounted_root, real_fs);
527 mos_warn(
"failed to mount filesystem");
532 pr_dinfo2(vfs,
"mounted filesystem '%s' on '%s'", fs, path);
539 if (IS_ERR(mounted_root))
540 return PTR_ERR(mounted_root);
546 mos_warn(
"refcount is not as expected");
556 mos_warn(
"failed to unmount filesystem");
565 MOS_ASSERT_X(mounted_root->
refcount == 0,
"fs->umount should release the last reference to the mounted root");
569 pr_info2(
"unmounted root filesystem");
580 pr_dinfo2(vfs,
"vfs_openat(fd=%d, path='%s', flags=%x)", fd, path, flags);
592 pr_dinfo2(vfs,
"vfs_fstatat(fd=%d, path='%p', stat=%p, flags=%x)", fd, (
void *) path, (
void *) statbuf, flags);
605 pr_dinfo2(vfs,
"vfs_fstatat(fd=%d, path='%s', stat=%p, flags=%x)", fd, path, (
void *) statbuf, flags);
608 return PTR_ERR(basedir);
615 return PTR_ERR(dentry);
628 return PTR_ERR(dentry);
641 return -ENAMETOOLONG;
648 pr_dinfo2(vfs,
"vfs_symlink(path='%s', target='%s')", path, target);
652 return PTR_ERR(dentry);
658 mos_warn(
"failed to create symlink '%s'", path);
661 return created ? 0 : -EIO;
670 return PTR_ERR(dentry);
683 mos_warn(
"failed to create directory '%s'", path);
686 return created ? 0 : -EIO;
695 return PTR_ERR(dentry);
707 mos_warn(
"failed to remove directory '%s'", path);
710 return removed ? 0 : -EIO;
715 pr_dinfo2(vfs,
"vfs_list_dir(io=%p, buf=%p, size=%zu)", (
void *) io, (
void *) user_buf, user_size);
736 size_t bytes_copied = 0;
746 const size_t entry_size =
sizeof(ino_t) +
sizeof(
off_t) +
sizeof(short) +
sizeof(
char) + entry->name_len + 1;
747 if (bytes_copied + entry_size > user_size)
750 struct dirent *dirent = (
struct dirent *) (((
char *) user_buf) + bytes_copied);
751 dirent->d_ino = entry->ino;
752 dirent->d_type = entry->type;
753 dirent->d_reclen = entry_size;
754 dirent->d_off = entry_size - 1;
755 memcpy(dirent->d_name, entry->name, entry->name_len);
756 dirent->d_name[entry->name_len] =
'\0';
757 bytes_copied += entry_size;
770 return PTR_ERR(dentry);
791 pr_dinfo2(vfs,
"vfs_fchmodat(fd=%d, path='%s', perm=%o, flags=%x)", fd, path, perm, flags);
795 return PTR_ERR(dentry);
805 pr_dinfo2(vfs,
"vfs_unlinkat(dirfd=%d, path='%s')", dirfd, path);
809 return PTR_ERR(dentry);
832 pr_dinfo2(vfs,
"vfs_fsync(io=%p, sync_metadata=%d, start=%ld, end=%ld)", (
void *) io, sync_metadata, start, end);
835 const off_t nbytes = end - start;
871 sysfs_printf(f,
"%-20s %-10s\n", pathbuf, mp->fs->name);
885 mountroot ?
" (mount root)" : (dentry->
is_mountpoint ?
" (mountpoint)" :
"")
#define MOS_ASSERT_X(cond, msg,...)
#define mos_warn(fmt,...)
#define MOS_PATH_MAX_LENGTH
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.
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.
void vfs_populate_listdir_buf(dentry_t *dir, vfs_listdir_state_t *state)
List the contents of a directory.
should_inline dentry_t * dentry_parent(const dentry_t *dentry)
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_check_refstat(const dentry_t *dentry)
Check the reference count of a dentry.
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.
#define LIST_HEAD_INIT(container)
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)
file_t * vfs_openat(int fd, const char *path, open_flags flags)
Open a file at a given path.
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_fstatat(fd_t fd, const char *path, file_stat_t *restrict statbuf, fstatat_flags flags)
Stat a file.
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.
file_t * vfs_do_open_dentry(dentry_t *entry, bool created, bool read, bool write, bool exec, bool truncate)
Open an directory dentry.
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)
#define container_of(ptr, type, member)
list_head vfs_mountpoint_list
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.
phyframe_t * pagecache_get_page_for_read(inode_cache_t *cache, off_t pgoff)
Get a page from 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_t *process, fd_t fd)
#define mutex_acquire(mutex)
#define mutex_release(mutex)
#define MOS_INIT(_comp, _fn)
#define SLAB_AUTOINIT(name, var, type)
#define spinlock_acquire(lock)
#define spinlock_release(lock)
superblock_t * superblock
bool(* open)(inode_t *inode, file_t *file, bool created)
called when a file is opened, or created
off_t(* seek)(file_t *file, off_t offset, io_seek_whence_t whence)
seek to a new position in the file
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
void(* unmount)(filesystem_t *fs, dentry_t *mountpoint)
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
size_t(* readlink)(dentry_t *dentry, char *buffer, size_t buflen)
read the contents of a symbolic link
bool(* unlink)(inode_t *dir, dentry_t *dentry)
remove a file name, this is called after nlinks is decremented
bool(* newfile)(inode_t *dir, dentry_t *dentry, file_type_t type, file_perm_t perm)
create a new file
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
long(* sync_inode)(inode_t *inode)
flush the inode to disk
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)
static bool vfs_io_ops_mmap(io_t *io, vmap_t *vmap, off_t offset)
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)
slab_t * superblock_cache
static void vfs_io_ops_close(io_t *io)
static bool vfs_sysfs_dentry_stats(sysfs_file_t *f)
static filesystem_t * vfs_find_filesystem(const char *name)
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 void vfs_io_ops_close_dir(io_t *io)
static void vfs_flusher_entry(void *arg)
static const io_op_t dir_io_ops
static bool vfs_verify_permissions(dentry_t *file_dentry, bool open, bool read, bool create, bool execute, bool write)
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 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 file_t * vfs_do_open(dentry_t *base, const char *path, open_flags flags)
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)
#define dentry_name(dentry)