Ejemplo n.º 1
0
/*
 * Given a filesystem and a block number, frees the given block in the
 * filesystem.
 *
 * This function may potentially block.
 *
 * The caller is responsible for ensuring that the block being placed on
 * the free list is actually free and is not resident.
 */
static void
s5_free_block(s5fs_t *fs, int blockno)
{
        s5_super_t *s = fs->s5f_super;


        lock_s5(fs);

        KASSERT(S5_NBLKS_PER_FNODE > s->s5s_nfree);

        if ((S5_NBLKS_PER_FNODE - 1) == s->s5s_nfree) {
                /* get the pframe where we will store the free block nums */
                pframe_t *prev_free_blocks = NULL;
                KASSERT(fs->s5f_bdev);
                pframe_get(&fs->s5f_bdev->bd_mmobj, blockno, &prev_free_blocks);
                KASSERT(prev_free_blocks->pf_addr);

                /* copy from the superblock to the new block on disk */
                memcpy(prev_free_blocks->pf_addr, (void *)(s->s5s_free_blocks),
                       S5_NBLKS_PER_FNODE * sizeof(int));
                pframe_dirty(prev_free_blocks);

                /* reset s->s5s_nfree and s->s5s_free_blocks */
                s->s5s_nfree = 0;
                s->s5s_free_blocks[S5_NBLKS_PER_FNODE - 1] = blockno;
        } else {
                s->s5s_free_blocks[s->s5s_nfree++] = blockno;
        }

        s5_dirty_super(fs);

        unlock_s5(fs);
}
Ejemplo n.º 2
0
/*
 * s5_alloc_block:
 * Allocate a new disk-block off the block free list and return it.
 * param *fs: the pointer to the file system object
 * return: the block number, or negative number if no space
 */
