Пример #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);
}
Пример #2
0
/*
 * s5fs_fillpage:
 * Read the page of 'vnode' containing 'offset' into the
 * page-aligned and page-sized buffer pointed to by
 * 'pagebuf'.
 * param *vnode: the pointer to the vnode object
 * param offset: the arbitrary offset of that file (bytes offset)
 * param pagebuf: the buffer for storing the data you have read
 * return: number of bytes that have been read, or negative number for errors
 */
static int
s5fs_fillpage(vnode_t *vnode, off_t offset, void *pagebuf)
{
    dbg(DBG_S5FS, "{\n");
    
    KASSERT(vnode != NULL);
    KASSERT(pagebuf != NULL);
    
    int disk_number = 0;
    if ((disk_number = s5_seek_to_block(vnode, offset, 0)) < 0)
    {
        return disk_number;
    }
    if (disk_number == 0)
    {
        memset(pagebuf, 0, PAGE_SIZE);
        return 0;
    }
    
    /* If the disk_number is zero, ignore pagebuf */
    int ret = VNODE_TO_S5FS(vnode)->s5f_bdev->bd_ops->read_block(
              VNODE_TO_S5FS(vnode)->s5f_bdev, pagebuf, disk_number, 1);
    
    dbg(DBG_S5FS, "}\n");
    
    return ret;
}
Пример #3
0
/*
 * See the comment in vnode.h for what is expected of this function.
 *
 * When this function returns, the inode refcount on the parent should be
 * decremented (since ".." in the removed directory no longer references
 * it). Remember that the directory must be empty (except for "." and
 * "..").
 *
 * You probably want to use s5_find_dirent() and s5_remove_dirent().
 */
static int
s5fs_rmdir(vnode_t *parent, const char *name, size_t namelen)
{
    KASSERT(!(namelen == 1 && name[0] == '.'));
    KASSERT(!(namelen == 2 && name[0] == '.' && name[1] == '.'));
    KASSERT(parent->vn_ops->rmdir != NULL);

    kmutex_lock(&parent->vn_mutex);

    int ino = s5_find_dirent(parent, name, namelen);

    /* we check in do_rmdir to make sure the directory exists */
    KASSERT(ino != -ENOENT);

    if (ino < 0){
        dbg(DBG_S5FS, "error finding child dir to delete\n");
        kmutex_unlock(&parent->vn_mutex);
        return ino;
    }

    vnode_t *child = vget(VNODE_TO_S5FS(parent)->s5f_fs, ino);
    kmutex_lock(&child->vn_mutex);

    int dot_lookup_res = s5_find_dirent(child, ".", 1);
    int dotdot_lookup_res = s5_find_dirent(child, "..", 2);

    KASSERT(dot_lookup_res != -ENOENT && dotdot_lookup_res != -ENOENT);

    if (dot_lookup_res < 0 || dotdot_lookup_res < 0){
        dbg(DBG_S5FS, "error reading dirents of directory to delete\n");
        kmutex_unlock(&child->vn_mutex);
        kmutex_unlock(&parent->vn_mutex);
        return (dot_lookup_res < 0) ? dot_lookup_res : dotdot_lookup_res;
    }

    KASSERT((unsigned) child->vn_len >= 2 * sizeof(s5_dirent_t));

    if ((unsigned) child->vn_len > 2 * sizeof(s5_dirent_t)){
        vput(child);
        kmutex_unlock(&child->vn_mutex);
        kmutex_unlock(&parent->vn_mutex);
        return -ENOTEMPTY;
    }

    vput(child);

    VNODE_TO_S5INODE(parent)->s5_linkcount--;
    s5_dirty_inode(VNODE_TO_S5FS(parent), VNODE_TO_S5INODE(parent));

    kmutex_unlock(&child->vn_mutex);
    kmutex_unlock(&parent->vn_mutex);
    return s5_remove_dirent(parent, name, namelen);
}
Пример #4
0
/*
 * s5fs_dirtypage:
 * A hook; an attempt is being made to dirty the page
 * belonging to 'vnode' that contains 'offset'. (If the
 * underlying fs supports sparse blocks/pages, and the page
 * containing this offset is currently sparse, this is
 * where an attempt should be made to allocate a block in
 * the underlying fs for that block/page). Return zero on
 * success and nonzero otherwise.
 * param vnode: the pointer to the vnode object
 * param offset: the arbitrary offset of that file (bytes offset)
 * return: the block number or 0; negative number for failure
 */
