Exemplo n.º 1
0
static int
sfs_rename(struct inode *node, const char *name, struct inode *new_node, const char *new_name) {
    if (strlen(name) > SFS_MAX_FNAME_LEN || strlen(new_name) > SFS_MAX_FNAME_LEN) {
        return -E_TOO_BIG;
    }
    if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0) {
        return -E_INVAL;
    }
    if (strcmp(new_name, ".") == 0 || strcmp(new_name, "..") == 0) {
        return -E_EXISTS;
    }
    struct sfs_fs *sfs = fsop_info(vop_fs(node), sfs);
    struct sfs_inode *sin = vop_info(node, sfs_inode), *newsin = vop_info(new_node, sfs_inode);
    int ret;
    lock_sfs_mutex(sfs);
    {
        if ((ret = trylock_sin(sin)) == 0) {
            if (sin == newsin) {
                ret = sfs_rename1_nolock(sfs, sin, name, new_name);
            }
            else if ((ret = trylock_sin(newsin)) == 0) {
                ret = sfs_rename2_nolock(sfs, sin, name, newsin, new_name);
                unlock_sin(newsin);
            }
            unlock_sin(sin);
        }
    }
    unlock_sfs_mutex(sfs);
    return ret;
}
Exemplo n.º 2
0
/*
 * sfs_getdirentry - according to the iob->io_offset, calculate the dir entry's slot in disk block,
                     get dir entry content from the disk
 */
static int
sfs_getdirentry(struct inode *node, struct iobuf *iob) {
    struct sfs_disk_entry *entry;
    if ((entry = kmalloc(sizeof(struct sfs_disk_entry))) == NULL) {
        return -E_NO_MEM;
    }

    struct sfs_fs *sfs = fsop_info(vop_fs(node), sfs);
    struct sfs_inode *sin = vop_info(node, sfs_inode);

    int ret, slot;
    off_t offset = iob->io_offset;
    if (offset < 0 || offset % sfs_dentry_size != 0) {
        kfree(entry);
        return -E_INVAL;
    }
    if ((slot = offset / sfs_dentry_size) > sin->din->blocks) {
        kfree(entry);
        return -E_NOENT;
    }
    lock_sin(sin);
    if ((ret = sfs_getdirentry_sub_nolock(sfs, sin, slot, entry)) != 0) {
        unlock_sin(sin);
        goto out;
    }
    unlock_sin(sin);
    ret = iobuf_move(iob, entry->name, sfs_dentry_size, 1, NULL);
out:
    kfree(entry);
    return ret;
}
Exemplo n.º 3
0
static int
sfs_namefile(struct inode *node, struct iobuf *iob) {
    struct sfs_disk_entry *entry;
    if (iob->io_resid <= 2 || (entry = kmalloc(sizeof(struct sfs_disk_entry))) == NULL) {
        return -E_NO_MEM;
    }

    struct sfs_fs *sfs = fsop_info(vop_fs(node), sfs);
    struct sfs_inode *sin = vop_info(node, sfs_inode);

    int ret;
    uint32_t ino;
    char *ptr = iob->io_base + iob->io_resid;
    size_t alen, resid = iob->io_resid - 2;
    
    vop_ref_inc(node);
    while ((ino = sin->ino) != SFS_BLKN_ROOT) {
        struct inode *parent;
        if ((ret = sfs_load_parent(sfs, sin, &parent)) != 0) {
            goto failed;
        }
        vop_ref_dec(node);
        
        node = parent, sin = vop_info(node, sfs_inode);
        assert(ino != sin->ino && sin->din->type == SFS_TYPE_DIR);

        if ((ret = trylock_sin(sin)) != 0) {
            goto failed;
        }
        ret = sfs_dirent_findino_nolock(sfs, sin, ino, entry);
        unlock_sin(sin);

        if (ret != 0) {
            goto failed;
        }

        if ((alen = strlen(entry->name) + 1) > resid) {
            goto failed_nomem;
        }
        resid -= alen, ptr -= alen;
        memcpy(ptr, entry->name, alen - 1);
        ptr[alen - 1] = '/';
    }
    vop_ref_dec(node);
    alen = iob->io_resid - resid - 2;
    ptr = memmove(iob->io_base + 1, ptr, alen);
    ptr[-1] = '/', ptr[alen] = '\0';
    iobuf_skip(iob, alen);
    kfree(entry);
    return 0;

failed_nomem:
    ret = -E_NO_MEM;
failed:
    vop_ref_dec(node);
    kfree(entry);
    return ret;
}
Exemplo n.º 4
0
static int
sfs_lookup_once(struct sfs_fs *sfs, struct sfs_inode *sin, const char *name, struct inode **node_store, int *slot) {
    int ret;
    uint32_t ino;
    lock_sin(sin);
    {
        ret = sfs_dirent_search_nolock(sfs, sin, name, &ino, slot, NULL);
    }
    unlock_sin(sin);
    if (ret == 0) {
        ret = sfs_load_inode(sfs, node_store, ino);
    }
    return ret;
}
Exemplo n.º 5
0
/*
 * sfs_lookup_once - find inode corresponding the file name in DIR's sin inode
 * @sfs:        sfs file system
 * @sin:        DIR sfs inode in memory
 * @name:       the file name in DIR
 * @node_store: the inode corresponding the file name in DIR
 * @slot:       the logical index of file entry
 */
