You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
riscv-pke/kernel/hostfs.c

301 lines
7.4 KiB

/*
* Interface functions between VFS and host-fs. added @lab4_1.
*/
#include "hostfs.h"
#include "pmm.h"
#include "spike_interface/spike_file.h"
#include "spike_interface/spike_utils.h"
#include "util/string.h"
#include "util/types.h"
#include "vfs.h"
/**** host-fs vinode interface ****/
const struct vinode_ops hostfs_i_ops = {
.viop_read = hostfs_read,
.viop_write = hostfs_write,
.viop_create = hostfs_create,
.viop_lseek = hostfs_lseek,
.viop_lookup = hostfs_lookup,
.viop_hook_open = hostfs_hook_open,
.viop_hook_close = hostfs_hook_close,
.viop_write_back_vinode = hostfs_write_back_vinode,
// not implemented
.viop_link = hostfs_link,
.viop_unlink = hostfs_unlink,
.viop_readdir = hostfs_readdir,
.viop_mkdir = hostfs_mkdir,
};
/**** hostfs utility functions ****/
//
// append hostfs to the fs list.
//
int register_hostfs() {
struct file_system_type *fs_type = (struct file_system_type *)alloc_page();
fs_type->type_num = HOSTFS_TYPE;
fs_type->get_superblock = hostfs_get_superblock;
for (int i = 0; i < MAX_SUPPORTED_FS; i++) {
if (fs_list[i] == NULL) {
fs_list[i] = fs_type;
return 0;
}
}
return -1;
}
//
// append new device under "name" to vfs_dev_list.
//
struct device *init_host_device(char *name) {
// find rfs in registered fs list
struct file_system_type *fs_type = NULL;
for (int i = 0; i < MAX_SUPPORTED_FS; i++) {
if (fs_list[i] != NULL && fs_list[i]->type_num == HOSTFS_TYPE) {
fs_type = fs_list[i];
break;
}
}
if (!fs_type)
panic("init_host_device: No HOSTFS file system found!\n");
// allocate a vfs device
struct device *device = (struct device *)alloc_page();
// set the device name and index
strcpy(device->dev_name, name);
// we only support one host-fs device
device->dev_id = 0;
device->fs_type = fs_type;
// add the device to the vfs device list
for (int i = 0; i < MAX_VFS_DEV; i++) {
if (vfs_dev_list[i] == NULL) {
vfs_dev_list[i] = device;
break;
}
}
return device;
}
//
// recursive call to assemble a path.
//
void path_backtrack(char *path, struct dentry *dentry) {
if (dentry->parent == NULL) {
return;
}
path_backtrack(path, dentry->parent);
strcat(path, "/");
strcat(path, dentry->name);
}
//
// obtain the absolute path for "dentry", from root to file.
//
void get_path_string(char *path, struct dentry *dentry) {
strcpy(path, H_ROOT_DIR);
path_backtrack(path, dentry);
}
//
// allocate a vfs inode for an host fs file.
//
struct vinode *hostfs_alloc_vinode(struct super_block *sb) {
struct vinode *vinode = default_alloc_vinode(sb);
vinode->inum = -1;
vinode->i_fs_info = NULL;
vinode->i_ops = &hostfs_i_ops;
return vinode;
}
int hostfs_write_back_vinode(struct vinode *vinode) { return 0; }
//
// populate the vfs inode of an hostfs file, according to its stats.
//
int hostfs_update_vinode(struct vinode *vinode) {
spike_file_t *f = vinode->i_fs_info;
if ((int64)f < 0) { // is a direntry
vinode->type = H_DIR;
return -1;
}
struct stat stat;
spike_file_stat(f, &stat);
vinode->inum = stat.st_ino;
vinode->size = stat.st_size;
vinode->nlinks = stat.st_nlink;
vinode->blocks = stat.st_blocks;
if (S_ISDIR(stat.st_mode)) {
vinode->type = H_DIR;
} else if (S_ISREG(stat.st_mode)) {
vinode->type = H_FILE;
} else {
sprint("hostfs_lookup:unknown file type!");
return -1;
}
return 0;
}
/**** vfs-host-fs interface functions ****/
//
// read a hostfs file.
//
ssize_t hostfs_read(struct vinode *f_inode, char *r_buf, ssize_t len,
int *offset) {
spike_file_t *pf = (spike_file_t *)f_inode->i_fs_info;
if (pf < 0) {
sprint("hostfs_read: invalid file handle!\n");
return -1;
}
int read_len = spike_file_read(pf, r_buf, len);
// obtain current offset
*offset = spike_file_lseek(pf, 0, 1);
return read_len;
}
//
// write a hostfs file.
//
ssize_t hostfs_write(struct vinode *f_inode, const char *w_buf, ssize_t len,
int *offset) {
spike_file_t *pf = (spike_file_t *)f_inode->i_fs_info;
if (pf < 0) {
sprint("hostfs_write: invalid file handle!\n");
return -1;
}
int write_len = spike_file_write(pf, w_buf, len);
// obtain current offset
*offset = spike_file_lseek(pf, 0, 1);
return write_len;
}
//
// lookup a hostfs file, and establish its vfs inode in PKE vfs.
//
struct vinode *hostfs_lookup(struct vinode *parent, struct dentry *sub_dentry) {
// get complete path string
char path[MAX_PATH_LEN];
get_path_string(path, sub_dentry);
spike_file_t *f = spike_file_open(path, O_RDWR, 0);
struct vinode *child_inode = hostfs_alloc_vinode(parent->sb);
child_inode->i_fs_info = f;
hostfs_update_vinode(child_inode);
child_inode->ref = 0;
return child_inode;
}
//
// creates a hostfs file, and establish its vfs inode.
//
struct vinode *hostfs_create(struct vinode *parent, struct dentry *sub_dentry) {
char path[MAX_PATH_LEN];
get_path_string(path, sub_dentry);
spike_file_t *f = spike_file_open(path, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
if ((int64)f < 0) {
sprint("hostfs_create cannot create the given file.\n");
return NULL;
}
struct vinode *new_inode = hostfs_alloc_vinode(parent->sb);
new_inode->i_fs_info = f;
if (hostfs_update_vinode(new_inode) != 0) return NULL;
new_inode->ref = 0;
return new_inode;
}
//
// reposition read/write file offset
//
int hostfs_lseek(struct vinode *f_inode, ssize_t new_offset, int whence,
int *offset) {
spike_file_t *f = (spike_file_t *)f_inode->i_fs_info;
if (f < 0) {
sprint("hostfs_lseek: invalid file handle!\n");
return -1;
}
*offset = spike_file_lseek(f, new_offset, whence);
if (*offset >= 0)
return 0;
return -1;
}
int hostfs_link(struct vinode *parent, struct dentry *sub_dentry,
struct vinode *link_node) {
panic("hostfs_link not implemented!\n");
return -1;
}
int hostfs_unlink(struct vinode *parent, struct dentry *sub_dentry, struct vinode *unlink_node) {
panic("hostfs_unlink not implemented!\n");
return -1;
}
int hostfs_readdir(struct vinode *dir_vinode, struct dir *dir, int *offset) {
panic("hostfs_readdir not implemented!\n");
return -1;
}
struct vinode *hostfs_mkdir(struct vinode *parent, struct dentry *sub_dentry) {
panic("hostfs_mkdir not implemented!\n");
return NULL;
}
/**** vfs-hostfs hook interface functions ****/
//
// open a hostfs file (after having its vfs inode).
//
int hostfs_hook_open(struct vinode *f_inode, struct dentry *f_dentry) {
if (f_inode->i_fs_info != NULL) return 0;
char path[MAX_PATH_LEN];
get_path_string(path, f_dentry);
spike_file_t *f = spike_file_open(path, O_RDWR, 0);
if ((int64)f < 0) {
sprint("hostfs_hook_open cannot open the given file.\n");
return -1;
}
f_inode->i_fs_info = f;
return 0;
}
//
// close a hostfs file.
//
int hostfs_hook_close(struct vinode *f_inode, struct dentry *dentry) {
spike_file_t *f = (spike_file_t *)f_inode->i_fs_info;
spike_file_close(f);
return 0;
}
/**** vfs-hostfs file system type interface functions ****/
struct super_block *hostfs_get_superblock(struct device *dev) {
// set the data for the vfs super block
struct super_block *sb = alloc_page();
sb->s_dev = dev;
struct vinode *root_inode = hostfs_alloc_vinode(sb);
root_inode->type = H_DIR;
struct dentry *root_dentry = alloc_vfs_dentry("/", root_inode, NULL);
sb->s_root = root_dentry;
return sb;
}