static int
s5fs_dirtypage(vnode_t *vnode, off_t offset)
{
    dbg(DBG_S5FS, "{\n");
    
    KASSERT(vnode != NULL);
    
    int disk_number = 0;
    int sparse      = 0;
    if ((sparse = s5_seek_to_block(vnode, offset, 0)) < 0)
    {
        return sparse;
        
    }
    else if (sparse > 0)
    {
        /* find the page */
        return 0;
    }
    
    if ((disk_number = s5_seek_to_block(vnode, offset, 1)) < 0)
    {
        return disk_number;
    }
    
    /* Dirty the page */
    
    s5_dirty_inode(VNODE_TO_S5FS(vnode), VNODE_TO_S5INODE(vnode));
    
    dbg(DBG_S5FS, "}\n");
    
    return 0;
}
Пример #5
0
/*
 * Locate the directory entry in the given inode with the given name,
 * and delete it. If there is no entry with the given name, return
 * -ENOENT.
 *
 * In order to ensure that the directory entries are contiguous in the
 * directory file, you will need to move the last directory entry into
 * the remove dirent's place.
 *
 * When this function returns, the inode refcount on the removed file
 * should be decremented.
 *
 * It would be a nice extension to free blocks from the end of the
 * directory file which are no longer needed.
 *
 * Don't forget to dirty appropriate blocks!
 *
 * You probably want to use vget(), vput(), s5_read_file(),
 * s5_write_file(), and s5_dirty_inode().
 */
int
s5_remove_dirent(vnode_t *vnode, const char *name, size_t namelen)
{
    dbg_print("s5_remove_dirent: Removing Dirent");
    int inode = s5_find_dirent(vnode,name,namelen);
    if(inode == -ENOENT)
    {
        dbg_print("s5_remove_dirent: ERROR, Directory not found");
        return -ENOENT;
    }
    else
    {
        vnode_t* vnode_to_remove = vget(vnode->vn_fs,inode);
        s5_inode_t* inode_to_remove = VNODE_TO_S5INODE(vnode_to_remove);
        inode_to_remove->s5_linkcount--;
        vput(vnode_to_remove);

        /* Need to get the offset of where the dirent is */
        int total_count = 0;
        int dir_index = 0;

        /* Loop through the inode blocks until the dirent is found. */
        s5_dirent_t traverse_dir;
        while (s5_read_file(vnode, dir_index * sizeof(s5_dirent_t), (char *) &traverse_dir, sizeof(s5_dirent_t)) > 0)
        {
            /* Once found, return. */
            if (name_match(traverse_dir.s5d_name, name, namelen))
            {
                dir_index = total_count;
            }
            total_count++;
        }
        total_count--;

        if(dir_index != total_count)
        {
            /* swap dir with last */
            char* last_buffer = kmalloc(sizeof(s5_dirent_t));
            s5_dirent_t* dirent = (s5_dirent_t*)last_buffer;
            int read = s5_read_file(vnode,vnode->vn_len - sizeof(s5_dirent_t),last_buffer,sizeof(s5_dirent_t));
            KASSERT(read == sizeof(s5_dirent_t));

            int write = s5_write_file(vnode, dir_index * sizeof(s5_dirent_t), last_buffer, sizeof(s5_dirent_t));
            KASSERT(write == sizeof(s5_dirent_t));
        }

        s5_inode_t* inode = VNODE_TO_S5INODE(vnode);

        vnode->vn_len -= sizeof(s5_dirent_t);
        inode->s5_size -= sizeof(s5_dirent_t);

        s5_dirty_inode(VNODE_TO_S5FS(vnode),inode);

        return 0;
    }
        /* NOT_YET_IMPLEMENTED("S5FS: s5_remove_dirent");
        * return -1;
        */
}
Пример #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);
}
Пример #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;
}
Пример #8
0
/*
 * Create a new directory entry in directory 'parent' with the given name, which
 * refers to the same file as 'child'.
 *
 * When this function returns, the inode refcount on the file that was linked to
 * should be incremented.
 *
 * Remember to increment the ref counts appropriately
 *
 * You probably want to use s5_find_dirent(), s5_write_file(), and s5_dirty_inode().
 */
