Example #1
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;
}
Example #2
0
/*
 * s5fs_create:
 * s5fs_create is called by open_namev(). it should vget() a new vnode,
 * and create an entry for this vnode in 'dir' of the specified name.
 * param *dir:
 * param name: the name string
 * param namelen: the length of the name
 * param **result: pointer to the address of the result vnode
 * return: 0 on success; negative number on a variety of errors
 */
static int
s5fs_create(vnode_t *dir, const char *name, size_t namelen, vnode_t **result)
{
    dbg(DBG_S5FS, "{\n");
    
    KASSERT(dir != NULL);
    KASSERT(name != NULL);
    KASSERT(namelen <= NAME_LEN-1);
    
    vnode_t* vn = NULL;
    /* Must be non-exist */
    KASSERT(0 != s5fs_lookup(dir, name, namelen, result));
    /* Lock base */
    kmutex_lock(&dir->vn_mutex);
    int ino;
    if ((ino = s5_alloc_inode(dir->vn_fs, S5_TYPE_DATA, 0)) < 0)
    {
        /* Unsuccessfull*/
        kmutex_unlock(&dir->vn_mutex);
        return ino;
    }
    
    /* May block here */
    vn = vget(dir->vn_fs, (ino_t)ino);
    KASSERT(vn->vn_vno == (ino_t)ino);
    KASSERT(vn != NULL);

    int ret = 0;
    if ((ret = s5_link(dir, vn, name, namelen)) < 0)
    {
        /* May block here */
        vput(vn);
        kmutex_unlock(&dir->vn_mutex);
        return ret;
    }
    
    KASSERT(VNODE_TO_S5INODE(vn)->s5_linkcount == 2);
    KASSERT(vn->vn_refcount == 1);
    *result = vn;
    kmutex_unlock(&dir->vn_mutex);
    
    dbg(DBG_S5FS, "}\n");
    
    return 0;
}
Example #3
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;
}
Example #4
0
/*
 * s5fs_mkdir:
 * s5fs_mkdir creates a directory called name in dir
 * param *dir: the pointer to the vnode object of the parent directory
 * param *name: the name string
 * param namelen: the length of the name
 * return: 0 on success; negative number on a variety of errors
 */
static int
s5fs_mkdir(vnode_t *dir, const char *name, size_t namelen)
{
    dbg(DBG_S5FS, "{\n");
    
    KASSERT(dir != NULL);
    KASSERT(name != NULL);
    KASSERT(namelen <= NAME_LEN-1);
    
    vnode_t* result = NULL;
    /* Must be non-exist */
    KASSERT(s5fs_lookup(dir, name, namelen, &result) < 0);
    
    /* Lock */
    kmutex_lock(&dir->vn_mutex);
    s5_inode_t* dir_inode = VNODE_TO_S5INODE(dir);
    int parent_link = dir_inode->s5_linkcount;
    int ino = 0;
    /* Allocate an inode */
    if ((ino = s5_alloc_inode(dir->vn_fs, S5_TYPE_DIR, 0)) < 0)
    {
        /* Unsuccess */
        kmutex_unlock(&dir->vn_mutex);
        return ino;
    }
    
    /* May block here */
    vnode_t* vn = vget(dir->vn_fs, ino);
    
    KASSERT(vn != NULL);
    
    int ret = 0;
    ret = s5_link(dir, vn, name, namelen);
    if (ret < 0)
    {
        /* May block here */
        vput(vn);
        kmutex_unlock(&dir->vn_mutex);
        return -1;
    }
    
    s5_inode_t* inode = VNODE_TO_S5INODE(vn);
    
    ret = s5_link(vn, vn, ".", 1);
    if (ret < 0)
    {
        /* May block here */
        vput(vn);
        kmutex_unlock(&dir->vn_mutex);
        return -1;
    }
    int a = inode->s5_direct_blocks[0];
    ret = s5_link(vn, dir, "..", 2);
    if (ret < 0)
    {
        /* May block here */
        vput(vn);
        kmutex_unlock(&dir->vn_mutex);
        return -1;
    }
    int b = inode->s5_direct_blocks[0];
    if (a != b)
    {
        KASSERT(0);
        b = a;
    }
    KASSERT(inode->s5_linkcount == 2); /* one is VFS, one is from the parent */
    /* Not clear */
    KASSERT(parent_link + 1 == dir_inode->s5_linkcount);
    
    /* May block here */
    vput(vn);
    kmutex_unlock(&dir->vn_mutex);
    KASSERT(ret == 0);
    
    dbg(DBG_S5FS, "}\n");
    
    return ret;
}
Example #5
0
/*
 * s5fs_mknod:
 * s5fs_mknod creates a special file for the device specified by
 * 'devid' and an entry for it in 'dir' of the specified name.
 * param dir: the pointer to the 
 * param name: the name string
 * param namelen: the length of the name string
 * param mode: device mode
 * param devid: device id
 * return: 0 on success; negative number on a variety of errors
 */
static int
s5fs_mknod(vnode_t *dir, const char *name, size_t namelen, int mode, devid_t devid)
{
    dbg(DBG_S5FS, "{\n");
    
    KASSERT(S_ISCHR(mode) || S_ISBLK(mode));
    KASSERT(namelen <= S5_NAME_LEN-1);
    KASSERT(name != NULL);
    KASSERT(dir != NULL);
    
    
    vnode_t* vn = NULL;
    /* Must be non-exist */
    vnode_t* result = NULL;
    
    KASSERT(0 != s5fs_lookup(dir, name, namelen, &result));
    
    /* lock */
    kmutex_lock(&dir->vn_mutex);
    int ino = 0;
    if (S_ISCHR(mode))
    {
        if ((ino = s5_alloc_inode(dir->vn_fs, S5_TYPE_CHR, devid)) < 0)
        {
            /* Unsuccessfull*/
            kmutex_unlock(&dir->vn_mutex);
            return ino;
        }
    }else if (S_ISBLK(mode))
    {
        if ((ino = s5_alloc_inode(dir->vn_fs, S5_TYPE_BLK, devid)) < 0)
        {
            /* Unsuccessfull*/
            kmutex_unlock(&dir->vn_mutex);
            return ino;
        }
    }
    else
    {
        panic("Impossible to get here!");
    }
    
    /* May block here */
    vn = vget(dir->vn_fs, (ino_t)ino);
    KASSERT(vn != NULL);
    KASSERT(vn->vn_vno == (ino_t)ino);
    int ret = 0;
    if ((ret = s5_link(dir, vn, name, namelen)) < 0)
    {
        /* May block here */
        vput(vn);
        kmutex_unlock(&dir->vn_mutex);
        return ret;
    }
    /* new vnode */
    KASSERT(vn->vn_refcount == 1);
    
    /* May block here */
    vput(vn);
    kmutex_unlock(&dir->vn_mutex);
    dbg(DBG_S5FS, "}\n");
    
    return 0;
}
Example #6
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;
}