Esempio n. 1
0
/*
 * 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);
}
Esempio n. 2
0
/*
 * Read fs->fs_dev and set fs_op, fs_root, and fs_i.
 *
 * Point fs->fs_i to an s5fs_t*, and initialize it.  Be sure to
 * verify the superblock (using s5_check_super()).  Use vget() to get
 * the root vnode for fs_root.
 *
 * Return 0 on success, negative on failure.
 */
int
s5fs_mount(struct fs *fs)
{
        int num;
        blockdev_t *dev;
        s5fs_t *s5;
        pframe_t *vp;

        KASSERT(fs);

        if (sscanf(fs->fs_dev, "disk%d", &num) != 1) {
                return -EINVAL;
        }

        if (!(dev = blockdev_lookup(MKDEVID(1, num)))) {
                return -EINVAL;
        }

        /* allocate and initialize an s5fs_t: */
        s5 = (s5fs_t *)kmalloc(sizeof(s5fs_t));

        if (!s5)
                return -ENOMEM;

        /*     init s5f_disk: */
        s5->s5f_bdev  = dev;

        /*     init s5f_super: */
        pframe_get(S5FS_TO_VMOBJ(s5), S5_SUPER_BLOCK, &vp);

        KASSERT(vp);

        s5->s5f_super = (s5_super_t *)(vp->pf_addr);

        if (s5_check_super(s5->s5f_super)) {
                /* corrupt */
                kfree(s5);
                return -EINVAL;
        }

        pframe_pin(vp);

        /*     init s5f_mutex: */
        kmutex_init(&s5->s5f_mutex);

        /*     init s5f_fs: */
        s5->s5f_fs = fs;


        /* Init the members of fs that we (the fs-implementation) are
         * responsible for initializing: */
        fs->fs_i = s5;
        fs->fs_op = &s5fs_fsops;
        fs->fs_root = vget(fs, s5->s5f_super->s5s_root_inode);

        return 0;
}
Esempio n. 3
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;
    }
}
Esempio n. 4
0
/*
 * 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;
        */
}
Esempio n. 5
0
/*
 * 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;
}
Esempio n. 6
0
/*
 * See the comment in vfs.h for what is expected of this function.
 *
 * When this function returns, the inode link count should be incremented.
 * Note that most UNIX filesystems don't do this, they have a separate
 * flag to indicate that the VFS is using a file. However, this is
 * simpler to implement.
 *
 * To get the inode you need to use pframe_get then use the pf_addr
 * and the S5_INODE_OFFSET(vnode) to get the inode
 *
 * Don't forget to update linkcounts and pin the page.
 *
 * Note that the devid is stored in the indirect_block in the case of
 * a char or block device
 *
 * Finally, the main idea is to do special initialization based on the
 * type of inode (i.e. regular, directory, char/block device, etc').
 *
 */
static void
s5fs_read_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");
    }

    pframe_pin(p);

    s5_inode_t *inode = ((s5_inode_t *) p->pf_addr) + S5_INODE_OFFSET(vnode->vn_vno);
    
    /* generic initializations */
    vnode->vn_len = inode->s5_size;
    vnode->vn_i = (void *) inode;
    inode->s5_linkcount++;

    /* type-specific initializations */
    KASSERT(inode->s5_type == S5_TYPE_DATA
            || inode->s5_type == S5_TYPE_DIR
            || inode->s5_type == S5_TYPE_CHR
            || inode->s5_type == S5_TYPE_BLK);

    switch (inode->s5_type){
        case S5_TYPE_DATA:
            vnode->vn_ops = &s5fs_file_vops; 
            vnode->vn_mode = S_IFREG;
            break;
        case S5_TYPE_DIR:
            vnode->vn_ops = &s5fs_dir_vops;
            vnode->vn_mode = S_IFDIR;
            break;
        case S5_TYPE_CHR:
            vnode->vn_mode = S_IFCHR;
            vnode->vn_devid = inode->s5_indirect_block;
            break;
        default: /* S5_TYPE_BLK */
            vnode->vn_mode = S_IFBLK;
            vnode->vn_devid = inode->s5_indirect_block;
    }

    s5_dirty_inode(VNODE_TO_S5FS(vnode), inode);
}
Esempio n. 7
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;
}
Esempio n. 8
0
/*
 * 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;
}
Esempio n. 9
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");
}
Esempio n. 10
0
/*
 * 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)
{
    s5_inode_t *inode = VNODE_TO_S5INODE(vnode);
    int allocated_blocks = 0;

    int i;
    for (i = 0; i < S5_NDIRECT_BLOCKS; i++){
        if (inode->s5_direct_blocks[i] != 0){
            allocated_blocks++;
        }
    }

    if (inode->s5_indirect_block == 0){
        return allocated_blocks;
    }

    /* count the indirect block as an allocated block */
    allocated_blocks++;

    pframe_t *p;
    mmobj_t *mmobj = S5FS_TO_VMOBJ(VNODE_TO_S5FS(vnode));

    int get_res = pframe_get(mmobj, inode->s5_indirect_block, &p);

    if (get_res < 0){
        return get_res;
    }

    int j;
    for (j = 0; j < S5_NDIRECT_BLOCKS; j++){
        if (((int *)p->pf_addr)[j] != 0){
            allocated_blocks++;
        }
    }

    return allocated_blocks;
}
Esempio n. 11
0
/*
 * s5_inode_blocks:
 * Return the number of blocks that this inode has allocated on disk.
 * This should include the indirect block, but not include sparse
 * blocks.
 * param *vnode: the pointer to the vnode object
 * return: the number of blocks that this inode has allocated
 */