static int
sfs_lookup_once(struct sfs_fs *sfs, struct sfs_inode *sin, const char *name, struct inode **node_store, int *slot) {
    int ret;
    uint32_t ino;
    lock_sin(sin);
    {   // find the NO. of disk block and logical index of file entry
        ret = sfs_dirent_search_nolock(sfs, sin, name, &ino, slot, NULL);
    }
    unlock_sin(sin);
    if (ret == 0) {
		// load the content of inode with the the NO. of disk block
        ret = sfs_load_inode(sfs, node_store, ino);
    }
    return ret;
}
static int
sfs_getdirentry(struct inode *node, struct iobuf *iob) {
    struct sfs_disk_entry *entry;
    if ((entry = kmalloc(sizeof(struct sfs_disk_entry))) == NULL) {
        // kprintf("%s %s %d -E_NO_MEM\n", __FILE__, __func__, __LINE__);
        return -E_NO_MEM;
    }

    struct sfs_fs *sfs = fsop_info(vop_fs(node), sfs);
    struct sfs_inode *sin = vop_info(node, sfs_inode);

    int ret, slot;
    off_t offset = iob->io_offset;
    if (offset < 0 || offset % sfs_dentry_size != 0) {
        // kprintf("%s %s %d -E_INVAL\n", __FILE__, __func__, __LINE__);
        kfree(entry);
        return -E_INVAL;
    }
    if ((slot = offset / sfs_dentry_size) > sin->din->blocks) {
        // kprintf("%s %s %d -E_NOENT\n", __FILE__, __func__, __LINE__);
        kfree(entry);
        return -E_NOENT;
    }
    lock_sin(sin);
    if ((ret = sfs_getdirentry_sub_nolock(sfs, sin, slot, entry)) != 0) {
        unlock_sin(sin);
        // kprintf("%s %s %d can not find!!! slot is %d\n", __FILE__, __func__, __LINE__, slot);
        goto out;
    }
    unlock_sin(sin);
    // kprintf("sfs_getdirentry\n");
    ret = iobuf_move(iob, entry->name, sfs_dentry_size, 1, NULL);
out:
    kfree(entry);
    return ret;
}
Exemplo n.º 7
0
/*
 * sfs_io - Rd/Wr file. the wrapper of sfs_io_nolock
            with lock protect
 */
