#include <defs.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <kmalloc.h>
|
|
#include <list.h>
|
|
#include <fs.h>
|
|
#include <vfs.h>
|
|
#include <dev.h>
|
|
#include <sfs.h>
|
|
#include <inode.h>
|
|
#include <iobuf.h>
|
|
#include <bitmap.h>
|
|
#include <error.h>
|
|
#include <assert.h>
|
|
|
|
/*
|
|
* 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);
|
|
}
|
|
|