|
|
|
/*
|
|
|
|
* 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;
|
|
|
|
}
|