static inline int
sfs_io(struct inode *node, struct iobuf *iob, bool write) {
    struct sfs_fs *sfs = fsop_info(vop_fs(node), sfs);
    struct sfs_inode *sin = vop_info(node, sfs_inode);
    int ret;
    lock_sin(sin);
    {
        size_t alen = iob->io_resid;
        ret = sfs_io_nolock(sfs, sin, iob->io_base, iob->io_offset, &alen, write);
        if (alen != 0) {
            iobuf_skip(iob, alen);
        }
    }
    unlock_sin(sin);
    return ret;
}
Exemplo n.º 8
0
static int
sfs_mkdir(struct inode *node, const char *name) {
    if (strlen(name) > SFS_MAX_FNAME_LEN) {
        return -E_TOO_BIG;
    }
    if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0) {
        return -E_EXISTS;
    }
    struct sfs_fs *sfs = fsop_info(vop_fs(node), sfs);
    struct sfs_inode *sin = vop_info(node, sfs_inode);
    int ret;
    if ((ret = trylock_sin(sin)) == 0) {
        ret = sfs_mkdir_nolock(sfs, sin, name);
        unlock_sin(sin);
    }
    return ret;
}
Exemplo n.º 9
0
/*
 * sfs_truncfile : reszie the file with new length
 */
static int
sfs_truncfile(struct inode *node, off_t len) {
    if (len < 0 || len > SFS_MAX_FILE_SIZE) {
        return -E_INVAL;
    }
    struct sfs_fs *sfs = fsop_info(vop_fs(node), sfs);
    struct sfs_inode *sin = vop_info(node, sfs_inode);
    struct sfs_disk_inode *din = sin->din;

    int ret = 0;
	//new number of disk blocks of file
    uint32_t nblks, tblks = ROUNDUP_DIV(len, SFS_BLKSIZE);
    if (din->size == len) {
        assert(tblks == din->blocks);
        return 0;
    }

    lock_sin(sin);
	// old number of disk blocks of file
    nblks = din->blocks;
    if (nblks < tblks) {
		// try to enlarge the file size by add new disk block at the end of file
        while (nblks != tblks) {
            if ((ret = sfs_bmap_load_nolock(sfs, sin, nblks, NULL)) != 0) {
                goto out_unlock;
            }
            nblks ++;
        }
    }
    else if (tblks < nblks) {
		// try to reduce the file size
        while (tblks != nblks) {
            if ((ret = sfs_bmap_truncate_nolock(sfs, sin)) != 0) {
                goto out_unlock;
            }
            nblks --;
        }
    }
    assert(din->blocks == tblks);
    din->size = len;
    sin->dirty = 1;

out_unlock:
    unlock_sin(sin);
    return ret;
}
Exemplo n.º 10
0
static int
sfs_truncfile(struct inode *node, off_t len) {
    if (len < 0 || len > SFS_MAX_FILE_SIZE) {
        return -E_INVAL;
    }
    struct sfs_fs *sfs = fsop_info(vop_fs(node), sfs);
    struct sfs_inode *sin = vop_info(node, sfs_inode);
    struct sfs_disk_inode *din = sin->din;
    assert(din->type != SFS_TYPE_DIR);

    int ret = 0;
    uint32_t nblks, tblks = ROUNDUP_DIV(len, SFS_BLKSIZE);
    if (din->fileinfo.size == len) {
        assert(tblks == din->blocks);
        return 0;
    }

    if ((ret = trylock_sin(sin)) != 0) {
        return ret;
    }
    nblks = din->blocks;
    if (nblks < tblks) {
        while (nblks != tblks) {
            if ((ret = sfs_bmap_load_nolock(sfs, sin, nblks, NULL)) != 0) {
                goto out_unlock;
            }
            nblks ++;
        }
    }
    else if (tblks < nblks) {
        while (tblks != nblks) {
            if ((ret = sfs_bmap_truncate_nolock(sfs, sin)) != 0) {
                goto out_unlock;
            }
            nblks --;
        }
    }
    assert(din->blocks == tblks);
    din->fileinfo.size = len;
    sin->dirty = 1;

out_unlock:
    unlock_sin(sin);
    return ret;
}
Exemplo n.º 11
0
/*
 * sfs_fsync - Force any dirty inode info associated with this file to stable storage.
 */