int
s5_link(vnode_t *parent, vnode_t *child, const char *name, size_t namelen)
{
    KASSERT(parent->vn_ops->mkdir != NULL);
    KASSERT(s5_find_dirent(parent, name, namelen) < 0 && "file exists\n");

    int init_refcount = VNODE_TO_S5INODE(child)->s5_linkcount;

    s5_dirent_t d;
    d.s5d_inode = VNODE_TO_S5INODE(child)->s5_number;
    memcpy(d.s5d_name, name, namelen);
    d.s5d_name[namelen] = '\0';

    off_t write_offset = parent->vn_len; /*find_empty_dirent(parent);*/

    if (write_offset < 0){
        dbg(DBG_S5FS, "error finding dirent to write to\n");
    }

    int res = s5_write_file(parent, write_offset, (char *) &d,
            sizeof(s5_dirent_t));

    if (res < 0){
        dbg(DBG_S5FS, "error writing child entry in parent\n");
        return res;
    }

    s5_dirty_inode(VNODE_TO_S5FS(parent), VNODE_TO_S5INODE(parent));

    if (parent != child){
        dbg(DBG_S5FS, "incrementing link count on inode %d from %d to %d\n",
            VNODE_TO_S5INODE(child)->s5_number, VNODE_TO_S5INODE(child)->s5_linkcount,
            VNODE_TO_S5INODE(child)->s5_linkcount + 1);

        VNODE_TO_S5INODE(child)->s5_linkcount++;
        s5_dirty_inode(VNODE_TO_S5FS(child), VNODE_TO_S5INODE(child));

        KASSERT(VNODE_TO_S5INODE(child)->s5_linkcount == init_refcount + 1 &&
                "link count not incremented properly");
    }

    return 0;
}
Пример #9
0
/*
 * See the comment in vnode.h for what is expected of this function.
 *
 * This function is similar to s5fs_create, but it creates a special
 * file specified by 'devid'.
 *
 * You probably want to use s5_alloc_inode, s5_link(), vget(), and vput().
 */
static int
s5fs_mknod(vnode_t *dir, const char *name, size_t namelen, int mode, devid_t devid)
{
    KASSERT(namelen < NAME_LEN);

    kmutex_lock(&dir->vn_mutex);

    fs_t *fs = VNODE_TO_S5FS(dir)->s5f_fs;

    int ino;

    if (S_ISCHR(mode)){
        ino = s5_alloc_inode(fs, S5_TYPE_CHR, devid);
    } else if (S_ISBLK(mode)){
        ino = s5_alloc_inode(fs, S5_TYPE_BLK, devid);
    } else {
        panic("invalid mode");
    }

    if (ino < 0){
        dbg(DBG_S5FS, "unable to alloc a new inode\n");
        kmutex_unlock(&dir->vn_mutex);
        return ino;
    }
    
    vnode_t *child = vget(fs, ino);

    kmutex_lock(&child->vn_mutex);

    /* make sure the state of the new vnode is correct */
    assert_new_vnode_state(child, ino, S_ISCHR(mode) ? S5_TYPE_CHR : S5_TYPE_BLK,
            devid);
    
    int link_res = s5_link(dir, child, name, namelen);

    if (link_res < 0){
        dbg(DBG_S5FS, "error creating entry for new directory in parent dir\n");
        vput(child);
        kmutex_unlock(&child->vn_mutex);
        kmutex_unlock(&dir->vn_mutex);
        /*s5_free_inode(child);*/
        return link_res;
    }

    vput(child);

    KASSERT(child->vn_refcount == 0);
    KASSERT(VNODE_TO_S5INODE(child)->s5_linkcount == 1);

    kmutex_unlock(&child->vn_mutex);
    kmutex_unlock(&dir->vn_mutex);
    return 0;
}
Пример #10
0
/*
 * s5fs_cleanpage:
 * Write the contents of the page-aligned and page-sized
 * buffer pointed to by 'pagebuf' to the page of 'vnode'
 * containing 'offset'.
 * param *vnode: the pointer to the vnode object
 * param offset: the arbitrary offset of that file (bytes offset)
 * param pagebuf: the source buffer
 * return: number of bytes that have been written, or negative number for errors
 */
