aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsotech117 <michael_foiani@brown.edu>2024-04-25 16:04:44 +0000
committersotech117 <michael_foiani@brown.edu>2024-04-25 16:04:44 +0000
commit4f1fb377b55f04399dd9520ca8ff6122a0703887 (patch)
tree13ac5672bbe4288b21eff9b6ad8b3f70b6267215
parentc9f4da6024393310e254a2cba679b1f1cc67607a (diff)
s5 hopes
-rw-r--r--kernel/fs/s5fs/s5fs.c18
-rw-r--r--kernel/fs/s5fs/s5fs_subr.c442
2 files changed, 441 insertions, 19 deletions
diff --git a/kernel/fs/s5fs/s5fs.c b/kernel/fs/s5fs/s5fs.c
index 2bcec7d..819b106 100644
--- a/kernel/fs/s5fs/s5fs.c
+++ b/kernel/fs/s5fs/s5fs.c
@@ -221,9 +221,15 @@ static void s5fs_read_vnode(fs_t *fs, vnode_t *vn)
// Update linkcount
s5_inode->s5_linkcount++;
- // Get the inode from the disk
+ // Get the page frame for the inode
pframe_t *pf;
- s5_get_file_disk_block(vn, S5_INODE_BLOCK(vn->vn_vno), S5_INODE_OFFSET(vn->vn_vno), 0, &pf);
+ long err = s5fs_get_pframe(vn, &vn->vn_mobj, 0, &pf);
+ // Check if the page frame was not found
+ if (err < 0)
+ {
+ return;
+ }
+ // Copy the inode from the page frame
memcpy(s5_inode, pf->pf_addr, sizeof(s5_inode_t));
// Release the disk block
@@ -300,7 +306,13 @@ static void s5fs_delete_vnode(fs_t *fs, vnode_t *vn)
{
// Write the inode back to disk and return
pframe_t *pf;
- s5_get_file_disk_block(vn, S5_INODE_BLOCK(vn->vn_vno), S5_INODE_OFFSET(vn->vn_vno), 1, &pf);
+ long err = s5fs_get_pframe(vn, &vn->vn_mobj, 1, &pf);
+ // Check if the page frame was not found
+ if (err < 0)
+ {
+ return;
+ }
+ // Copy the inode to the page frame
memcpy(pf->pf_addr, s5_inode, sizeof(s5_inode_t));
s5_release_disk_block(&pf);
return;
diff --git a/kernel/fs/s5fs/s5fs_subr.c b/kernel/fs/s5fs/s5fs_subr.c
index 27b6a92..0d12030 100644
--- a/kernel/fs/s5fs/s5fs_subr.c
+++ b/kernel/fs/s5fs/s5fs_subr.c
@@ -131,8 +131,123 @@ static inline void s5_release_file_block(pframe_t **pfp)
long s5_file_block_to_disk_block(s5_node_t *sn, size_t file_blocknum,
int alloc, int *newp)
{
- NOT_YET_IMPLEMENTED("S5FS: s5_file_block_to_disk_block");
- return -1;
+ // NOT_YET_IMPLEMENTED("S5FS: s5_file_block_to_disk_block");
+ *newp = 0; // assign any garbage values to 0
+
+ // Check if file_blocknum is greater than or equal to S5_MAX_FILE_BLOCKS
+ if (file_blocknum >= S5_MAX_FILE_BLOCKS)
+ {
+ return -EINVAL;
+ }
+
+ // clearer renaming
+ int is_indirect_block_allocated = sn->inode.s5_indirect_block;
+
+ // Case 1: file_blocknum < S5_NDIRECT_BLOCKS
+ if (file_blocknum < S5_NDIRECT_BLOCKS)
+ {
+ size_t disk_blocknum = sn->inode.s5_direct_blocks[file_blocknum];
+ // Check if disk_blocknum has been already. If so, ret it
+ if (disk_blocknum)
+ {
+ return disk_blocknum;
+ }
+
+ // Check if alloc is clear. If so, ret 0
+ if (!alloc)
+ {
+ return 0;
+ }
+
+ // Else, allocate the block
+ disk_blocknum = s5_alloc_block(VNODE_TO_S5FS(&sn->vnode));
+ // Propogate errors from s5_alloc_block
+ if (disk_blocknum < 0)
+ {
+ return disk_blocknum;
+ }
+ // Update the inode
+ sn->inode.s5_direct_blocks[file_blocknum] = disk_blocknum;
+ sn->dirtied_inode = 1;
+
+ // set ret params and return
+ *newp = 1;
+ return disk_blocknum;
+ }
+
+ // Case 2: Indirect block is not allocated but alloc is set
+ else if (!is_indirect_block_allocated && alloc)
+ {
+ size_t disk_blocknum = s5_alloc_block(VNODE_TO_S5FS(&sn->vnode));
+ // Propogate errors from s5_alloc_block
+ if (disk_blocknum < 0)
+ {
+ return disk_blocknum;
+ }
+ // Update the inode
+ sn->inode.s5_indirect_block = disk_blocknum;
+ sn->dirtied_inode = 1;
+
+ // Create a corresponding pframe_t on the mobj
+ pframe_t *pf = s5_cache_and_clear_block(&sn->vnode.vn_mobj, disk_blocknum, 0);
+ // memset(pf->pf_addr, 0, PAGE_SIZE);
+ // pf->pf_dirty = 1; (already done in s5_cache_and_clear_block)
+
+ // set ret params and return
+ *newp = 1;
+ return disk_blocknum;
+ }
+
+ // Case 3: Indirect block is allocated
+ else if (is_indirect_block_allocated)
+ {
+ size_t indirect_blocknum = sn->inode.s5_indirect_block;
+
+ // Get the disk block number of the desired file block
+ pframe_t *pf;
+ s5_get_meta_disk_block(VNODE_TO_S5FS(&sn->vnode), indirect_blocknum, 0, &pf);
+ uint32_t *indirect_block = pf->pf_addr;
+
+ // Get the index of the indirect block
+ size_t indirect_block_index = file_blocknum - S5_NDIRECT_BLOCKS;
+ size_t disk_blocknum = indirect_block[indirect_block_index];
+
+ // Release the indirect block, now that we have the desired block number
+ s5_release_disk_block(&pf);
+
+ // Check if disk_blocknum has been already. If so, ret it
+ if (disk_blocknum)
+ {
+ return disk_blocknum;
+ }
+
+ // Check if alloc is clear. If so, we're done.
+ if (!alloc)
+ {
+ return 0;
+ }
+
+ // Else, allocate the block
+ disk_blocknum = s5_alloc_block(VNODE_TO_S5FS(&sn->vnode));
+ // Propogate errors from s5_alloc_block
+ if (disk_blocknum < 0)
+ {
+ return disk_blocknum;
+ }
+ // Update the inode
+ indirect_block[indirect_block_index] = disk_blocknum;
+ sn->dirtied_inode = 1;
+
+ // set ret params and return
+ *newp = 1;
+ return disk_blocknum;
+ }
+
+ // Case 4: The indirect block has not been allocated and alloc is clear
+ else
+ {
+ return 0;
+ }
}
pframe_t *s5_cache_and_clear_block(mobj_t *mo, long block, long loc) {
@@ -165,8 +280,55 @@ pframe_t *s5_cache_and_clear_block(mobj_t *mo, long block, long loc) {
*/
ssize_t s5_read_file(s5_node_t *sn, size_t pos, char *buf, size_t len)
{
- NOT_YET_IMPLEMENTED("S5FS: s5_read_file");
- return -1;
+ // NOT_YET_IMPLEMENTED("S5FS: s5_read_file");
+
+ // Check if pos is greater than or equal to the length of the file
+ if (pos >= sn->inode.s5_un.s5_size)
+ {
+ return 0;
+ }
+
+ // Calculate the number of bytes to read
+ size_t bytes_to_read = min(len, sn->inode.s5_un.s5_size - pos);
+
+ // Initialize the number of bytes read
+ size_t bytes_read = 0;
+
+ while (bytes_read < bytes_to_read)
+ {
+ // Get the block number of the desired file block
+ int new_block;
+ size_t file_blocknum = pos / S5_BLOCK_SIZE;
+ size_t block_offset = pos % S5_BLOCK_SIZE;
+ size_t disk_blocknum = s5_file_block_to_disk_block(sn, file_blocknum, 0, &new_block);
+
+ // Propogate errors from s5_file_block_to_disk_block
+ if (disk_blocknum < 0)
+ {
+ return disk_blocknum;
+ }
+
+ // Get the pframe containing the block data
+ pframe_t *pf;
+ s5_get_file_block(sn, file_blocknum, 0, &pf);
+
+ // Calculate the number of bytes to read in the current iteration
+ size_t bytes_read_in_iteration = min(bytes_to_read - bytes_read, S5_BLOCK_SIZE - block_offset);
+
+ // Copy the data from the block to the buffer
+ memcpy(buf + bytes_read, pf->pf_addr + block_offset, bytes_read_in_iteration);
+
+ // Update the number of bytes read
+ bytes_read += bytes_read_in_iteration;
+
+ // Release the pframe
+ s5_release_file_block(&pf);
+
+ // Update the position
+ pos += bytes_read_in_iteration;
+ }
+
+ return bytes_read;
}
/* Write to a file.
@@ -201,8 +363,61 @@ ssize_t s5_read_file(s5_node_t *sn, size_t pos, char *buf, size_t len)
*/
ssize_t s5_write_file(s5_node_t *sn, size_t pos, const char *buf, size_t len)
{
- NOT_YET_IMPLEMENTED("S5FS: s5_write_file");
- return -1;
+ // NOT_YET_IMPLEMENTED("S5FS: s5_write_file");
+
+ // Check if pos was beyond S5_MAX_FILE_SIZE
+ if (pos > S5_MAX_FILE_SIZE)
+ {
+ return -EFBIG;
+ }
+
+ // Calculate the number of bytes to write
+ size_t bytes_to_write = min(len, S5_MAX_FILE_SIZE - pos);
+
+ // Initialize the number of bytes written
+ size_t bytes_written = 0;
+
+ while (bytes_written < bytes_to_write)
+ {
+ // Get the block number of the desired file block
+ int new_block;
+ size_t file_blocknum = pos / S5_BLOCK_SIZE;
+ size_t block_offset = pos % S5_BLOCK_SIZE;
+ size_t disk_blocknum = s5_file_block_to_disk_block(sn, file_blocknum, 1, &new_block);
+
+ // Propogate errors from s5_file_block_to_disk_block
+ if (disk_blocknum < 0)
+ {
+ return disk_blocknum;
+ }
+
+ // Get the pframe containing the block data
+ pframe_t *pf;
+ s5_get_file_block(sn, file_blocknum, 1, &pf);
+
+ // Calculate the number of bytes to write in the current iteration
+ size_t bytes_written_in_iteration = min(bytes_to_write - bytes_written, S5_BLOCK_SIZE - block_offset);
+
+ // Copy the data from the buffer to the block
+ memcpy(pf->pf_addr + block_offset, buf + bytes_written, bytes_written_in_iteration);
+
+ // Update the number of bytes written
+ bytes_written += bytes_written_in_iteration;
+
+ // Release the pframe
+ s5_release_file_block(&pf);
+
+ // Update the position
+ pos += bytes_written_in_iteration;
+
+ // Update the inode's s5_size and mark the inode dirty
+ sn->inode.s5_un.s5_size = max(sn->inode.s5_un.s5_size, pos);
+ sn->dirtied_inode = 1;
+ }
+
+ // TODO: check for partial write
+
+ return bytes_written;
}
/* Allocate one block from the filesystem.
@@ -233,8 +448,49 @@ ssize_t s5_write_file(s5_node_t *sn, size_t pos, const char *buf, size_t len)
*/
static long s5_alloc_block(s5fs_t *s5fs)
{
- NOT_YET_IMPLEMENTED("S5FS: s5_alloc_block");
- return -1;
+ // NOT_YET_IMPLEMENTED("S5FS: s5_alloc_block");
+
+ // Protect access to the super block
+ s5_lock_super(s5fs);
+
+ // Get the super block
+ s5_super_t *s = &s5fs->s5f_super;
+
+ // Check if there are no more free blocks
+ if (s->s5s_nfree == 0)
+ {
+ blocknum_t new_block_num = s->s5s_free_blocks[S5_NBLKS_PER_FNODE - 1];
+ // Check if there are no more free blocks remaining
+ if (new_block_num == (blocknum_t)-1)
+ {
+ s5_unlock_super(s5fs);
+ return -ENOSPC;
+ }
+
+
+ // Collapse the next node of the free list into the super block
+ pframe_t *pf;
+ s5_get_meta_disk_block(s5fs, new_block_num, 1, &pf);
+ memcpy(s->s5s_free_blocks, pf->pf_addr, sizeof(s->s5s_free_blocks));
+ s->s5s_nfree = S5_NBLKS_PER_FNODE - 1;
+ s5_release_disk_block(&pf);
+
+ // Update the super block
+ s->s5s_free_blocks[S5_NBLKS_PER_FNODE - 1] = new_block_num;
+
+ // Unlock the super block
+ s5_unlock_super(s5fs);
+ return new_block_num;
+ }
+ else
+ {
+ // Update the super block
+ s->s5s_nfree--;
+
+ // Unlock the super block
+ s5_unlock_super(s5fs);
+ return s->s5s_free_blocks[s->s5s_nfree];
+ }
}
/*
@@ -428,8 +684,39 @@ long s5_find_dirent(s5_node_t *sn, const char *name, size_t namelen,
{
KASSERT(S_ISDIR(sn->vnode.vn_mode) && "should be handled at the VFS level");
KASSERT(S5_BLOCK_SIZE == PAGE_SIZE && "be wary, thee");
- NOT_YET_IMPLEMENTED("S5FS: s5_find_dirent");
- return -1;
+ // NOT_YET_IMPLEMENTED("S5FS: s5_find_dirent");
+
+ // Initialize the file position
+ size_t pos = 0;
+
+ // Initialize the directory entry
+ s5_dirent_t dirent;
+
+ // Read the directory entry
+ while (s5_read_file(sn, pos, (char *)&dirent, sizeof(s5_dirent_t)) == sizeof(s5_dirent_t))
+ {
+ // Check if the directory entry has the specified name
+ if (
+ strlen(dirent.s5d_name) == namelen
+ &&
+ strncmp(dirent.s5d_name, name, namelen) == 0
+ )
+ {
+ // Update the file position
+ if (filepos)
+ {
+ *filepos = pos;
+ }
+
+ // Return the inode number
+ return dirent.s5d_inode;
+ }
+
+ // Update the file position
+ pos += sizeof(s5_dirent_t);
+ }
+
+ return -ENOENT;
}
/* Remove the directory entry specified by name and namelen from the directory
@@ -460,7 +747,38 @@ void s5_remove_dirent(s5_node_t *sn, const char *name, size_t namelen,
{
vnode_t *dir = &sn->vnode;
s5_inode_t *inode = &sn->inode;
- NOT_YET_IMPLEMENTED("S5FS: s5_remove_dirent");
+ // NOT_YET_IMPLEMENTED("S5FS: s5_remove_dirent");
+
+ // Assert that the directory exists
+ KASSERT(S_ISDIR(dir->vn_mode));
+
+ // Find the position of the entry being removed
+ size_t filepos;
+ long inode_num = s5_find_dirent(sn, name, namelen, &filepos);
+ KASSERT(inode_num >= 0);
+
+ // Assert that the found directory entry corresponds to child
+ KASSERT(inode_num == child->inode.s5_number);
+
+ // Overwrite the removed entry with the last directory entry
+ s5_dirent_t last_dirent;
+ size_t last_filepos = inode->s5_un.s5_size - sizeof(s5_dirent_t);
+ s5_read_file(sn, last_filepos, (char *)&last_dirent, sizeof(s5_dirent_t));
+ s5_write_file(sn, filepos, (char *)&last_dirent, sizeof(s5_dirent_t));
+
+ // Truncate the length of the directory by sizeof(s5_dirent_t)
+ inode->s5_un.s5_size -= sizeof(s5_dirent_t);
+ sn->dirtied_inode = 1;
+
+ // Decrement the child's linkcount
+ child->inode.s5_linkcount--;
+
+ // Decrease len of the directory
+ dir->vn_len -= sizeof(s5_dirent_t);
+
+ // Mark the inodes as dirtied
+ child->dirtied_inode = 1;
+ sn->dirtied_inode = 1;
}
/* Replace a directory entry.
@@ -490,7 +808,38 @@ void s5_replace_dirent(s5_node_t *sn, const char *name, size_t namelen,
{
vnode_t *dir = &sn->vnode;
s5_inode_t *inode = &sn->inode;
- NOT_YET_IMPLEMENTED("S5FS: s5_replace_dirent");
+ // NOT_YET_IMPLEMENTED("S5FS: s5_replace_dirent");
+
+ // Assert that the directory exists
+ KASSERT(S_ISDIR(dir->vn_mode));
+
+ // Find the position of the old directory entry
+ size_t filepos;
+ long inode_num = s5_find_dirent(sn, name, namelen, &filepos);
+
+ // Assert that the directory entry exists
+ KASSERT(inode_num >= 0);
+ // Assert that the directory entry corresponds to the old s5_node
+ KASSERT(inode_num == old->inode.s5_number);
+
+ // Form the new directory entry
+ s5_dirent_t new_dirent;
+ strncpy(new_dirent.s5d_name, name, namelen);
+ new_dirent.s5d_inode = new->inode.s5_number;
+
+ // Write the new directory entry
+ s5_write_file(sn, filepos, (char *)&new_dirent, sizeof(s5_dirent_t));
+
+ // Update linkcounts and dirty inodes appropriately
+ old->inode.s5_linkcount--;
+
+ new->inode.s5_linkcount++;
+ new->dirtied_inode = 1;
+
+ sn->dirtied_inode = 1;
+
+ // Update the directory length
+ dir->vn_len = inode->s5_un.s5_size;
}
/* Create a directory entry.
@@ -514,8 +863,42 @@ long s5_link(s5_node_t *dir, const char *name, size_t namelen,
{
KASSERT(kmutex_owns_mutex(&dir->vnode.vn_mobj.mo_mutex));
- NOT_YET_IMPLEMENTED("S5FS: s5_link");
- return -1;
+ // NOT_YET_IMPLEMENTED("S5FS: s5_link");
+
+ // Find the position of the directory entry
+ size_t filepos;
+ long inode_num = s5_find_dirent(dir, name, namelen, &filepos);
+
+ // Check if the directory entry already exists
+ if (inode_num >= 0)
+ {
+ return -EEXIST;
+ }
+
+ // Form the new directory entry
+ s5_dirent_t new_dirent;
+ strncpy(new_dirent.s5d_name, name, namelen);
+ new_dirent.s5d_inode = child->inode.s5_number;
+
+ // Write the new directory entry
+ long bytes_written = s5_write_file(dir, dir->inode.s5_un.s5_size, (char *)&new_dirent, sizeof(s5_dirent_t));
+ // Propagate errors from s5_write_file
+ if (bytes_written < 0)
+ {
+ return bytes_written;
+ }
+
+ // Update linkcounts and mark inodes dirty appropriately
+ child->inode.s5_linkcount++;
+ child->dirtied_inode = 1;
+
+ dir->inode.s5_un.s5_size += sizeof(s5_dirent_t);
+ dir->dirtied_inode = 1;
+
+ // Assert that the directory entry exists and that its inode is, as expected, the inode of child
+ KASSERT(s5_find_dirent(dir, name, namelen, NULL) == child->inode.s5_number);
+
+ return 0;
}
/* Return the number of file blocks allocated for sn. This means any
@@ -530,8 +913,35 @@ long s5_link(s5_node_t *dir, const char *name, size_t namelen,
*/
long s5_inode_blocks(s5_node_t *sn)
{
- NOT_YET_IMPLEMENTED("S5FS: s5_inode_blocks");
- return -1;
+ // NOT_YET_IMPLEMENTED("S5FS: s5_inode_blocks");
+
+ // Initialize the number of file blocks
+ long num_file_blocks = 0;
+
+ // Get the inode
+ s5_inode_t *inode = &sn->inode;
+
+ // Check if the inode is a special character or block file
+ if (sn->inode.s5_type == S5_TYPE_CHR || sn->inode.s5_type == S5_TYPE_BLK)
+ {
+ return 0;
+ }
+
+ // Count the number of file blocks
+ for (unsigned i = 0; i < S5_NDIRECT_BLOCKS; i++)
+ {
+ if (inode->s5_direct_blocks[i])
+ {
+ num_file_blocks++;
+ }
+ }
+
+ if (inode->s5_indirect_block)
+ {
+ num_file_blocks++;
+ }
+
+ return num_file_blocks;
}
/**