static int
sfs_fsync(struct inode *node) {
    struct sfs_fs *sfs = fsop_info(vop_fs(node), sfs);
    struct sfs_inode *sin = vop_info(node, sfs_inode);
    int ret = 0;
    if (sin->dirty) {
        lock_sin(sin);
        {
            if (sin->dirty) {
                sin->dirty = 0;
                if ((ret = sfs_wbuf(sfs, sin->din, sizeof(struct sfs_disk_inode), sin->ino, 0)) != 0) {
                    sin->dirty = 1;
                }
            }
        }
        unlock_sin(sin);
    }
    return ret;
}
Exemplo n.º 12
0
static int
sfs_getdirentry(struct inode *node, struct iobuf *iob) {
    struct sfs_disk_entry *entry;
    if ((entry = kmalloc(sizeof(struct sfs_disk_entry))) == NULL) {
        return -E_NO_MEM;
    }

    struct sfs_fs *sfs = fsop_info(vop_fs(node), sfs);
    struct sfs_inode *sin = vop_info(node, sfs_inode);

    off_t offset = iob->io_offset;
    if (offset < 0 || offset % sfs_dentry_size != 0) {
        kfree(entry);
        return -E_INVAL;
    }

    int ret, slot = offset / sfs_dentry_size;
    if (slot >= sin->din->dirinfo.slots + 2) {
        kfree(entry);
        return -E_NOENT;
    }
    switch (slot) {
    case 0:
        strcpy(entry->name, ".");
        break;
    case 1:
        strcpy(entry->name, "..");
        break;
    default:
        if ((ret = trylock_sin(sin)) != 0) {
            goto out;
        }
        ret = sfs_getdirentry_sub_nolock(sfs, sin, slot - 2, entry);
        unlock_sin(sin);
        if (ret != 0) {
            goto out;
        }
    }
    ret = iobuf_move(iob, entry->name, sfs_dentry_size, 1, NULL);
out:
    kfree(entry);
    return ret;
}
Exemplo n.º 13
0
static int
sfs_fsync(struct inode *node) {
    struct sfs_fs *sfs = fsop_info(vop_fs(node), sfs);
    struct sfs_inode *sin = vop_info(node, sfs_inode);
    if (sin->din->nlinks == 0 || !sin->dirty) {
        return 0;
    }
    int ret;
    if ((ret = trylock_sin(sin)) != 0) {
        return ret;
    }
    if (sin->dirty) {
        sin->dirty = 0;
        if ((ret = sfs_wbuf(sfs, sin->din, sizeof(struct sfs_disk_inode), sin->ino, 0)) != 0) {
            sin->dirty = 1;
        }
    }
    unlock_sin(sin);
    return ret;
}
Exemplo n.º 14
0
static int
sfs_link(struct inode *node, const char *name, struct inode *link_node) {
    if (strlen(name) > SFS_MAX_FNAME_LEN) {
        return -E_TOO_BIG;
    }
    if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0) {
        return -E_EXISTS;
    }
    struct sfs_inode *lnksin = vop_info(link_node, sfs_inode);
    if (lnksin->din->type == SFS_TYPE_DIR) {
        return -E_ISDIR;
    }
    struct sfs_fs *sfs = fsop_info(vop_fs(node), sfs);
    struct sfs_inode *sin = vop_info(node, sfs_inode);
    int ret;
    if ((ret = trylock_sin(sin)) == 0) {
        ret = sfs_link_nolock(sfs, sin, lnksin, name);
        unlock_sin(sin);
    }
    return ret;
}
Exemplo n.º 15
0
static int
sfs_unlink_nolock(struct sfs_fs *sfs, struct sfs_inode *sin, const char *name) {
    int ret, slot;
    uint32_t ino;
    if ((ret = sfs_dirent_search_nolock(sfs, sin, name, &ino, &slot, NULL)) != 0) {
        return ret;
    }
    struct inode *link_node;
    if ((ret = sfs_load_inode(sfs, &link_node, ino)) != 0) {
        return ret;
    }
    struct sfs_inode *lnksin = vop_info(link_node, sfs_inode);
    if (lnksin->din->type != SFS_TYPE_DIR) {
        ret = sfs_dirent_unlink_nolock(sfs, sin, slot, lnksin);
    }
    else {
        if ((ret = trylock_sin(lnksin)) == 0) {
            if (lnksin->din->dirinfo.slots != 0) {
                ret = -E_NOTEMPTY;
            }
            else if ((ret = sfs_dirent_unlink_nolock(sfs, sin, slot, lnksin)) == 0) {
                /* lnksin must be empty, so set SFS_removed bit to invalidate further trylock opts */
                SetSFSInodeRemoved(lnksin);

                /* remove '.' link */
                sfs_nlinks_dec_nolock(lnksin);

                /* remove '..' link */
                sfs_nlinks_dec_nolock(sin);
            }
            unlock_sin(lnksin);
        }
    }
    vop_ref_dec(link_node);
    return ret;
}
static int
sfs_create(struct inode *node, const char *name, bool excl, struct inode **node_store) {
    // kprintf("ready to create a file\n");
    if (strlen(name) > SFS_MAX_FNAME_LEN) {
        return -1;
    }
    // sfs_create_inode(struct sfs_fs *sfs, struct sfs_disk_inode *din, uint32_t ino, struct inode **node_store)
    struct sfs_fs *sfs = fsop_info(vop_fs(node), sfs);
    struct sfs_inode *sin = vop_info(node, sfs_inode);
    int ret;
    // sfs_create_inode(struct sfs_fs *sfs, struct sfs_disk_inode *din, uint32_t ino, struct inode **node_store)
    struct inode *node_tmp = NULL;
    int empty_slot = -1;
    lock_sfs_fs(sfs);
    // sfs_block_alloc(struct sfs_fs *sfs, uint32_t *ino_store)
    sfs_dirent_search_nolock(sfs, sin, name, node_tmp, NULL, &empty_slot);
    // kprintf("%s\n", __func__);
    if (node_tmp) {
        node_store = node_tmp;
    } else {
        if (empty_slot < 0) {
            kprintf("no slot\n");
            return -1;
        }
        struct sfs_disk_inode *din = alloc_disk_inode(SFS_TYPE_FILE);
        int ino;
        sfs_block_alloc(sfs, &ino);
        // kprintf("%s\n", __func__);
        // if (sfs_block_inuse(sfs, ino)) {
        //     kprintf("be sure use\n");
        // } else {
        //     kprintf("not used\n");
        // }
        sfs_create_inode(sfs, din, ino, &node_tmp);
        ++ (din->__nlinks__);
        sfs_set_links(sfs, vop_info(node_tmp, sfs_inode));
        // kprintf("0x%08x\n", node_tmp);
        // sfs_namefile(struct inode *node, struct iobuf *iob)
        // sfs_dirent_write_nolock(struct sfs_fs *sfs, struct sfs_inode *sin, int slot, uint32_t ino, const char *name)
        sfs_dirent_write_nolock(sfs, sin, empty_slot, ino, name);
        // ++ sin->din->blocks;
        int secno = ram2block(ino);
        swapper_block_changed(secno);
        swapper_block_late_sync(secno);
        // kprintf("sin->ino is %d\n", sin->ino);
        sin->dirty = 1;
        lock_sin(sin);
        {
            if (sin->dirty) {
                sin->dirty = 0;
                if ((ret = sfs_wbuf(sfs, sin->din, sizeof(struct sfs_disk_inode), sin->ino, 0)) != 0) {
                    sin->dirty = 1;
                }
            }
        }
        unlock_sin(sin);
        secno = ram2block(sin->ino);
        swapper_block_changed(secno);
        swapper_block_late_sync(secno);
        vop_info(node_tmp, sfs_inode)->dirty = 1;
        sfs->super_dirty = 1;
        // if ((ret = sfs_bmap_load_nolock(sfs, sin, slot, &ino)) != 0) {
        //     return ret;
        // }
        // assert(sfs_block_inuse(sfs, ino));
        // kprintf("ino is %d\n", ino);
        // kprintf("empty slot is %d\n", empty_slot);
        // kprintf("father ino is %d\n", sin->ino);
        *node_store = node_tmp;
    }
    unlock_sfs_fs(sfs);
    // sfs_create_inode(sfs, struct sfs_disk_inode *din, uint32_t ino, struct inode **node_store)
    return 0;
}
static int
sfs_fsync(struct inode *node) {
    struct sfs_fs *sfs = fsop_info(vop_fs(node), sfs);
    struct sfs_inode *sin = vop_info(node, sfs_inode);
    int ret = 0;


    // if (sfs->super_dirty) {
    //     lock_sfs_fs(sfs);
    //     if (sfs->super_dirty) {
    //         sfs->super_dirty = 0;
    //         if ((ret = sfs_wbuf(sfs, sfs->freemap, sizeof(uint32_t) * 400, 1, 0)) != 0) {
    //             // sfs_wbuf(struct sfs_fs *sfs, void *buf, size_t len, uint32_t blkno, off_t offset)
    //             sfs->super_dirty = 1;
    //         }
    //     }
    //     unlock_sfs_fs(sfs);
    // }
    if (sfs->super_dirty) {
        sfs_sync_super(sfs);
        sfs_sync_freemap(sfs);
        swapper_block_changed(0);
    }

    int secno = -1;

    if (sin->dirty) {
        lock_sin(sin);
        {
            if (sin->dirty) {
                sin->dirty = 0;
                if ((ret = sfs_wbuf(sfs, sin->din, sizeof(struct sfs_disk_inode), sin->ino, 0)) != 0) {
                    sin->dirty = 1;
                }
            }
        }
        // int secno = 0;
        // kprintf("in %s: sin->din is %d sin->ino is %d\n", __func__, sin->din, sin->ino);
        int tmp_din = sin->ino;
        while (tmp_din >= 0) {
            secno += 1; // start from `-1`
            tmp_din -= 32;
        }
        unlock_sin(sin);
    }

    // kprintf("secno is %d sfs->super_dirty is %s\n", secno, sfs->super_dirty ? "true" : "false");
    // assert((secno < 0 && !sfs->super_dirty) || (secno >= 0 && sfs->super_dirty));
    if (secno != 0) {
        // kprintf("sync is secno %d\n", secno);
        if (sfs->super_dirty) {
            sfs->super_dirty = 0;
            swapper_block_sync(0);
        }
        if (secno > 0) {
            swapper_block_sync(secno);
        }
    }
    if (secno == 0) {
        swapper_block_sync(0);
    }
    swapper_block_real_sync();
    // kprintf("super->unused_blocks is %d\n", sfs->super.unused_blocks);
    // uint16_t *begin = (uint16_t *)_initrd_begin;
    // int item = 0;
    // for (item = 0; item < 4000; ++item) {
    //     kprintf("0x%04x ", begin[item]);
    // }
    // kprintf("in %s: %d is %s and addr. of sfs is 0x%08x addr. of freemap is 0x%08x\n",
    // __func__, 436, sfs_block_inuse(sfs, 436)?"used":"free", sfs, sfs->freemap);
    return ret;
}