static int pipe_root_lookup(struct inode *__node, char *path, struct inode **node_store) { assert((path[0] == 'r' || path[0] == 'w') && path[1] == '_'); struct inode *node[2]; struct pipe_fs *pipe = fsop_info(vop_fs(__node), pipe); lock_pipe(pipe); { lookup_pipe_nolock(pipe, path + 2, &node[0], &node[1]); } unlock_pipe(pipe); if (path[0] != 'r') { struct inode *tmp = node[0]; node[0] = node[1], node[1] = tmp; } if (node[1] != NULL) { vop_ref_dec(node[1]); } if (node[0] == NULL) { return -E_NOENT; } *node_store = node[0]; return 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; }
/* * 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_sync(struct fs *fs) { struct sfs_fs *sfs = fsop_info(fs, sfs); lock_sfs_fs(sfs); // 应该是用信号量锁定这个玩意 { list_entry_t *list = &(sfs->inode_list), *le = list; while ((le = list_next(le)) != list) { struct sfs_inode *sin = le2sin(le, inode_link); vop_fsync(info2node(sin, sfs_inode)); } } unlock_sfs_fs(sfs); int ret; if (sfs->super_dirty) { sfs->super_dirty = 0; if ((ret = sfs_sync_super(sfs)) != 0) { sfs->super_dirty = 1; return ret; } if ((ret = sfs_sync_freemap(sfs)) != 0) { sfs->super_dirty = 1; return ret; } } return 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; }
static int sfs_sync(struct fs *fs) { struct sfs_fs *sfs = fsop_info(fs, sfs); lock_sfs_fs(sfs); /* * Get the sfs_fs from the generic abstract fs. * * Note that the abstract struct fs, which is all the VFS * layer knows about, is actually a member of struct sfs_fs. * The pointer in the struct fs points back to the top of the * struct sfs_fs - essentially the same object. This can be a * little confusing at first. * * The following diagram may help: * * struct sfs_fs <-----------------\ * : | * : sfs_absfs (struct fs) | <------\ * : : | | * : : various members | | * : : | | * : : fs_info(__sfs_info) ---/ | * : : ...|... * : . VFS . * : . layer . * : other members ....... * : * : * * This construct is repeated with inodes and devices and other * similar things all over the place in ucore, so taking the * time to straighten it out in your mind is worthwhile. */ { list_entry_t *list = &(sfs->inode_list), *le = list; while ((le = list_next(le)) != list) { struct sfs_inode *sin = le2sin(le, inode_link); vop_fsync(info2node(sin, sfs_inode)); } } unlock_sfs_fs(sfs); int ret; if (sfs->super_dirty) { sfs->super_dirty = 0; /* If the superblock needs to be written, write it. */ if ((ret = sfs_sync_super(sfs)) != 0) { sfs->super_dirty = 1; return ret; } /* If the free block map needs to be written, write it. */ if ((ret = sfs_sync_freemap(sfs)) != 0) { sfs->super_dirty = 1; return ret; } } return 0; }
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 struct inode * sfs_get_root(struct fs *fs) { struct inode *node; int ret; if ((ret = sfs_load_inode(fsop_info(fs, sfs), &node, SFS_BLKN_ROOT)) != 0) { panic("load sfs root failed: %e", ret); } return node; }
/* return root inode of filesystem */ static struct inode *ffs_get_root(struct fs *fs) { struct inode *node; int ret; if ((ret = ffs_load_inode(fsop_info(fs, ffs), &node, "0:/", NULL)) != 0) { panic("load ffs root failed: %e", ret); } return node; }
static int sfs_sync(struct fs *fs) { // debug // int u; // kprintf("--- %d ---\n", 1); // for (u = _initrd_begin; u < _initrd_end; ++u) { // kprintf("%02x ", *((char *)u)); // } // kprintf("\n"); struct sfs_fs *sfs = fsop_info(fs, sfs); lock_sfs_fs(sfs); { list_entry_t *list = &(sfs->inode_list), *le = list; while ((le = list_next(le)) != list) { struct sfs_inode *sin = le2sin(le, inode_link); vop_fsync(info2node(sin, sfs_inode)); } } unlock_sfs_fs(sfs); // kprintf("--- %d ---\n", 2); // for (u = _initrd_begin; u < _initrd_end; ++u) { // kprintf("%02x ", *((char *)u)); // } // kprintf("\n"); int ret; if (sfs->super_dirty) { sfs->super_dirty = 0; if ((ret = sfs_sync_super(sfs)) != 0) { sfs->super_dirty = 1; return ret; } if ((ret = sfs_sync_freemap(sfs)) != 0) { sfs->super_dirty = 1; return ret; } } // kprintf("--- %d ---\n", 3); // for (u = _initrd_begin; u < _initrd_end; ++u) { // kprintf("%02x ", *((char *)u)); // } // kprintf("\n"); swapper_all_block_sync(); return 0; }
static int sfs_unmount(struct fs *fs) { struct sfs_fs *sfs = fsop_info(fs, sfs); if (!list_empty(&(sfs->inode_list))) { return -E_BUSY; } assert(!sfs->super_dirty); bitmap_destroy(sfs->freemap); kfree(sfs->sfs_buffer); kfree(sfs->hash_list); kfree(sfs); return 0; }
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; }
/* attempt unmount of filesystem */ static int ffs_unmount(struct fs *fs) { //TODO FAT_PRINTF("[ffs_unmount]\n"); struct ffs_fs *ffs = fsop_info(fs, ffs); if (ffs->inode_list->next != NULL) { return -E_BUSY; } kfree(ffs->fatfs); kfree(ffs->inode_list); kfree(ffs); return 0; }
static void pipe_fs_init(struct fs *fs) { struct pipe_fs *pipe = fsop_info(fs, pipe); if ((pipe->root = pipe_create_root(fs)) == NULL) { panic("pipe: create root inode failed.\n"); } sem_init(&(pipe->pipe_sem), 1); list_init(&(pipe->pipe_list)); fs->fs_sync = pipe_sync; fs->fs_get_root = pipe_get_root; fs->fs_unmount = pipe_unmount; fs->fs_cleanup = pipe_cleanup; }
/* * flush all dirty buffers to disk * return 0 if sync successful */ static int ffs_sync(struct fs *fs) { //TODO return 0; FAT_PRINTF("[ffs_sync]\n"); struct ffs_fs *ffs = fsop_info(fs, ffs); struct ffs_inode_list *inode_list = ffs->inode_list; while (inode_list->next != NULL) { inode_list = inode_list->next; vop_fsync(info2node(inode_list->f_inode, ffs_inode)); } return 0; }
static void sfs_cleanup(struct fs *fs) { struct sfs_fs *sfs = fsop_info(fs, sfs); uint32_t blocks = sfs->super.blocks, unused_blocks = sfs->super.unused_blocks; cprintf("sfs: cleanup: '%s' (%d/%d/%d)\n", sfs->super.info, blocks - unused_blocks, unused_blocks, blocks); int i, ret; for (i = 0; i < 32; i ++) { if ((ret = fsop_sync(fs)) == 0) { break; } } if (ret != 0) { warn("sfs: sync error: '%s': %e.\n", sfs->super.info, 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 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; }
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; }
/* * 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_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; }
/* * 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_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_do_mount(struct device *dev, struct fs **fs_store) { /* * Make sure SFS on-disk structures aren't messed up */ static_assert(SFS_BLKSIZE >= sizeof(struct sfs_super)); static_assert(SFS_BLKSIZE >= sizeof(struct sfs_disk_inode)); static_assert(SFS_BLKSIZE >= sizeof(struct sfs_disk_entry)); /* * We can't mount on devices with the wrong sector size. * * (Note: for all intents and purposes here, "sector" and * "block" are interchangeable terms. Technically a filesystem * block may be composed of several hardware sectors, but we * don't do that in sfs.) */ if (dev->d_blocksize != SFS_BLKSIZE) { return -E_NA_DEV; } /* allocate fs structure */ struct fs *fs; if ((fs = alloc_fs(sfs)) == NULL) { return -E_NO_MEM; } /* get sfs from fs.fs_info.__sfs_info */ struct sfs_fs *sfs = fsop_info(fs, sfs); sfs->dev = dev; int ret = -E_NO_MEM; void *sfs_buffer; if ((sfs->sfs_buffer = sfs_buffer = kmalloc(SFS_BLKSIZE)) == NULL) { goto failed_cleanup_fs; } /* load and check sfs's superblock */ if ((ret = sfs_init_read(dev, SFS_BLKN_SUPER, sfs_buffer)) != 0) { goto failed_cleanup_sfs_buffer; } ret = -E_INVAL; struct sfs_super *super = sfs_buffer; /* Make some simple sanity checks */ if (super->magic != SFS_MAGIC) { cprintf("sfs: wrong magic in superblock. (%08x should be %08x).\n", super->magic, SFS_MAGIC); goto failed_cleanup_sfs_buffer; } if (super->blocks > dev->d_blocks) { cprintf("sfs: fs has %u blocks, device has %u blocks.\n", super->blocks, dev->d_blocks); goto failed_cleanup_sfs_buffer; } super->info[SFS_MAX_INFO_LEN] = '\0'; sfs->super = *super; ret = -E_NO_MEM; uint32_t i; /* alloc and initialize hash list */ list_entry_t *hash_list; if ((sfs->hash_list = hash_list = kmalloc(sizeof(list_entry_t) * SFS_HLIST_SIZE)) == NULL) { goto failed_cleanup_sfs_buffer; } for (i = 0; i < SFS_HLIST_SIZE; i ++) { list_init(hash_list + i); } /* load and check freemap (free space bitmap in disk) */ struct bitmap *freemap; uint32_t freemap_size_nbits = sfs_freemap_bits(super); if ((sfs->freemap = freemap = bitmap_create(freemap_size_nbits)) == NULL) { goto failed_cleanup_hash_list; } uint32_t freemap_size_nblks = sfs_freemap_blocks(super); if ((ret = sfs_init_freemap(dev, freemap, SFS_BLKN_FREEMAP, freemap_size_nblks, sfs_buffer)) != 0) { goto failed_cleanup_freemap; } uint32_t blocks = sfs->super.blocks, unused_blocks = 0; for (i = 0; i < freemap_size_nbits; i ++) { if (bitmap_test(freemap, i)) { unused_blocks ++; } } assert(unused_blocks == sfs->super.unused_blocks); /* and other fields */ sfs->super_dirty = 0; sem_init(&(sfs->fs_sem), 1); sem_init(&(sfs->io_sem), 1); sem_init(&(sfs->mutex_sem), 1); list_init(&(sfs->inode_list)); cprintf("sfs: mount: '%s' (%d/%d/%d)\n", sfs->super.info, blocks - unused_blocks, unused_blocks, blocks); /* Set up abstract fs calls */ fs->fs_sync = sfs_sync; fs->fs_get_root = sfs_get_root; fs->fs_unmount = sfs_unmount; fs->fs_cleanup = sfs_cleanup; *fs_store = fs; return 0; failed_cleanup_freemap: bitmap_destroy(freemap); failed_cleanup_hash_list: kfree(hash_list); failed_cleanup_sfs_buffer: kfree(sfs_buffer); failed_cleanup_fs: kfree(fs); return ret; }