static int
s5_alloc_block(s5fs_t *fs)
{
    dbg(DBG_S5FS, "{\n");
    KASSERT(fs != NULL);

    lock_s5(fs);
    s5_super_t* super = fs->s5f_super;
    pframe_t* next_free_block = NULL;
    int ret = 0;
    int block_number = 0;

    if (super->s5s_nfree == 0) /* no free pages */
    {
        int ret = pframe_get( S5FS_TO_VMOBJ(fs),
                              super->s5s_free_blocks[S5_NBLKS_PER_FNODE - 1],
                              &next_free_block);

        if (ret < 0 || next_free_block == NULL)
        {
            /* No more free blocks */

            unlock_s5(fs);
            dbg(DBG_S5FS, "}(error code returned)\n");
            return -ENOSPC;
        }
        else
        {
            block_number = super->s5s_free_blocks[S5_NBLKS_PER_FNODE - 1];
            /* copy the next free block into the super block */
            memcpy((void*)(super->s5s_free_blocks), next_free_block->pf_addr,
                   S5_NBLKS_PER_FNODE * sizeof(uint32_t));

            memset(next_free_block->pf_addr, 0, S5_BLOCK_SIZE);

            pframe_dirty(next_free_block);
            pframe_clean(next_free_block);
            pframe_free(next_free_block);
            /* now full */
            super->s5s_nfree = S5_NBLKS_PER_FNODE-1;

            s5_dirty_super(fs);
            unlock_s5(fs);
            dbg(DBG_S5FS, "}\n");
            return block_number;
        }
    }
    else /* there is some free pages */
    {
        block_number = super->s5s_free_blocks[super->s5s_nfree - 1];
        super->s5s_nfree--;
        s5_dirty_super(fs);
        unlock_s5(fs);
        dbg(DBG_S5FS, "}\n");
        return block_number;
    }
}
Ejemplo n.º 3
0
/* allocated an indirect block for a vnode who's indirect block is currently sparse */
static int alloc_indirect_block(vnode_t *v){

    /* an array of 0's that we'll use to quickly create blocks of zeros */
    static int zero_array[BLOCK_SIZE] = {};

    s5_inode_t *inode = VNODE_TO_S5INODE(v);

    KASSERT(inode->s5_indirect_block == 0);

    /* first, get an indirect block */
    int indirect_block = s5_alloc_block(VNODE_TO_S5FS(v));

    if (indirect_block == -ENOSPC){
        dbg(DBG_S5FS, "couldn't alloc a new block\n");
        return -ENOSPC;
    }

    KASSERT(indirect_block > 0 && "forgot to handle an error case");

    /* then, zero it */
    pframe_t *ind_page;
    mmobj_t *mmo = S5FS_TO_VMOBJ(VNODE_TO_S5FS(v));

    int get_res = pframe_get(mmo, indirect_block, &ind_page);

    if (get_res < 0){
        return get_res;
    }

    memcpy(ind_page->pf_addr, zero_array, BLOCK_SIZE);

    int dirty_res = pframe_dirty(ind_page);

    if (dirty_res < 0){
        return dirty_res;
    }

    /* finally, set this block to be the indirect block of the inode */
    inode->s5_indirect_block = indirect_block;
    s5_dirty_inode(VNODE_TO_S5FS(v), inode);

    return 0;
}
Ejemplo n.º 4
0
/*
 * 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)
{

        int forwrite = 0;
        if( vaddr<(USER_MEM_LOW) ||vaddr >= (USER_MEM_HIGH)){
                dbg(DBG_PRINT, "(GRADING3D) ADDRESS NOT VALID \n");
                do_exit(EFAULT);
                return;
        }
        vmarea_t *container = vmmap_lookup(curproc->p_vmmap, ADDR_TO_PN(vaddr));
        if(container == NULL){
          dbg(DBG_PRINT, "(GRADING3D) VMAREA NOT VALID \n");
                do_exit(EFAULT);
                return;
        }
        if(container->vma_prot == PROT_NONE){
          dbg(DBG_PRINT, "(GRADING3D) PROT NOT VALID \n");
                do_exit(EFAULT);
                return;
        }
        if((cause & FAULT_WRITE) && !(container->vma_prot & PROT_WRITE)){
          dbg(DBG_PRINT, "(GRADING3D) CONTAINER PROT NOT VALID \n");
                do_exit(EFAULT);
                return;
        }
        if(!(container->vma_prot & PROT_READ)){
          dbg(DBG_PRINT, "(GRADING3D)  PROT IS NOT PROT READ \n");
                do_exit(EFAULT);
                return;
        }
        int pagenum = ADDR_TO_PN(vaddr)-container->vma_start+container->vma_off;
        pframe_t *pf;
        if((container->vma_prot & PROT_WRITE) && (cause & FAULT_WRITE)){
          dbg(DBG_PRINT, "(GRADING3D) prot write fault write \n");
            int pf_res = pframe_lookup(container->vma_obj, pagenum, 1, &pf);
            if(pf_res<0){
              dbg(DBG_PRINT, "(GRADING3D) pframe lookup failed\n");
                do_exit(EFAULT);
            }
            pframe_dirty(pf);
        }else{
          dbg(DBG_PRINT, "(GRADING3D) prot write fault write else \n");
            int pf_res = pframe_lookup(container->vma_obj, pagenum, forwrite, &pf);
            if(pf_res<0){
              dbg(DBG_PRINT, "(GRADING3D) pframe lookup failed \n");
                do_exit(EFAULT);
            }
        }
        KASSERT(pf);
        dbg(DBG_PRINT, "(GRADING3A 5.a) pf is not NULL\n");
        KASSERT(pf->pf_addr);
        dbg(DBG_PRINT, "(GRADING3A 5.a) pf->addr is not NULL\n");
        uint32_t pdflags = PD_PRESENT | PD_USER;
        uint32_t ptflags = PT_PRESENT | PT_USER;
        if(cause & FAULT_WRITE){
          dbg(DBG_PRINT, "(GRADING3D) cause is fault write \n");
            pdflags = pdflags | PD_WRITE;
            ptflags = ptflags | PT_WRITE;
        }
        int ptmap_res = pt_map(curproc->p_pagedir, (uintptr_t)PAGE_ALIGN_DOWN(vaddr), pt_virt_to_phys((uintptr_t)pf->pf_addr), pdflags, ptflags);
}
Ejemplo n.º 5
0
/*
 * 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;
        }
    }
}
Ejemplo n.º 6
0
/*
 * 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;
}
Ejemplo n.º 7
0
/*
 * 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);

}
Ejemplo n.º 8
0
/*
 * 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)
{
    if (seek < 0){
        dbg(DBG_S5FS, "invalid seek value\n");
        return -EINVAL;
    }

    if (seek + len >= S5_MAX_FILE_SIZE){
        len = S5_MAX_FILE_SIZE - seek - 1;
    }

    /* extend file size, if necessary */
    uint32_t newlength = max(seek + len, vnode->vn_len);