static int
s5fs_cleanpage(vnode_t *vnode, off_t offset, void *pagebuf)
{
    dbg(DBG_S5FS, "{\n");
    
    KASSERT(vnode != NULL);
    KASSERT(pagebuf != NULL);
    
    /* Alloc */
    int disk_number = 0;
    if ((disk_number = s5_seek_to_block(vnode, offset, 0)) < 0)
    {
        return disk_number;/* error */
    }
    /* If the disk_number is zero, ignore pagebuf */
    int ret = VNODE_TO_S5FS(vnode)->s5f_bdev->bd_ops->write_block(
              VNODE_TO_S5FS(vnode)->s5f_bdev, pagebuf, disk_number, 1);
    
    dbg(DBG_S5FS, "}\n");
    
    return ret;
}
Пример #11
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;
}
Пример #12
0
/*
 * s5_link:
 * Create a new directory entry in directory 'parent' with the given name, which
 * refers to the same file as 'child'.
 * param *parent: the pointer to the parent vnode object of the vnode child
 * param *child: the pointer to the child vnode object
 * param *name: name string
 * param namelen: the length of the name
 * return: bytes that has been added to the parent's block, or negative number
 *         on failure
 */
int
s5_link(vnode_t *parent, vnode_t *child, const char *name, size_t namelen)
{
    dbg(DBG_S5FS, "{\n");

    KASSERT(parent != NULL);
    KASSERT(child != NULL);
    KASSERT(name != NULL);
    KASSERT(S_ISDIR(parent->vn_mode));
    KASSERT((uint32_t)parent->vn_len == VNODE_TO_S5INODE(parent)->s5_size);
    KASSERT((uint32_t)child->vn_len == VNODE_TO_S5INODE(child)->s5_size);

    int exist = s5_find_dirent(parent, name, namelen);
    if (exist >= 0)
    {
        return -1;
    }
    else
    {
        s5_inode_t* child_inode = VNODE_TO_S5INODE(child);
        ino_t child_inode_num   = child_inode->s5_number;
        KASSERT(child_inode_num == child->vn_vno);

        s5_dirent_t dirent;
        memcpy(dirent.s5d_name, name, S5_NAME_LEN);
        KASSERT(dirent.s5d_name[namelen] == '\0');

        dirent.s5d_inode = child_inode_num;
        s5_inode_t* inode_parent = VNODE_TO_S5INODE(parent);

        KASSERT((uint32_t)parent->vn_len == inode_parent->s5_size);
        int bytes = s5_write_file(parent, inode_parent->s5_size,
                                  (char*)&dirent, sizeof(s5_dirent_t));
        if (bytes == sizeof(s5_dirent_t))
        {
            /* If not '.' or '..', we need to add the link */
            if (!name_match(name, ".", 1))
            {
                child_inode->s5_linkcount++;
                s5_dirty_inode(VNODE_TO_S5FS(child), child_inode);
            }
            dbg(DBG_S5FS, "}\n");
            return 0;
        }
        return bytes;
    }
}
Пример #13
0
/*
 * See the comment in vnode.h for what is expected of this function.
 *
 * When this function returns, the inode refcount of the file should be 2
 * and the vnode refcount should be 1.
 *
 * You probably want to use s5_alloc_inode(), s5_link(), and vget().
 */
