diff --git a/kernel/rustkernel/src/fs/file.rs b/kernel/rustkernel/src/fs/file.rs index 59ec72d..2db3215 100644 --- a/kernel/rustkernel/src/fs/file.rs +++ b/kernel/rustkernel/src/fs/file.rs @@ -54,23 +54,28 @@ impl File { #[repr(C)] pub struct Inode { /// Device number. - device: u32, + pub device: u32, /// Inode number. - inum: u32, + pub inum: u32, /// Reference count. - references: i32, + pub references: i32, - lock: Sleeplock, + pub lock: Sleeplock, /// Inode has been read from disk? - valid: i32, + pub valid: i32, // Copy of DiskInode - kind: i16, - major: i16, - minor: i16, - num_links: i16, - size: u32, - addresses: [u32; crate::fs::NDIRECT + 1], + pub kind: i16, + pub major: i16, + pub minor: i16, + pub num_links: i16, + pub size: u32, + pub addresses: [u32; crate::fs::NDIRECT + 1], +} +impl Inode { + pub fn lock(&mut self) -> InodeLockGuard<'_> { + InodeLockGuard::new(self) + } } pub struct InodeLockGuard<'i> { @@ -236,7 +241,10 @@ pub unsafe extern "C" fn fileread(file: *mut File, addr: u64, num_bytes: i32) -> } match (*file).kind { - FileType::Pipe => (*(*file).pipe).read(addr, num_bytes as usize).map(|n| n as i32).unwrap_or(-1i32), + FileType::Pipe => (*(*file).pipe) + .read(addr, num_bytes as usize) + .map(|n| n as i32) + .unwrap_or(-1i32), FileType::Device => { if (*file).major < 0 || (*file).major >= crate::NDEV as i16 { return -1; @@ -269,7 +277,10 @@ pub unsafe extern "C" fn filewrite(file: *mut File, addr: u64, num_bytes: i32) - } match (*file).kind { - FileType::Pipe => (*(*file).pipe).write(addr, num_bytes as usize).map(|n| n as i32).unwrap_or(-1i32), + FileType::Pipe => (*(*file).pipe) + .write(addr, num_bytes as usize) + .map(|n| n as i32) + .unwrap_or(-1i32), FileType::Device => { if (*file).major < 0 || (*file).major >= crate::NDEV as i16 { return -1; diff --git a/kernel/rustkernel/src/fs/mod.rs b/kernel/rustkernel/src/fs/mod.rs index c944880..91b6ff5 100644 --- a/kernel/rustkernel/src/fs/mod.rs +++ b/kernel/rustkernel/src/fs/mod.rs @@ -100,5 +100,6 @@ extern "C" { pub fn stati(ip: *mut Inode, st: *mut stat::Stat); pub fn readi(ip: *mut Inode, user_dst: i32, dst: u64, off: u32, n: u32) -> i32; pub fn writei(ip: *mut Inode, user_src: i32, src: u64, off: u32, n: u32) -> i32; + pub fn namei(path: *mut u8) -> *mut Inode; // pub fn namecmp() } diff --git a/kernel/rustkernel/src/fs/stat.rs b/kernel/rustkernel/src/fs/stat.rs index 043173f..000bd87 100644 --- a/kernel/rustkernel/src/fs/stat.rs +++ b/kernel/rustkernel/src/fs/stat.rs @@ -1,9 +1,6 @@ -#[repr(C)] -pub enum StatType { - Directory = 1, - File, - Device, -} +pub const KIND_DIR: i16 = 1; +pub const KIND_FILE: i16 = 2; +pub const KIND_DEVICE: i16 = 3; #[repr(C)] #[derive(Default)] diff --git a/kernel/rustkernel/src/proc.rs b/kernel/rustkernel/src/proc.rs index 3d7f572..87f670a 100644 --- a/kernel/rustkernel/src/proc.rs +++ b/kernel/rustkernel/src/proc.rs @@ -2,6 +2,7 @@ use crate::{ arch::riscv::{intr_get, r_tp, Pagetable, PTE_W}, + fs::file::{File, Inode}, mem::kalloc::kfree, sync::spinlock::{Spinlock, SpinlockGuard}, }; @@ -214,9 +215,9 @@ pub struct Proc { /// swtch() here to run process pub context: Context, /// Open files - pub ofile: *mut u8, // TODO: Change u8 ptr to File ptr. + pub ofile: [*mut File; crate::NOFILE], /// Current directory - pub cwd: *mut u8, // TODO: Change u8 ptr to inode ptr. + pub cwd: *mut Inode, /// Process name (debugging) pub name: [c_char; 16], } diff --git a/kernel/rustkernel/src/syscall.rs b/kernel/rustkernel/src/syscall.rs index 2284719..dc279da 100644 --- a/kernel/rustkernel/src/syscall.rs +++ b/kernel/rustkernel/src/syscall.rs @@ -1,30 +1,33 @@ use crate::{ arch::riscv::memlayout::QEMU_POWER, + fs::{ + self, + file::{self, File, Inode}, + log::{self, LogOperation}, + stat::KIND_DIR, + }, mem::virtual_memory::{copyin, copyinstr}, println, proc::{self, myproc}, string::strlen, trap::CLOCK_TICKS, + NOFILE, }; use core::{ mem::size_of, - ptr::{addr_of, addr_of_mut}, + ptr::{addr_of, addr_of_mut, null_mut}, }; extern "C" { fn sys_pipe() -> u64; - fn sys_read() -> u64; fn sys_exec() -> u64; fn sys_fstat() -> u64; fn sys_chdir() -> u64; - fn sys_dup() -> u64; fn sys_open() -> u64; - fn sys_write() -> u64; fn sys_mknod() -> u64; fn sys_unlink() -> u64; fn sys_link() -> u64; fn sys_mkdir() -> u64; - fn sys_close() -> u64; } pub enum Syscall { @@ -66,16 +69,76 @@ impl Syscall { proc::wait(p) as u64 } Syscall::Pipe => sys_pipe(), - Syscall::Read => sys_read(), + Syscall::Read => { + let mut file: *mut File = null_mut(); + let mut num_bytes: i32 = 0; + let mut ptr: u64 = 0; + + if argfd(0, null_mut(), addr_of_mut!(file)) >= 0 { + argaddr(1, addr_of_mut!(ptr)); + argint(2, addr_of_mut!(num_bytes)); + file::fileread(file, ptr, num_bytes) as i64 as u64 + } else { + -1i64 as u64 + } + } Syscall::Kill => { let mut pid = 0i32; argint(0, addr_of_mut!(pid)); proc::kill(pid) as u64 } Syscall::Exec => sys_exec(), - Syscall::Fstat => sys_fstat(), - Syscall::Chdir => sys_chdir(), - Syscall::Dup => sys_dup(), + Syscall::Fstat => { + let mut file: *mut File = null_mut(); + // User pointer to struct stat. + let mut stat: u64 = 0; + + if argfd(0, null_mut(), addr_of_mut!(file)) >= 0 { + argaddr(1, addr_of_mut!(stat)); + file::filestat(file, stat) as i64 as u64 + } else { + -1i64 as u64 + } + } + Syscall::Chdir => { + let mut path = [0u8; crate::MAXPATH]; + let mut inode: *mut Inode = null_mut(); + let mut p = myproc(); + + let _operation = LogOperation::new(); + + if argstr(0, addr_of_mut!(path).cast(), path.len() as i32) < 0 { + return -1i64 as u64; + } + inode = fs::namei(addr_of_mut!(path).cast()); + if inode.is_null() { + return -1i64 as u64; + } + fs::ilock(inode); + if (*inode).kind != KIND_DIR { + fs::iunlock(inode); + fs::iput(inode); + return -1i64 as u64; + } + fs::iunlock(inode); + fs::iput((*p).cwd); + (*p).cwd = inode; + 0 + } + Syscall::Dup => { + let mut file: *mut File = null_mut(); + + if argfd(0, null_mut(), addr_of_mut!(file)) < 0 { + return -1i64 as u64; + } + + let Ok(file_descriptor) = fdalloc(file) else { + return -1i64 as u64; + }; + + file::filedup(file); + file_descriptor as u64 + } Syscall::Getpid => (*myproc()).pid as u64, Syscall::Sbrk => { let mut n = 0i32; @@ -106,12 +169,36 @@ impl Syscall { // Returns how many clock tick interrupts have occured since start. Syscall::Uptime => *CLOCK_TICKS.lock_spinning() as u64, Syscall::Open => sys_open(), - Syscall::Write => sys_write(), + Syscall::Write => { + let mut file: *mut File = null_mut(); + let mut num_bytes: i32 = 0; + let mut ptr: u64 = 0; + + if argfd(0, null_mut(), addr_of_mut!(file)) >= 0 { + argaddr(1, addr_of_mut!(ptr)); + argint(2, addr_of_mut!(num_bytes)); + file::filewrite(file, ptr, num_bytes) as i64 as u64 + } else { + -1i64 as u64 + } + } + Syscall::Mknod => sys_mknod(), Syscall::Unlink => sys_unlink(), Syscall::Link => sys_link(), Syscall::Mkdir => sys_mkdir(), - Syscall::Close => sys_close(), + Syscall::Close => { + let mut file_descriptor: i32 = 0; + let mut file: *mut File = null_mut(); + + if argfd(0, addr_of_mut!(file_descriptor), addr_of_mut!(file)) >= 0 { + (*myproc()).ofile[file_descriptor as usize] = null_mut(); + file::fileclose(file); + 0 + } else { + -1i64 as u64 + } + } Syscall::Shutdown => { let qemu_power = QEMU_POWER as usize as *mut u32; qemu_power.write_volatile(0x5555u32); @@ -214,10 +301,22 @@ pub unsafe extern "C" fn fetchstr(addr: u64, buf: *mut u8, max: i32) -> i32 { } } -#[no_mangle] -pub unsafe extern "C" fn argraw(n: i32) -> u64 { +/// Allocate a file descriptor for the given file. +/// Takes over file reference from caller on success. +unsafe fn fdalloc(file: *mut File) -> Result { let p = myproc(); - match n { + for file_descriptor in 0..crate::NOFILE { + if (*p).ofile[file_descriptor].is_null() { + (*p).ofile[file_descriptor] = file; + return Ok(file_descriptor); + } + } + Err(()) +} + +unsafe fn argraw(argument_index: usize) -> u64 { + let p = myproc(); + match argument_index { 0 => (*(*p).trapframe).a0, 1 => (*(*p).trapframe).a1, 2 => (*(*p).trapframe).a2, @@ -231,7 +330,7 @@ pub unsafe extern "C" fn argraw(n: i32) -> u64 { /// Fetch the n-th 32-bit syscall argument. #[no_mangle] pub unsafe extern "C" fn argint(n: i32, ip: *mut i32) { - *ip = argraw(n) as i32; + *ip = argraw(n as usize) as i32; } /// Retrieve an argument as a pointer. @@ -240,7 +339,34 @@ pub unsafe extern "C" fn argint(n: i32, ip: *mut i32) { /// copyin/copyout will do that. #[no_mangle] pub unsafe extern "C" fn argaddr(n: i32, ip: *mut u64) { - *ip = argraw(n); + *ip = argraw(n as usize); +} + +/// Fetch the n-th word-sized syscall argument as a file descriptor +/// and return both the descriptor and the corresponding struct file. +#[no_mangle] +pub unsafe extern "C" fn argfd( + n: i32, + file_descriptor_out: *mut i32, + file_out: *mut *mut File, +) -> i32 { + let file_descriptor = argraw(n as usize) as usize; + if file_descriptor >= NOFILE { + return -1; + } + + let file: *mut File = (*myproc()).ofile[file_descriptor]; + if file.is_null() { + return -1; + } + + if !file_descriptor_out.is_null() { + *file_descriptor_out = file_descriptor as i32; + } + if !file_out.is_null() { + *file_out = file; + } + 0 } /// Fetch the n-th word-sized syscall argument as a null-terminated string. diff --git a/kernel/sysfile.c b/kernel/sysfile.c index 16b668c..29e8bc1 100644 --- a/kernel/sysfile.c +++ b/kernel/sysfile.c @@ -18,21 +18,7 @@ // Fetch the nth word-sized system call argument as a file descriptor // and return both the descriptor and the corresponding struct file. -static int -argfd(int n, int *pfd, struct file **pf) -{ - int fd; - struct file *f; - - argint(n, &fd); - if(fd < 0 || fd >= NOFILE || (f=myproc()->ofile[fd]) == 0) - return -1; - if(pfd) - *pfd = fd; - if(pf) - *pf = f; - return 0; -} +int argfd(int n, int *pfd, struct file **pf); // Allocate a file descriptor for the given file. // Takes over file reference from caller on success. @@ -42,8 +28,10 @@ fdalloc(struct file *f) int fd; struct proc *p = myproc(); - for(fd = 0; fd < NOFILE; fd++){ - if(p->ofile[fd] == 0){ + for (fd = 0; fd < NOFILE; fd++) + { + if (p->ofile[fd] == 0) + { p->ofile[fd] = f; return fd; } @@ -51,74 +39,6 @@ fdalloc(struct file *f) return -1; } -uint64 -sys_dup(void) -{ - struct file *f; - int fd; - - if(argfd(0, 0, &f) < 0) - return -1; - if((fd=fdalloc(f)) < 0) - return -1; - filedup(f); - return fd; -} - -uint64 -sys_read(void) -{ - struct file *f; - int n; - uint64 p; - - argaddr(1, &p); - argint(2, &n); - if(argfd(0, 0, &f) < 0) - return -1; - return fileread(f, p, n); -} - -uint64 -sys_write(void) -{ - struct file *f; - int n; - uint64 p; - - argaddr(1, &p); - argint(2, &n); - if(argfd(0, 0, &f) < 0) - return -1; - - return filewrite(f, p, n); -} - -uint64 -sys_close(void) -{ - int fd; - struct file *f; - - if(argfd(0, &fd, &f) < 0) - return -1; - myproc()->ofile[fd] = 0; - fileclose(f); - return 0; -} - -uint64 -sys_fstat(void) -{ - struct file *f; - uint64 st; // user pointer to struct stat - - argaddr(1, &st); - if(argfd(0, 0, &f) < 0) - return -1; - return filestat(f, st); -} - // Create the path new as a link to the same inode as old. uint64 sys_link(void) @@ -126,17 +46,19 @@ sys_link(void) char name[DIRSIZ], new[MAXPATH], old[MAXPATH]; struct inode *dp, *ip; - if(argstr(0, old, MAXPATH) < 0 || argstr(1, new, MAXPATH) < 0) + if (argstr(0, old, MAXPATH) < 0 || argstr(1, new, MAXPATH) < 0) return -1; begin_op(); - if((ip = namei(old)) == 0){ + if ((ip = namei(old)) == 0) + { end_op(); return -1; } ilock(ip); - if(ip->type == T_DIR){ + if (ip->type == T_DIR) + { iunlockput(ip); end_op(); return -1; @@ -146,10 +68,11 @@ sys_link(void) iupdate(ip); iunlock(ip); - if((dp = nameiparent(new, name)) == 0) + if ((dp = nameiparent(new, name)) == 0) goto bad; ilock(dp); - if(dp->dev != ip->dev || dirlink(dp, name, ip->inum) < 0){ + if (dp->dev != ip->dev || dirlink(dp, name, ip->inum) < 0) + { iunlockput(dp); goto bad; } @@ -176,10 +99,11 @@ isdirempty(struct inode *dp) int off; struct dirent de; - for(off=2*sizeof(de); offsize; off+=sizeof(de)){ - if(readi(dp, 0, (uint64)&de, off, sizeof(de)) != sizeof(de)) + for (off = 2 * sizeof(de); off < dp->size; off += sizeof(de)) + { + if (readi(dp, 0, (uint64)&de, off, sizeof(de)) != sizeof(de)) panic("isdirempty: readi"); - if(de.inum != 0) + if (de.inum != 0) return 0; } return 1; @@ -193,11 +117,12 @@ sys_unlink(void) char name[DIRSIZ], path[MAXPATH]; uint off; - if(argstr(0, path, MAXPATH) < 0) + if (argstr(0, path, MAXPATH) < 0) return -1; begin_op(); - if((dp = nameiparent(path, name)) == 0){ + if ((dp = nameiparent(path, name)) == 0) + { end_op(); return -1; } @@ -205,24 +130,26 @@ sys_unlink(void) ilock(dp); // Cannot unlink "." or "..". - if(namecmp(name, ".") == 0 || namecmp(name, "..") == 0) + if (namecmp(name, ".") == 0 || namecmp(name, "..") == 0) goto bad; - if((ip = dirlookup(dp, name, &off)) == 0) + if ((ip = dirlookup(dp, name, &off)) == 0) goto bad; ilock(ip); - if(ip->nlink < 1) + if (ip->nlink < 1) panic("unlink: nlink < 1"); - if(ip->type == T_DIR && !isdirempty(ip)){ + if (ip->type == T_DIR && !isdirempty(ip)) + { iunlockput(ip); goto bad; } memset(&de, 0, sizeof(de)); - if(writei(dp, 0, (uint64)&de, off, sizeof(de)) != sizeof(de)) + if (writei(dp, 0, (uint64)&de, off, sizeof(de)) != sizeof(de)) panic("unlink: writei"); - if(ip->type == T_DIR){ + if (ip->type == T_DIR) + { dp->nlink--; iupdate(dp); } @@ -242,27 +169,29 @@ bad: return -1; } -static struct inode* +static struct inode * create(char *path, short type, short major, short minor) { struct inode *ip, *dp; char name[DIRSIZ]; - if((dp = nameiparent(path, name)) == 0) + if ((dp = nameiparent(path, name)) == 0) return 0; ilock(dp); - if((ip = dirlookup(dp, name, 0)) != 0){ + if ((ip = dirlookup(dp, name, 0)) != 0) + { iunlockput(dp); ilock(ip); - if(type == T_FILE && (ip->type == T_FILE || ip->type == T_DEVICE)) + if (type == T_FILE && (ip->type == T_FILE || ip->type == T_DEVICE)) return ip; iunlockput(ip); return 0; } - if((ip = ialloc(dp->dev, type)) == 0){ + if ((ip = ialloc(dp->dev, type)) == 0) + { iunlockput(dp); return 0; } @@ -273,18 +202,20 @@ create(char *path, short type, short major, short minor) ip->nlink = 1; iupdate(ip); - if(type == T_DIR){ // Create . and .. entries. + if (type == T_DIR) + { // Create . and .. entries. // No ip->nlink++ for ".": avoid cyclic ref count. - if(dirlink(ip, ".", ip->inum) < 0 || dirlink(ip, "..", dp->inum) < 0) + if (dirlink(ip, ".", ip->inum) < 0 || dirlink(ip, "..", dp->inum) < 0) goto fail; } - if(dirlink(dp, name, ip->inum) < 0) + if (dirlink(dp, name, ip->inum) < 0) goto fail; - if(type == T_DIR){ + if (type == T_DIR) + { // now that success is guaranteed: - dp->nlink++; // for ".." + dp->nlink++; // for ".." iupdate(dp); } @@ -292,7 +223,7 @@ create(char *path, short type, short major, short minor) return ip; - fail: +fail: // something went wrong. de-allocate ip. ip->nlink = 0; iupdate(ip); @@ -311,48 +242,59 @@ sys_open(void) int n; argint(1, &omode); - if((n = argstr(0, path, MAXPATH)) < 0) + if ((n = argstr(0, path, MAXPATH)) < 0) return -1; begin_op(); - if(omode & O_CREATE){ + if (omode & O_CREATE) + { ip = create(path, T_FILE, 0, 0); - if(ip == 0){ + if (ip == 0) + { end_op(); return -1; } - } else { - if((ip = namei(path)) == 0){ + } + else + { + if ((ip = namei(path)) == 0) + { end_op(); return -1; } ilock(ip); - if(ip->type == T_DIR && omode != O_RDONLY){ + if (ip->type == T_DIR && omode != O_RDONLY) + { iunlockput(ip); end_op(); return -1; } } - if(ip->type == T_DEVICE && (ip->major < 0 || ip->major >= NDEV)){ + if (ip->type == T_DEVICE && (ip->major < 0 || ip->major >= NDEV)) + { iunlockput(ip); end_op(); return -1; } - if((f = filealloc()) == 0 || (fd = fdalloc(f)) < 0){ - if(f) + if ((f = filealloc()) == 0 || (fd = fdalloc(f)) < 0) + { + if (f) fileclose(f); iunlockput(ip); end_op(); return -1; } - if(ip->type == T_DEVICE){ + if (ip->type == T_DEVICE) + { f->type = FD_DEVICE; f->major = ip->major; - } else { + } + else + { f->type = FD_INODE; f->off = 0; } @@ -360,7 +302,8 @@ sys_open(void) f->readable = !(omode & O_WRONLY); f->writable = (omode & O_WRONLY) || (omode & O_RDWR); - if((omode & O_TRUNC) && ip->type == T_FILE){ + if ((omode & O_TRUNC) && ip->type == T_FILE) + { itrunc(ip); } @@ -377,7 +320,8 @@ sys_mkdir(void) struct inode *ip; begin_op(); - if(argstr(0, path, MAXPATH) < 0 || (ip = create(path, T_DIR, 0, 0)) == 0){ + if (argstr(0, path, MAXPATH) < 0 || (ip = create(path, T_DIR, 0, 0)) == 0) + { end_op(); return -1; } @@ -396,8 +340,9 @@ sys_mknod(void) begin_op(); argint(1, &major); argint(2, &minor); - if((argstr(0, path, MAXPATH)) < 0 || - (ip = create(path, T_DEVICE, major, minor)) == 0){ + if ((argstr(0, path, MAXPATH)) < 0 || + (ip = create(path, T_DEVICE, major, minor)) == 0) + { end_op(); return -1; } @@ -406,31 +351,6 @@ sys_mknod(void) return 0; } -uint64 -sys_chdir(void) -{ - char path[MAXPATH]; - struct inode *ip; - struct proc *p = myproc(); - - begin_op(); - if(argstr(0, path, MAXPATH) < 0 || (ip = namei(path)) == 0){ - end_op(); - return -1; - } - ilock(ip); - if(ip->type != T_DIR){ - iunlockput(ip); - end_op(); - return -1; - } - iunlock(ip); - iput(p->cwd); - end_op(); - p->cwd = ip; - return 0; -} - uint64 sys_exec(void) { @@ -439,37 +359,42 @@ sys_exec(void) uint64 uargv, uarg; argaddr(1, &uargv); - if(argstr(0, path, MAXPATH) < 0) { + if (argstr(0, path, MAXPATH) < 0) + { return -1; } memset(argv, 0, sizeof(argv)); - for(i=0;; i++){ - if(i >= NELEM(argv)){ + for (i = 0;; i++) + { + if (i >= NELEM(argv)) + { goto bad; } - if(fetchaddr(uargv+sizeof(uint64)*i, (uint64*)&uarg) < 0){ + if (fetchaddr(uargv + sizeof(uint64) * i, (uint64 *)&uarg) < 0) + { goto bad; } - if(uarg == 0){ + if (uarg == 0) + { argv[i] = 0; break; } argv[i] = kalloc(); - if(argv[i] == 0) + if (argv[i] == 0) goto bad; - if(fetchstr(uarg, argv[i], PGSIZE) < 0) + if (fetchstr(uarg, argv[i], PGSIZE) < 0) goto bad; } int ret = exec(path, argv); - for(i = 0; i < NELEM(argv) && argv[i] != 0; i++) + for (i = 0; i < NELEM(argv) && argv[i] != 0; i++) kfree(argv[i]); return ret; - bad: - for(i = 0; i < NELEM(argv) && argv[i] != 0; i++) +bad: + for (i = 0; i < NELEM(argv) && argv[i] != 0; i++) kfree(argv[i]); return -1; } @@ -483,18 +408,20 @@ sys_pipe(void) struct proc *p = myproc(); argaddr(0, &fdarray); - if(pipealloc(&rf, &wf) < 0) + if (pipealloc(&rf, &wf) < 0) return -1; fd0 = -1; - if((fd0 = fdalloc(rf)) < 0 || (fd1 = fdalloc(wf)) < 0){ - if(fd0 >= 0) + if ((fd0 = fdalloc(rf)) < 0 || (fd1 = fdalloc(wf)) < 0) + { + if (fd0 >= 0) p->ofile[fd0] = 0; fileclose(rf); fileclose(wf); return -1; } - if(copyout(p->pagetable, fdarray, (char*)&fd0, sizeof(fd0)) < 0 || - copyout(p->pagetable, fdarray+sizeof(fd0), (char *)&fd1, sizeof(fd1)) < 0){ + if (copyout(p->pagetable, fdarray, (char *)&fd0, sizeof(fd0)) < 0 || + copyout(p->pagetable, fdarray + sizeof(fd0), (char *)&fd1, sizeof(fd1)) < 0) + { p->ofile[fd0] = 0; p->ofile[fd1] = 0; fileclose(rf);