diff --git a/kernel/filesystem/fs_server/fs_rpc.c b/kernel/filesystem/fs_server/fs_rpc.c index 8ca1da91..a29462f2 100644 --- a/kernel/filesystem/fs_server/fs_rpc.c +++ b/kernel/filesystem/fs_server/fs_rpc.c @@ -1,10 +1,12 @@ // SPDX-License-Identifier: GPL-3.0-or-later -// filesystem server RPCs +// userspace filesystems #include "mos/filesystem/dentry.h" #include "mos/filesystem/vfs.h" #include "mos/filesystem/vfs_types.h" #include "mos/filesystem/vfs_utils.h" +#include "mos/mm/mm.h" +#include "mos/mm/physical/pmm.h" #include "mos/mm/slab_autoinit.h" #include "mos/printk.h" #include "mos/setup.h" @@ -40,6 +42,7 @@ SLAB_AUTOINIT("userfs", userfs_slab, userfs_t); static const inode_ops_t userfs_iops; static const file_ops_t userfs_fops; +static const inode_cache_ops_t userfs_inode_cache_ops; static inode_t *i_from_pb(const pb_inode *pbi, superblock_t *sb) { @@ -161,6 +164,7 @@ static bool userfs_iop_lookup(inode_t *dir, dentry_t *dentry) dentry->inode = i; dentry->superblock = i->superblock = dir->superblock; i->ops = &userfs_iops; + i->cache.ops = &userfs_inode_cache_ops; i->file_ops = &userfs_fops; ret = true; @@ -294,6 +298,52 @@ static const file_ops_t userfs_fops = { .munmap = NULL, }; +static phyframe_t *userfs_inode_cache_fill_cache(inode_cache_t *cache, off_t pgoff) +{ + // get a page from the server + userfs_t *userfs = container_of(cache->owner->superblock->fs, userfs_t, fs); + mos_rpc_fs_getpage_request req = { 0 }; + i_to_pb(cache->owner, &req.inode); + req.pgoff = pgoff; + + mos_rpc_fs_getpage_response resp = { 0 }; + userfs_ensure_connected(userfs); + int result = fs_client_getpage(userfs->rpc_server, &req, &resp); + if (result != RPC_RESULT_OK) + { + pr_warn("userfs_inode_cache_fill_cache: failed to getpage %s: %d", dentry_name(cache->owner->superblock->root), result); + goto bail_out; + } + + if (!resp.result.success) + { + pr_warn("userfs_inode_cache_fill_cache: failed to getpage %s: %s", dentry_name(cache->owner->superblock->root), resp.result.error); + goto bail_out; + } + + // allocate a page + phyframe_t *page = pmm_ref_one(mm_get_free_page()); + if (!page) + { + pr_warn("userfs_inode_cache_fill_cache: failed to allocate page"); + goto bail_out; + } + + // copy the data from the server + memcpy((void *) phyframe_va(page), resp.data->bytes, MIN(resp.data->size, MOS_PAGE_SIZE)); + return page; + +bail_out: + pb_release(mos_rpc_fs_getpage_response_fields, &resp); + return ERR_PTR(-EIO); +} + +static const inode_cache_ops_t userfs_inode_cache_ops = { + .fill_cache = userfs_inode_cache_fill_cache, + .page_write_begin = NULL, + .page_write_end = NULL, +}; + static dentry_t *userfs_fsop_mount(filesystem_t *fs, const char *device, const char *options) { userfs_t *userfs = container_of(fs, userfs_t, fs); diff --git a/kernel/include/public/mos/proto/fs_server.h b/kernel/include/public/mos/proto/fs_server.h index fd17474e..9ed68bcd 100644 --- a/kernel/include/public/mos/proto/fs_server.h +++ b/kernel/include/public/mos/proto/fs_server.h @@ -17,4 +17,5 @@ RPC_DEFINE_ENUMS(fs_manager, FS_MANAGER, FS_MANAGER_X) PB(xarg, 0, mount, MOUNT, mos_rpc_fs_mount_request, mos_rpc_fs_mount_response) \ PB(xarg, 1, readdir, READDIR, mos_rpc_fs_readdir_request, mos_rpc_fs_readdir_response) \ PB(xarg, 2, lookup, LOOKUP, mos_rpc_fs_lookup_request, mos_rpc_fs_lookup_response) \ - PB(xarg, 3, readlink, READLINK, mos_rpc_fs_readlink_request, mos_rpc_fs_readlink_response) + PB(xarg, 3, readlink, READLINK, mos_rpc_fs_readlink_request, mos_rpc_fs_readlink_response) \ + PB(xarg, 4, getpage, GETPAGE, mos_rpc_fs_getpage_request, mos_rpc_fs_getpage_response) diff --git a/proto/filesystem.proto b/proto/filesystem.proto index a0edac78..20c73eb2 100644 --- a/proto/filesystem.proto +++ b/proto/filesystem.proto @@ -122,3 +122,15 @@ message mos_rpc_fs_readlink_response mos_rpc_result result = 1; string target = 2; // the target of the symlink } + +message mos_rpc_fs_getpage_request +{ + pb_inode inode = 1; // the inode of the file + uint64 pgoff = 2; // the offset of the page, in number of pages +} + +message mos_rpc_fs_getpage_response +{ + mos_rpc_result result = 1; + bytes data = 2; // the data of the page +} diff --git a/userspace/programs/init/bootstrapper/cpiofs_server.c b/userspace/programs/init/bootstrapper/cpiofs_server.c index dca225fd..efff822d 100644 --- a/userspace/programs/init/bootstrapper/cpiofs_server.c +++ b/userspace/programs/init/bootstrapper/cpiofs_server.c @@ -267,6 +267,32 @@ static int cpiofs_readlink(rpc_server_t *server, mos_rpc_fs_readlink_request *re return RPC_RESULT_OK; } +static int cpiofs_getpage(rpc_server_t *server, mos_rpc_fs_getpage_request *req, mos_rpc_fs_getpage_response *resp, void *data) +{ + MOS_UNUSED(server); + MOS_UNUSED(data); + + cpio_inode_t *cpio_i = (cpio_inode_t *) req->inode.private_data; + const size_t bytes_to_read = MIN((size_t) MOS_PAGE_SIZE, cpio_i->pb_i.stat.size - req->pgoff * MOS_PAGE_SIZE); + + resp->data = malloc(sizeof(pb_bytes_array_t) + bytes_to_read); + resp->data->size = bytes_to_read; + + const size_t read = read_initrd(resp->data->bytes, bytes_to_read, cpio_i->data_offset + req->pgoff * MOS_PAGE_SIZE); + if (read != bytes_to_read) + { + puts("cpiofs_getpage: failed to read page"); + resp->result.success = false; + resp->result.error = strdup("failed to read page"); + + free(resp->data); + return RPC_RESULT_OK; + } + + resp->result.success = true; + return RPC_RESULT_OK; +} + void cpiofs_run_server() { cpiofs = rpc_server_create(CPIOFS_RPC_SERVER_NAME, NULL);