static int
s5fs_create(vnode_t *dir, const char *name, size_t namelen, vnode_t **result)
{
    KASSERT(namelen < NAME_LEN);

    kmutex_lock(&dir->vn_mutex);

    fs_t *fs = VNODE_TO_S5FS(dir)->s5f_fs;

    int ino = s5_alloc_inode(fs, S5_TYPE_DATA, NULL);

    if (ino < 0){
        dbg(DBG_S5FS, "unable to alloc a new inode\n");
        kmutex_unlock(&dir->vn_mutex);
        return ino;
    }

    vnode_t *child = vget(fs, ino);

    kmutex_lock(&child->vn_mutex);

    /* make sure the state of the new vnode is correct */
    assert_new_vnode_state(child, ino, S5_TYPE_DATA, 0);
    
    int link_res = s5_link(dir, child, name, namelen);

    if (link_res < 0){
        dbg(DBG_S5FS, "error creating entry for new directory in parent dir\n");
        vput(child);
        kmutex_unlock(&child->vn_mutex);
        kmutex_unlock(&dir->vn_mutex);
        /*s5_free_inode(child);*/
        return link_res;
    }

    KASSERT(child->vn_refcount == 1);
    KASSERT(VNODE_TO_S5INODE(child)->s5_linkcount == 2);

    *result = child;

    kmutex_unlock(&child->vn_mutex);
    kmutex_unlock(&dir->vn_mutex);
    return 0;
}
Пример #14
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");
}
Пример #15
0
/*
 * See the comment in vnode.h for what is expected of this function.
 *
 * You probably want to use s5_find_dirent() and vget().
 */
int
s5fs_lookup(vnode_t *base, const char *name, size_t namelen, vnode_t **result)
{
    kmutex_lock(&base->vn_mutex);
    int ino = s5_find_dirent(base, name, namelen);

    if (ino == -ENOENT){
        kmutex_unlock(&base->vn_mutex);
        return -ENOENT;
    }

    KASSERT(ino >= 0 && "forgot an error case\n");

    vnode_t *child = vget(VNODE_TO_S5FS(base)->s5f_fs, ino);

    KASSERT(child != NULL);

    *result = child;

    kmutex_unlock(&base->vn_mutex);
    return 0;
}
Пример #16
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;
}
Пример #17
0
/*
 * Create a new directory entry in directory 'parent' with the given name, which
 * refers to the same file as 'child'.
 *
 * When this function returns, the inode refcount on the file that was linked to
 * should be incremented.
 *
 * Remember to incrament the ref counts appropriately
 *
 * You probably want to use s5_find_dirent(), s5_write_file(), and s5_dirty_inode().
 */
