/* * See the comment in vfs.h for what is expected of this function. * * When this function returns, the inode refcount should be decremented. * * You probably want to use s5_free_inode() if there are no more links to * the inode, and dont forget to unpin the page */ static void s5fs_delete_vnode(vnode_t *vnode) { pframe_t *p; mmobj_t *fs_mmobj = S5FS_TO_VMOBJ(VNODE_TO_S5FS(vnode)); if (pframe_get(fs_mmobj, S5_INODE_BLOCK(vnode->vn_vno), &p)){ panic("pframe_get failed. What the hell do we do?\n"); } s5_inode_t *inode = ((s5_inode_t *) p->pf_addr) + S5_INODE_OFFSET(vnode->vn_vno); dbg(DBG_S5FS, "decrementing link count on inode %d from %d to %d\n", inode->s5_number, inode->s5_linkcount,inode->s5_linkcount - 1); inode->s5_linkcount--; if (inode->s5_linkcount == 0){ s5_free_inode(vnode); } else { s5_dirty_inode(VNODE_TO_S5FS(vnode), inode); } pframe_unpin(p); }
/* * s5_alloc_inode: * Creates a new inode from the free list and initializes its fields. * Uses S5_INODE_BLOCK to get the page from which to create the inode * * This function may block. * param *fs: the pointer to the file system * param type: the type of this new inode * param devid: device id * return: the inode number, or -1 for any errors */ int s5_alloc_inode(fs_t *fs, uint16_t type, devid_t devid) { s5fs_t *s5fs = FS_TO_S5FS(fs); pframe_t *inodep = NULL; s5_inode_t *inode = NULL; int ret = -1; KASSERT((S5_TYPE_DATA == type) || (S5_TYPE_DIR == type) || (S5_TYPE_CHR == type) || (S5_TYPE_BLK == type)); lock_s5(s5fs); if (s5fs->s5f_super->s5s_free_inode == (uint32_t) - 1) { unlock_s5(s5fs); return -ENOSPC; } pframe_get(&s5fs->s5f_bdev->bd_mmobj, S5_INODE_BLOCK(s5fs->s5f_super->s5s_free_inode), &inodep); KASSERT(inodep); inode = (s5_inode_t *)(inodep->pf_addr) + S5_INODE_OFFSET(s5fs->s5f_super->s5s_free_inode); KASSERT(inode->s5_number == s5fs->s5f_super->s5s_free_inode); ret = inode->s5_number; /* reset s5s_free_inode; remove the inode from the inode free list: */ s5fs->s5f_super->s5s_free_inode = inode->s5_next_free; pframe_pin(inodep); s5_dirty_super(s5fs); pframe_unpin(inodep); /* init the newly-allocated inode: */ inode->s5_size = 0; inode->s5_type = type; inode->s5_linkcount = 0; memset(inode->s5_direct_blocks, 0, S5_NDIRECT_BLOCKS * sizeof(int)); if ((S5_TYPE_CHR == type) || (S5_TYPE_BLK == type)) inode->s5_indirect_block = devid; else inode->s5_indirect_block = 0; s5_dirty_inode(s5fs, inode); unlock_s5(s5fs); return ret; }
/* * Read up to len bytes from the given inode, starting at seek bytes * from the beginning of the inode. On success, return the number of * bytes actually read, or 0 if the end of the file has been reached; on * failure, return -errno. * * This function should allow reading from files or directories, * treating them identically. * * Reading from a sparse block of the file should act like reading * zeros; it should not cause the sparse blocks to be allocated. * * Similarly as in s5_write_file(), do not call s5_seek_to_block() * directly from this function. * * If the region to be read would extend past the end of the file, less * data will be read than was requested. * * You probably want to use pframe_get(), memcpy(). */ int s5_read_file(struct vnode *vnode, off_t seek, char *dest, size_t len) { dbg_print("s5_read_file: Reading File, Length: %i\n",len); if(seek >= vnode->vn_len) { dbg_print("s5_read_file: Exiting with Value: 0\n"); return 0; } int block_index = S5_DATA_BLOCK(seek); int block_offset = S5_DATA_OFFSET(seek); int length; if((int)len < vnode->vn_len - seek) { length = len; } else { length = vnode->vn_len - seek; } pframe_t *pf; if(block_index < S5_NDIRECT_BLOCKS) { /* Direct Block */ dbg_print("s5_read_file: Reading from Direct Block\n"); pframe_get(&vnode->vn_mmobj, block_index, &pf); pframe_pin(pf); memcpy(dest,(char*)pf->pf_addr + block_offset, length); } else { s5_inode_t* inode = VNODE_TO_S5INODE(vnode); if(inode->s5_indirect_block != 0) { dbg_print("s5_read_file: Reading from INDIRECT Block\n"); pframe_get(&vnode->vn_mmobj, inode->s5_indirect_block, &pf); pframe_pin(pf); memcpy(dest,(char*)pf->pf_addr + (block_index - S5_NDIRECT_BLOCKS), length); } else { return 0; } } pframe_unpin(pf); return length; }
/* * Allocate a new disk-block off the block free list and return it. If * there are no free blocks, return -ENOSPC. * * This will not initialize the contents of an allocated block; these * contents are undefined. * * If the super block's s5s_nfree is 0, you need to refill * s5s_free_blocks and reset s5s_nfree. You need to read the contents * of this page using the pframe system in order to obtain the next set of * free block numbers. * * Don't forget to dirty the appropriate blocks! * * You'll probably want to use lock_s5(), unlock_s5(), pframe_get(), * and s5_dirty_super() */ static int s5_alloc_block(s5fs_t *fs) { dbg_print("s5_alloc_block: Entering Function\n"); /* get the super block frame */ s5_super_t* superblock = fs->s5f_super; int block_return; lock_s5(fs); if(((int)superblock->s5s_free_blocks[S5_NBLKS_PER_FNODE - 1] == -1) && (superblock->s5s_nfree == 0)) { dbg_print("s5_alloc_block: No free blocks, returning error"); unlock_s5(fs); return -ENOSPC; } if(superblock->s5s_nfree == 0) { dbg_print("s5_alloc_block: Out of free blocks, getting more!\n"); struct mmobj* fs_vmobj = S5FS_TO_VMOBJ(fs); int next_block = superblock->s5s_free_blocks[S5_NBLKS_PER_FNODE - 1]; pframe_t* pf; pframe_get(fs_vmobj,next_block,&pf); pframe_pin(pf); memcpy(((char*)superblock->s5s_free_blocks),pf->pf_addr,S5_NBLKS_PER_FNODE * sizeof(uint32_t)); superblock->s5s_nfree = S5_NBLKS_PER_FNODE - 1; block_return = next_block; pframe_unpin(pf); } else { /* Frre blocks are available */ dbg_print("s5_alloc_block: Free block available\n"); superblock->s5s_nfree--; block_return = superblock->s5s_free_blocks[superblock->s5s_nfree]; } s5_dirty_super(fs); unlock_s5(fs); dbg_print("s5_alloc_block: Exiting Function\n"); return block_return; /* NOT_YET_IMPLEMENTED("S5FS: s5_alloc_block"); * return -1; */ }
/* * Return the number of blocks that this inode has allocated on disk. * This should include the indirect block, but not include sparse * blocks. * * This is only used by s5fs_stat(). * * You'll probably want to use pframe_get(). */ int s5_inode_blocks(vnode_t *vnode) { /* NOT_YET_IMPLEMENTED("S5FS: s5_inode_blocks"); * return -1; */ s5_inode_t* inode = VNODE_TO_S5INODE(vnode); int max_blocks = S5_DATA_BLOCK(vnode->vn_len); int count = 0; int block_index = 0; while(block_index < max_blocks) { if(block_index < S5_NDIRECT_BLOCKS) { if(inode->s5_direct_blocks[block_index] != 0) { /* Not a sparse block */ count++; } } else { /* Indirect block */ if(inode->s5_indirect_block == 0) { /* No indirect blocks */ /* Do Nothing */ } else { pframe_t* pf; pframe_get(S5FS_TO_VMOBJ(VNODE_TO_S5FS(vnode)),inode->s5_indirect_block,&pf); pframe_pin(pf); uint32_t indirect_map = block_index - S5_NDIRECT_BLOCKS; uint32_t* block_array = (uint32_t*)pf->pf_addr; if(block_array[indirect_map] != 0) { count++; } pframe_unpin(pf); } } block_index++; } return count; }
/* * s5fs_check_refcounts() * vput root vnode */ static int s5fs_umount(fs_t *fs) { s5fs_t *s5 = (s5fs_t *)fs->fs_i; blockdev_t *bd = s5->s5f_bdev; pframe_t *sbp; int ret; if (s5fs_check_refcounts(fs)) { dbg(DBG_PRINT, "s5fs_umount: WARNING: linkcount corruption " "discovered in fs on block device with major %d " "and minor %d!!\n", MAJOR(bd->bd_id), MINOR(bd->bd_id)); } if (s5_check_super(s5->s5f_super)) { dbg(DBG_PRINT, "s5fs_umount: WARNING: corrupted superblock " "discovered on fs on block device with major %d " "and minor %d!!\n", MAJOR(bd->bd_id), MINOR(bd->bd_id)); } vnode_flush_all(fs); vput(fs->fs_root); if (0 > (ret = pframe_get(S5FS_TO_VMOBJ(s5), S5_SUPER_BLOCK, &sbp))) { panic("s5fs_umount: failed to pframe_get super block. " "This should never happen (the page should already " "be resident and pinned, and even if it wasn't, " "block device readpage entry point does not " "fail.\n"); } KASSERT(sbp); pframe_unpin(sbp); kfree(s5); blockdev_flush_all(bd); return 0; }
/* * s5fs_delete_vnode: * s5fs_delete_vnode is called by vput when the * specified vnode_t no longer needs to exist * param *vnode: the pointer to the vnode object */ static void s5fs_delete_vnode(vnode_t *vnode) { dbg(DBG_S5FS, "{\n"); KASSERT(vnode != NULL); KASSERT(vnode->vn_fs != NULL); /* Lock */ kmutex_lock(&vnode->vn_mutex); pframe_t* page = NULL; int ret = pframe_get(S5FS_TO_VMOBJ(FS_TO_S5FS(vnode->vn_fs)), S5_INODE_BLOCK(vnode->vn_vno), &page); KASSERT(ret == 0); KASSERT(page != NULL); s5_inode_t* inode = ((s5_inode_t*)page->pf_addr) + S5_INODE_OFFSET(vnode->vn_vno); inode->s5_linkcount--; s5_dirty_inode(VNODE_TO_S5FS(vnode), inode); KASSERT(VNODE_TO_S5INODE(vnode) == inode); KASSERT(inode->s5_linkcount >= 0); if (inode->s5_linkcount== 0) { s5_free_inode(vnode); } pframe_unpin(page); /* Unlock */ kmutex_unlock(&vnode->vn_mutex); dbg(DBG_S5FS, "}\n"); }
/* * s5_free_inode: * Free an inode by freeing its disk blocks and putting it back on the * inode free list. * param *vnode: the pointer to the vnode object */ void s5_free_inode(vnode_t *vnode) { uint32_t i = 0; s5_inode_t *inode = VNODE_TO_S5INODE(vnode); s5fs_t *fs = VNODE_TO_S5FS(vnode); KASSERT((S5_TYPE_DATA == inode->s5_type) || (S5_TYPE_DIR == inode->s5_type) || (S5_TYPE_CHR == inode->s5_type) || (S5_TYPE_BLK == inode->s5_type)); /* free any direct blocks */ for (i = 0; i < S5_NDIRECT_BLOCKS; ++i) { if (inode->s5_direct_blocks[i]) { dprintf("freeing block %d\n", inode->s5_direct_blocks[i]); s5_free_block(fs, inode->s5_direct_blocks[i]); s5_dirty_inode(fs, inode); inode->s5_direct_blocks[i] = 0; } } if (((S5_TYPE_DATA == inode->s5_type) || (S5_TYPE_DIR == inode->s5_type)) && inode->s5_indirect_block) { pframe_t *ibp; uint32_t *b; pframe_get(S5FS_TO_VMOBJ(fs), (unsigned)inode->s5_indirect_block, &ibp); KASSERT(ibp && "because never fails for block_device " "vm_objects"); pframe_pin(ibp); b = (uint32_t *)(ibp->pf_addr); for (i = 0; i < S5_NIDIRECT_BLOCKS; ++i) { KASSERT(b[i] != inode->s5_indirect_block); if (b[i]) s5_free_block(fs, b[i]); } pframe_unpin(ibp); s5_free_block(fs, inode->s5_indirect_block); } inode->s5_indirect_block = 0; inode->s5_type = S5_TYPE_FREE; s5_dirty_inode(fs, inode); lock_s5(fs); inode->s5_next_free = fs->s5f_super->s5s_free_inode; fs->s5f_super->s5s_free_inode = inode->s5_number; unlock_s5(fs); s5_dirty_inode(fs, inode); s5_dirty_super(fs); }
/* * s5_seek_to_block: * Return the disk-block number for the given seek pointer (aka file * position). * param vnode: pointer to vnode * param seekptr: seek offset * alloc: allocate new page or not * return: the block number, or negative number on failure */ int s5_seek_to_block(vnode_t *vnode, off_t seekptr, int alloc) { KASSERT(vnode != 0); KASSERT(alloc == 1 || alloc == 0); KASSERT(seekptr >= 0); s5_inode_t* inode = VNODE_TO_S5INODE(vnode); uint32_t block_number = S5_DATA_BLOCK(seekptr); /* check if the block_number is valid */ if (block_number >= S5_NIDIRECT_BLOCKS + S5_NDIRECT_BLOCKS) { return -1; } if (block_number < S5_NDIRECT_BLOCKS) { /* sparse block */ if (inode->s5_direct_blocks[block_number] == 0) { /* alloc is zero, simply return */ if (alloc == 0) { return 0; } else { /* alloc a new disk block */ int block_num = s5_alloc_block(VNODE_TO_S5FS(vnode)); if (block_num < 0) { /* error */ return block_num; } else { /* add the new block to inode */ inode->s5_direct_blocks[block_number] = block_num; /* dirty the inode */ s5_dirty_inode((VNODE_TO_S5FS(vnode)), inode); return block_num; } } } else /* already there*/ { return inode->s5_direct_blocks[block_number]; } } else { /* indirect blocks */ /* if the indirect block is zero, alloc it firstly */ pframe_t* page = NULL; if (inode->s5_indirect_block == 0) { int block_num = 0; if ((block_num = s5_alloc_block(FS_TO_S5FS(vnode->vn_fs))) < 0) { return block_num; } else { int ret = pframe_get(S5FS_TO_VMOBJ(FS_TO_S5FS(vnode->vn_fs)), block_num, &page); if (ret < 0 || page == NULL) { return ret; } else { pframe_pin(page); memset(page->pf_addr, 0, S5_BLOCK_SIZE); pframe_dirty(page); pframe_unpin(page); inode->s5_indirect_block = block_num; s5_dirty_inode(FS_TO_S5FS(vnode->vn_fs), inode); } } } else { int ret = pframe_get(S5FS_TO_VMOBJ(FS_TO_S5FS(vnode->vn_fs)), inode->s5_indirect_block, &page); if (ret < 0 || page == NULL) return ret; } KASSERT(page != NULL); pframe_pin(page); int off = block_number - S5_NDIRECT_BLOCKS; int32_t* addr = ((int32_t*)page->pf_addr) + off; pframe_unpin(page); if (*addr == 0) { if (alloc == 0) { return 0; } else { int block_num = s5_alloc_block(VNODE_TO_S5FS(vnode)); if (block_num < 0) { return block_num; } else { pframe_pin(page); *addr = block_num; pframe_dirty(page); pframe_unpin(page); return block_num; } } } else { /* already there, return */ return *addr; } } }
/* * s5_read_file: * Read up to len bytes from the given inode, starting at seek bytes * from the beginning of the inode. On success, return the number of * bytes actually read, or 0 if the end of the file has been reached; on * failure, return -errno. * param *vnode: the pointer to the vnode object * param seek: the seek position * param *bytes: the destination buffer * param len: the length of the destination buffer in bytes * return: the number of bytes actually read; on failure, return -errno. */ int s5_read_file(struct vnode *vnode, off_t seek, char *dest, size_t len) { dbg(DBG_S5FS, "{\n"); KASSERT(vnode != NULL); KASSERT(dest != NULL); KASSERT(PAGE_SIZE == S5_BLOCK_SIZE); KASSERT((uint32_t)vnode->vn_len == VNODE_TO_S5INODE(vnode)->s5_size); if (seek >= vnode->vn_len) { return 0;/* EOF*/ } uint32_t bytes = 0; off_t start_pos = seek; int start_block = S5_DATA_BLOCK(start_pos); int ret = 0; pframe_t* start = NULL; pframe_t* end = NULL; ret = pframe_get(&vnode->vn_mmobj, start_block, &start); if (ret < 0) { return ret; } off_t end_pos = MIN(start_pos + (off_t)len, vnode->vn_len); int end_block = S5_DATA_BLOCK(end_pos); ret = pframe_get(&vnode->vn_mmobj, end_block, &end); if (ret < 0) { return ret; } if (start == end) /* page same */ { pframe_pin(start); memcpy(dest, (char*)start->pf_addr + S5_DATA_OFFSET(start_pos), end_pos - start_pos); pframe_unpin(start); bytes = end_pos - start_pos; } else { /* copy the start page */ pframe_pin(start); memcpy(dest, (char*)start->pf_addr + S5_DATA_OFFSET(start_pos), S5_BLOCK_SIZE-S5_DATA_OFFSET(start_pos)); pframe_unpin(start); dest += (S5_BLOCK_SIZE - S5_DATA_OFFSET(start_pos)); bytes += (S5_BLOCK_SIZE - S5_DATA_OFFSET(start_pos)); /* find next page */ int off = start_pos + S5_BLOCK_SIZE - S5_DATA_OFFSET(start_pos); while(1) { pframe_t* tmp = NULL; int block_number = S5_DATA_BLOCK(off); ret = pframe_get(&vnode->vn_mmobj, block_number, &tmp); if (tmp == NULL) { dbg(DBG_S5FS, "}(error code returned)\n"); return ret; } if (tmp == end) { break; } else { pframe_pin(tmp); memcpy(dest, tmp->pf_addr, S5_BLOCK_SIZE); pframe_unpin(tmp); dest += S5_BLOCK_SIZE;/* shift the dest pointer */ bytes += S5_BLOCK_SIZE; } } pframe_pin(end); memcpy(dest, end->pf_addr, len - bytes); pframe_unpin(end); bytes = len; dbg(DBG_S5FS, "}\n"); } return bytes; }
/* * s5_write_file: * write len bytes to the given inode, starting at seek bytes from the * beginning of the inode. On success, * param *vnode: the pointer to the vnode object * param seek: the seek position * param *bytes: the source buffer * param len: the length of the source buffer in bytes * return: the number of bytes actually written; on failure, return -errno. */ int s5_write_file(vnode_t *vnode, off_t seek, const char *bytes, size_t len) { dbg(DBG_S5FS, "{\n"); KASSERT(vnode != NULL); KASSERT(bytes != NULL); KASSERT(PAGE_SIZE == S5_BLOCK_SIZE); KASSERT((uint32_t)vnode->vn_len == VNODE_TO_S5INODE(vnode)->s5_size); off_t start_pos = seek; off_t start_block_offset = S5_DATA_OFFSET(start_pos); off_t end_pos = MIN(seek + len, S5_MAX_FILE_BLOCKS*PAGE_SIZE); off_t end_block_offset = S5_DATA_OFFSET(end_pos); int start_block = S5_DATA_BLOCK(start_pos); int end_block = S5_DATA_BLOCK(end_pos); int ret = 0; pframe_t* start = NULL; ret = pframe_get(&vnode->vn_mmobj, start_block, &start); if (ret < 0) { dbg(DBG_S5FS, "}(error code returend)\n"); return ret; } pframe_t* end = NULL; ret = pframe_get(&vnode->vn_mmobj, end_block, &end); if (ret < 0) { dbg(DBG_S5FS, "}(error code returend)\n"); return ret; } uint32_t num_bytes = 0; if (start == end) { pframe_pin(start); memcpy((char*)start->pf_addr + start_block_offset, bytes, len); KASSERT((char*)start->pf_addr + start_block_offset + len == (char*)start->pf_addr + end_block_offset); /* dirty the page */ pframe_dirty(start); pframe_unpin(start); num_bytes = len; s5_inode_t* inode = VNODE_TO_S5INODE(vnode ); inode->s5_size = MAX(end_pos, vnode->vn_len); vnode->vn_len = inode->s5_size; s5_dirty_inode(VNODE_TO_S5FS(vnode),inode); } else { /* copy the start block */ pframe_pin(start); memcpy((char*)start->pf_addr + start_block_offset, bytes, S5_BLOCK_SIZE - start_block_offset); bytes += S5_BLOCK_SIZE - start_block_offset; num_bytes += S5_BLOCK_SIZE - start_block_offset; pframe_dirty(start); pframe_unpin(start); s5_inode_t* inode = VNODE_TO_S5INODE(vnode ); inode->s5_size = MAX(start_pos + num_bytes, (uint32_t)vnode->vn_len); vnode->vn_len = inode->s5_size; while (1) { pframe_t* tmp; int block_number = S5_DATA_BLOCK(start_pos + num_bytes ); ret = pframe_get(&vnode->vn_mmobj, block_number, &tmp); if (tmp == NULL) { VNODE_TO_S5INODE(vnode)->s5_size = MAX(start_pos + num_bytes, (uint32_t)vnode->vn_len); vnode->vn_len = VNODE_TO_S5INODE(vnode)->s5_size; s5_dirty_inode(VNODE_TO_S5FS(vnode),inode); return ret; } if (tmp == end) { break; } pframe_pin(tmp); memcpy(tmp->pf_addr, bytes, S5_BLOCK_SIZE); pframe_dirty(tmp); pframe_unpin(tmp); bytes += S5_BLOCK_SIZE; num_bytes += S5_BLOCK_SIZE; } /* copy the last one */ pframe_pin(end); memcpy(end->pf_addr, bytes, len - num_bytes); num_bytes += len - num_bytes; /* len */ pframe_dirty(end); pframe_unpin(end); /* add the size */ inode->s5_size = MAX(end_pos, vnode->vn_len); s5_dirty_inode(VNODE_TO_S5FS(vnode),inode); vnode->vn_len = inode->s5_size; } KASSERT((uint32_t)vnode->vn_len == VNODE_TO_S5INODE(vnode)->s5_size); dbg(DBG_S5FS, "}\n"); return num_bytes; }
/* * This gets called by _pt_fault_handler in mm/pagetable.c The * calling function has already done a lot of error checking for * us. In particular it has checked that we are not page faulting * while in kernel mode. Make sure you understand why an * unexpected page fault in kernel mode is bad in Weenix. You * should probably read the _pt_fault_handler function to get a * sense of what it is doing. * * Before you can do anything you need to find the vmarea that * contains the address that was faulted on. Make sure to check * the permissions on the area to see if the process has * permission to do [cause]. If either of these checks does not * pass kill the offending process, setting its exit status to * EFAULT (normally we would send the SIGSEGV signal, however * Weenix does not support signals). * * Now it is time to find the correct page (don't forget * about shadow objects, especially copy-on-write magic!). Make * sure that if the user writes to the page it will be handled * correctly. * * Finally call pt_map to have the new mapping placed into the * appropriate page table. * * @param vaddr the address that was accessed to cause the fault * * @param cause this is the type of operation on the memory * address which caused the fault, possible values * can be found in pagefault.h */ void handle_pagefault(uintptr_t vaddr, uint32_t cause) { /*NOT_YET_IMPLEMENTED("VM: handle_pagefault");*/ vmarea_t *vma; pframe_t *pf; int pflags = PD_PRESENT | PD_USER; int writeflag = 0; dbg(DBG_PRINT, "(GRADING3F)\n"); if ((vma = vmmap_lookup(curproc->p_vmmap, ADDR_TO_PN(vaddr))) == NULL) { dbg(DBG_PRINT, "(GRADING3C 1)\n"); proc_kill(curproc, EFAULT); return; } /* if (vma->vma_prot & PROT_NONE) { dbg(DBG_ERROR, "(GRADING3 3)\n"); proc_kill(curproc, EFAULT); return; }*/ if (!((cause & FAULT_WRITE) || (cause & FAULT_EXEC)) && !(vma->vma_prot & PROT_READ)) { dbg(DBG_PRINT, "(GRADING3D 3)\n"); proc_kill(curproc, EFAULT); return; } if ((cause & FAULT_WRITE) && !(vma->vma_prot & PROT_WRITE)) { dbg(DBG_PRINT, "(GRADING3D 3)\n"); proc_kill(curproc, EFAULT); return; }/* if ((cause & FAULT_EXEC) && !(vma->vma_prot & PROT_EXEC)) { dbg(DBG_ERROR, "(GRADING3 6)\n"); proc_kill(curproc, EFAULT); return;; }*/ if (cause & FAULT_WRITE) { dbg(DBG_PRINT, "(GRADING3F)\n"); writeflag = 1; } if (pframe_lookup(vma->vma_obj, ADDR_TO_PN(vaddr) - vma->vma_start + vma->vma_off, writeflag, &pf) < 0) { dbg(DBG_PRINT, "(GRADING3D 4)\n"); proc_kill(curproc, EFAULT); return; } if (cause & FAULT_WRITE) { pframe_pin(pf); dbg(DBG_PRINT, "(GRADING3F)\n"); pframe_dirty(pf); /* if ( < 0) { dbg(DBG_ERROR, "(GRADING3 10)\n"); pframe_unpin(pf); proc_kill(curproc, EFAULT); return; }*/ pframe_unpin(pf); pflags |= PD_WRITE; } pt_map(curproc->p_pagedir, (uintptr_t) PAGE_ALIGN_DOWN(vaddr), pt_virt_to_phys((uintptr_t) pf->pf_addr), pflags, pflags); }
/* * Return the disk-block number for the given seek pointer (aka file * position). * * If the seek pointer refers to a sparse block, and alloc is false, * then return 0. If the seek pointer refers to a sparse block, and * alloc is true, then allocate a new disk block (and make the inode * point to it) and return it. * * Be sure to handle indirect blocks! * * If there is an error, return -errno. * * You probably want to use pframe_get, pframe_pin, pframe_unpin, pframe_dirty. */ int s5_seek_to_block(vnode_t *vnode, off_t seekptr, int alloc) { int block_index = S5_DATA_BLOCK(seekptr); if ((unsigned) block_index >= S5_MAX_FILE_BLOCKS){ dbg(DBG_S5FS, "file too large"); return -EFBIG; } if (seekptr > vnode->vn_len && !alloc){ return 0; } s5_inode_t *inode = VNODE_TO_S5INODE(vnode); uint32_t block_num; if (block_index >= S5_NDIRECT_BLOCKS){ pframe_t *ind_page; mmobj_t *mmo = S5FS_TO_VMOBJ(VNODE_TO_S5FS(vnode)); if (inode->s5_indirect_block == 0){ if (!alloc){ return 0; } int alloc_res = alloc_indirect_block(vnode); if (alloc_res < 0){ dbg(DBG_S5FS, "error allocating indirect block\n"); return alloc_res; } } if (pframe_get(mmo, inode->s5_indirect_block, &ind_page) < 0){ panic("an indirect block is messed up\n"); } block_num = ((uint32_t *) ind_page->pf_addr)[block_index - S5_NDIRECT_BLOCKS]; /* case where we've found a sparse block and need to allocate*/ if (block_num == 0 && alloc){ pframe_pin(ind_page); int block_num = s5_alloc_block(VNODE_TO_S5FS(vnode)); pframe_unpin(ind_page); if (block_num == -ENOSPC){ dbg(DBG_S5FS, "couldn't alloc a new block\n"); return -ENOSPC; } KASSERT(block_num > 0 && "forgot to handle an error case"); ((uint32_t *) ind_page->pf_addr)[block_index - S5_NDIRECT_BLOCKS] = block_num; int dirty_res = pframe_dirty(ind_page); if (dirty_res < 0){ return dirty_res; } } } else { block_num = inode->s5_direct_blocks[block_index]; /* case where we've found a sparse block and need to allocate*/ if (block_num == 0 && alloc){ int block_num = s5_alloc_block(VNODE_TO_S5FS(vnode)); if (block_num == -ENOSPC){ dbg(DBG_S5FS, "couldn't alloc a new block\n"); return -ENOSPC; } KASSERT(block_num > 0 && "forgot to handle an error case"); inode->s5_direct_blocks[block_index] = block_num; s5_dirty_inode(VNODE_TO_S5FS(vnode), inode); } } return block_num; }
/* * Return the disk-block number for the given seek pointer (aka file * position). * * If the seek pointer refers to a sparse block, and alloc is false, * then return 0. If the seek pointer refers to a sparse block, and * alloc is true, then allocate a new disk block (and make the inode * point to it) and return it. * * Be sure to handle indirect blocks! * * If there is an error, return -errno. * * You probably want to use pframe_get, pframe_pin, pframe_unpin, pframe_dirty. */ int s5_seek_to_block(vnode_t *vnode, off_t seekptr, int alloc) { /* CASE BLOCK TYPE ALLOC Direct Sparse Indirect Sparse WAT DO? * 1 (BLOCK > Total Blocks) Return Error * 2 DIRECT FALSE TRUE N/A return block from s5_direct_blocks * 3 DIRECT TRUE TRUE N/A allocate new block and point inode (also memcpy) * 4 DIRECT TRUE FALSE N/A return block from s5_direct_blocks * 5 INDIRECT FALSE TRUE TRUE return 0 * 7 INDIRECT FALSE FALSE FALSE Find block we want * 8 INDIRECT TRUE FALSE FALSE Find block we want * 9 INDIRECT TRUE TRUE FALSE allocate new block, memcpy to 0, set data address in indirect * * INDIRECT TRUE N/A TRUE allocate new block, pframe_get on inode->indirect_block */ dbg_print("s5_seek_to_block: Entering Function, seekptr: %i, alloc: %i\n",seekptr,alloc); s5fs_t* vnode_s5fs = VNODE_TO_S5FS(vnode); s5_inode_t* vnode_inode = VNODE_TO_S5INODE(vnode); struct mmobj* vnode_vmobj = S5FS_TO_VMOBJ(vnode_s5fs); uint32_t data_block = S5_DATA_BLOCK(seekptr); pframe_t* pf; dbg_print("s5_seek_to_block: a\n"); if(data_block > S5_MAX_FILE_BLOCKS) { /* Case 1 */ dbg_print("s5_seek_to_block: Case 1\n"); return 0; } if(data_block < S5_NDIRECT_BLOCKS) { dbg_print("s5_seek_to_block: b\n"); /* Direct Block */ if(!alloc) { /* ALLOC FALSE */ /* CASE 2 */ dbg_print("s5_seek_to_block: c\n"); dbg_print("s5_seek_to_block: Case 2\n"); return vnode_inode->s5_direct_blocks[data_block]; } else { /* ALLOC TRUE */ dbg_print("s5_seek_to_block: d\n"); if(vnode_inode->s5_direct_blocks[data_block] == 0) { /* Sparse Block */ /* CASE 3 */ dbg_print("s5_seek_to_block: e\n"); pframe_get(vnode_vmobj,data_block,&pf); pframe_pin(pf); int block_alloc = s5_alloc_block(vnode_s5fs); dbg_print("s5_seek_to_block: f\n"); if(block_alloc == -ENOSPC) { /* Allocation Failure */ dbg_print("s5_seek_to_block: g\n"); pframe_unpin(pf); dbg_print("s5_seek_to_block: Allocation Failure #1\n"); return -ENOSPC; } else { /* Success in Allocation, Connect Inode and Dirty */ dbg_print("s5_seek_to_block: h\n"); vnode_inode->s5_direct_blocks[data_block] = block_alloc; /* memset(pf->pf_addr, 0, PAGE_SIZE); */ pframe_dirty(pf); s5_dirty_inode(vnode_s5fs,vnode_inode); pframe_unpin(pf); dbg_print("s5_seek_to_block: Case 3\n"); return block_alloc; } } else { /* Not Sparse Block */ /* CASE 4 */ dbg_print("s5_seek_to_block: Case 4\n"); return vnode_inode->s5_direct_blocks[data_block]; } } } else { /* Indirect Block */ dbg_print("s5_seek_to_block: i\n"); if(!alloc) { /* ALLOC FALSE */ dbg_print("s5_seek_to_block: j\n"); if(vnode_inode->s5_indirect_block == 0) { /* Sparse Block */ /* CASE 5 */ dbg_print("s5_seek_to_block: Case 5\n"); return 0; } else { /* Not Sparse Block */ /* CASE 7 */ dbg_print("s5_seek_to_block: Case 7\n"); return vnode_inode->s5_direct_blocks[data_block - S5_NDIRECT_BLOCKS]; } } else { /* ALLOC TRUE */ dbg_print("s5_seek_to_block: k\n"); if(vnode_inode->s5_indirect_block == 0) { /* Sparse Block */ /* CASE 5 */ dbg_print("s5_seek_to_block: l\n"); int indirect_alloc = s5_alloc_block(vnode_s5fs); if(indirect_alloc == -ENOSPC) { /* Allocation Failure */ dbg_print("s5_seek_to_block: Allocation Failure #2\n"); return -ENOSPC; } /* Success in Allocation, Connect Inode and Dirty */ dbg_print("s5_seek_to_block: m\n"); pframe_get(vnode_vmobj,vnode_inode->s5_indirect_block,&pf); pframe_pin(pf); /* memset(pf->pf_addr, 0, PAGE_SIZE); */ vnode_inode->s5_indirect_block = indirect_alloc; pframe_dirty(pf); s5_dirty_inode(vnode_s5fs,vnode_inode); dbg_print("s5_seek_to_block: n\n"); } else { /* Not Sparse Block */ dbg_print("s5_seek_to_block: o\n"); pframe_get(vnode_vmobj,vnode_inode->s5_indirect_block,&pf); pframe_pin(pf); } dbg_print("s5_seek_to_block: p\n"); uint32_t indirect_map = data_block - S5_NDIRECT_BLOCKS; uint32_t* block_array = (uint32_t*)pf->pf_addr; int direct_index = block_array[indirect_map]; if(direct_index == 0) { dbg_print("s5_seek_to_block: q\n"); direct_index = s5_alloc_block(vnode_s5fs); if(direct_index == -ENOSPC) { /* Allocation Failure */ dbg_print("s5_seek_to_block: Allocation Failure #3\n"); return -ENOSPC; } } dbg_print("s5_seek_to_block: rn"); block_array[indirect_map] = direct_index; pframe_dirty(pf); pframe_unpin(pf); dbg_print("s5_seek_to_block: Case 6\n"); return direct_index; } } /* NOT_YET_IMPLEMENTED("S5FS: s5_seek_to_block"); * return -1; */ }
/* * Write len bytes to the given inode, starting at seek bytes from the * beginning of the inode. On success, return the number of bytes * actually written (which should be 'len', unless there's only enough * room for a partial write); on failure, return -errno. * * This function should allow writing to files or directories, treating * them identically. * * Writing to a sparse block of the file should cause that block to be * allocated. Writing past the end of the file should increase the size * of the file. Blocks between the end and where you start writing will * be sparse. * * Do not call s5_seek_to_block() directly from this function. You will * use the vnode's pframe functions, which will eventually result in a * call to s5_seek_to_block(). * * You will need pframe_dirty(), pframe_get(), memcpy(). */ int s5_write_file(vnode_t *vnode, off_t seek, const char *bytes, size_t len) { dbg_print("s5_write_file: Writing to File, Length: %i\n",len); uint32_t to_write = len; /* Block Number */ uint32_t block_index = S5_DATA_BLOCK(seek); if(block_index >= S5_MAX_FILE_BLOCKS) { dbg_print("s5_write_file: Exiting with Value: 0\n"); return 0; } /* Offset within block */ uint32_t block_offset = S5_DATA_OFFSET(seek); uint32_t remaining = S5_BLOCK_SIZE - block_offset; int total_written = 0; s5_inode_t* inode = VNODE_TO_S5INODE(vnode); s5fs_t* dir_fs = VNODE_TO_S5FS(vnode); if(seek >= vnode->vn_len) { /* End to Start of Writing should be written as sparse */ } while(to_write > 0) { pframe_t* pf; pframe_get(&(vnode->vn_mmobj),block_index,&pf); pframe_pin(pf); if(to_write <= remaining) { memcpy((char*)pf->pf_addr + block_offset,bytes + total_written,to_write); total_written += to_write; block_offset = 0; to_write = 0; } else { /* to_write > remaining */ memcpy((char*)pf->pf_addr + block_offset,bytes + total_written,remaining); total_written += remaining; block_offset = 0; to_write -= remaining; block_index++; remaining = S5_BLOCK_SIZE; if(block_index == S5_MAX_FILE_BLOCKS) { break; } } pframe_dirty(pf); pframe_unpin(pf); } if(seek + total_written > vnode->vn_len) { vnode->vn_len = seek + total_written; inode->s5_size = seek + total_written; } s5_dirty_inode(dir_fs,inode); return total_written; }