merged layer1 refactor
This commit is contained in:
commit
c2922f4d15
14
.gitignore
vendored
14
.gitignore
vendored
@ -1 +1,15 @@
|
||||
build/*
|
||||
|
||||
# vscode gitignore
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
!.vscode/*.code-snippets
|
||||
|
||||
# Local History for Visual Studio Code
|
||||
.history/
|
||||
|
||||
# Built Visual Studio Code Extensions
|
||||
*.vsix
|
6
.vscode/settings.json
vendored
Normal file
6
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"cmake.configureOnOpen": false,
|
||||
"cSpell.words": [
|
||||
"unneccary"
|
||||
]
|
||||
}
|
@ -10,9 +10,15 @@ include_directories(
|
||||
|
||||
add_executable(fischl
|
||||
|
||||
# Header files
|
||||
lib/fischl.cpp
|
||||
lib/main.cpp
|
||||
lib/rawdisk.cpp
|
||||
lib/fs/datablock_manager.cpp
|
||||
lib/fs/fs_data_types.cpp
|
||||
lib/fs/fs_resize.cpp
|
||||
lib/fs/fs_read_write.cpp
|
||||
lib/fs/fs.cpp
|
||||
lib/fs/inode_manager.cpp
|
||||
|
||||
)
|
||||
|
||||
|
63
Issues.txt
Normal file
63
Issues.txt
Normal file
@ -0,0 +1,63 @@
|
||||
Problem - no header guards
|
||||
Problem - code in header file
|
||||
Problem - inconisitent use of SECTOR_SIZE IO_BLOCK_SIZE
|
||||
|
||||
|
||||
?18: what is directory
|
||||
|
||||
22: read of less than sector-size unpermitted
|
||||
|
||||
?25: does the casting here work as expected, would a bitmask be better
|
||||
|
||||
Question: why are we passing a disk every time to superblock functions, shouldn't that be associated with the superblock (i.e. the file system object)
|
||||
|
||||
37: same issues with this function
|
||||
|
||||
Superblock should be read and written to all at once to avoid unneccary io reads and should be stateful regarding the fs data (also it maybe good to rename superblock to fs and make it in charge of formatting the fs)
|
||||
|
||||
57: magic num
|
||||
|
||||
?69: strange reference pattern with current_pos - usually handled by func returning num bytes read
|
||||
|
||||
?69: should these helper functions be in the inode at all
|
||||
|
||||
?76: these two funcs could be combined together
|
||||
|
||||
?83: inode_construct may want to be named inode_load to fit pattern
|
||||
|
||||
inode objs (block_number) should likely be able to be made with out the use of inode_construct when they are first created
|
||||
|
||||
|
||||
132:
|
||||
|
||||
?142: odd use of block nums - byte addresses and io_block addresses
|
||||
|
||||
143: magic num 32?
|
||||
|
||||
?144: possibly make this a continue also use 0b11111111 and 0b01111111
|
||||
|
||||
?145: j = 0 twice
|
||||
|
||||
?76: why is this function read_byte_at if it reads 8 bytes
|
||||
|
||||
?144: why is the last bit of the bitmask unused
|
||||
|
||||
?171: returned free must be zeroed before use
|
||||
|
||||
177: no error handling for cannot allocate block (free list empty)
|
||||
|
||||
?215: should this be made into a recursive func
|
||||
|
||||
241: no error checking
|
||||
|
||||
278: the empty checking and adding to free list head seems busted
|
||||
|
||||
303: --
|
||||
|
||||
?315: && addr == 0 does nothing
|
||||
|
||||
398: can try to deallocate the super block so // deal with empty needs implementation
|
||||
|
||||
?433: why even mix sector size into free list
|
||||
|
||||
428: no limit checking
|
7
include/fischl.h
Normal file
7
include/fischl.h
Normal file
@ -0,0 +1,7 @@
|
||||
class fischl{
|
||||
|
||||
// declare
|
||||
public:
|
||||
int init(int argc, char *argv[]);
|
||||
|
||||
};
|
51
include/fs.hpp
Normal file
51
include/fs.hpp
Normal file
@ -0,0 +1,51 @@
|
||||
#ifndef FS_HPP
|
||||
#define FS_HPP
|
||||
|
||||
#include "fs/datablock_manager.hpp"
|
||||
#include "fs/fs_data_types.hpp"
|
||||
#include "fs/inode_manager.hpp"
|
||||
#include "fs_constants.hpp"
|
||||
#include "rawdisk.hpp"
|
||||
|
||||
// TEMP:
|
||||
class DatablockOperation;
|
||||
|
||||
class Fs {
|
||||
public:
|
||||
Fs(RawDisk *disk);
|
||||
~Fs();
|
||||
|
||||
int allocate_datablock(INode_Data *inode_data, u_int64_t *datablock_num);
|
||||
int deallocate_datablock(INode_Data *inode_data, u_int64_t *datablock_num);
|
||||
|
||||
ssize_t read(INode_Data *inode_data, char buf[], size_t count, size_t offset);
|
||||
ssize_t write(INode_Data *inode_data, char buf[], size_t count,
|
||||
size_t offset);
|
||||
|
||||
int sweep_inode_datablocks(INode_Data *inode_data,
|
||||
u_int64_t start_block_index, bool allocate,
|
||||
DatablockOperation *op);
|
||||
|
||||
int sweep_datablocks(u_int64_t *block_num, int indirect_num,
|
||||
u_int64_t start_block_index, bool allocate,
|
||||
DatablockOperation *op);
|
||||
|
||||
int format();
|
||||
|
||||
// should probably be private but is not for testing
|
||||
RawDisk *disk;
|
||||
SuperBlock_Data superblock;
|
||||
INode_Manager *inode_manager;
|
||||
DataBlock_Manager *datablock_manager;
|
||||
|
||||
int load_superblock();
|
||||
int save_superblock();
|
||||
|
||||
int save_free_list_head(u_int64_t new_free_list_head);
|
||||
int save_inode_list_head(u_int64_t new_inode_list_head);
|
||||
|
||||
int allocate_indirect(u_int64_t *storage, int n, u_int64_t *datablock_num);
|
||||
int deallocate_indirect(u_int64_t *storage, int n, u_int64_t *datablock_num);
|
||||
};
|
||||
|
||||
#endif
|
35
include/fs/datablock_manager.hpp
Normal file
35
include/fs/datablock_manager.hpp
Normal file
@ -0,0 +1,35 @@
|
||||
#ifndef DATABLOCK_MANAGER_HPP
|
||||
#define DATABLOCK_MANAGER_HPP
|
||||
|
||||
#include "fs_constants.hpp"
|
||||
|
||||
class Fs;
|
||||
|
||||
class DataBlock_Manager {
|
||||
public:
|
||||
DataBlock_Manager(Fs *fs, u_int64_t block_segment_start,
|
||||
u_int64_t block_segment_end);
|
||||
|
||||
virtual int new_datablock(u_int64_t *block_num) = 0;
|
||||
virtual int free_datablock(u_int64_t block_num) = 0;
|
||||
|
||||
virtual int format() = 0;
|
||||
|
||||
protected:
|
||||
Fs *fs;
|
||||
u_int64_t block_segment_start, block_segment_end;
|
||||
};
|
||||
|
||||
class DataBlock_Manager_Bitmap : public DataBlock_Manager {
|
||||
public:
|
||||
DataBlock_Manager_Bitmap(Fs *fs, u_int64_t block_segment_start,
|
||||
u_int64_t block_segment_end)
|
||||
: DataBlock_Manager(fs, block_segment_start, block_segment_end) {}
|
||||
|
||||
int new_datablock(u_int64_t *block_num) override;
|
||||
int free_datablock(u_int64_t block_num) override;
|
||||
|
||||
int format() override;
|
||||
};
|
||||
|
||||
#endif
|
51
include/fs/fs_data_types.hpp
Normal file
51
include/fs/fs_data_types.hpp
Normal file
@ -0,0 +1,51 @@
|
||||
#ifndef FS_DATA_TYPES_HPP
|
||||
#define FS_DATA_TYPES_HPP
|
||||
|
||||
#include "fs_constants.hpp"
|
||||
|
||||
size_t write_u64(u_int64_t num, char buf[]);
|
||||
|
||||
size_t read_u64(u_int64_t *num, char buf[]);
|
||||
|
||||
size_t write_u32(u_int32_t num, char buf[]);
|
||||
|
||||
size_t read_u32(u_int32_t *num, char buf[]);
|
||||
|
||||
class SuperBlock_Data {
|
||||
public:
|
||||
u_int64_t free_list_head;
|
||||
u_int64_t inode_list_head;
|
||||
SuperBlock_Data();
|
||||
void serialize(char buf[]);
|
||||
void deserialize(char buf[]);
|
||||
};
|
||||
|
||||
class INode_Data {
|
||||
public:
|
||||
u_int64_t inode_num;
|
||||
|
||||
#define NUMBER_OF_METADATA_BYTES \
|
||||
(4 * sizeof(u_int64_t) + (2 * sizeof(u_int32_t)))
|
||||
struct INode_MetaData {
|
||||
u_int64_t uid;
|
||||
u_int64_t gid;
|
||||
u_int64_t permissions;
|
||||
u_int64_t size; // not yet implemented
|
||||
u_int32_t reference_count;
|
||||
u_int32_t flags;
|
||||
} metadata;
|
||||
size_t serialize_metadata(char buf[]);
|
||||
size_t deserialize_metadata(char buf[]);
|
||||
|
||||
#define NUMBER_OF_DIRECT_BLOCKS \
|
||||
(((INODE_SIZE - NUMBER_OF_METADATA_BYTES) / sizeof(u_int64_t)) - 3)
|
||||
|
||||
u_int64_t single_indirect_block, double_indirect_block, triple_indirect_block;
|
||||
u_int64_t direct_blocks[NUMBER_OF_DIRECT_BLOCKS];
|
||||
|
||||
INode_Data(u_int64_t inode_num = 0xFFFFFFFFFFFFFFFF);
|
||||
void serialize(char buf[]);
|
||||
void deserialize(char buf[]);
|
||||
};
|
||||
|
||||
#endif
|
47
include/fs/inode_manager.hpp
Normal file
47
include/fs/inode_manager.hpp
Normal file
@ -0,0 +1,47 @@
|
||||
#ifndef INODE_MANAGER_HPP
|
||||
#define INODE_MANAGER_HPP
|
||||
|
||||
#include "fs_constants.hpp"
|
||||
#include "fs_data_types.hpp"
|
||||
|
||||
class Fs;
|
||||
|
||||
class INode_Manager {
|
||||
public:
|
||||
const int INODES_PER_BLOCK = IO_BLOCK_SIZE / INODE_SIZE;
|
||||
|
||||
INode_Manager(Fs *fs, u_int64_t block_segment_start,
|
||||
u_int64_t block_segment_end);
|
||||
|
||||
virtual int new_inode(u_int64_t uid, u_int64_t gid, u_int64_t permissions,
|
||||
INode_Data *inode_data) = 0;
|
||||
virtual int free_inode(INode_Data *inode_data) = 0;
|
||||
|
||||
virtual int format() = 0;
|
||||
|
||||
u_int64_t get_block_num(u_int64_t inode_data);
|
||||
u_int64_t get_block_offset(u_int64_t inode_data);
|
||||
|
||||
int load_inode(INode_Data *inode_data);
|
||||
int save_inode(INode_Data *inode_data);
|
||||
|
||||
protected:
|
||||
Fs *fs;
|
||||
u_int64_t block_segment_start, block_segment_end;
|
||||
u_int64_t max_num_inodes;
|
||||
};
|
||||
|
||||
class INode_Manager_Freelist : public INode_Manager {
|
||||
public:
|
||||
INode_Manager_Freelist(Fs *fs, u_int64_t block_segment_start,
|
||||
u_int64_t block_segment_end)
|
||||
: INode_Manager(fs, block_segment_start, block_segment_end) {}
|
||||
|
||||
int new_inode(u_int64_t uid, u_int64_t gid, u_int64_t permissions,
|
||||
INode_Data *inode_data) override;
|
||||
int free_inode(INode_Data *inode_data) override;
|
||||
|
||||
int format() override;
|
||||
};
|
||||
|
||||
#endif
|
24
include/fs_constants.hpp
Normal file
24
include/fs_constants.hpp
Normal file
@ -0,0 +1,24 @@
|
||||
#ifndef FS_CONSTANTS_HPP
|
||||
#define FS_CONSTANTS_HPP
|
||||
|
||||
#include <algorithm>
|
||||
#include <fcntl.h>
|
||||
#include <inttypes.h>
|
||||
#include <linux/fs.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define IO_BLOCK_SIZE 4096
|
||||
|
||||
#define NUM_INODE_BLOCKS 1023
|
||||
#define NUM_BLOCKS 2048
|
||||
|
||||
#define INODE_SIZE 512
|
||||
|
||||
// TODO: explore the optimal value for this
|
||||
#define DATABLOCKS_PER_BITMAP_BLOCK 2047
|
||||
|
||||
#endif
|
40
include/rawdisk.hpp
Normal file
40
include/rawdisk.hpp
Normal file
@ -0,0 +1,40 @@
|
||||
#ifndef RAWDISK_HPP
|
||||
#define RAWDISK_HPP
|
||||
|
||||
#include "fs_constants.hpp"
|
||||
|
||||
class RawDisk {
|
||||
public:
|
||||
u_int64_t diskSize;
|
||||
|
||||
virtual int read_block(u_int64_t block_number, char *buffer) = 0;
|
||||
virtual int write_block(u_int64_t block_number, char *buffer) = 0;
|
||||
|
||||
void print_block(u_int64_t block_number);
|
||||
};
|
||||
|
||||
class RealRawDisk : public RawDisk {
|
||||
public:
|
||||
int fd;
|
||||
const char *dir;
|
||||
u_int64_t numSectors;
|
||||
|
||||
RealRawDisk(const char *directory);
|
||||
~RealRawDisk();
|
||||
|
||||
int read_block(u_int64_t block_number, char *buffer) override;
|
||||
int write_block(u_int64_t block_number, char *buffer) override;
|
||||
};
|
||||
|
||||
class FakeRawDisk : public RawDisk {
|
||||
public:
|
||||
char *disk;
|
||||
|
||||
FakeRawDisk(u_int64_t num_blocks);
|
||||
~FakeRawDisk();
|
||||
|
||||
int read_block(u_int64_t block_number, char *buffer) override;
|
||||
int write_block(u_int64_t block_number, char *buffer) override;
|
||||
};
|
||||
|
||||
#endif
|
@ -38,7 +38,7 @@ static void show_help(const char *progname)
|
||||
"\n");
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
int fischl::init(int argc, char *argv[])
|
||||
{
|
||||
int ret;
|
||||
struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
|
||||
|
136
lib/fs/datablock_manager.cpp
Normal file
136
lib/fs/datablock_manager.cpp
Normal file
@ -0,0 +1,136 @@
|
||||
#include "fs.hpp"
|
||||
|
||||
DataBlock_Manager::DataBlock_Manager(Fs *fs, u_int64_t block_segment_start,
|
||||
u_int64_t block_segment_end)
|
||||
: fs(fs), block_segment_start(block_segment_start),
|
||||
block_segment_end(block_segment_end) {}
|
||||
|
||||
class BitmapBlock_Data {
|
||||
public:
|
||||
char buf[IO_BLOCK_SIZE];
|
||||
u_int64_t datablocks_per_bitmap;
|
||||
|
||||
BitmapBlock_Data(u_int64_t datablocks_per_bitmap_)
|
||||
: datablocks_per_bitmap(datablocks_per_bitmap_) {}
|
||||
|
||||
u_int64_t get_next_node() {
|
||||
u_int64_t block_num;
|
||||
read_u64(&block_num, buf);
|
||||
return block_num;
|
||||
}
|
||||
void set_next_node(u_int64_t block_num) { write_u64(block_num, buf); }
|
||||
|
||||
u_int64_t find_unfilled() {
|
||||
const char *data = &buf[8];
|
||||
u_int64_t i = 0;
|
||||
|
||||
for (; i < datablocks_per_bitmap; ++i)
|
||||
if ((data[i / 8] & (1 << (i % 8))) == 0)
|
||||
return i + 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
u_int64_t claim_relative_block() {
|
||||
u_int64_t unfilled = find_unfilled();
|
||||
if (unfilled)
|
||||
buf[((unfilled - 1) / 8) + 8] |= (1 << ((unfilled - 1) % 8));
|
||||
return unfilled;
|
||||
}
|
||||
|
||||
void release_relative_block(u_int64_t relative_block_num) {
|
||||
relative_block_num -= 1;
|
||||
size_t index = (relative_block_num / 8) + 8;
|
||||
int offset = relative_block_num % 8;
|
||||
buf[index] &= ~(1 << offset);
|
||||
}
|
||||
};
|
||||
|
||||
int DataBlock_Manager_Bitmap::new_datablock(u_int64_t *block_num) {
|
||||
int err;
|
||||
BitmapBlock_Data bitmap = BitmapBlock_Data(DATABLOCKS_PER_BITMAP_BLOCK);
|
||||
u_int64_t bitmap_block_num = fs->superblock.free_list_head;
|
||||
char zero_buf[IO_BLOCK_SIZE] = {0};
|
||||
|
||||
if (bitmap_block_num < block_segment_start ||
|
||||
bitmap_block_num >= block_segment_end)
|
||||
return -1;
|
||||
|
||||
if ((err = fs->disk->read_block(bitmap_block_num, bitmap.buf)) < 0)
|
||||
return err;
|
||||
|
||||
u_int64_t relative_block_num = bitmap.claim_relative_block();
|
||||
|
||||
if (relative_block_num == 0)
|
||||
return -1;
|
||||
|
||||
u_int64_t block_num_ = relative_block_num + bitmap_block_num;
|
||||
|
||||
// NOTE: this could be removed for speed
|
||||
if ((err = fs->disk->write_block(block_num_, zero_buf)) < 0)
|
||||
return err;
|
||||
|
||||
// Could be optimized
|
||||
if (bitmap.find_unfilled() == 0) {
|
||||
if ((err = fs->save_free_list_head(bitmap.get_next_node())) < 0)
|
||||
return err;
|
||||
bitmap.set_next_node(0);
|
||||
}
|
||||
|
||||
if ((err = fs->disk->write_block(bitmap_block_num, bitmap.buf)) < 0)
|
||||
return err;
|
||||
|
||||
(*block_num) = block_num_;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int DataBlock_Manager_Bitmap::free_datablock(u_int64_t block_num) {
|
||||
int err;
|
||||
BitmapBlock_Data bitmap = BitmapBlock_Data(DATABLOCKS_PER_BITMAP_BLOCK);
|
||||
const u_int64_t bitmap_region_size = DATABLOCKS_PER_BITMAP_BLOCK + 1;
|
||||
bool update_freelist = false;
|
||||
|
||||
u_int64_t bitmap_block_num =
|
||||
(((block_num - block_segment_start) / bitmap_region_size) *
|
||||
bitmap_region_size) +
|
||||
block_segment_start;
|
||||
|
||||
if ((err = fs->disk->read_block(bitmap_block_num, bitmap.buf)) < 0)
|
||||
return err;
|
||||
|
||||
if (bitmap.find_unfilled() == 0) {
|
||||
update_freelist = true;
|
||||
bitmap.set_next_node(fs->superblock.free_list_head);
|
||||
}
|
||||
|
||||
bitmap.release_relative_block(block_num - bitmap_block_num);
|
||||
|
||||
if ((err = fs->disk->write_block(bitmap_block_num, bitmap.buf)) < 0)
|
||||
return err;
|
||||
|
||||
if (update_freelist)
|
||||
if ((err = fs->save_free_list_head(bitmap_block_num)) < 0)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
|
||||
// placing almost full bitmaps back at start of freelist is slow
|
||||
// potentially like 256 times slower throughput
|
||||
}
|
||||
|
||||
int DataBlock_Manager_Bitmap::format() {
|
||||
const u_int64_t bitmap_region_size = DATABLOCKS_PER_BITMAP_BLOCK + 1;
|
||||
char buf[IO_BLOCK_SIZE] = {0};
|
||||
int err;
|
||||
u_int64_t i = block_segment_start;
|
||||
for (; i <= block_segment_end - (2 * bitmap_region_size);
|
||||
i += bitmap_region_size) {
|
||||
write_u64(i + bitmap_region_size, buf);
|
||||
if ((err = fs->disk->write_block(i, buf)) < 0)
|
||||
return err;
|
||||
}
|
||||
if ((err = fs->disk->write_block(i, buf)) < 0)
|
||||
return err;
|
||||
if ((err = fs->save_free_list_head(block_segment_start)) < 0)
|
||||
return err;
|
||||
return 0;
|
||||
}
|
68
lib/fs/fs.cpp
Normal file
68
lib/fs/fs.cpp
Normal file
@ -0,0 +1,68 @@
|
||||
#include "fs.hpp"
|
||||
|
||||
Fs::Fs(RawDisk *disk) : disk(disk) {
|
||||
superblock = SuperBlock_Data();
|
||||
inode_manager = new INode_Manager_Freelist(this, 1, 1 + NUM_INODE_BLOCKS);
|
||||
datablock_manager =
|
||||
new DataBlock_Manager_Bitmap(this, 1 + NUM_INODE_BLOCKS, NUM_BLOCKS);
|
||||
};
|
||||
|
||||
Fs::~Fs() {
|
||||
delete inode_manager;
|
||||
delete datablock_manager;
|
||||
};
|
||||
|
||||
int Fs::format() {
|
||||
int err;
|
||||
if ((err = save_superblock()) < 0)
|
||||
return err;
|
||||
if ((err = inode_manager->format()) < 0)
|
||||
return err;
|
||||
if ((err = datablock_manager->format()) < 0)
|
||||
return err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Fs::load_superblock() {
|
||||
char buf[IO_BLOCK_SIZE];
|
||||
int err;
|
||||
|
||||
if ((err = disk->read_block(0, buf)) < 0)
|
||||
return err;
|
||||
|
||||
superblock.deserialize(buf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
int Fs::save_superblock() {
|
||||
char buf[IO_BLOCK_SIZE] = {0};
|
||||
int err;
|
||||
|
||||
superblock.serialize(buf);
|
||||
|
||||
if ((err = disk->write_block(0, buf)) < 0)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Fs::save_free_list_head(u_int64_t new_free_list_head) {
|
||||
u_int64_t temp = superblock.free_list_head;
|
||||
int err;
|
||||
superblock.free_list_head = new_free_list_head;
|
||||
if ((err = save_superblock()) < 0) {
|
||||
superblock.free_list_head = temp;
|
||||
return err;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
int Fs::save_inode_list_head(u_int64_t new_inode_list_head) {
|
||||
u_int64_t temp = superblock.inode_list_head;
|
||||
int err;
|
||||
superblock.inode_list_head = new_inode_list_head;
|
||||
if ((err = save_superblock()) < 0) {
|
||||
superblock.inode_list_head = temp;
|
||||
return err;
|
||||
}
|
||||
return 0;
|
||||
}
|
104
lib/fs/fs_data_types.cpp
Normal file
104
lib/fs/fs_data_types.cpp
Normal file
@ -0,0 +1,104 @@
|
||||
#include "fs.hpp"
|
||||
|
||||
template <typename T> T write_int(T num, char buf[]) {
|
||||
size_t i = 0;
|
||||
for (; i < sizeof(T); ++i)
|
||||
buf[i] = (char)(num >> (i * 8));
|
||||
return i;
|
||||
}
|
||||
|
||||
template <typename T> T read_int(T *num, char buf[]) {
|
||||
size_t i = 0;
|
||||
T temp = 0;
|
||||
for (; i < sizeof(T); ++i)
|
||||
temp |= (((T)buf[i]) & 0xFF) << (8 * i);
|
||||
(*num) = temp;
|
||||
return i;
|
||||
}
|
||||
|
||||
size_t write_u64(u_int64_t num, char buf[]) {
|
||||
return write_int<u_int64_t>(num, buf);
|
||||
}
|
||||
|
||||
size_t read_u64(u_int64_t *num, char buf[]) {
|
||||
return read_int<u_int64_t>(num, buf);
|
||||
}
|
||||
|
||||
size_t write_u32(u_int32_t num, char buf[]) {
|
||||
return write_int<u_int32_t>(num, buf);
|
||||
}
|
||||
|
||||
size_t read_u32(u_int32_t *num, char buf[]) {
|
||||
return read_int<u_int32_t>(num, buf);
|
||||
}
|
||||
|
||||
SuperBlock_Data::SuperBlock_Data() {
|
||||
free_list_head = 0;
|
||||
inode_list_head = 0;
|
||||
}
|
||||
|
||||
void SuperBlock_Data::serialize(char buf[]) {
|
||||
size_t i = 0;
|
||||
i += write_u64(free_list_head, &buf[i]);
|
||||
i += write_u64(inode_list_head, &buf[i]);
|
||||
}
|
||||
|
||||
void SuperBlock_Data::deserialize(char buf[]) {
|
||||
size_t i = 0;
|
||||
i += read_u64(&free_list_head, &buf[i]);
|
||||
i += read_u64(&inode_list_head, &buf[i]);
|
||||
}
|
||||
|
||||
INode_Data::INode_Data(u_int64_t inode_num) : inode_num(inode_num) {
|
||||
metadata.uid = -1;
|
||||
metadata.gid = -1;
|
||||
metadata.permissions = -1;
|
||||
metadata.size = 0;
|
||||
metadata.reference_count = 0;
|
||||
|
||||
single_indirect_block = double_indirect_block = triple_indirect_block = 0;
|
||||
|
||||
for (size_t i = 0; i < NUMBER_OF_DIRECT_BLOCKS; ++i)
|
||||
direct_blocks[i] = 0;
|
||||
}
|
||||
|
||||
size_t INode_Data::serialize_metadata(char buf[]) {
|
||||
size_t i = 0;
|
||||
i += write_u64(metadata.uid, &buf[i]);
|
||||
i += write_u64(metadata.gid, &buf[i]);
|
||||
i += write_u64(metadata.permissions, &buf[i]);
|
||||
i += write_u64(metadata.size, &buf[i]);
|
||||
i += write_u32(metadata.reference_count, &buf[i]);
|
||||
i += write_u32(metadata.flags, &buf[i]);
|
||||
return i;
|
||||
}
|
||||
|
||||
size_t INode_Data::deserialize_metadata(char buf[]) {
|
||||
size_t i = 0;
|
||||
i += read_u64(&metadata.uid, &buf[i]);
|
||||
i += read_u64(&metadata.gid, &buf[i]);
|
||||
i += read_u64(&metadata.permissions, &buf[i]);
|
||||
i += read_u64(&metadata.size, &buf[i]);
|
||||
i += read_u32(&metadata.reference_count, &buf[i]);
|
||||
i += read_u32(&metadata.flags, &buf[i]);
|
||||
return i;
|
||||
}
|
||||
|
||||
void INode_Data::serialize(char buf[]) {
|
||||
size_t i = 0;
|
||||
for (size_t j = 0; j < NUMBER_OF_DIRECT_BLOCKS; ++j)
|
||||
i += write_u64(direct_blocks[j], &buf[i]);
|
||||
i += write_u64(single_indirect_block, &buf[i]);
|
||||
i += write_u64(double_indirect_block, &buf[i]);
|
||||
i += write_u64(triple_indirect_block, &buf[i]);
|
||||
i += serialize_metadata(&buf[i]);
|
||||
}
|
||||
void INode_Data::deserialize(char buf[]) {
|
||||
size_t i = 0;
|
||||
for (size_t j = 0; j < NUMBER_OF_DIRECT_BLOCKS; ++j)
|
||||
i += read_u64(&direct_blocks[j], &buf[i]);
|
||||
i += read_u64(&single_indirect_block, &buf[i]);
|
||||
i += read_u64(&double_indirect_block, &buf[i]);
|
||||
i += read_u64(&triple_indirect_block, &buf[i]);
|
||||
i += deserialize_metadata(&buf[i]);
|
||||
}
|
212
lib/fs/fs_read_write.cpp
Normal file
212
lib/fs/fs_read_write.cpp
Normal file
@ -0,0 +1,212 @@
|
||||
#include "fs.hpp"
|
||||
|
||||
class DatablockOperation {
|
||||
public:
|
||||
char *buf;
|
||||
size_t count;
|
||||
size_t offset;
|
||||
size_t bytes_completed;
|
||||
RawDisk *disk;
|
||||
virtual int operation(u_int64_t block_num) = 0;
|
||||
};
|
||||
|
||||
int Fs::sweep_inode_datablocks(INode_Data *inode_data,
|
||||
u_int64_t start_block_index, bool allocate,
|
||||
DatablockOperation *op) {
|
||||
int result;
|
||||
|
||||
u_int64_t start_index = start_block_index;
|
||||
for (size_t i = start_index; i < NUMBER_OF_DIRECT_BLOCKS; ++i) {
|
||||
if ((result = sweep_datablocks(&(inode_data->direct_blocks[i]), 0, 0,
|
||||
allocate, op)) <= 0)
|
||||
return result;
|
||||
start_index = NUMBER_OF_DIRECT_BLOCKS;
|
||||
}
|
||||
|
||||
start_index -= NUMBER_OF_DIRECT_BLOCKS;
|
||||
|
||||
if (start_index < IO_BLOCK_SIZE) {
|
||||
if ((result = sweep_datablocks(&(inode_data->single_indirect_block), 1,
|
||||
start_index, allocate, op)) <= 0)
|
||||
return result;
|
||||
start_index = IO_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
start_index -= IO_BLOCK_SIZE;
|
||||
|
||||
if (start_index < IO_BLOCK_SIZE * IO_BLOCK_SIZE) {
|
||||
if ((result = sweep_datablocks(&(inode_data->double_indirect_block), 2,
|
||||
start_index, allocate, op)) <= 0)
|
||||
return result;
|
||||
start_index = IO_BLOCK_SIZE * IO_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
start_index -= IO_BLOCK_SIZE * IO_BLOCK_SIZE;
|
||||
|
||||
if (start_index < (u_int64_t)IO_BLOCK_SIZE * IO_BLOCK_SIZE * IO_BLOCK_SIZE) {
|
||||
if ((result = sweep_datablocks(&(inode_data->triple_indirect_block), 3,
|
||||
start_index, allocate, op)) <= 0)
|
||||
return result;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// This can simply be made non recursive by copy pasting - it is just
|
||||
// written this way as a proof of concept
|
||||
int Fs::sweep_datablocks(u_int64_t *block_num, int indirect_num,
|
||||
u_int64_t start_block_index, bool allocate,
|
||||
DatablockOperation *op) {
|
||||
char buf[IO_BLOCK_SIZE];
|
||||
int err;
|
||||
int result = -1;
|
||||
|
||||
if (allocate && (*block_num) == 0)
|
||||
if ((err = datablock_manager->new_datablock(block_num)) < 0)
|
||||
return err;
|
||||
|
||||
if (indirect_num == 0)
|
||||
return op->operation(*block_num);
|
||||
|
||||
if ((*block_num) == 0) {
|
||||
memset(buf, 0, sizeof(buf));
|
||||
} else {
|
||||
if ((err = disk->read_block(*block_num, buf)) < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
u_int64_t indirect_block_size = 1;
|
||||
for (int i = 1; i < indirect_num; ++i)
|
||||
indirect_block_size *= IO_BLOCK_SIZE;
|
||||
|
||||
u_int64_t this_layer_start_index = start_block_index / indirect_block_size;
|
||||
u_int64_t next_layer_start_index =
|
||||
start_block_index - (indirect_block_size * this_layer_start_index);
|
||||
|
||||
u_int64_t temp;
|
||||
u_int64_t next_block_num;
|
||||
bool modified = false;
|
||||
|
||||
for (size_t i = this_layer_start_index * sizeof(u_int64_t); i < IO_BLOCK_SIZE;
|
||||
i += sizeof(u_int64_t)) {
|
||||
read_u64(&temp, &buf[i]);
|
||||
next_block_num = temp;
|
||||
if ((result = sweep_datablocks(&next_block_num, indirect_num - 1,
|
||||
next_layer_start_index, allocate, op)) < 0)
|
||||
return result;
|
||||
if (next_block_num != temp) {
|
||||
write_u64(next_block_num, &buf[i]);
|
||||
modified = true;
|
||||
}
|
||||
if (result == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (modified)
|
||||
if ((err = disk->write_block(*block_num, buf)) < 0)
|
||||
return err;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
class ReadDatablockOperation : public DatablockOperation {
|
||||
public:
|
||||
int operation(u_int64_t block_num) override {
|
||||
char datablock_buf[IO_BLOCK_SIZE];
|
||||
int err;
|
||||
|
||||
// printf("PRINT: (%d) %d %d %d\n", block_num, count, offset,
|
||||
// bytes_completed);
|
||||
|
||||
size_t read_size =
|
||||
std::min(IO_BLOCK_SIZE - offset, count - bytes_completed);
|
||||
|
||||
if (block_num != 0) {
|
||||
if ((err = disk->read_block(block_num, datablock_buf)) < 0)
|
||||
return err;
|
||||
|
||||
memcpy(&buf[bytes_completed], &datablock_buf[offset], read_size);
|
||||
} else {
|
||||
memset(&buf[bytes_completed], 0, read_size);
|
||||
}
|
||||
|
||||
offset = 0;
|
||||
bytes_completed += read_size;
|
||||
|
||||
if (bytes_completed >= count)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
};
|
||||
|
||||
class WriteDatablockOperation : public DatablockOperation {
|
||||
public:
|
||||
int operation(u_int64_t block_num) override {
|
||||
char datablock_buf[IO_BLOCK_SIZE];
|
||||
int err;
|
||||
|
||||
size_t write_size =
|
||||
std::min(IO_BLOCK_SIZE - offset, count - bytes_completed);
|
||||
|
||||
if (write_size < IO_BLOCK_SIZE)
|
||||
if ((err = disk->read_block(block_num, datablock_buf)) < 0)
|
||||
return err;
|
||||
|
||||
memcpy(&datablock_buf[offset], &buf[bytes_completed], write_size);
|
||||
|
||||
if ((err = disk->write_block(block_num, datablock_buf)) < 0)
|
||||
return err;
|
||||
|
||||
offset = 0;
|
||||
bytes_completed += write_size;
|
||||
|
||||
if (bytes_completed >= count)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
};
|
||||
|
||||
ssize_t Fs::read(INode_Data *inode_data, char buf[], size_t count,
|
||||
size_t offset) {
|
||||
int err;
|
||||
|
||||
u_int64_t start_block_index = offset / IO_BLOCK_SIZE;
|
||||
size_t internal_offset = offset - (start_block_index * IO_BLOCK_SIZE);
|
||||
|
||||
ReadDatablockOperation op = ReadDatablockOperation();
|
||||
op.offset = internal_offset;
|
||||
op.buf = buf;
|
||||
op.count = std::min(count, inode_data->metadata.size - offset);
|
||||
op.bytes_completed = 0;
|
||||
op.disk = disk;
|
||||
|
||||
if ((err = sweep_inode_datablocks(inode_data, start_block_index, false,
|
||||
&op)) < 0)
|
||||
return err;
|
||||
|
||||
return op.bytes_completed;
|
||||
}
|
||||
|
||||
ssize_t Fs::write(INode_Data *inode_data, char buf[], size_t count,
|
||||
size_t offset) {
|
||||
int err;
|
||||
|
||||
u_int64_t start_block_index = offset / IO_BLOCK_SIZE;
|
||||
size_t internal_offset = offset - (start_block_index * IO_BLOCK_SIZE);
|
||||
|
||||
WriteDatablockOperation op = WriteDatablockOperation();
|
||||
op.offset = internal_offset;
|
||||
op.buf = buf;
|
||||
op.count = count;
|
||||
op.bytes_completed = 0;
|
||||
op.disk = disk;
|
||||
|
||||
if ((err = sweep_inode_datablocks(inode_data, start_block_index, true, &op)) <
|
||||
0)
|
||||
return err;
|
||||
|
||||
inode_data->metadata.size =
|
||||
std::max(offset + op.bytes_completed, inode_data->metadata.size);
|
||||
|
||||
return op.bytes_completed;
|
||||
}
|
141
lib/fs/fs_resize.cpp
Normal file
141
lib/fs/fs_resize.cpp
Normal file
@ -0,0 +1,141 @@
|
||||
#include "fs.hpp"
|
||||
|
||||
int Fs::allocate_datablock(INode_Data *inode_data, u_int64_t *datablock_num) {
|
||||
int result;
|
||||
|
||||
for (size_t i = 0; i < NUMBER_OF_DIRECT_BLOCKS; ++i) {
|
||||
result =
|
||||
allocate_indirect(&(inode_data->direct_blocks[i]), 0, datablock_num);
|
||||
if (result <= 0)
|
||||
return result;
|
||||
}
|
||||
|
||||
result =
|
||||
allocate_indirect(&(inode_data->single_indirect_block), 1, datablock_num);
|
||||
if (result <= 0)
|
||||
return result;
|
||||
|
||||
result =
|
||||
allocate_indirect(&(inode_data->double_indirect_block), 2, datablock_num);
|
||||
if (result <= 0)
|
||||
return result;
|
||||
|
||||
result =
|
||||
allocate_indirect(&(inode_data->triple_indirect_block), 3, datablock_num);
|
||||
if (result <= 0)
|
||||
return result;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// This can simply be made non recursive by copy pasting - it is just written
|
||||
// this way as a proof of concept
|
||||
int Fs::allocate_indirect(u_int64_t *storage, int n, u_int64_t *datablock_num) {
|
||||
char buf[IO_BLOCK_SIZE];
|
||||
int result;
|
||||
|
||||
if ((*storage) == 0) {
|
||||
if ((result = datablock_manager->new_datablock(storage)) < 0)
|
||||
return result;
|
||||
if (n == 0) {
|
||||
(*datablock_num) = (*storage);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (n == 0)
|
||||
return 1;
|
||||
|
||||
u_int64_t temp;
|
||||
|
||||
if ((result = disk->read_block(*storage, buf)) < 0)
|
||||
return result;
|
||||
|
||||
for (size_t i = 0; i < IO_BLOCK_SIZE; i += sizeof(u_int64_t)) {
|
||||
read_u64(&temp, &buf[i]);
|
||||
result = allocate_indirect(&temp, n - 1, datablock_num);
|
||||
if (result < 0)
|
||||
return result;
|
||||
if (result == 0) {
|
||||
write_u64(temp, &buf[i]);
|
||||
if ((result = disk->write_block(*storage, buf)) < 0)
|
||||
return result;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int Fs::deallocate_datablock(INode_Data *inode_data, u_int64_t *datablock_num) {
|
||||
int result;
|
||||
|
||||
result = deallocate_indirect(&(inode_data->triple_indirect_block), 3,
|
||||
datablock_num);
|
||||
if (result <= 0)
|
||||
return result;
|
||||
|
||||
result = deallocate_indirect(&(inode_data->double_indirect_block), 2,
|
||||
datablock_num);
|
||||
if (result <= 0)
|
||||
return result;
|
||||
|
||||
result = deallocate_indirect(&(inode_data->single_indirect_block), 1,
|
||||
datablock_num);
|
||||
if (result <= 0)
|
||||
return result;
|
||||
|
||||
for (size_t i = NUMBER_OF_DIRECT_BLOCKS - 1; i >= 0; --i) {
|
||||
result =
|
||||
deallocate_indirect(&(inode_data->direct_blocks[i]), 0, datablock_num);
|
||||
if (result <= 0)
|
||||
return result;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int Fs::deallocate_indirect(u_int64_t *storage, int n,
|
||||
u_int64_t *datablock_num) {
|
||||
char buf[IO_BLOCK_SIZE];
|
||||
int result;
|
||||
|
||||
if (*storage == 0)
|
||||
return 1;
|
||||
|
||||
if (n == 0) {
|
||||
u_int64_t temp_datablock_num = (*storage);
|
||||
if ((result = datablock_manager->free_datablock(*storage)) < 0)
|
||||
return result;
|
||||
(*datablock_num) = temp_datablock_num;
|
||||
(*storage) = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
u_int64_t temp;
|
||||
|
||||
if ((result = disk->read_block(*storage, buf)) < 0)
|
||||
return result;
|
||||
|
||||
for (size_t i = IO_BLOCK_SIZE - sizeof(u_int64_t); i >= 0;
|
||||
i -= sizeof(u_int64_t)) {
|
||||
read_u64(&temp, &buf[i]);
|
||||
result = deallocate_indirect(&temp, n - 1, datablock_num);
|
||||
if (result < 0)
|
||||
return result;
|
||||
if (result == 0) {
|
||||
if (i == 0 && temp == 0) {
|
||||
if ((result = datablock_manager->free_datablock(*storage)) < 0)
|
||||
return result;
|
||||
(*storage) = 0;
|
||||
} else {
|
||||
write_u64(temp, &buf[i]);
|
||||
if ((result = disk->write_block(*storage, buf)) < 0)
|
||||
return result;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
134
lib/fs/inode_manager.cpp
Normal file
134
lib/fs/inode_manager.cpp
Normal file
@ -0,0 +1,134 @@
|
||||
#include "fs.hpp"
|
||||
|
||||
INode_Manager::INode_Manager(Fs *fs, u_int64_t block_segment_start,
|
||||
u_int64_t block_segment_end)
|
||||
: fs(fs), block_segment_start(block_segment_start),
|
||||
block_segment_end(block_segment_end) {
|
||||
max_num_inodes = (block_segment_end - block_segment_start) * INODES_PER_BLOCK;
|
||||
}
|
||||
|
||||
u_int64_t INode_Manager::get_block_num(u_int64_t inode_num) {
|
||||
if (inode_num > max_num_inodes || inode_num == 0)
|
||||
return 0;
|
||||
u_int64_t block_num =
|
||||
block_segment_start + ((inode_num - 1) / INODES_PER_BLOCK);
|
||||
return block_num;
|
||||
}
|
||||
u_int64_t INode_Manager::get_block_offset(u_int64_t inode_num) {
|
||||
return ((inode_num - 1) % INODES_PER_BLOCK) * INODE_SIZE;
|
||||
}
|
||||
|
||||
int INode_Manager::load_inode(INode_Data *inode_data) {
|
||||
char buf[IO_BLOCK_SIZE];
|
||||
int err;
|
||||
|
||||
u_int64_t block_num = get_block_num(inode_data->inode_num);
|
||||
if (block_num == 0)
|
||||
return -1;
|
||||
u_int64_t block_offset = get_block_offset(inode_data->inode_num);
|
||||
|
||||
if ((err = fs->disk->read_block(block_num, buf)) < 0)
|
||||
return err;
|
||||
|
||||
inode_data->deserialize(&buf[block_offset]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
int INode_Manager::save_inode(INode_Data *inode_data) {
|
||||
char buf[IO_BLOCK_SIZE];
|
||||
int err;
|
||||
|
||||
u_int64_t block_num = get_block_num(inode_data->inode_num);
|
||||
if (block_num == 0)
|
||||
return -1;
|
||||
u_int64_t block_offset = get_block_offset(inode_data->inode_num);
|
||||
|
||||
if ((err = fs->disk->read_block(block_num, buf)) < 0)
|
||||
return err;
|
||||
|
||||
inode_data->serialize(&buf[block_offset]);
|
||||
|
||||
if ((err = fs->disk->write_block(block_num, buf)) < 0)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int INode_Manager_Freelist::new_inode(u_int64_t uid, u_int64_t gid,
|
||||
u_int64_t permissions,
|
||||
INode_Data *inode_data) {
|
||||
char buf[IO_BLOCK_SIZE];
|
||||
int err;
|
||||
u_int64_t inode_num = fs->superblock.inode_list_head;
|
||||
if (inode_num > max_num_inodes)
|
||||
return -1;
|
||||
|
||||
u_int64_t block_num = get_block_num(inode_num);
|
||||
u_int64_t block_offset = get_block_offset(inode_num);
|
||||
|
||||
if (block_num == 0)
|
||||
return -1;
|
||||
|
||||
if ((err = fs->disk->read_block(block_num, buf)) < 0)
|
||||
return err;
|
||||
|
||||
u_int64_t new_inode_list_head = 0;
|
||||
read_u64(&new_inode_list_head, &buf[block_offset]);
|
||||
if ((err = fs->save_inode_list_head(new_inode_list_head)) < 0)
|
||||
return err;
|
||||
|
||||
(*inode_data) = INode_Data(inode_num);
|
||||
|
||||
inode_data->metadata.uid = uid;
|
||||
inode_data->metadata.gid = gid;
|
||||
inode_data->metadata.permissions = permissions;
|
||||
|
||||
// It is debatable if this function should do this:
|
||||
if ((err = save_inode(inode_data)) < 0) {
|
||||
inode_data->inode_num = 0xFFFFFFFFFFFFFFFF;
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
int INode_Manager_Freelist::free_inode(INode_Data *inode_data) {
|
||||
char buf[IO_BLOCK_SIZE];
|
||||
int err;
|
||||
|
||||
u_int64_t block_num = get_block_num(inode_data->inode_num);
|
||||
u_int64_t block_offset = get_block_offset(inode_data->inode_num);
|
||||
|
||||
if (block_num == 0)
|
||||
return -1;
|
||||
|
||||
if ((err = fs->disk->read_block(block_num, buf)) < 0)
|
||||
return err;
|
||||
|
||||
write_u64(fs->superblock.inode_list_head, &buf[block_offset]);
|
||||
|
||||
if ((err = fs->disk->write_block(block_num, buf)) < 0)
|
||||
return err;
|
||||
|
||||
if ((err = fs->save_inode_list_head(inode_data->inode_num)) < 0)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int INode_Manager_Freelist::format() {
|
||||
char buf[IO_BLOCK_SIZE];
|
||||
int err;
|
||||
u_int64_t next_inode_num = 2;
|
||||
for (u_int64_t i = block_segment_start; i < block_segment_end; ++i) {
|
||||
for (int j = 0; j < INODES_PER_BLOCK; ++next_inode_num, ++j) {
|
||||
if (next_inode_num > max_num_inodes)
|
||||
next_inode_num = 0;
|
||||
write_u64(next_inode_num, &buf[j * INODE_SIZE]);
|
||||
}
|
||||
if ((err = fs->disk->write_block(i, buf)) < 0)
|
||||
return err;
|
||||
}
|
||||
if ((err = fs->save_inode_list_head(1)) < 0)
|
||||
return err;
|
||||
return 0;
|
||||
}
|
89
lib/main.cpp
89
lib/main.cpp
@ -1,9 +1,86 @@
|
||||
#include "fischl.h"
|
||||
#include "rawdisk.h"
|
||||
#include "fs.hpp"
|
||||
#include <stdio.h>
|
||||
|
||||
int main(){
|
||||
fischl();
|
||||
char *d = strdup("/dev/vdc");
|
||||
RawDisk *H = new RawDisk(d);
|
||||
return 0;
|
||||
int main() {
|
||||
// printf("hello word!");
|
||||
// fischl *F = new fischl;
|
||||
// F->init();
|
||||
// char *d = strdup("/dev/vdc");
|
||||
|
||||
// RawDisk *disk = new FakeRawDisk(2048);
|
||||
// Fs *fs = new Fs(disk);
|
||||
// fs->format();
|
||||
// disk->print_block(0);
|
||||
// disk->print_block(1);
|
||||
// INode_Data inode_data = INode_Data();
|
||||
// fs->inode_manager->new_inode(1, 2, 3, &inode_data);
|
||||
// int err;
|
||||
// u_int64_t block_num = 0;
|
||||
// for (int i = 0; i < 56 + 512 + 4; ++i)
|
||||
// err = fs->allocate_datablock(&inode_data, &block_num);
|
||||
|
||||
// for (int i = 0; i < 5; ++i)
|
||||
// printf("%d\n", err = fs->deallocate_datablock(&inode_data, &block_num));
|
||||
|
||||
// fs->inode_manager->save_inode(&inode_data);
|
||||
|
||||
// disk->print_block(0);
|
||||
// disk->print_block(1);
|
||||
|
||||
// disk->print_block(1081);
|
||||
|
||||
// disk->print_block(1596);
|
||||
|
||||
// disk->print_block(1597);
|
||||
|
||||
int err;
|
||||
|
||||
RawDisk *disk = new FakeRawDisk(2048);
|
||||
Fs *fs = new Fs(disk);
|
||||
fs->format();
|
||||
disk->print_block(0);
|
||||
disk->print_block(1);
|
||||
|
||||
INode_Data inode_data;
|
||||
fs->inode_manager->new_inode(1, 2, 3, &inode_data);
|
||||
|
||||
disk->print_block(0);
|
||||
disk->print_block(1);
|
||||
|
||||
int BL_SIZE = 4096 / 8;
|
||||
|
||||
u_int64_t buf[BL_SIZE * (56 + 512 + 10)];
|
||||
|
||||
for (int i = 0; i < BL_SIZE * (56 + 512 + 10); ++i)
|
||||
buf[i] = (i / BL_SIZE) + 1;
|
||||
|
||||
err = fs->write(&inode_data, (char *)buf, 4096 * (56 + 3) + 16 + 8, 0);
|
||||
fs->inode_manager->save_inode(&inode_data);
|
||||
|
||||
printf("Write %d", err);
|
||||
|
||||
disk->print_block(0);
|
||||
disk->print_block(1);
|
||||
disk->print_block(1025);
|
||||
disk->print_block(1026);
|
||||
disk->print_block(1027);
|
||||
disk->print_block(1080);
|
||||
disk->print_block(1081);
|
||||
disk->print_block(1082);
|
||||
disk->print_block(1083);
|
||||
disk->print_block(1084);
|
||||
disk->print_block(1085);
|
||||
|
||||
int N = 5;
|
||||
|
||||
u_int64_t buf2[4096] = {0};
|
||||
err = fs->read(&inode_data, (char *)buf2, (8 * N), 4096 - 8 - 8);
|
||||
|
||||
printf("\n\nREAD: %d\n", err);
|
||||
for (int i = 0; i < N; ++i)
|
||||
printf("%d ", buf2[i]);
|
||||
printf("\n");
|
||||
|
||||
return 0;
|
||||
}
|
134
lib/rawdisk.cpp
Normal file
134
lib/rawdisk.cpp
Normal file
@ -0,0 +1,134 @@
|
||||
#include "fs.hpp"
|
||||
|
||||
void RawDisk::print_block(u_int64_t block_number) {
|
||||
const int nums_per_line = 64;
|
||||
char buf[IO_BLOCK_SIZE];
|
||||
u_int64_t num;
|
||||
|
||||
if (read_block(block_number, buf) < 0) {
|
||||
perror("Error printing datablock");
|
||||
return;
|
||||
}
|
||||
|
||||
printf("\nBlock %llu:\n", block_number);
|
||||
for (int i = 0; i < IO_BLOCK_SIZE; i += sizeof(u_int64_t)) {
|
||||
num = 0;
|
||||
for (int j = 0; j < 8; j++)
|
||||
num |= ((u_int64_t)(unsigned char)buf[i + j]) << (8 * j);
|
||||
printf("%llu ", num);
|
||||
if ((i / sizeof(u_int64_t)) % nums_per_line == nums_per_line - 1)
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
RealRawDisk::RealRawDisk(const char *directory)
|
||||
: fd(-1), dir(nullptr), numSectors(0) {
|
||||
dir = directory;
|
||||
diskSize = 0;
|
||||
/*dir = strdup("/dev/vdc");
|
||||
numSectors = 62914560;
|
||||
diskSize = 32212254720;*/
|
||||
|
||||
// Open the block device (replace /dev/sdX with the actual device)
|
||||
fd = open(dir, O_RDWR); // Allow read and write
|
||||
if (fd == -1) {
|
||||
perror("Error opening device");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Use ioctl with BLKGETSIZE to get the number of sectors
|
||||
if (ioctl(fd, BLKGETSIZE64, &diskSize) == -1) {
|
||||
perror("Error getting disk size");
|
||||
close(fd);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Calculate the size in bytes
|
||||
numSectors = diskSize / 512; // Assuming a sector size of 512 bytes
|
||||
|
||||
printf("====Initializing RawDisk====\n");
|
||||
printf("Number of sectors: %llu\n", numSectors);
|
||||
printf("Disk size (in bytes): %llu\n", diskSize);
|
||||
}
|
||||
|
||||
RealRawDisk::~RealRawDisk() {
|
||||
if (fd != -1) {
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
|
||||
int RealRawDisk::read_block(u_int64_t block_number, char *buffer) {
|
||||
u_int64_t offset = block_number * IO_BLOCK_SIZE;
|
||||
|
||||
if (lseek(fd, offset, SEEK_SET) == (u_int64_t)-1) {
|
||||
perror("Error seeking to offset");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// TODO: this is incorrect
|
||||
ssize_t bytesRead = read(fd, buffer, IO_BLOCK_SIZE);
|
||||
if (bytesRead < IO_BLOCK_SIZE) {
|
||||
perror("Error reading from device");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int RealRawDisk::write_block(u_int64_t block_number, char *buffer) {
|
||||
u_int64_t offset = block_number * IO_BLOCK_SIZE;
|
||||
|
||||
if (lseek(fd, offset, SEEK_SET) == (u_int64_t)-1) {
|
||||
perror("Error seeking to offset");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// TODO: this is incorrect
|
||||
ssize_t bytesWritten = write(fd, buffer, IO_BLOCK_SIZE);
|
||||
if (bytesWritten < IO_BLOCK_SIZE) {
|
||||
perror("Error writing to device");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
FakeRawDisk::FakeRawDisk(u_int64_t num_blocks) {
|
||||
diskSize = num_blocks * IO_BLOCK_SIZE;
|
||||
disk = new char[diskSize];
|
||||
if (disk == nullptr) {
|
||||
perror("Error allocating fake disk");
|
||||
exit(1);
|
||||
}
|
||||
printf("====Initializing FAKE RawDisk====\n");
|
||||
printf("FAKE Disk size (in bytes): %llu\n", diskSize);
|
||||
perror("!!! USING FAKE RawDisk - THIS IS FOR TESTING ONLY !!!");
|
||||
}
|
||||
|
||||
FakeRawDisk::~FakeRawDisk() { delete[] disk; }
|
||||
|
||||
int FakeRawDisk::read_block(u_int64_t block_number, char *buffer) {
|
||||
u_int64_t offset = block_number * IO_BLOCK_SIZE;
|
||||
|
||||
if (offset + IO_BLOCK_SIZE > diskSize) {
|
||||
perror("Error reading past fake disk size");
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(buffer, &disk[offset], IO_BLOCK_SIZE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int FakeRawDisk::write_block(u_int64_t block_number, char *buffer) {
|
||||
u_int64_t offset = block_number * IO_BLOCK_SIZE;
|
||||
|
||||
if (offset + IO_BLOCK_SIZE > diskSize) {
|
||||
perror("Error writing past fake disk size");
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(&disk[offset], buffer, IO_BLOCK_SIZE);
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,17 +1,34 @@
|
||||
set(TARGET_LAYER0 test_layer0)
|
||||
set(TARGET_LAYER1_API test_layer1_API)
|
||||
# set(TARGET_LAYER1_TEST1 test_layer1_test1)
|
||||
set(DIR_PLACE /dev/vdb)
|
||||
|
||||
# add test sources here ...
|
||||
add_executable(${TARGET_LAYER0}
|
||||
# add need lib and source code here
|
||||
layer0.cpp
|
||||
|
||||
../lib/rawdisk.cpp
|
||||
|
||||
)
|
||||
add_executable(${TARGET_LAYER1_API}
|
||||
# add need lib and source code here
|
||||
layer1_API.cpp
|
||||
|
||||
../lib/fischl.cpp
|
||||
../lib/rawdisk.cpp
|
||||
../lib/fs/datablock_manager.cpp
|
||||
../lib/fs/fs_data_types.cpp
|
||||
../lib/fs/fs_resize.cpp
|
||||
../lib/fs/fs.cpp
|
||||
../lib/fs/inode_manager.cpp
|
||||
)
|
||||
# add_executable(${TARGET_LAYER1_TEST1}
|
||||
# # add need lib and source code here
|
||||
# layer1_test1.cpp
|
||||
# )
|
||||
|
||||
# add test to activate ctest -VV
|
||||
add_test(NAME ${TARGET_LAYER0} COMMAND sudo ./${TARGET_LAYER0} ${DIR_PLACE})
|
||||
add_test(NAME ${TARGET_LAYER1_API} COMMAND sudo ./${TARGET_LAYER1_API} ${DIR_PLACE})
|
||||
# add_test(NAME ${TARGET_LAYER1_TEST1} COMMAND sudo ./${TARGET_LAYER1_TEST1} ${DIR_PLACE})
|
@ -1,29 +1,32 @@
|
||||
#include "rawdisk.hpp"
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include "rawdisk.h"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
const char* d = (argc < 2) ? "/dev/vdc" : argv[1];
|
||||
const char *d = (argc < 2) ? "/dev/vdc" : argv[1];
|
||||
|
||||
RawDisk *H = new RawDisk(d);
|
||||
RawDisk *H = new RealRawDisk(d);
|
||||
|
||||
char *buf = "iloveosdfjlseirfnerig";
|
||||
char readBuffer[512] = {0}; // Initialize to zeros
|
||||
char *buf = "iloveosdfjlseirfnerig";
|
||||
char readBuffer[IO_BLOCK_SIZE] = {0}; // Initialize to zeros
|
||||
|
||||
//printf("dir %s, numSectors %lld, diskSize %lld \n", H->dir, H->numSectors, H->diskSize);
|
||||
// printf("dir %s, numSectors %lld, diskSize %lld \n", H->dir, H->numSectors,
|
||||
// H->diskSize);
|
||||
|
||||
//use number to substitute H->getnumSector(), getnumSectors() are not yest implemented
|
||||
for(u_int64_t i = 0; i < 10; i++) {
|
||||
H->rawdisk_write(i*512, buf, strlen(buf));//Change write_API
|
||||
}
|
||||
//use number to substitute H->getnumSector(), getnumSectors() are not yest implemented
|
||||
for(u_int64_t i = 0; i < 10; i++) {
|
||||
H->rawdisk_read(i*512, readBuffer, sizeof(readBuffer));//Change read_API
|
||||
assert(strncmp(readBuffer, buf, strlen(buf)) == 0);
|
||||
}
|
||||
// use number to substitute H->getnumSector(), getnumSectors() are not yest
|
||||
// implemented
|
||||
for (u_int64_t i = 0; i < 10; i++) {
|
||||
H->write_block(i, buf); // Change write_API
|
||||
}
|
||||
// use number to substitute H->getnumSector(), getnumSectors() are not yest
|
||||
// implemented
|
||||
for (u_int64_t i = 0; i < 10; i++) {
|
||||
H->read_block(i, readBuffer); // Change read_API
|
||||
assert(strncmp(readBuffer, buf, strlen(buf)) == 0);
|
||||
}
|
||||
|
||||
delete H; // Delete the RawDisk object
|
||||
delete H; // Delete the RawDisk object
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,118 +1,144 @@
|
||||
#include "fs.hpp"
|
||||
#include <assert.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include "fs.h"
|
||||
#include <inttypes.h>
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
const char* d = (argc < 2) ? "/dev/vdc" : argv[1];
|
||||
// const char* d = (argc < 2) ? "/dev/vdc" : argv[1];
|
||||
|
||||
RawDisk *H = new RawDisk(d);
|
||||
RawDisk *H = new FakeRawDisk(2048);
|
||||
Fs *fs = new Fs(H);
|
||||
|
||||
printf("test inode\n");
|
||||
INodeOperation inop;
|
||||
inop.initialize(*H);//for inode initialization and datablock initialization
|
||||
char buffer[8] = {0};
|
||||
/**************************test inode Initialization***************************/
|
||||
//test the begining of inode 1th
|
||||
H->rawdisk_read((1) * SECTOR_SIZE, buffer, sizeof(buffer));
|
||||
u_int64_t t = 0;
|
||||
for (int j = 0; j < 8; j++)
|
||||
t |= ((u_int64_t)(unsigned char)buffer[j]) << (8 * j);
|
||||
printf("test inode\n");
|
||||
fs->format();
|
||||
char buffer[IO_BLOCK_SIZE] = {0};
|
||||
/**************************test inode
|
||||
* Initialization***************************/
|
||||
// test the begining of inode 1th
|
||||
H->read_block(1, buffer);
|
||||
u_int64_t t = 0;
|
||||
for (int j = 0; j < 8; j++)
|
||||
t |= ((u_int64_t)(unsigned char)buffer[j]) << (8 * j);
|
||||
|
||||
assert(t == 2);//the first 1th unused inode will store the next unused inode 2th
|
||||
//test the number before end of inode 524286th
|
||||
H->rawdisk_read((MAX_INODE - 2) * SECTOR_SIZE, buffer, sizeof(buffer));
|
||||
t = 0;
|
||||
for (int j = 0; j < 8; j++)
|
||||
t |= ((u_int64_t)(unsigned char)buffer[j]) << (8 * j);
|
||||
assert(t ==
|
||||
2); // the first 1th unused inode will store the next unused inode 2th
|
||||
|
||||
assert(t == MAX_INODE - 1);//store the maximun th inode
|
||||
//test the end of inode 524287th
|
||||
H->rawdisk_read((MAX_INODE - 1) * SECTOR_SIZE, buffer, sizeof(buffer));
|
||||
t = 0;
|
||||
for (int j = 0; j < 8; j++)
|
||||
t |= ((u_int64_t)(unsigned char)buffer[j]) << (8 * j);
|
||||
assert(IO_BLOCK_SIZE == 4096);
|
||||
assert(INODE_SIZE == 512);
|
||||
|
||||
assert(t == 0);//the end of inode(524287th inode) do not have the next inode address
|
||||
/**************************test datablock Initialization***************************/
|
||||
//we separate 2048 4kB I/O block(1+2047) as a group and the first I/O block will manage the following 2047 I/O block usage.
|
||||
//the first 8 bytes(0~7) in first I/O block store the address of next first I/O block, the following 256(8~263) bytes record 2047 I/O block usage.
|
||||
//test the begining of free datablock
|
||||
H->rawdisk_read((MAX_INODE) * SECTOR_SIZE, buffer, sizeof(buffer));//the begining of free datablock will store from address (MAX_INODE) * SECTOR_SIZE
|
||||
t = 0;
|
||||
for (int j = 0; j < 8; j++)
|
||||
t |= ((u_int64_t)(unsigned char)buffer[j]) << (8 * j);
|
||||
// test the number before end of inode
|
||||
H->read_block(NUM_INODE_BLOCKS, buffer);
|
||||
t = 0;
|
||||
for (int j = 0; j < 8; j++)
|
||||
t |=
|
||||
((u_int64_t)(unsigned char)buffer[j + IO_BLOCK_SIZE - (INODE_SIZE * 2)])
|
||||
<< (8 * j);
|
||||
|
||||
assert(t == (MAX_INODE+2048*8)*SECTOR_SIZE);//the first 8 bytes of 4k I/O block will store the next address(after 2048*4k I/O block)
|
||||
//test the end of the datablock
|
||||
H->rawdisk_read((MAX_BLOCKNUM - 2048*8) * SECTOR_SIZE, buffer, sizeof(buffer));
|
||||
t = 0;
|
||||
for (int j = 0; j < 8; j++)
|
||||
t |= ((u_int64_t)(unsigned char)buffer[j]) << (8 * j);
|
||||
assert(t == NUM_INODE_BLOCKS *
|
||||
(IO_BLOCK_SIZE / INODE_SIZE)); // store the maximun th inode
|
||||
|
||||
assert(t == (MAX_BLOCKNUM)*SECTOR_SIZE);
|
||||
// test the end of inode
|
||||
t = 0;
|
||||
for (int j = 0; j < 8; j++)
|
||||
t |= ((u_int64_t)(unsigned char)buffer[j + IO_BLOCK_SIZE - INODE_SIZE])
|
||||
<< (8 * j);
|
||||
|
||||
/***************************test inode de/allocation**********************************/
|
||||
//when requesting an inode, the inode_allocation will give you the inode number, we use inode_list to store the sequence allocate inode
|
||||
//arrary version
|
||||
int inode_list[20] = {0};
|
||||
int record_free[10] = {0};//should do a pop up structure to record the free inode
|
||||
int rec = 9;
|
||||
//printf("Allocate 20 inode num:{");
|
||||
for(int i=0;i<20;i++){
|
||||
inode_list[i] = inop.inode_allocate(*H);
|
||||
assert(inode_list[i] == i+1);
|
||||
//printf(" %d", inode_list[i]);
|
||||
assert(
|
||||
t ==
|
||||
0); // the end of inode(524287th inode) do not have the next inode address
|
||||
/**************************test datablock
|
||||
* Initialization***************************/
|
||||
// we separate 2048 4kB I/O block(1+2047) as a group and the first I/O block
|
||||
// will manage the following 2047 I/O block usage. the first 8 bytes(0~7) in
|
||||
// first I/O block store the address of next first I/O block, the following
|
||||
// 256(8~263) bytes record 2047 I/O block usage. test the begining of free
|
||||
// datablock
|
||||
H->read_block(NUM_INODE_BLOCKS + 1,
|
||||
buffer); // the begining of free datablock will store
|
||||
// from address (MAX_INODE) * SECTOR_SIZE
|
||||
t = 0;
|
||||
for (int j = 0; j < 8; j++)
|
||||
t |= ((u_int64_t)(unsigned char)buffer[j]) << (8 * j);
|
||||
|
||||
assert(t == NUM_INODE_BLOCKS + 1 + DATABLOCKS_PER_BITMAP_BLOCK +
|
||||
1); // the first 8 bytes of 4k I/O block will store
|
||||
// the next address(after 2048*4k I/O block)
|
||||
// test the end of the datablock
|
||||
H->read_block(NUM_BLOCKS - DATABLOCKS_PER_BITMAP_BLOCK - 1, buffer);
|
||||
t = 0;
|
||||
for (int j = 0; j < 8; j++)
|
||||
t |= ((u_int64_t)(unsigned char)buffer[j]) << (8 * j);
|
||||
|
||||
assert(t == NUM_BLOCKS - DATABLOCKS_PER_BITMAP_BLOCK - 1);
|
||||
|
||||
/***************************test inode
|
||||
* de/allocation**********************************/
|
||||
// when requesting an inode, the inode_allocation will give you the inode
|
||||
// number, we use inode_list to store the sequence allocate inode arrary
|
||||
// version
|
||||
INode_Data inode_list[20];
|
||||
u_int64_t record_free[10] = {
|
||||
0}; // should do a pop up structure to record the free inode
|
||||
int rec = 9;
|
||||
// printf("Allocate 20 inode num:{");
|
||||
for (int i = 0; i < 20; i++) {
|
||||
fs->inode_manager->new_inode(0, 0, 0, &inode_list[i]);
|
||||
|
||||
assert(inode_list[i].inode_num == i + 1);
|
||||
// printf(" %d", inode_list[i].inode_num);
|
||||
}
|
||||
// printf("}\n");
|
||||
for (int i = 10; i < 20; i++) {
|
||||
record_free[i - 10] = inode_list[i].inode_num;
|
||||
fs->inode_manager->free_inode(
|
||||
&inode_list[i]); // free the 10 element from inode_list[10]
|
||||
}
|
||||
// allocate again the last 10
|
||||
printf("Allocate again: inode num:{");
|
||||
for (int i = 10; i < 20; i++) {
|
||||
fs->inode_manager->new_inode(0, 0, 0, &inode_list[i]);
|
||||
// printf("inode %d, rec_f %d\n,", inode_list[i],record_free[rec]);
|
||||
assert(inode_list[i].inode_num == record_free[rec]);
|
||||
rec--;
|
||||
}
|
||||
printf("}\n");
|
||||
/***************************test direct blocks[48]
|
||||
* de/allocation**********************************/
|
||||
// after free the datablock, the program will find the first smallest address
|
||||
// of datablock to give to the inode should test random resize each node, but
|
||||
// should use datablock_free data structure to record
|
||||
u_int64_t rec_datablock_free[10][3] = {0}; // array version
|
||||
u_int64_t temp_block_num = 0;
|
||||
for (int i = 0; i < 10; i++) {
|
||||
// printf("%dth data block starting addres: ", i);
|
||||
for (int j = 0; j < 6; j++) {
|
||||
fs->allocate_datablock(&inode_list[i], &temp_block_num);
|
||||
// printf("%d," ,inode_inside[i].datablock_allocate(*H));
|
||||
}
|
||||
//printf("}\n");
|
||||
for(int i=10;i<20;i++){
|
||||
inop.inode_free(*H,inode_list[i]);//free the 10 element from inode_list[10]
|
||||
record_free[i-10] = inode_list[i];
|
||||
}
|
||||
//allocate again the last 10
|
||||
printf("Allocate again: inode num:{");
|
||||
for(int i=10;i<20;i++){
|
||||
inode_list[i] = inop.inode_allocate(*H);
|
||||
//printf("inode %d, rec_f %d\n,", inode_list[i],record_free[rec]);
|
||||
assert(inode_list[i] == record_free[rec]);
|
||||
rec--;
|
||||
}
|
||||
printf("}\n");
|
||||
/***************************test direct blocks[48] de/allocation**********************************/
|
||||
//after free the datablock, the program will find the first smallest address of datablock to give to the inode
|
||||
//should test random resize each node, but should use datablock_free data structure to record
|
||||
INode inode_inside[10];
|
||||
u_int64_t rec_datablock_free[10][3] = {0};//array version
|
||||
for(int i=0;i<10;i++){
|
||||
inode_inside[i].inode_construct(inode_list[i],*H);
|
||||
//printf("%dth data block starting addres: ", i);
|
||||
for(int j=0;j<6;j++){
|
||||
inode_inside[i].datablock_allocate(*H);
|
||||
//printf("%d," ,inode_inside[i].datablock_allocate(*H));
|
||||
}
|
||||
//printf("\n");
|
||||
}
|
||||
for(int i=0;i<10;i++){
|
||||
//printf("%dth data block free addres: ", i);
|
||||
for(int j = 2;j >=0;j--){
|
||||
rec_datablock_free[i][j] = inode_inside[i].datablock_deallocate(*H);
|
||||
//printf("", rec_datablock_free[i][j]);
|
||||
}
|
||||
//printf("\n");
|
||||
// printf("\n");
|
||||
}
|
||||
for (int i = 0; i < 10; i++) {
|
||||
// printf("%dth data block free addres: ", i);
|
||||
for (int j = 2; j >= 0; j--) {
|
||||
fs->deallocate_datablock(&inode_list[i], &(rec_datablock_free[i][j]));
|
||||
// printf("", rec_datablock_free[i][j]);
|
||||
}
|
||||
// printf("\n");
|
||||
}
|
||||
|
||||
for(int i=0;i<10;i++){
|
||||
//printf("%dth data block allocate again addres: ", i);
|
||||
for(int j=0;j<3;j++){
|
||||
assert(inode_inside[i].datablock_allocate(*H) == rec_datablock_free[i][j]);
|
||||
//printf("%d," ,inode_inside[i].datablock_allocate(*H));
|
||||
}
|
||||
//printf("\n");
|
||||
for (int i = 0; i < 10; i++) {
|
||||
// printf("%dth data block allocate again addres: ", i);
|
||||
for (int j = 0; j < 3; j++) {
|
||||
fs->allocate_datablock(&inode_list[i], &temp_block_num);
|
||||
assert(temp_block_num == rec_datablock_free[i][j]);
|
||||
// printf("%d," ,inode_inside[i].datablock_allocate(*H));
|
||||
}
|
||||
// printf("\n");
|
||||
}
|
||||
|
||||
//printf("}\n");
|
||||
delete H; // Delete the RawDisk object
|
||||
// printf("}\n");
|
||||
delete H; // Delete the RawDisk object
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
130
test/layer1_test1.cpp
Normal file
130
test/layer1_test1.cpp
Normal file
@ -0,0 +1,130 @@
|
||||
// #include "fs.h"
|
||||
// #include <assert.h>
|
||||
// #include <inttypes.h>
|
||||
// #include <stdio.h>
|
||||
// #include <string.h>
|
||||
|
||||
// // in fs.h:
|
||||
// // #define MAX_INODE 2048
|
||||
// // #define MAX_BLOCKNUM 51200
|
||||
// // 51200 Sectors = 2048 * 25 Sectors = 25MB
|
||||
// // Free List Heads: 2048*512, 2048*9*512, 2048*17*512
|
||||
// // Available INodes: 2047 (-1 because superblock)
|
||||
// // Available DataBlocks (including Indirect Blocks): 2047 * 3 = 6141
|
||||
|
||||
// int main(int argc, char *argv[]) {
|
||||
// const char *d = (argc < 2) ? "/dev/vdc" : argv[1];
|
||||
|
||||
// RawDisk *H = new FakeRawDisk(d);
|
||||
|
||||
// printf("=== INode Alloc/Dealloc Test ===\n");
|
||||
// INodeOperation inop;
|
||||
// inop.initialize(*H);
|
||||
|
||||
// // Test INode alloc and dealloc
|
||||
// int inode_list[2046] = {
|
||||
// 0}; // if we allocate 2047 inodes head will be 0 (faulty)
|
||||
// printf("freeInodeHead: %d \n",
|
||||
// SuperBlock::getFreeINodeHead(*H)); // this impl should give 1
|
||||
// for (int i = 0; i < 2046; i++) {
|
||||
// inode_list[i] = inop.inode_allocate(*H);
|
||||
// if (SuperBlock::getFreeINodeHead(*H) == 0) {
|
||||
// printf("%d\n", i);
|
||||
// assert(false);
|
||||
// }
|
||||
// }
|
||||
// printf("freeInodeHead: %d \n",
|
||||
// SuperBlock::getFreeINodeHead(*H)); // this impl should give 2047
|
||||
// for (int i = 0; i < 1024; i++) {
|
||||
// inop.inode_free(*H, inode_list[i]);
|
||||
// }
|
||||
// for (int i = 0; i < 1022; i++) {
|
||||
// inode_list[i] = inop.inode_allocate(*H);
|
||||
// assert(SuperBlock::getFreeINodeHead(*H) != 0);
|
||||
// }
|
||||
// printf("freeInodeHead: %d \n",
|
||||
// SuperBlock::getFreeINodeHead(*H)); // this impl should give 2
|
||||
// inode_list[1022] = inop.inode_allocate(*H);
|
||||
// printf("freeInodeHead: %d \n",
|
||||
// SuperBlock::getFreeINodeHead(*H)); // this impl should give 1
|
||||
// inode_list[1023] = inop.inode_allocate(*H);
|
||||
// printf("freeInodeHead: %d \n",
|
||||
// SuperBlock::getFreeINodeHead(*H)); // this impl should give 2047
|
||||
|
||||
// // Test Many Files
|
||||
// printf("=== Many Files Test ===\n");
|
||||
// INode inode_inside[100];
|
||||
// for (int i = 0; i < 100; i++) {
|
||||
// inode_inside[i].inode_construct(inode_list[i], *H);
|
||||
// for (int j = 0; j < 60;
|
||||
// j++) { // Note that 1 indirect block is used for each file
|
||||
// u_int64_t allcBlockNum = inode_inside[i].datablock_allocate(*H);
|
||||
// if (SuperBlock::getFreeListHead(*H) >= (u_int64_t)51200 * 512) {
|
||||
// printf("Bad FreeListHead: %d, %d, %llu\n", i, j,
|
||||
// SuperBlock::getFreeListHead(*H));
|
||||
// assert(false);
|
||||
// }
|
||||
// if (allcBlockNum % 2048 != 0 || allcBlockNum < 2048 * 512 ||
|
||||
// allcBlockNum >= 25 * 2048 * 512) {
|
||||
// printf("Bad Allocated Block Number: %d, %d, %llu\n", i, j,
|
||||
// allcBlockNum);
|
||||
// assert(false);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// printf("Finished Allocating\n");
|
||||
// // in this impl should give 17*2048*512 = 17825792
|
||||
// printf(
|
||||
// "freeListHead: %llu \n",
|
||||
// SuperBlock::getFreeListHead(
|
||||
// *H)); // if all 6141 blocks allocated, would give 51200*512
|
||||
// (faulty)
|
||||
// for (int i = 0; i < 100; i++) {
|
||||
// for (int j = 0; j < 59; j++) {
|
||||
// u_int64_t freedBlkNum = inode_inside[i].datablock_deallocate(*H);
|
||||
// u_int64_t fh = SuperBlock::getFreeListHead(*H);
|
||||
// if (freedBlkNum % 2048 != 0 || freedBlkNum < 2048 * 512 ||
|
||||
// freedBlkNum >= 25 * 2048 * 512 || fh >= 51200 * 512) {
|
||||
// printf("%d, %d, Freed Block Number: %llu\n", i, j, freedBlkNum);
|
||||
// printf("FreeListHead is %llu\n", fh);
|
||||
// assert(false);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// printf("Finished Deallocating\n");
|
||||
// printf("freeListHead: %d \n", SuperBlock::getFreeListHead(*H));
|
||||
|
||||
// // Test Big File (Use direct, single indirect, double indirect)
|
||||
// printf("=== Big File Test ===\n");
|
||||
// u_int64_t lastAllc = 0;
|
||||
// for (int j = 0; j < 5000; j++) {
|
||||
// u_int64_t allcBlockNum = inode_inside[0].datablock_allocate(*H);
|
||||
// lastAllc = allcBlockNum;
|
||||
// u_int64_t fh = SuperBlock::getFreeListHead(*H);
|
||||
// if (allcBlockNum % 2048 != 0 || allcBlockNum < 2048 * 512 ||
|
||||
// allcBlockNum >= 25 * 2048 * 512 || fh >= 51200 * 512) {
|
||||
// printf("%d, Alloc Block Number: %llu\n", j, allcBlockNum);
|
||||
// printf("FreeListHead is %llu\n", fh);
|
||||
// assert(false);
|
||||
// }
|
||||
// }
|
||||
// printf("last allocate for big file: %llu\n", lastAllc);
|
||||
// printf("Finished Allocating\n");
|
||||
// printf("freeListHead: %d \n", SuperBlock::getFreeListHead(*H));
|
||||
// for (int j = 0; j < 5000; j++) {
|
||||
// u_int64_t freedBlkNum = inode_inside[0].datablock_deallocate(*H);
|
||||
// u_int64_t fh = SuperBlock::getFreeListHead(*H);
|
||||
// if (freedBlkNum % 2048 != 0 || freedBlkNum < 2048 * 512 ||
|
||||
// freedBlkNum >= 25 * 2048 * 512 || fh >= 51200 * 512) {
|
||||
// printf("%d, Freed Block Number: %llu\n", j, freedBlkNum);
|
||||
// printf("FreeListHead is %llu\n", fh);
|
||||
// assert(false);
|
||||
// }
|
||||
// }
|
||||
// printf("Finished Deallocating\n");
|
||||
// printf("freeListHead: %d \n", SuperBlock::getFreeListHead(*H));
|
||||
|
||||
// delete H; // Delete the RawDisk object
|
||||
|
||||
// return 0;
|
||||
// }
|
Loading…
x
Reference in New Issue
Block a user