/* * 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; }
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; }
static int pipe_root_create(struct inode *__node, const char *name, bool excl, struct inode **node_store) { assert((name[0] == 'r' || name[0] == 'w') && name[1] == '_'); int ret = 0; bool readonly = (name[0] == 'r'); name += 2; struct inode *node[2]; struct fs *fs = vop_fs(__node); struct pipe_fs *pipe = fsop_info(fs, pipe); lock_pipe(pipe); lookup_pipe_nolock(pipe, name, &node[0], &node[1]); if (!readonly) { struct inode *tmp = node[0]; node[0] = node[1], node[1] = tmp; } if (node[0] != NULL) { if (excl) { ret = -E_EXISTS, vop_ref_dec(node[0]); goto out; } *node_store = node[0]; goto out; } ret = -E_NO_MEM; struct pipe_state *state; if (node[1] == NULL) { if ((state = pipe_state_create()) == NULL) { goto out; } } else { state = vop_info(node[1], pipe_inode)->state; pipe_state_acquire(state); } struct inode *new_node; if ((new_node = pipe_create_inode(fs, name, state, readonly)) == NULL) { pipe_state_release(state); goto out; } list_add(&(pipe->pipe_list), &(vop_info(new_node, pipe_inode)->pipe_link)); ret = 0, *node_store = new_node; out: unlock_pipe(pipe); if (node[1] != NULL) { vop_ref_dec(node[1]); } return ret; }
static int sfs_reclaim(struct inode *node) { struct sfs_fs *sfs = fsop_info(vop_fs(node), sfs); struct sfs_inode *sin = vop_info(node, sfs_inode); lock_sfs_fs(sfs); int ret = -E_BUSY; assert(sin->reclaim_count > 0); if ((-- sin->reclaim_count) != 0) { goto failed_unlock; } assert(inode_ref_count(node) == 0 && inode_open_count(node) == 0); if (sin->din->nlinks == 0) { uint32_t nblks; for (nblks = sin->din->blocks; nblks != 0; nblks --) { sfs_bmap_truncate_nolock(sfs, sin); } } else if (sin->dirty) { if ((ret = vop_fsync(node)) != 0) { goto failed_unlock; } } sfs_remove_links(sin); unlock_sfs_fs(sfs); if (sin->din->nlinks == 0) { sfs_block_free(sfs, sin->ino); uint32_t ent; if ((ent = sin->din->indirect) != 0) { sfs_block_free(sfs, ent); } if ((ent = sin->din->db_indirect) != 0) { int i; for (i = 0; i < SFS_BLK_NENTRY; i ++) { sfs_bmap_free_sub_nolock(sfs, ent, i); } sfs_block_free(sfs, ent); } } kfree(sin->din); vop_kill(node); return 0; failed_unlock: unlock_sfs_fs(sfs); return ret; }
/* * 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; }
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; }
/* * 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; }
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; }
static int sfs_lookup(struct inode *node, char *path, struct inode **node_store) { struct sfs_fs *sfs = fsop_info(vop_fs(node), sfs); assert(*path != '\0' && *path != '/'); vop_ref_inc(node); do { struct sfs_inode *sin = vop_info(node, sfs_inode); if (sin->din->type != SFS_TYPE_DIR) { vop_ref_dec(node); return -E_NOTDIR; } char *subpath; next: subpath = sfs_lookup_subpath(path); if (strcmp(path, ".") == 0) { if ((path = subpath) != NULL) { goto next; } break; } int ret; struct inode *subnode; if (strcmp(path, "..") == 0) { ret = sfs_load_parent(sfs, sin, &subnode); } else { if (strlen(path) > SFS_MAX_FNAME_LEN) { vop_ref_dec(node); return -E_TOO_BIG; } ret = sfs_lookup_once(sfs, sin, path, &subnode, NULL); } vop_ref_dec(node); if (ret != 0) { return ret; } node = subnode, path = subpath; } while (path != NULL); *node_store = node; return 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; }
static int pipe_inode_reclaim(struct inode *node) { struct pipe_inode *pin = vop_info(node, pipe_inode); if (pin->name != NULL) { struct pipe_fs *pipe = fsop_info(vop_fs(node), pipe); lock_pipe(pipe); assert(pin->reclaim_count > 0); if ((--pin->reclaim_count) != 0 || inode_ref_count(node) != 0) { unlock_pipe(pipe); return -E_BUSY; } list_del(&(pin->pipe_link)); unlock_pipe(pipe); kfree(pin->name); } pipe_state_release(pin->state); vop_kill(node); return 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; }
/* * sfs_lookup - Parse path relative to the passed directory * DIR, and hand back the inode for the file it * refers to. */ static int sfs_lookup(struct inode *node, char *path, struct inode **node_store) { struct sfs_fs *sfs = fsop_info(vop_fs(node), sfs); assert(*path != '\0' && *path != '/'); vop_ref_inc(node); struct sfs_inode *sin = vop_info(node, sfs_inode); if (sin->din->type != SFS_TYPE_DIR) { vop_ref_dec(node); return -E_NOTDIR; } struct inode *subnode; int ret = sfs_lookup_once(sfs, sin, path, &subnode, NULL); vop_ref_dec(node); if (ret != 0) { return ret; } *node_store = subnode; 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); 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; }
int pipe_open(struct inode **rnode_store, struct inode **wnode_store) { int ret; struct inode *root; if ((ret = vfs_get_root("pipe", &root)) != 0) { return ret; } ret = -E_NO_MEM; struct pipe_state *state; if ((state = pipe_state_create()) == NULL) { goto out; } struct fs *fs = vop_fs(root); struct inode *node[2] = { NULL, NULL }; if ((node[0] = pipe_create_inode(fs, NULL, state, 1)) == NULL) { goto failed_cleanup_state; } pipe_state_acquire(state); if ((node[1] = pipe_create_inode(fs, NULL, state, 0)) == NULL) { goto failed_cleanup_node0; } vop_open_inc(node[0]), vop_open_inc(node[1]); *rnode_store = node[0]; *wnode_store = node[1]; ret = 0; out: vop_ref_dec(root); return ret; failed_cleanup_node0: vop_ref_dec(node[0]); failed_cleanup_state: pipe_state_release(state); goto out; }
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; }
/* * sfs_reclaim - Free all resources inode occupied . Called when inode is no longer in use. */ static int sfs_reclaim(struct inode *node) { struct sfs_fs *sfs = fsop_info(vop_fs(node), sfs); struct sfs_inode *sin = vop_info(node, sfs_inode); int ret = -E_BUSY; uint32_t ent; lock_sfs_fs(sfs); assert(sin->reclaim_count > 0); if ((-- sin->reclaim_count) != 0 || inode_ref_count(node) != 0) { goto failed_unlock; } if (sin->din->nlinks == 0) { if ((ret = vop_truncate(node, 0)) != 0) { goto failed_unlock; } } if (sin->dirty) { if ((ret = vop_fsync(node)) != 0) { goto failed_unlock; } } sfs_remove_links(sin); unlock_sfs_fs(sfs); if (sin->din->nlinks == 0) { sfs_block_free(sfs, sin->ino); if ((ent = sin->din->indirect) != 0) { sfs_block_free(sfs, ent); } } kfree(sin->din); vop_kill(node); return 0; failed_unlock: unlock_sfs_fs(sfs); 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; }
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; }