#include #include #include #include #include #include #include #include #include #include #include #include #include #include /* * sfs_sync - sync sfs's superblock and freemap in memroy into disk */ 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; } /* * sfs_get_root - get the root directory inode from disk (SFS_BLKN_ROOT,1) */ 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; } /* * sfs_unmount - unmount sfs, and free the memorys contain sfs->freemap/sfs_buffer/hash_liskt and sfs itself. */ 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; } /* * sfs_cleanup - when sfs failed, then should call this function to sync sfs by calling sfs_sync * * NOTICE: nouse now. */ 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_init_read - used in sfs_do_mount to read disk block(blkno, 1) directly. * * @dev: the block device * @blkno: the NO. of disk block * @blk_buffer: the buffer used for read * * (1) init iobuf * (2) read dev into iobuf */ static int sfs_init_read(struct device *dev, uint32_t blkno, void *blk_buffer) { struct iobuf __iob, *iob = iobuf_init(&__iob, blk_buffer, SFS_BLKSIZE, blkno * SFS_BLKSIZE); return dop_io(dev, iob, 0); } /* * sfs_init_freemap - used in sfs_do_mount to read freemap data info in disk block(blkno, nblks) directly. * * @dev: the block device * @bitmap: the bitmap in memroy * @blkno: the NO. of disk block * @nblks: Rd number of disk block * @blk_buffer: the buffer used for read * * (1) get data addr in bitmap * (2) read dev into iobuf */ static int sfs_init_freemap(struct device *dev, struct bitmap *freemap, uint32_t blkno, uint32_t nblks, void *blk_buffer) { size_t len; void *data = bitmap_getdata(freemap, &len); assert(data != NULL && len == nblks * SFS_BLKSIZE); while (nblks != 0) { int ret; if ((ret = sfs_init_read(dev, blkno, data)) != 0) { return ret; } blkno ++, nblks --, data += SFS_BLKSIZE; } return 0; } /* * sfs_do_mount - mount sfs file system. * * @dev: the block device contains sfs file system * @fs_store: the fs struct in memroy */ static int sfs_do_mount(struct device *dev, struct fs **fs_store) { 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)); 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; } 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 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; 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 */ 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); /* link addr of sync/get_root/unmount/cleanup funciton fs's function pointers*/ 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; } int sfs_mount(const char *devname) { return vfs_mount(devname, sfs_do_mount); }