/*    if (seek + len > (unsigned) vnode->vn_len){*/
        /*vnode->vn_len = seek + len;*/
        /*VNODE_TO_S5INODE(vnode)->s5_size = vnode->vn_len;*/
        /*s5_dirty_inode(VNODE_TO_S5FS(vnode), VNODE_TO_S5INODE(vnode));*/
    /*}*/

    off_t start_pos = seek;
    /*off_t end_pos = min(seek + len, vnode->vn_len);*/
    off_t end_pos = min(seek + len, newlength);

    unsigned int srcpos = 0;
    int get_res;
    int write_size;
    pframe_t *p;

    uint32_t err = 0;

    while (srcpos < len){
        int data_offset = S5_DATA_OFFSET(seek);

        get_res = pframe_get(&vnode->vn_mmobj, S5_DATA_BLOCK(seek), &p);

        if (get_res < 0){
            dbg(DBG_S5FS, "error getting page\n");
            err = get_res;
            break;
        }

        write_size = min(PAGE_SIZE - data_offset, end_pos - seek);

        KASSERT(write_size >= 0 && "write size is negative");
        memcpy((char *) p->pf_addr + data_offset, (void *) bytes, write_size);
        int dirty_res = pframe_dirty(p);

        if (dirty_res < 0){
            err = dirty_res;
            break;
        }

        srcpos += write_size;
        seek += write_size; 
    }

    if (seek > vnode->vn_len){
        vnode->vn_len = seek;
        VNODE_TO_S5INODE(vnode)->s5_size = vnode->vn_len;
        s5_dirty_inode(VNODE_TO_S5FS(vnode), VNODE_TO_S5INODE(vnode));
    }

    return err ? err : srcpos;
}
Ejemplo n.º 9
0
/*
 * 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;
}
Ejemplo n.º 10
0
/*
 * 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;
        */
}
Ejemplo n.º 11
0
/*
 * 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;
}
Ejemplo n.º 12
0
void
handle_pagefault(uintptr_t vaddr, uint32_t cause)
{

   
    pframe_t *pf;
        int ret_val;
        vmarea_t *vma = vmmap_lookup(curproc->p_vmmap, ADDR_TO_PN(vaddr));
        if(vma == NULL)
        {
            dbg(DBG_PRINT,"(GRADING3D 1): No vmarea found\n");
            proc_kill(curproc,EFAULT);
            return;
        }

        if(cause & FAULT_WRITE)
        {
            dbg(DBG_VM,"grade14\n");
            dbg(DBG_PRINT,"(GRADING3D 1),checking permission for writing\n");
            if(vma->vma_prot & PROT_WRITE)
            {
                dbg(DBG_VM,"grade15\n");
                 dbg(DBG_PRINT,"(GRADING3D 1),Vmarea has write permission\n");
                ret_val = pframe_lookup(vma->vma_obj, ADDR_TO_PN(vaddr) - vma->vma_start + vma->vma_off, (cause & FAULT_WRITE),&pf);
                if(ret_val<0)
                {
                    dbg(DBG_VM,"grade16\n");
                    dbg(DBG_PRINT,"(GRADING3D 1),pframe could not be found\n");
                     proc_kill(curproc,EFAULT);
                    return;  
                }
                pframe_dirty(pf);

                KASSERT(pf);
                dbg(DBG_PRINT,"(GRADING3A 5.a),pframe is not NULL\n");
                KASSERT(pf->pf_addr);
                dbg(DBG_PRINT,"(GRADING3A 5.a),pf->pf_addr is not NULL\n");
            }
            else
            {
                dbg(DBG_VM,"grade17\n");
                dbg(DBG_PRINT,"(GRADING3D 1),Vmarea does not have write permission\n"); 
              proc_kill(curproc,EFAULT);
            return;  
            }
            dbg(DBG_VM,"grade18\n");
            dbg(DBG_PRINT,"(GRADING3D 1),Calling pt_map after write\n");
            pt_map(curproc->p_pagedir,(uintptr_t)PAGE_ALIGN_DOWN(vaddr),pt_virt_to_phys((uintptr_t)pf->pf_addr), 
                (PD_WRITE|PD_PRESENT|PD_USER), (PT_WRITE|PT_PRESENT|PT_USER));
        }

        else

            {
                dbg(DBG_VM,"grade19\n");
                dbg(DBG_PRINT,"(GRADING3D 1),checking permission for reading\n");
            if(vma->vma_prot & PROT_READ)
            {
                dbg(DBG_VM,"grade20\n");
                dbg(DBG_PRINT,"(GRADING3D 1),Vmarea has read permission\n");
                ret_val = pframe_lookup(vma->vma_obj, ADDR_TO_PN(vaddr) - vma->vma_start + vma->vma_off, (cause & FAULT_WRITE),&pf);
                if(ret_val<0)
                {
                    dbg(DBG_VM,"grade21\n");
                    dbg(DBG_PRINT,"(GRADING3D 1),pframe could not be found\n");
                     proc_kill(curproc,EFAULT);
                    return;  
                }
                    dbg(DBG_VM,"grade22\n");
                KASSERT(pf);
                dbg(DBG_PRINT,"(GRADING3A 5.a),pframe is not NULL\n");
                KASSERT(pf->pf_addr);
                dbg(DBG_PRINT,"(GRADING3A 5.a),pf->pf_addr is not NULL\n");
            }
            else
            {
                dbg(DBG_VM,"grade23\n");
                dbg(DBG_PRINT,"(GRADING3D 1),Vmarea does not have read permission\n");
              proc_kill(curproc,EFAULT);
            return;  
            }
            dbg(DBG_VM,"grade24\n");
            dbg(DBG_PRINT,"(GRADING3D 1),Calling pt_map after read\n");
            pt_map(curproc->p_pagedir,(uintptr_t)PAGE_ALIGN_DOWN(vaddr),pt_virt_to_phys((uintptr_t)pf->pf_addr), 
               (PD_PRESENT|PD_USER), (PT_PRESENT|PT_USER));
        }


   
}