init commit of lab4_2

lab4_2_directory
Zhiyuan Shao 2 years ago
parent bbcac5cf62
commit 3e29933551

@ -68,7 +68,7 @@ USER_CPPS := user/*.c
USER_CPPS := $(wildcard $(USER_CPPS))
USER_OBJS := $(addprefix $(OBJ_DIR)/, $(patsubst %.c,%.o,$(USER_CPPS)))
USER_TARGET := $(OBJ_DIR)/app_file
USER_TARGET := $(OBJ_DIR)/app_directory
#------------------------targets------------------------
$(OBJ_DIR):
@-mkdir -p $(OBJ_DIR)

@ -22,6 +22,10 @@ const struct vinode_ops hostfs_i_ops = {
.viop_hook_close = hostfs_hook_close,
.viop_write_back_vinode = hostfs_write_back_vinode,
// not implemented
.viop_readdir = hostfs_readdir,
.viop_mkdir = hostfs_mkdir,
};
/**** hostfs utility functions ****/
@ -229,6 +233,16 @@ int hostfs_lseek(struct vinode *f_inode, ssize_t new_offset, int whence,
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).

@ -30,6 +30,8 @@ int hostfs_lseek(struct vinode *f_inode, ssize_t new_offset, int whence,
int *offset);
int hostfs_hook_open(struct vinode *f_inode, struct dentry *f_dentry);
int hostfs_hook_close(struct vinode *f_inode, struct dentry *dentry);
int hostfs_readdir(struct vinode *dir_vinode, struct dir *dir, int *offset);
struct vinode *hostfs_mkdir(struct vinode *parent, struct dentry *sub_dentry);
struct super_block *hostfs_get_superblock(struct device *dev);
extern const struct vinode_ops hostfs_node_ops;

@ -160,3 +160,50 @@ int do_close(int fd) {
struct file *pfile = get_opened_file(fd);
return vfs_close(pfile);
}
//
// open a directory
// return: the fd of the directory file
//
int do_opendir(char *pathname) {
struct file *opened_file = NULL;
if ((opened_file = vfs_opendir(pathname)) == NULL) return -1;
int fd = 0;
struct file *pfile;
for (fd = 0; fd < MAX_FILES; ++fd) {
pfile = &(current->pfiles->opened_files[fd]);
if (pfile->status == FD_NONE) break;
}
if (pfile->status != FD_NONE) // no free entry
panic("do_opendir: no file entry for current process!\n");
// initialize this file structure
memcpy(pfile, opened_file, sizeof(struct file));
++current->pfiles->nfiles;
return fd;
}
//
// read a directory entry
//
int do_readdir(int fd, struct dir *dir) {
struct file *pfile = get_opened_file(fd);
return vfs_readdir(pfile, dir);
}
//
// make a new directory
//
int do_mkdir(char *pathname) {
return vfs_mkdir(pathname);
}
//
// close a directory
//
int do_closedir(int fd) {
struct file *pfile = get_opened_file(fd);
return vfs_closedir(pfile);
}

@ -16,6 +16,11 @@ int do_stat(int fd, struct istat *istat);
int do_disk_stat(int fd, struct istat *istat);
int do_close(int fd);
int do_opendir(char *pathname);
int do_readdir(int fd, struct dir *dir);
int do_mkdir(char *pathname);
int do_closedir(int fd);
void fs_init(void);
// data structure that manages all openned files in a PCB

