From 2d74b6e6fa47d5ed6b608ff4b6feb8627ab04ef0 Mon Sep 17 00:00:00 2001 From: Stephen Marz Date: Sat, 16 May 2020 10:41:38 -0400 Subject: [PATCH] Formatting --- risc_v/src/buffer.rs | 3 +- risc_v/src/fs.rs | 237 ++++++++++++++++++++++++++++++------------- 2 files changed, 165 insertions(+), 75 deletions(-) diff --git a/risc_v/src/buffer.rs b/risc_v/src/buffer.rs index 7a1a729..5e8dde2 100755 --- a/risc_v/src/buffer.rs +++ b/risc_v/src/buffer.rs @@ -4,8 +4,7 @@ // Stephen Marz use crate::{cpu::memcpy, kmem::{kmalloc, kfree}}; -use core::ptr::null_mut; -use core::ops::{Index, IndexMut}; +use core::{ptr::null_mut, ops::{Index, IndexMut}}; // We need a Buffer that can automatically be created and destroyed // in the lifetime of our read and write functions. In C, this would entail // goto statements that "unravel" all of the allocations that we made. Take diff --git a/risc_v/src/fs.rs b/risc_v/src/fs.rs index 3c63489..127797b 100755 --- a/risc_v/src/fs.rs +++ b/risc_v/src/fs.rs @@ -4,14 +4,15 @@ // 16 March 2020 use crate::{kmem::{talloc, tfree}, - process::{add_kernel_process_args, get_by_pid, set_running, set_waiting}, + process::{add_kernel_process_args, + get_by_pid, + set_running, + set_waiting}, syscall::syscall_block_read}; -use crate::cpu::memcpy; -use alloc::string::String; -use alloc::collections::BTreeMap; +use crate::{buffer::Buffer, cpu::memcpy}; +use alloc::{collections::BTreeMap, string::String}; use core::mem::size_of; -use crate::buffer::Buffer; pub const MAGIC: u16 = 0x4d5a; pub const BLOCK_SIZE: u32 = 1024; @@ -35,7 +36,7 @@ pub struct SuperBlock { pub magic: u16, pub pad2: u16, pub block_size: u16, - pub disk_version: u8, + pub disk_version: u8 } /// An inode stores the "meta-data" to a file. The mode stores the permissions @@ -54,7 +55,7 @@ pub struct Inode { pub atime: u32, pub mtime: u32, pub ctime: u32, - pub zones: [u32; 10], + pub zones: [u32; 10] } /// Notice that an inode does not contain the name of a file. This is because @@ -64,7 +65,7 @@ pub struct Inode { #[repr(C)] pub struct DirEntry { pub inode: u32, - pub name: [u8; 60], + pub name: [u8; 60] } /// The MinixFileSystem implements the FileSystem trait for the VFS. @@ -72,16 +73,8 @@ pub struct MinixFileSystem; // The plan for this in the future is to have a single inode cache. What we // will do is have a cache of Node structures which will combine the Inode // with the block drive. -static mut MFS_INODE_CACHE: [Option>; 8] = [ - None, - None, - None, - None, - None, - None, - None, - None -]; +static mut MFS_INODE_CACHE: [Option>; 8] = + [None, None, None, None, None, None, None, None]; impl MinixFileSystem { /// Inodes are the meta-data of a file, including the mode (permissions and type) and @@ -101,7 +94,8 @@ impl MinixFileSystem { // For Rust-ers, I'm showing two ways here. The first way is to get a reference // from a pointer. You will see the &* a lot in Rust for references. Rust // makes dereferencing a pointer cumbersome, which lends to not using them. - let super_block = unsafe { &*(buffer.get_mut() as *mut SuperBlock) }; + let super_block = + unsafe { &*(buffer.get_mut() as *mut SuperBlock) }; // I opted for a pointer here instead of a reference because we will be offsetting the inode by a certain amount. let inode = buffer.get_mut() as *mut Inode; // Read from the block device. The size is 1 sector (512 bytes) and our offset is past @@ -113,15 +107,29 @@ impl MinixFileSystem { // have to skip the bitmaps blocks. We have a certain number of inode map blocks (imap) // and zone map blocks (zmap). // The inode comes to us as a NUMBER, not an index. So, we need to subtract 1. - let inode_offset = (2 + super_block.imap_blocks + super_block.zmap_blocks) as usize * BLOCK_SIZE as usize + ((inode_num as usize - 1) / (BLOCK_SIZE as usize / size_of::())) * BLOCK_SIZE as usize; + let inode_offset = (2 + + super_block.imap_blocks + + super_block.zmap_blocks) + as usize * BLOCK_SIZE as usize + + ((inode_num as usize - 1) + / (BLOCK_SIZE as usize + / size_of::())) + * BLOCK_SIZE as usize; // Now, we read the inode itself. // The block driver requires that our offset be a multiple of 512. We do that with the // inode_offset. However, we're going to be reading a group of inodes. - syc_read(bdev, buffer.get_mut(), 1024, inode_offset as u32); + syc_read( + bdev, + buffer.get_mut(), + 1024, + inode_offset as u32 + ); // There are 1024 / size_of() inodes in each read that we can do. However, we need to figure out which inode in that group we need to read. We just take the % of this to find out. - let read_this_node = (inode_num as usize - 1) % (BLOCK_SIZE as usize / size_of::()); + let read_this_node = (inode_num as usize - 1) + % (BLOCK_SIZE as usize + / size_of::()); // We copy the inode over. This might not be the best thing since the Inode will // eventually have to change after writing. @@ -135,10 +143,18 @@ impl MinixFileSystem { impl MinixFileSystem { /// Init is where we would cache the superblock and inode to avoid having to read - /// it over and over again, like we do for read right now. - fn cache_at(btm: &mut BTreeMap, cwd: &String, inode_num: u32, bdev: usize) { + /// it over and over again, like we do for read right now. + fn cache_at(btm: &mut BTreeMap, + cwd: &String, + inode_num: u32, + bdev: usize) + { let ino = Self::get_inode(bdev, inode_num).unwrap(); - let mut buf = Buffer::new(((ino.size + BLOCK_SIZE - 1) & !BLOCK_SIZE) as usize); + let mut buf = Buffer::new( + ((ino.size + BLOCK_SIZE - 1) + & !BLOCK_SIZE) + as usize + ); let dirents = buf.get() as *const DirEntry; let sz = Self::read(bdev, &ino, buf.get_mut(), BLOCK_SIZE, 0); let num_dirents = sz as usize / size_of::(); @@ -146,7 +162,8 @@ impl MinixFileSystem { for i in 2..num_dirents { unsafe { let ref d = *dirents.add(i); - let d_ino = Self::get_inode(bdev, d.inode).unwrap(); + let d_ino = + Self::get_inode(bdev, d.inode).unwrap(); let mut new_cwd = String::with_capacity(120); for i in cwd.bytes() { new_cwd.push(i as char); @@ -167,7 +184,10 @@ impl MinixFileSystem { if d_ino.mode & S_IFDIR != 0 { // This is a directory, cache these. This is a recursive call, // which I don't really like. - Self::cache_at(btm, &new_cwd, d.inode, bdev); + Self::cache_at( + btm, &new_cwd, d.inode, + bdev + ); } else { btm.insert(new_cwd, d_ino); @@ -175,28 +195,34 @@ impl MinixFileSystem { } } } + // Run this ONLY in a process! pub fn init(bdev: usize) { - if unsafe {MFS_INODE_CACHE[bdev-1].is_none() } { + if unsafe { MFS_INODE_CACHE[bdev - 1].is_none() } { let mut btm = BTreeMap::new(); let cwd = String::from("/"); // Let's look at the root (inode #1) Self::cache_at(&mut btm, &cwd, 1, bdev); unsafe { - MFS_INODE_CACHE[bdev-1] = Some(btm); + MFS_INODE_CACHE[bdev - 1] = Some(btm); } } else { - println!("KERNEL: Initialized an already initialized filesystem {}", bdev); + println!( + "KERNEL: Initialized an already initialized \ + filesystem {}", + bdev + ); } } /// The goal of open is to traverse the path given by path. If we cache the inodes /// in RAM, it might make this much quicker. For now, this doesn't do anything since /// we're just testing read based on if we know the Inode we're looking for. - pub fn open(bdev: usize, path: &str) -> Result { - if let Some(cache) = unsafe { MFS_INODE_CACHE[bdev-1].take() } { + pub fn open(bdev: usize, path: &str) -> Result { + if let Some(cache) = unsafe { MFS_INODE_CACHE[bdev - 1].take() } + { let ret; if let Some(inode) = cache.get(path) { ret = Ok(*inode); @@ -205,7 +231,7 @@ impl MinixFileSystem { ret = Err(FsError::FileNotFound); } unsafe { - MFS_INODE_CACHE[bdev-1].replace(cache); + MFS_INODE_CACHE[bdev - 1].replace(cache); } ret } @@ -214,7 +240,13 @@ impl MinixFileSystem { } } - pub fn read(bdev: usize, inode: &Inode, buffer: *mut u8, size: u32, offset: u32) -> u32 { + pub fn read(bdev: usize, + inode: &Inode, + buffer: *mut u8, + size: u32, + offset: u32) + -> u32 + { // Our strategy here is to use blocks to see when we need to start reading // based on the offset. That's offset_block. Then, the actual byte within // that block that we need is offset_byte. @@ -264,13 +296,20 @@ impl MinixFileSystem { let zone_offset = inode.zones[i] * BLOCK_SIZE; // We read the zone, which is where the data is located. The zone offset is simply the block // size times the zone number. This makes it really easy to read! - syc_read(bdev, block_buffer.get_mut(), BLOCK_SIZE, zone_offset); + syc_read( + bdev, + block_buffer.get_mut(), + BLOCK_SIZE, + zone_offset + ); // There's a little bit of math to see how much we need to read. We don't want to read // more than the buffer passed in can handle, and we don't want to read if we haven't // taken care of the offset. For example, an offset of 10000 with a size of 2 means we // can only read bytes 10,000 and 10,001. - let read_this_many = if BLOCK_SIZE - offset_byte > bytes_left { + let read_this_many = if BLOCK_SIZE - offset_byte + > bytes_left + { bytes_left } else { @@ -280,9 +319,11 @@ impl MinixFileSystem { // is written in cpu.rs. unsafe { memcpy( - buffer.add(bytes_read as usize,), - block_buffer.get().add(offset_byte as usize,), - read_this_many as usize, + buffer.add(bytes_read as usize), + block_buffer.get().add( + offset_byte as usize + ), + read_this_many as usize ); } // Regardless of whether we have an offset or not, we reset the offset byte back to 0. This @@ -308,9 +349,14 @@ impl MinixFileSystem { // point to zones where the data can be found. Just like with the direct zones, // we need to make sure the zone isn't 0. A zone of 0 means skip it. if inode.zones[7] != 0 { - syc_read(bdev, indirect_buffer.get_mut(), BLOCK_SIZE, BLOCK_SIZE * inode.zones[7]); + syc_read( + bdev, + indirect_buffer.get_mut(), + BLOCK_SIZE, + BLOCK_SIZE * inode.zones[7] + ); let izones = indirect_buffer.get() as *const u32; - for i in 0..NUM_INDIRECT_POINTERS{ + for i in 0..NUM_INDIRECT_POINTERS { // Where do I put unsafe? Dereferencing the pointers and memcpy are the unsafe functions. unsafe { if izones.add(i).read() != 0 { @@ -321,19 +367,25 @@ impl MinixFileSystem { BLOCK_SIZE, BLOCK_SIZE * izones.add(i,).read(), ); - let read_this_many = if BLOCK_SIZE - offset_byte > bytes_left { - bytes_left - } - else { - BLOCK_SIZE - offset_byte - }; + let read_this_many = + if BLOCK_SIZE + - offset_byte + > bytes_left + { + bytes_left + } + else { + BLOCK_SIZE - offset_byte + }; memcpy( buffer.add(bytes_read as usize,), block_buffer.get().add(offset_byte as usize,), read_this_many as usize, ); - bytes_read += read_this_many; - bytes_left -= read_this_many; + bytes_read += + read_this_many; + bytes_left -= + read_this_many; offset_byte = 0; if bytes_left == 0 { return bytes_read; @@ -348,13 +400,22 @@ impl MinixFileSystem { // // DOUBLY INDIRECT ZONES // //////////////////////////////////////////// if inode.zones[8] != 0 { - syc_read(bdev, indirect_buffer.get_mut(), BLOCK_SIZE, BLOCK_SIZE * inode.zones[8]); + syc_read( + bdev, + indirect_buffer.get_mut(), + BLOCK_SIZE, + BLOCK_SIZE * inode.zones[8] + ); unsafe { for i in 0..NUM_INDIRECT_POINTERS { if izones.add(i).read() != 0 { syc_read(bdev, iindirect_buffer.get_mut(), BLOCK_SIZE, BLOCK_SIZE * izones.add(i).read()); - for j in 0..NUM_INDIRECT_POINTERS { - if iizones.add(j).read() != 0 { + for j in + 0..NUM_INDIRECT_POINTERS + { + if iizones.add(j).read() + != 0 + { // Notice that this inner code is the same for all end-zone pointers. I'm thinking about // moving this out of here into a function of its own, but that might make it harder // to follow. @@ -383,7 +444,8 @@ impl MinixFileSystem { return bytes_read; } } - blocks_seen += 1; + blocks_seen += + 1; } } } @@ -394,13 +456,22 @@ impl MinixFileSystem { // // TRIPLY INDIRECT ZONES // //////////////////////////////////////////// if inode.zones[9] != 0 { - syc_read(bdev, indirect_buffer.get_mut(), BLOCK_SIZE, BLOCK_SIZE * inode.zones[9]); + syc_read( + bdev, + indirect_buffer.get_mut(), + BLOCK_SIZE, + BLOCK_SIZE * inode.zones[9] + ); unsafe { for i in 0..NUM_INDIRECT_POINTERS { if izones.add(i).read() != 0 { syc_read(bdev, iindirect_buffer.get_mut(), BLOCK_SIZE, BLOCK_SIZE * izones.add(i).read()); - for j in 0..NUM_INDIRECT_POINTERS { - if iizones.add(j).read() != 0 { + for j in + 0..NUM_INDIRECT_POINTERS + { + if iizones.add(j).read() + != 0 + { syc_read( bdev, iiindirect_buffer.get_mut(), @@ -452,7 +523,13 @@ impl MinixFileSystem { bytes_read } - pub fn write(&mut self, _desc: &Inode, _buffer: *const u8, _offset: u32, _size: u32) -> u32 { + pub fn write(&mut self, + _desc: &Inode, + _buffer: *const u8, + _offset: u32, + _size: u32) + -> u32 + { 0 } @@ -460,7 +537,7 @@ impl MinixFileSystem { Stat { mode: inode.mode, size: inode.size, uid: inode.uid, - gid: inode.gid, } + gid: inode.gid } } } @@ -480,7 +557,7 @@ struct ProcArgs { pub buffer: *mut u8, pub size: u32, pub offset: u32, - pub node: u32, + pub node: u32 } // This is the actual code ran inside of the read process. @@ -489,9 +566,15 @@ fn read_proc(args_addr: usize) { let args = unsafe { args_ptr.as_ref().unwrap() }; // Start the read! Since we're in a kernel process, we can block by putting this - // process into a waiting state and wait until the block driver returns. + // process into a waiting state and wait until the block driver returns. let inode = MinixFileSystem::get_inode(args.dev, args.node); - let bytes = MinixFileSystem::read(args.dev, &inode.unwrap(), args.buffer, args.size, args.offset); + let bytes = MinixFileSystem::read( + args.dev, + &inode.unwrap(), + args.buffer, + args.size, + args.offset + ); // Let's write the return result into regs[10], which is A0. unsafe { @@ -512,7 +595,13 @@ fn read_proc(args_addr: usize) { /// System calls will call process_read, which will spawn off a kernel process to read /// the requested data. -pub fn process_read(pid: u16, dev: usize, node: u32, buffer: *mut u8, size: u32, offset: u32) { +pub fn process_read(pid: u16, + dev: usize, + node: u32, + buffer: *mut u8, + size: u32, + offset: u32) +{ // println!("FS read {}, {}, 0x{:x}, {}, {}", pid, dev, buffer as usize, size, offset); let args = talloc::().unwrap(); args.pid = pid; @@ -522,7 +611,10 @@ pub fn process_read(pid: u16, dev: usize, node: u32, buffer: *mut u8, size: u32, args.offset = offset; args.node = node; set_waiting(pid); - let _ = add_kernel_process_args(read_proc, args as *mut ProcArgs as usize); + let _ = add_kernel_process_args( + read_proc, + args as *mut ProcArgs as usize + ); } /// Stats on a file. This generally mimics an inode @@ -530,17 +622,16 @@ pub fn process_read(pid: u16, dev: usize, node: u32, buffer: *mut u8, size: u32, /// However, inodes are filesystem specific, and we /// want a more generic stat. pub struct Stat { - pub mode: u16, - pub size: u32, - pub uid: u16, - pub gid: u16, + pub mode: u16, + pub size: u32, + pub uid: u16, + pub gid: u16 } pub enum FsError { - Success, - FileNotFound, - Permission, - IsFile, - IsDirectory, + Success, + FileNotFound, + Permission, + IsFile, + IsDirectory } -