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; }
/* * 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 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; }
/* * 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; }
/* * 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; }
/* * 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; }
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 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; }
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; }
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; }