int
s5_inode_blocks(vnode_t *vnode)
{
    dbg(DBG_S5FS, "{\n");
    KASSERT(vnode != NULL);

    s5_inode_t* inode = VNODE_TO_S5INODE(vnode);
    /* Firstly count number of direct blocks */
    int num = 0;
    uint32_t i = 0;
    for (i = 0; i < S5_NDIRECT_BLOCKS; i++)
    {
        if (inode->s5_direct_blocks[i] != 0)
        {
            num++;
        }
    }
    /* Secondly count the number of indirect blocks */
    pframe_t* page = NULL;
    /* May block */
    int ret = pframe_get(S5FS_TO_VMOBJ(FS_TO_S5FS(vnode->vn_fs)),
                         inode->s5_indirect_block, &page);
    KASSERT(ret == 0);
    KASSERT(page != NULL);
    /* Conver to array */
    uint32_t* pageptr = (uint32_t*)(page->pf_addr);
    for (i = 0; i < S5_NIDIRECT_BLOCKS; i++, pageptr++)
    {
        if (*pageptr != 0)
        {
            num++;
        }
    }

    dbg(DBG_S5FS, "}\n");
    return num;
}
Esempio n. 12
0
/*
 * 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);
}
Esempio n. 13
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;
        }
    }
}
Esempio n. 14
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;
}
Esempio n. 15
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;
        */
}
Esempio n. 16
0
/*
 * s5fs_read_vnode:
 * s5fs_read_vnode will be passed a vnode_t*, which will have its vn_fs
 * and vn_vno fields initialized.
 * param *vnode: the pointer to the vnode object
 */
static void
s5fs_read_vnode(vnode_t *vnode)
{
    dbg(DBG_S5FS, "{\n");
    
    KASSERT(vnode != NULL);
    KASSERT(vnode->vn_fs != NULL);
    
    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);
    
    pframe_pin(page);
    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);
    vnode->vn_i   = inode;
    vnode->vn_len = inode->s5_size;
    
    switch(inode->s5_type)
    {
        case S5_TYPE_DIR:
        {
            vnode->vn_mode  = S_IFDIR;
            vnode->vn_ops   = &s5fs_dir_vops;
            break;
        }
        case S5_TYPE_DATA:
        {
            vnode->vn_mode  = S_IFREG;
            vnode->vn_ops   = &s5fs_file_vops;
            break;
        }
        case S5_TYPE_CHR:
        {
            vnode->vn_mode  = S_IFCHR;
            vnode->vn_ops   = NULL;
            vnode->vn_devid = (devid_t)(inode->s5_indirect_block);
            vnode->vn_cdev  = bytedev_lookup(vnode->vn_devid);
            break;
        }
        case S5_TYPE_BLK:
        {
            vnode->vn_mode  = S_IFBLK;
            vnode->vn_ops   = NULL;
            vnode->vn_devid = (devid_t)(inode->s5_indirect_block);
            vnode->vn_bdev  = blockdev_lookup(vnode->vn_devid);
            break;
        }
        default:
        {
            panic("inode %d has unknown/invalid type %d!!\n",
                  (int)vnode->vn_vno, (int)inode->s5_type);
        }
    }
    
    kmutex_unlock(&vnode->vn_mutex);
    
    dbg(DBG_S5FS, "}\n");
}