Skip to content

Commit a971c1a

Browse files
committed
ch6 lab; fix efs increase_size
1 parent 7be2e81 commit a971c1a

File tree

12 files changed

+489
-55
lines changed

12 files changed

+489
-55
lines changed

easy-fs/src/layout.rs

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use crate::{block_cache::get_block_cache, block_dev::BlockDevice, BLOCK_SZ};
55
/// Magic number for sanity check
66
const EFS_MAGIC: u32 = 0x3b800001;
77
/// The max number of direct inodes
8-
const INODE_DIRECT_COUNT: usize = 28;
8+
const INODE_DIRECT_COUNT: usize = 26;
99
/// The max length of inode name
1010
const NAME_LENGTH_LIMIT: usize = 27;
1111
/// The max number of indirect1 inodes
@@ -73,7 +73,9 @@ type DataBlock = [u8; BLOCK_SZ];
7373
#[repr(C)] // size == 32*u32 = 128B == 1/4 block
7474
pub struct DiskInode {
7575
pub size: u32,
76-
// when file is small, `direct` refs 28 data blocks == 28*512 = 14KB
76+
pub nlink: u32, // nlink taks 4B
77+
_rsv: u32, // reserve make `direct` is even
78+
// when file is small, `direct` refs 28-2 data blocks == (28-2)*512 = 14-1KB
7779
pub direct: [u32; INODE_DIRECT_COUNT],
7880
// when file is large, `indirect1` refs to L1 index block, every u32 in it refs to
7981
// data block, so total 512/4*512 = 64KB
@@ -92,6 +94,7 @@ pub enum DiskInodeType {
9294
impl DiskInode {
9395
pub fn initialize(&mut self, type_: DiskInodeType) {
9496
self.size = 0;
97+
self.nlink = 1;
9598
self.direct.fill(0);
9699
self.indirect1 = 0;
97100
self.indirect2 = 0;
@@ -231,10 +234,11 @@ impl DiskInode {
231234
// new_total > `INODE_DIRECT_COUNT`
232235
// alloc `indrect1`
233236
if new_total > INODE_DIRECT_COUNT {
234-
assert_eq!(curr_total, INODE_DIRECT_COUNT);
235-
self.indirect1 = iter_new.next().unwrap();
237+
if curr_total == INODE_DIRECT_COUNT {
238+
self.indirect1 = iter_new.next().unwrap();
239+
}
236240
// re-pos
237-
curr_total -= INODE_DIRECT_COUNT; // 0
241+
curr_total -= INODE_DIRECT_COUNT;
238242
new_total -= INODE_DIRECT_COUNT;
239243
} else {
240244
return;
@@ -253,10 +257,11 @@ impl DiskInode {
253257
// new_total > `INODE_DIRECT1_COUNT`
254258
// alloc `indrect2`
255259
if new_total > INODE_INDIRECT1_COUNT {
256-
assert_eq!(curr_total, INODE_INDIRECT1_COUNT);
257-
self.indirect2 = iter_new.next().unwrap();
260+
if curr_total == INODE_INDIRECT1_COUNT {
261+
self.indirect2 = iter_new.next().unwrap();
262+
}
258263
// re-pos
259-
curr_total -= INODE_INDIRECT1_COUNT; // 0
264+
curr_total -= INODE_INDIRECT1_COUNT;
260265
new_total -= INODE_INDIRECT1_COUNT;
261266
} else {
262267
return;
@@ -280,13 +285,13 @@ impl DiskInode {
280285
.lock()
281286
.modify(0, |indirect1: &mut IndirectBlock| {
282287
let end = if a0 < a1 { INODE_INDIRECT1_COUNT } else { b1 };
283-
for i in 0..end {
288+
for i in b0..end {
284289
indirect1[i] = iter_new.next().unwrap();
285290
}
286-
curr_total += end;
291+
curr_total += (b0..end).count();
287292
});
288293
}
289-
})
294+
});
290295
}
291296

292297
/// Clear size to zero and return blocks that should be deallocated.

easy-fs/src/vfs.rs

Lines changed: 103 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use crate::{
99
};
1010

1111
/// Virtual filesystem layer over easy-fs
12+
#[derive(Clone)]
1213
pub struct Inode {
1314
inode_id: u32,
1415

@@ -55,7 +56,7 @@ impl Inode {
5556
/// Find inode under a disk inode by name
5657
fn find_inode_id(&self, name: &str, disk_inode: &DiskInode) -> Option<u32> {
5758
assert!(disk_inode.is_dir());
58-
// data of `disk_node` should be array of `Dirent`s
59+
// data of `disk_inode` should be array of `Dirent`s
5960
let file_count = (disk_inode.size as usize) / DIRENT_SZ;
6061
let mut dirent = DirEntry::new_empty();
6162
for i in 0..file_count {
@@ -243,9 +244,7 @@ impl Inode {
243244
self.create_inode(name, DiskInodeType::Directory)
244245
}
245246

246-
/// Clear the data in current inode
247-
pub fn clear(&self) {
248-
let mut fs = self.fs.lock();
247+
fn clear_locked(&self, fs: &mut EasyFileSystem) {
249248
self.modify_disk_inode(|disk_inode| {
250249
assert!(disk_inode.is_file());
251250
let size = disk_inode.size;
@@ -261,6 +260,12 @@ impl Inode {
261260
block_cache_sync_all();
262261
}
263262

263+
/// Clear the data in current inode
264+
pub fn clear(&self) {
265+
let mut fs = self.fs.lock();
266+
self.clear_locked(&mut fs);
267+
}
268+
264269
/// Read data from current inode
265270
pub fn read_at(&self, offset: usize, buf: &mut [u8]) -> usize {
266271
self.read_disk_inode(|disk_inode| disk_inode.read_at(offset, buf, &self.block_device))
@@ -296,4 +301,98 @@ impl Inode {
296301
pub fn is_file(&self) -> bool {
297302
self.read_disk_inode(|disk_inode| disk_inode.is_file())
298303
}
304+
305+
/// Get link number
306+
pub fn nlink(&self) -> u32 {
307+
self.read_disk_inode(|disk_inode| disk_inode.nlink)
308+
}
309+
310+
/// Create hard link `name` from `src`
311+
pub fn link(&self, name: &str, src: &Inode) -> Option<Arc<Inode>> {
312+
let mut fs = self.fs.lock();
313+
314+
let op = |root_inode: &DiskInode| {
315+
assert!(root_inode.is_dir());
316+
self.find_inode_id(name, root_inode)
317+
};
318+
// exist already
319+
if self.read_disk_inode(op).is_some() {
320+
return None;
321+
}
322+
323+
// add dirent under self
324+
self.modify_disk_inode(|disk_inode| {
325+
let file_count = (disk_inode.size as usize) / DIRENT_SZ;
326+
let new_size = (file_count + 1) * DIRENT_SZ;
327+
self.increase_size(new_size as u32, disk_inode, &mut fs);
328+
let dirent = DirEntry::new(name, src.inode_id);
329+
disk_inode.write_at(
330+
file_count * DIRENT_SZ,
331+
dirent.as_bytes(),
332+
&self.block_device,
333+
);
334+
});
335+
// inc src nlink
336+
src.modify_disk_inode(|disk_inode| disk_inode.nlink += 1);
337+
Some(Arc::new(Self::clone(src)))
338+
}
339+
340+
/// Remove hard link (return if removed successfully)
341+
pub fn unlink(&self, name: &str) -> bool {
342+
let mut fs = self.fs.lock();
343+
// self is dir && "name" exists
344+
let target = self.modify_disk_inode(|disk_inode| {
345+
if !disk_inode.is_dir() {
346+
return None;
347+
}
348+
let file_count = (disk_inode.size as usize) / DIRENT_SZ;
349+
let mut dirent = DirEntry::new_empty();
350+
let mut swap = DirEntry::new_empty();
351+
match (0..file_count).position(|i| {
352+
assert_eq!(
353+
disk_inode.read_at(i * DIRENT_SZ, dirent.as_bytes_mut(), &self.block_device),
354+
DIRENT_SZ
355+
);
356+
dirent.name() == name
357+
}) {
358+
Some(i) => {
359+
// target
360+
let target_inode_id = dirent.inode_number();
361+
let (target_block_id, target_block_offset) =
362+
fs.get_disk_inode_pos(target_inode_id);
363+
let target = Self::new(
364+
target_inode_id,
365+
target_block_id,
366+
target_block_offset,
367+
self.fs.clone(),
368+
self.block_device.clone(),
369+
);
370+
// we don't actually delete i-th, but swap last to i-th, and decrease disk_inode.size only
371+
// in real world we should decrease data of this dir's actual space (at proper time?)
372+
disk_inode.read_at(
373+
(file_count - 1) * DIRENT_SZ,
374+
swap.as_bytes_mut(),
375+
&self.block_device,
376+
);
377+
disk_inode.write_at(i * DIRENT_SZ, swap.as_bytes(), &self.block_device);
378+
disk_inode.size -= DIRENT_SZ as u32;
379+
Some(target)
380+
}
381+
_ => None, // no such file
382+
}
383+
});
384+
// clear target's data if link decrease to 0
385+
if let Some(target) = target {
386+
if target.modify_disk_inode(|disk_inode| {
387+
disk_inode.nlink -= 1;
388+
disk_inode.nlink
389+
}) == 0
390+
{
391+
target.clear_locked(&mut fs);
392+
}
393+
true
394+
} else {
395+
false
396+
}
397+
}
299398
}

os/src/fs/inode.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,19 @@ pub fn open_file_at(base: &Inode, name: &str, flags: OpenFlags) -> Option<Arc<OS
149149
}
150150
}
151151

152+
/// Unlink file relative to base TODO move to fs.rs?
153+
pub fn unlink_file_at(base: &Inode, name: &str) -> bool {
154+
let (path, fname) = match name.rsplit_once('/') {
155+
Some(v) => v,
156+
_ => (".", name),
157+
};
158+
159+
match base.find(path) {
160+
Some(parent) => parent.unlink(fname),
161+
_ => false,
162+
}
163+
}
164+
152165
pub fn find_file(path: &str) -> Option<Arc<OSInode>> {
153166
assert!(path.starts_with('/'));
154167
ROOT_INODE

os/src/fs/mod.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,7 @@ use crate::{cast::DowncastArc, mm::UserBuffer};
44

55
mod inode;
66
mod stdio;
7-
pub use inode::{
8-
find_file, ls_root, name_for_inode, open_file, open_file_at, OSInode, OpenFlags, ROOT_INODE,
9-
};
7+
pub use inode::*;
108
pub use stdio::{Stdin, Stdout};
119

1210
pub trait File: Any + Send + Sync {

0 commit comments

Comments
 (0)