int
s5_link(vnode_t *parent, vnode_t *child, const char *name, size_t namelen)
{
        /* NOT_YET_IMPLEMENTED("S5FS: s5_link");
        * return -1;
        */
        dbg_print("s5_link: Linking!\n");
        s5_inode_t* child_inode = VNODE_TO_S5INODE(child);

        if(s5_find_dirent(parent,name,namelen) >= 0)
        {
            /* Directory already exists */
            dbg_print("s5_link: Directory Already Exists, Name: %s\n",name);
            return -1;
        }
        else
        {
            s5_dirent_t* new_dir = kmalloc(sizeof(s5_dirent_t));
            /* memset(new_dir, 0, sizeof(s5_dirent_t)); */
            new_dir->s5d_inode = child_inode->s5_number;
            /* Copy Over name for Directory */
            memcpy(new_dir->s5d_name,name,namelen);
            new_dir->s5d_name[namelen] = '\0';

            int write_dir = s5_write_file(parent,parent->vn_len,(char*)new_dir,sizeof(s5_dirent_t));
            KASSERT(write_dir == sizeof(s5_dirent_t));

            /* Increment indoe refcount */
            dbg_print("s5_link: Incrementing Linkcount for Inode: %s\n",name);
            child_inode->s5_linkcount++;
            dbg_print("s5_link: Linkcount for Inode: %s is: %i\n",name,child_inode->s5_linkcount);
            s5_dirty_inode(VNODE_TO_S5FS(parent),child_inode);
            kfree(new_dir);
            return 0;
        }
}
Пример #18
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);
}
Пример #19
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;
        }
    }
}
Пример #20
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;
}
Пример #21
0
/*
 * Locate the directory entry in the given inode with the given name,
 * and delete it. If there is no entry with the given name, return
 * -ENOENT.
 *
 * In order to ensure that the directory entries are contiguous in the
 * directory file, you will need to move the last directory entry into
 * the remove dirent's place.
 *
 * When this function returns, the inode refcount on the removed file
 * should be decremented.
 *
 * It would be a nice extension to free blocks from the end of the
 * directory file which are no longer needed.
 *
 * Don't forget to dirty appropriate blocks!
 *
 * You probably want to use vget(), vput(), s5_read_file(),
 * s5_write_file(), and s5_dirty_inode().
 */
int
s5_remove_dirent(vnode_t *vnode, const char *name, size_t namelen)
{
    static unsigned int dirent_size = sizeof(s5_dirent_t);

    KASSERT(vnode->vn_ops->mkdir != NULL);

    int deleted_ino;
    off_t dir_offset;

    int find_res = 
        s5_find_dirent_helper(vnode, name, namelen, &dir_offset, &deleted_ino);

    if (find_res == -ENOENT){
        dbg(DBG_S5FS, "couldn't find specified dirent\n");
        return -ENOENT;
    }

    KASSERT(find_res == 0 && "you missed an error case");
    KASSERT((unsigned) vnode->vn_len >= dir_offset + dirent_size);

    /* if the dirent to remove isn't the last dirent, we need to
     * copy the last dirent into its place */
    if ((unsigned) vnode->vn_len > dir_offset + dirent_size){
        KASSERT((unsigned) vnode->vn_len >= dir_offset + (2 * dirent_size));

        s5_dirent_t to_move;

        int read_res = s5_read_file(vnode, vnode->vn_len - dirent_size,
                (char *) &to_move, dirent_size);

        if (read_res < 0){
            dbg(DBG_S5FS, "error reading final dirent in directory\n");
            return read_res;
        }

        int write_res = s5_write_file(vnode, dir_offset,
                (char *) &to_move, dirent_size);

        if (write_res < 0){
            dbg(DBG_S5FS, "error overwriting dirent to remove with last dirent\n");
            return write_res;
        }
    }

    s5fs_t *fs = VNODE_TO_S5FS(vnode);

    /* decrease the length of the directory file */
    s5_inode_t *dir_inode = VNODE_TO_S5INODE(vnode);

    vnode->vn_len -= dirent_size;     

    dir_inode->s5_size -= dirent_size;
    s5_dirty_inode(fs, dir_inode);

    /* decrement the linkcount on the unlinked file */
    vnode_t *deleted_vnode = vget(fs->s5f_fs, deleted_ino);
    s5_inode_t *deleted_inode = VNODE_TO_S5INODE(deleted_vnode);

    deleted_inode->s5_linkcount--;

    KASSERT(deleted_inode->s5_linkcount >= 0 && "linkcount went below 0!");

    s5_dirty_inode(fs, deleted_inode);

    vput(deleted_vnode);

    return 0;
}
Пример #22
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;
}
Пример #23
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;
}
Пример #24
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;
}
Пример #25
0
/*
 * See the comment in vnode.h for what is expected of this function.
 *
 * You need to create the "." and ".." directory entries in the new
 * directory. These are simply links to the new directory and its
 * parent.
 *
 * When this function returns, the inode refcount on the parent should
 * be incremented, and the inode refcount on the new directory should be
 * 1. It might make more sense for the inode refcount on the new
 * directory to be 2 (since "." refers to it as well as its entry in the
 * parent dir), but convention is that empty directories have only 1
 * link.
 *
 * You probably want to use s5_alloc_inode, and s5_link().
 *
 * Assert, a lot.
 */
