diff options
author | sotech117 <michael_foiani@brown.edu> | 2024-04-25 16:04:44 +0000 |
---|---|---|
committer | sotech117 <michael_foiani@brown.edu> | 2024-04-25 16:04:44 +0000 |
commit | 4f1fb377b55f04399dd9520ca8ff6122a0703887 (patch) | |
tree | 13ac5672bbe4288b21eff9b6ad8b3f70b6267215 | |
parent | c9f4da6024393310e254a2cba679b1f1cc67607a (diff) |
s5 hopes
-rw-r--r-- | kernel/fs/s5fs/s5fs.c | 18 | ||||
-rw-r--r-- | kernel/fs/s5fs/s5fs_subr.c | 442 |
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; } /** |