@ -27,7 +27,13 @@ const struct vinode_ops rfs_i_ops = {
.viop_disk_stat = rfs_disk_stat,
.viop_lookup = rfs_lookup,
.viop_readdir = rfs_readdir,
.viop_mkdir = rfs_mkdir,
.viop_write_back_vinode = rfs_write_back_vinode,
.viop_hook_opendir = rfs_hook_opendir,
.viop_hook_closedir = rfs_hook_closedir,
};
/**** rfs utility functions ****/
@ -565,6 +571,137 @@ int rfs_disk_stat(struct vinode *vinode, struct istat *istat) {
return 0;
}
//
// when a directory is opened, the contents of the directory file are read
// into the memory for directory read operations
//
int rfs_hook_opendir(struct vinode *dir_vinode, struct dentry *dentry) {
// allocate space and read the contents of the dir block into memory
void *pdire = NULL;
void *previous = NULL;
struct rfs_device *rdev = rfs_device_list[dir_vinode->sb->s_dev->dev_id];
// read-in the directory file, store all direntries in dir cache.
for (int i = dir_vinode->blocks - 1; i >= 0; i--) {
previous = pdire;
pdire = alloc_page();
if (previous != NULL && previous - pdire != RFS_BLKSIZE)
panic("rfs_hook_opendir: memory discontinuity");
rfs_r1block(rdev, dir_vinode->addrs[i]);
memcpy(pdire, rdev->iobuffer, RFS_BLKSIZE);
}
// save the pointer to the directory block in the vinode
struct rfs_dir_cache *dir_cache = (struct rfs_dir_cache *)alloc_page();
dir_cache->block_count = dir_vinode->blocks;
dir_cache->dir_base_addr = (struct rfs_direntry *)pdire;
dir_vinode->i_fs_info = dir_cache;
return 0;
}
//
// when a directory is closed, the memory space allocated for the directory
// block is freed
//
int rfs_hook_closedir(struct vinode *dir_vinode, struct dentry *dentry) {
struct rfs_dir_cache *dir_cache =
(struct rfs_dir_cache *)dir_vinode->i_fs_info;
// reclaim the dir cache
for (int i = 0; i < dir_cache->block_count; ++i) {
free_page((char *)dir_cache->dir_base_addr + i * RFS_BLKSIZE);
}
return 0;
}
//
// read a directory entry from the directory "dir", and the "offset" indicate
// the position of the entry to be read. if offset is 0, the first entry is read,
// if offset is 1, the second entry is read, and so on.
// return: 0 on success, -1 when there are no more entry (end of the list).
//
int rfs_readdir(struct vinode *dir_vinode, struct dir *dir, int *offset) {
int total_direntrys = dir_vinode->size / sizeof(struct rfs_direntry);
int one_block_direntrys = RFS_BLKSIZE / sizeof(struct rfs_direntry);
int direntry_index = *offset;
if (direntry_index >= total_direntrys) {
// no more direntry
return -1;
}
// reads a directory entry from the directory cache stored in vfs inode.
struct rfs_dir_cache *dir_cache =
(struct rfs_dir_cache *)dir_vinode->i_fs_info;
struct rfs_direntry *p_direntry = dir_cache->dir_base_addr + direntry_index;
// TODO (lab4_2): implement the code to read a directory entry.
// hint: in the above code, we had found the directory entry that located at the
// *offset, and used p_direntry to point it.
// in the remaining processing, we need to return our discovery.
// the method of returning is to popular proper members of "dir", more specifically,
// dir->name and dir->inum.
// note: DO NOT DELETE CODE BELOW PANIC.
panic("You need to implement the code for reading a directory entry of rfs in lab4_2.\n" );
// DO NOT DELETE CODE BELOW.
(*offset)++;
return 0;
}
//
// make a new direntry named "sub_dentry->name" under the directory "parent",
// return the vfs inode of subdir being created.
//
struct vinode *rfs_mkdir(struct vinode *parent, struct dentry *sub_dentry) {
struct rfs_device *rdev = rfs_device_list[parent->sb->s_dev->dev_id];
// ** find a free disk inode to store the file that is going to be created
struct rfs_dinode *free_dinode = NULL;
int free_inum = 0;
for (int i = 0; i < (RFS_BLKSIZE / RFS_INODESIZE * RFS_MAX_INODE_BLKNUM); i++) {
free_dinode = rfs_read_dinode(rdev, i);
if (free_dinode->type == R_FREE) { // found
free_inum = i;
break;
}
free_page(free_dinode);
}
if (free_dinode == NULL)
panic( "rfs_mkdir: no more free disk inode, we cannot create directory.\n" );
// initialize the states of the file being created
free_dinode->size = 0;
free_dinode->type = R_DIR;
free_dinode->nlinks = 1;
free_dinode->blocks = 1;
// allocate a free block for the file
free_dinode->addrs[0] = rfs_alloc_block(parent->sb);
// ** write the disk inode of file being created to disk
rfs_write_dinode(rdev, free_dinode, free_inum);
free_page(free_dinode);
// ** add a direntry to the directory
int result = rfs_add_direntry(parent, sub_dentry->name, free_inum);
if (result == -1) {
sprint("rfs_mkdir: rfs_add_direntry failed");
return NULL;
}
// ** allocate a new vinode
struct vinode *sub_vinode = rfs_alloc_vinode(parent->sb);
sub_vinode->inum = free_inum;
rfs_update_vinode(sub_vinode);
return sub_vinode;
}
/**** vfs-rfs file system type interface functions ****/
struct super_block *rfs_get_superblock(struct device *dev) {
struct rfs_device *rdev = rfs_device_list[dev->dev_id];

@ -80,6 +80,11 @@ struct vinode *rfs_create(struct vinode *parent, struct dentry *sub_dentry);
int rfs_lseek(struct vinode *f_inode, ssize_t new_offset, int whence, int *offset);
int rfs_disk_stat(struct vinode *vinode, struct istat *istat);
int rfs_hook_opendir(struct vinode *dir_vinode, struct dentry *dentry);
int rfs_hook_closedir(struct vinode *dir_vinode, struct dentry *dentry);
int rfs_readdir(struct vinode *dir_vinode, struct dir *dir, int *offset);
struct vinode *rfs_mkdir(struct vinode *parent, struct dentry *sub_dentry);
struct super_block *rfs_get_superblock(struct device *dev);
extern const struct vinode_ops rfs_i_ops;

@ -165,6 +165,37 @@ ssize_t sys_user_close(int fd) {
return do_close(fd);
}
//
// lib call to opendir
//
ssize_t sys_user_opendir(char * pathva){
char * pathpa = (char*)user_va_to_pa((pagetable_t)(current->pagetable), pathva);
return do_opendir(pathpa);
}
//
// lib call to readdir
//
ssize_t sys_user_readdir(int fd, struct dir *vdir){
struct dir * pdir = (struct dir *)user_va_to_pa((pagetable_t)(current->pagetable), vdir);
return do_readdir(fd, pdir);
}
//
// lib call to mkdir
//
ssize_t sys_user_mkdir(char * pathva){
char * pathpa = (char*)user_va_to_pa((pagetable_t)(current->pagetable), pathva);
return do_mkdir(pathpa);
}
//
// lib call to closedir
//
ssize_t sys_user_closedir(int fd){
return do_closedir(fd);
}
//
// [a0]: the syscall number; [a1] ... [a7]: arguments to the syscalls.
// returns the code of success, (e.g., 0 means success, fail for otherwise)
@ -199,6 +230,15 @@ long do_syscall(long a0, long a1, long a2, long a3, long a4, long a5, long a6, l
return sys_user_disk_stat(a1, (struct istat *)a2);
case SYS_user_close:
return sys_user_close(a1);
// added @lab4_2
case SYS_user_opendir:
return sys_user_opendir((char *)a1);
case SYS_user_readdir:
return sys_user_readdir(a1, (struct dir *)a2);
case SYS_user_mkdir:
return sys_user_mkdir((char *)a1);
case SYS_user_closedir:
return sys_user_closedir(a1);
default:
panic("Unknown syscall %ld \n", a0);
}

@ -22,6 +22,11 @@
#define SYS_user_stat (SYS_user_base + 21)
#define SYS_user_disk_stat (SYS_user_base + 22)
#define SYS_user_close (SYS_user_base + 23)
// added @lab4_2
#define SYS_user_opendir (SYS_user_base + 24)
#define SYS_user_readdir (SYS_user_base + 25)
#define SYS_user_mkdir (SYS_user_base + 26)
#define SYS_user_closedir (SYS_user_base + 27)
long do_syscall(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7);

@ -296,6 +296,113 @@ int vfs_close(struct file *file) {
return 0;
}
//
// open a dir at vfs layer. the directory must exist on disk.
//
struct file *vfs_opendir(const char *path) {
struct dentry *parent = vfs_root_dentry;
char miss_name[MAX_PATH_LEN];
// lookup the dir
struct dentry *file_dentry = lookup_final_dentry(path, &parent, miss_name);
if (!file_dentry || file_dentry->dentry_inode->type != DIR_I) {
sprint("vfs_opendir: cannot find the direntry!\n");
return NULL;
}
// allocate a vfs file with readable/non-writable flag.
struct file *file = alloc_vfs_file(file_dentry, 1, 0, 0);
// additional open direntry operations for a specific file system
// rfs needs duild dir cache.
if (file_dentry->dentry_inode->i_ops->viop_hook_opendir) {
if (file_dentry->dentry_inode->i_ops->
viop_hook_opendir(file_dentry->dentry_inode, file_dentry) != 0) {
sprint("vfs_opendir: hook opendir failed!\n");
}
}
return file;
}
//
// read a direntry entry from a direntry specified by "file"
// the read direntry entry is stored in "dir"
//
int vfs_readdir(struct file *file, struct dir *dir) {
if (file->f_dentry->dentry_inode->type != DIR_I) {
sprint("vfs_readdir: cannot read a file!\n");
return -1;
}
return viop_readdir(file->f_dentry->dentry_inode, dir, &(file->offset));
}
//
// make a new directory specified by "path" at vfs layer.
// note that only the last level directory of the path will be created,
// and its parent directory must exist.
//
int vfs_mkdir(const char *path) {
struct dentry *parent = vfs_root_dentry;
char miss_name[MAX_PATH_LEN];
// lookup the dir, find its parent direntry
struct dentry *file_dentry = lookup_final_dentry(path, &parent, miss_name);
if (file_dentry) {
sprint("vfs_mkdir: the directory already exists!\n");
return -1;
}
char basename[MAX_PATH_LEN];
get_base_name(path, basename);
if (strcmp(miss_name, basename) != 0) {
sprint("vfs_mkdir: cannot create directory in a non-exist directory!\n");
return -1;
}
// do real mkdir
struct dentry *new_dentry = alloc_vfs_dentry(basename, NULL, parent);
struct vinode *new_dir_inode = viop_mkdir(parent->dentry_inode, new_dentry);
if (!new_dir_inode) {
free_page(new_dentry);
sprint("vfs_mkdir: cannot create directory!\n");
return -1;
}
new_dentry->dentry_inode = new_dir_inode;
new_dir_inode->ref++;
hash_put_dentry(new_dentry);
hash_put_vinode(new_dir_inode);
return 0;
}
//
// close a directory at vfs layer
//
int vfs_closedir(struct file *file) {
if (file->f_dentry->dentry_inode->type != DIR_I) {
sprint("vfs_closedir: cannot close a file!\n");
return -1;
}
// even if a directory is no longer referenced, it will not be freed because
// it will serve as a cache for later lookup operations on it or its
// descendants
file->f_dentry->d_ref--;
file->status = FD_NONE;
// additional close direntry operations for a specific file system
// rfs needs reclaim dir cache.
if (file->f_dentry->dentry_inode->i_ops->viop_hook_closedir) {
if (file->f_dentry->dentry_inode->i_ops->
viop_hook_closedir(file->f_dentry->dentry_inode, file->f_dentry) != 0) {
sprint("vfs_closedir: hook closedir failed!\n");
}
}
return 0;
}
//
// lookup the "path" and return its dentry (or NULL if not found).
// the lookup starts from parent, and stop till the full "path" is parsed.

@ -30,6 +30,12 @@ int vfs_stat(struct file *file, struct istat *istat);
int vfs_disk_stat(struct file *file, struct istat *istat);
int vfs_close(struct file *file);
// directory interfaces
struct file *vfs_opendir(const char *path);
int vfs_readdir(struct file *file, struct dir *dir);
int vfs_mkdir(const char *path);
int vfs_closedir(struct file *file);
/**** vfs abstract object types ****/
// system root direntry
extern struct dentry *vfs_root_dentry;
@ -137,6 +143,10 @@ struct vinode_ops {
struct vinode *(*viop_lookup)(struct vinode *parent,
struct dentry *sub_dentry);
// directory operations
int (*viop_readdir)(struct vinode *dir_vinode, struct dir *dir, int *offset);
struct vinode *(*viop_mkdir)(struct vinode *parent, struct dentry *sub_dentry);
// write back inode to disk
int (*viop_write_back_vinode)(struct vinode *node);
@ -148,6 +158,8 @@ struct vinode_ops {
// times.
int (*viop_hook_open)(struct vinode *node, struct dentry *dentry);
int (*viop_hook_close)(struct vinode *node, struct dentry *dentry);
int (*viop_hook_opendir)(struct vinode *node, struct dentry *dentry);
int (*viop_hook_closedir)(struct vinode *node, struct dentry *dentry);
};
// vinode operation interface
@ -160,6 +172,8 @@ struct vinode_ops {
#define viop_lseek(node, new_off, whence, off) (node->i_ops->viop_lseek(node, new_off, whence, off))
#define viop_disk_stat(node, istat) (node->i_ops->viop_disk_stat(node, istat))
#define viop_lookup(parent, sub_dentry) (parent->i_ops->viop_lookup(parent, sub_dentry))
#define viop_readdir(dir_vinode, dir, offset) (dir_vinode->i_ops->viop_readdir(dir_vinode, dir, offset))
#define viop_mkdir(dir, sub_dentry) (dir->i_ops->viop_mkdir(dir, sub_dentry))
#define viop_write_back_vinode(node) (node->i_ops->viop_write_back_vinode(node))
// vinode hash table

@ -0,0 +1,60 @@
#include "user_lib.h"
#include "util/string.h"
#include "util/types.h"
void ls(char *path) {
int dir_fd = opendir_u(path);
printu("------------------------------\n");
printu("ls \"%s\":\n", path);
printu("[name] [inode_num]\n");
struct dir dir;
int width = 20;
while(readdir_u(dir_fd, &dir) == 0) {
// we do not have %ms :(
char name[width + 1];
memset(name, ' ', width + 1);
name[width] = '\0';
if (strlen(dir.name) < width) {
strcpy(name, dir.name);
name[strlen(dir.name)] = ' ';
printu("%s %d\n", name, dir.inum);
}
else
printu("%s %d\n", dir.name, dir.inum);
}
printu("------------------------------\n");
closedir_u(dir_fd);
}
int main(int argc, char *argv[]) {
char str[] = "hello world";
int fd;
printu("\n======== Test 1: open and read dir ========\n");
ls("/RAMDISK0");
printu("\n======== Test 2: make dir ========\n");
mkdir_u("/RAMDISK0/sub_dir");
printu("make: /RAMDISK0/sub_dir\n");
ls("/RAMDISK0");
// try to write a file in the new dir
printu("write: /RAMDISK0/sub_dir/ramfile\n");
fd = open("/RAMDISK0/sub_dir/ramfile", O_RDWR | O_CREAT);
printu("file descriptor fd: %d\n", fd);
write_u(fd, str, strlen(str));
printu("write content: \n%s\n", str);
close(fd);
ls("/RAMDISK0/sub_dir");
printu("\nAll tests passed!\n\n");
exit(0);
return 0;
}

@ -1,63 +0,0 @@
#include "user_lib.h"
#include "util/string.h"
#include "util/types.h"
int main(int argc, char *argv[]) {
int fd;
int MAXBUF = 512;
char buf[MAXBUF];
char str[] = "hello world";
int fd1, fd2;
printu("\n======== Test 1: read host file ========\n");
printu("read: /hostfile.txt\n");
fd = open("/hostfile.txt", O_RDONLY);
printu("file descriptor fd: %d\n", fd);
read_u(fd, buf, MAXBUF);
printu("read content: \n%s\n", buf);
close(fd);
printu("\n======== Test 2: create/write rfs file ========\n");
printu("write: /RAMDISK0/ramfile\n");
fd = open("/RAMDISK0/ramfile", O_RDWR | O_CREAT);
printu("file descriptor fd: %d\n", fd);
write_u(fd, buf, strlen(buf));
printu("write content: \n%s\n", buf);
close(fd);
printu("\n======== Test 3: read rfs file ========\n");
printu("read: /RAMDISK0/ramfile\n");
fd = open("/RAMDISK0/ramfile", O_RDWR);
printu("file descriptor fd: %d\n", fd);
read_u(fd, buf, MAXBUF);
printu("read content: \n%s\n", buf);
close(fd);
printu("\n======== Test 4: open twice ========\n");
fd1 = open("/RAMDISK0/ramfile", O_RDWR | O_CREAT);
fd2 = open("/RAMDISK0/ramfile", O_RDWR | O_CREAT);
printu("file descriptor fd1(ramfile): %d\n", fd1);
printu("file descriptor fd2(ramfile): %d\n", fd2);
write_u(fd1, str, strlen(str));
printu("write content: \n%s\n", str);
read_u(fd2, buf, MAXBUF);
printu("read content: \n%s\n", buf);
close(fd1);
close(fd2);
printu("\nAll tests passed!\n\n");
exit(0);
return 0;
}

@ -119,6 +119,34 @@ int disk_stat_u(int fd, struct istat *istat) {
return do_user_call(SYS_user_disk_stat, fd, (uint64)istat, 0, 0, 0, 0, 0);
}
//
// lib call to open dir
//
int opendir_u(const char *dirname) {
return do_user_call(SYS_user_opendir, (uint64)dirname, 0, 0, 0, 0, 0, 0);
}
//
// lib call to read dir
//
int readdir_u(int fd, struct dir *dir) {
return do_user_call(SYS_user_readdir, fd, (uint64)dir, 0, 0, 0, 0, 0);
}
//
// lib call to make dir
//
int mkdir_u(const char *pathname) {
return do_user_call(SYS_user_mkdir, (uint64)pathname, 0, 0, 0, 0, 0, 0);
}
//
// lib call to close dir
//
int closedir_u(int fd) {
return do_user_call(SYS_user_closedir, fd, 0, 0, 0, 0, 0, 0);
}
//
// lib call to close
//

@ -23,4 +23,10 @@ int stat_u(int fd, struct istat *istat);
int disk_stat_u(int fd, struct istat *istat);
int close(int fd);
// added @ lab4_2
int opendir_u(const char *pathname);
int readdir_u(int fd, struct dir *dir);
int mkdir_u(const char *pathname);
int closedir_u(int fd);
#endif

@ -42,6 +42,11 @@ typedef unsigned long size_t;
#define MAX_FILE_NAME_LEN 32
struct dir {
char name[MAX_FILE_NAME_LEN];
int inum;
};
struct istat {
int st_inum;
int st_size;

Loading…
Cancel
Save