static int
s5fs_mkdir(vnode_t *dir, const char *name, size_t namelen)
{
    static const char *dotstring = ".";
    static const char *dotdotstring = "..";

    KASSERT(namelen < NAME_LEN);
    KASSERT(dir->vn_ops->mkdir != NULL);

    kmutex_lock(&dir->vn_mutex);

    fs_t *fs = VNODE_TO_S5FS(dir)->s5f_fs;

    int ino = s5_alloc_inode(fs, S5_TYPE_DIR, NULL);

    if (ino < 0){
        dbg(DBG_S5FS, "unable to alloc a new inode\n");
        kmutex_unlock(&dir->vn_mutex);
        return ino;
    }

    vnode_t *child = vget(fs, ino);

    kmutex_lock(&child->vn_mutex);

    /* make sure the state of the new vnode is correct */
    assert_new_vnode_state(child, ino, S5_TYPE_DIR, 0);

    int link_res = s5_link(child, child, dotstring, 1); 

    if (link_res < 0){
        dbg(DBG_S5FS, "error creating entry for \'.\' in new directory\n");
        /* TODO make sure we should be vputting */
        /*s5_free_inode(child);*/
        vput(child);
        kmutex_unlock(&child->vn_mutex);
        kmutex_unlock(&dir->vn_mutex);
        return link_res;
    }

    KASSERT(VNODE_TO_S5INODE(child)->s5_linkcount == 1);

    link_res = s5_link(child, dir, dotdotstring, 2);

    if (link_res < 0){
        dbg(DBG_S5FS, "error creating entry for \'..\' in new directory\n");
        /*s5_free_inode(child);*/
        vput(child);
        kmutex_unlock(&child->vn_mutex);
        kmutex_unlock(&dir->vn_mutex);
        return link_res;
    }

    link_res = s5_link(dir, child, name, namelen);

    if (link_res < 0){
        dbg(DBG_S5FS, "error creating entry for new directory in parent dir\n");
        /*s5_free_inode(child);*/
        vput(child);
        kmutex_unlock(&child->vn_mutex);
        kmutex_unlock(&dir->vn_mutex);
        return link_res;
    }

    KASSERT(VNODE_TO_S5INODE(child)->s5_linkcount == 2);

    vput(child);

    KASSERT(child->vn_refcount - child->vn_nrespages == 0);

    kmutex_unlock(&child->vn_mutex);
    kmutex_unlock(&dir->vn_mutex);
    return 0;
}
Пример #26
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");
}
Пример #27
0
/*
 * s5_remove_dirent:
 * Locate the directory entry in the given inode with the given name,
 * and delete it. If there is no entry with the given name, return
 * -ENOENT.
 * param *vnode: the pointer to the vnode object
 * param *name: the name string
 * param namelen: the length of the name string
 * return: 0 on success and -ENOENT if there is no entry
 */
int
s5_remove_dirent(vnode_t *vnode, const char *name, size_t namelen)
{
    dbg(DBG_S5FS, "{\n");

    KASSERT(vnode != NULL);
    KASSERT(name != NULL);
    KASSERT(namelen <= S5_NAME_LEN - 1);
    KASSERT((uint32_t)vnode->vn_len == VNODE_TO_S5INODE(vnode)->s5_size);
    KASSERT(vnode->vn_len%sizeof(s5_dirent_t) == 0);
    s5_dirent_t tmp;

    off_t offset = 0;
    while (1)
    {
        int bytes = s5_read_file(vnode, offset, (char*)&tmp, sizeof(s5_dirent_t));

        if (bytes < 0)
        {
            return bytes;
        }
        else if (bytes == 0)
        {
            return -ENOENT;
        }
        else if (bytes != sizeof(s5_dirent_t))
        {
            return -1;
        }
        else
        {
            if (name_match(tmp.s5d_name, name, namelen))
            {
                if (offset + (off_t)sizeof(s5_dirent_t) < vnode->vn_len)
                {
                    s5_dirent_t last_dirent;
                    int bytes2 = s5_read_file(vnode, vnode->vn_len - sizeof(s5_dirent_t),
                                              (char*)&last_dirent, sizeof(s5_dirent_t));
                    if (bytes2 < 0)
                    {
                        return bytes2;
                    }
                    else if (bytes2 != sizeof(s5_dirent_t))
                    {
                        return -1;
                    }
                    else
                    {
                        bytes2 = s5_write_file(vnode, offset, (char*)&last_dirent,
                                               sizeof(s5_dirent_t));
                        if (bytes2 < 0)
                        {
                            return bytes2;
                        }
                    }
                }

                vnode->vn_len -= sizeof(s5_dirent_t);
                s5_inode_t* inode = VNODE_TO_S5INODE(vnode );
                inode->s5_size = vnode->vn_len;
                s5_dirty_inode(VNODE_TO_S5FS(vnode),inode);

                vnode_t* vn = vget(vnode->vn_fs,tmp.s5d_inode);

                KASSERT(vn);
                s5_inode_t* remove_inode = VNODE_TO_S5INODE(vn);
                remove_inode->s5_linkcount--;
                s5_dirty_inode(FS_TO_S5FS(vn->vn_fs), remove_inode);
                vput(vn);

                return 0;
            }
            else
            {
                offset+= sizeof(s5_dirent_t);
            }
        }
    }
    KASSERT(0);
}
Пример #28
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;
        */
}
Пример #29
0
/*
 * s5fs_rmdir:
 * s5fs_rmdir removes the directory called name from dir. the directory
 * to be removed must be empty (except for . and .. of course).
 * param *parent: the pointer to the parent dir of the name specified
 * param *name: name string
 * param namelen: the length of the name string
 * return: 0 on success; negative numbers on a variety of errors
 */
static int
s5fs_rmdir(vnode_t *parent, const char *name, size_t namelen)
{
    dbg(DBG_S5FS, "{\n");
    
    KASSERT(parent != NULL);
    KASSERT(name != NULL);
    KASSERT(namelen <= NAME_LEN - 1);
    KASSERT((uint32_t)parent->vn_len == VNODE_TO_S5INODE(parent)->s5_size);
    
    kmutex_lock(&parent->vn_mutex);
    
    int inode_number = 0;
    if ((inode_number = s5_find_dirent(parent, name, namelen)) < 0)
    {
        kmutex_unlock(&parent->vn_mutex);
        /* Need vput? */
        return inode_number;
    }
    
    /* May block here */
    vnode_t* vn = vget(parent->vn_fs, inode_number);
    KASSERT(vn != NULL);
    
    if (!S_ISDIR(vn->vn_mode))
    {
        /* May block here */
        vput(vn);
        kmutex_unlock(&parent->vn_mutex);
        return -ENOTDIR;
    }
    
    /* Check empty */
    if (VNODE_TO_S5INODE(vn)->s5_size > sizeof(dirent_t)*2)
    {
        vput(vn);
        kmutex_unlock(&parent->vn_mutex);
        return -ENOTEMPTY;
    }
    
    int ret;
    if ((ret = s5_remove_dirent(parent, name, namelen)) < 0)
    {
        /* May block here */
        vput(vn);
        kmutex_unlock(&parent->vn_mutex);
        return ret;
    }
    /* Decrease the linkcount because .. is removed */
    s5_inode_t* parent_inode = VNODE_TO_S5INODE(parent);
    parent_inode->s5_linkcount--;
    s5_dirty_inode(VNODE_TO_S5FS(parent), parent_inode);
    
    /* May block here */
    vput(vn);
    kmutex_unlock(&parent->vn_mutex);
    
    dbg(DBG_S5FS, "}\n");
    
    return ret;
}