update name of code to labcodes

This commit is contained in:
chyyuu
2013-09-17 22:21:48 +08:00
parent 759eca9dda
commit 3f8d5876b9
726 changed files with 0 additions and 0 deletions

View File

@@ -0,0 +1,114 @@
#include <defs.h>
#include <string.h>
#include <bitmap.h>
#include <kmalloc.h>
#include <error.h>
#include <assert.h>
#define WORD_TYPE uint32_t
#define WORD_BITS (sizeof(WORD_TYPE) * CHAR_BIT)
struct bitmap {
uint32_t nbits;
uint32_t nwords;
WORD_TYPE *map;
};
// bitmap_create - allocate a new bitmap object.
struct bitmap *
bitmap_create(uint32_t nbits) {
static_assert(WORD_BITS != 0);
assert(nbits != 0 && nbits + WORD_BITS > nbits);
struct bitmap *bitmap;
if ((bitmap = kmalloc(sizeof(struct bitmap))) == NULL) {
return NULL;
}
uint32_t nwords = ROUNDUP_DIV(nbits, WORD_BITS);
WORD_TYPE *map;
if ((map = kmalloc(sizeof(WORD_TYPE) * nwords)) == NULL) {
kfree(bitmap);
return NULL;
}
bitmap->nbits = nbits, bitmap->nwords = nwords;
bitmap->map = memset(map, 0xFF, sizeof(WORD_TYPE) * nwords);
/* mark any leftover bits at the end in use(0) */
if (nbits != nwords * WORD_BITS) {
uint32_t ix = nwords - 1, overbits = nbits - ix * WORD_BITS;
assert(nbits / WORD_BITS == ix);
assert(overbits > 0 && overbits < WORD_BITS);
for (; overbits < WORD_BITS; overbits ++) {
bitmap->map[ix] ^= (1 << overbits);
}
}
return bitmap;
}
// bitmap_alloc - locate a cleared bit, set it, and return its index.
int
bitmap_alloc(struct bitmap *bitmap, uint32_t *index_store) {
WORD_TYPE *map = bitmap->map;
uint32_t ix, offset, nwords = bitmap->nwords;
for (ix = 0; ix < nwords; ix ++) {
if (map[ix] != 0) {
for (offset = 0; offset < WORD_BITS; offset ++) {
WORD_TYPE mask = (1 << offset);
if (map[ix] & mask) {
map[ix] ^= mask;
*index_store = ix * WORD_BITS + offset;
return 0;
}
}
assert(0);
}
}
return -E_NO_MEM;
}
// bitmap_translate - according index, get the related word and mask
static void
bitmap_translate(struct bitmap *bitmap, uint32_t index, WORD_TYPE **word, WORD_TYPE *mask) {
assert(index < bitmap->nbits);
uint32_t ix = index / WORD_BITS, offset = index % WORD_BITS;
*word = bitmap->map + ix;
*mask = (1 << offset);
}
// bitmap_test - according index, get the related value (0 OR 1) in the bitmap
bool
bitmap_test(struct bitmap *bitmap, uint32_t index) {
WORD_TYPE *word, mask;
bitmap_translate(bitmap, index, &word, &mask);
return (*word & mask);
}
// bitmap_free - according index, set related bit to 1
void
bitmap_free(struct bitmap *bitmap, uint32_t index) {
WORD_TYPE *word, mask;
bitmap_translate(bitmap, index, &word, &mask);
assert(!(*word & mask));
*word |= mask;
}
// bitmap_destroy - free memory contains bitmap
void
bitmap_destroy(struct bitmap *bitmap) {
kfree(bitmap->map);
kfree(bitmap);
}
// bitmap_getdata - return bitmap->map, return the length of bits to len_store
void *
bitmap_getdata(struct bitmap *bitmap, size_t *len_store) {
if (len_store != NULL) {
*len_store = sizeof(WORD_TYPE) * bitmap->nwords;
}
return bitmap->map;
}

View File

@@ -0,0 +1,32 @@
#ifndef __KERN_FS_SFS_BITMAP_H__
#define __KERN_FS_SFS_BITMAP_H__
#include <defs.h>
/*
* Fixed-size array of bits. (Intended for storage management.)
*
* Functions:
* bitmap_create - allocate a new bitmap object.
* Returns NULL on error.
* bitmap_getdata - return pointer to raw bit data (for I/O).
* bitmap_alloc - locate a cleared bit, set it, and return its index.
* bitmap_mark - set a clear bit by its index.
* bitmap_unmark - clear a set bit by its index.
* bitmap_isset - return whether a particular bit is set or not.
* bitmap_destroy - destroy bitmap.
*/
struct bitmap;
struct bitmap *bitmap_create(uint32_t nbits); // allocate a new bitmap object.
int bitmap_alloc(struct bitmap *bitmap, uint32_t *index_store); // locate a cleared bit, set it, and return its index.
bool bitmap_test(struct bitmap *bitmap, uint32_t index); // return whether a particular bit is set or not.
void bitmap_free(struct bitmap *bitmap, uint32_t index); // according index, set related bit to 1
void bitmap_destroy(struct bitmap *bitmap); // free memory contains bitmap
void *bitmap_getdata(struct bitmap *bitmap, size_t *len_store); // return pointer to raw bit data (for I/O)
#endif /* !__KERN_FS_SFS_BITMAP_H__ */

View File

@@ -0,0 +1,19 @@
#include <defs.h>
#include <sfs.h>
#include <error.h>
#include <assert.h>
/*
* sfs_init - mount sfs on disk0
*
* CALL GRAPH:
* kern_init-->fs_init-->sfs_init
*/
void
sfs_init(void) {
int ret;
if ((ret = sfs_mount("disk0")) != 0) {
panic("failed: sfs: sfs_mount: %e.\n", ret);
}
}

View File

@@ -0,0 +1,129 @@
#ifndef __KERN_FS_SFS_SFS_H__
#define __KERN_FS_SFS_SFS_H__
#include <defs.h>
#include <mmu.h>
#include <list.h>
#include <sem.h>
#include <unistd.h>
/*
* Simple FS (SFS) definitions visible to ucore. This covers the on-disk format
* and is used by tools that work on SFS volumes, such as mksfs.
*/
#define SFS_MAGIC 0x2f8dbe2a /* magic number for sfs */
#define SFS_BLKSIZE PGSIZE /* size of block */
#define SFS_NDIRECT 12 /* # of direct blocks in inode */
#define SFS_MAX_INFO_LEN 31 /* max length of infomation */
#define SFS_MAX_FNAME_LEN FS_MAX_FNAME_LEN /* max length of filename */
#define SFS_MAX_FILE_SIZE (1024UL * 1024 * 128) /* max file size (128M) */
#define SFS_BLKN_SUPER 0 /* block the superblock lives in */
#define SFS_BLKN_ROOT 1 /* location of the root dir inode */
#define SFS_BLKN_FREEMAP 2 /* 1st block of the freemap */
/* # of bits in a block */
#define SFS_BLKBITS (SFS_BLKSIZE * CHAR_BIT)
/* # of entries in a block */
#define SFS_BLK_NENTRY (SFS_BLKSIZE / sizeof(uint32_t))
/* file types */
#define SFS_TYPE_INVAL 0 /* Should not appear on disk */
#define SFS_TYPE_FILE 1
#define SFS_TYPE_DIR 2
#define SFS_TYPE_LINK 3
/*
* On-disk superblock
*/
struct sfs_super {
uint32_t magic; /* magic number, should be SFS_MAGIC */
uint32_t blocks; /* # of blocks in fs */
uint32_t unused_blocks; /* # of unused blocks in fs */
char info[SFS_MAX_INFO_LEN + 1]; /* infomation for sfs */
};
/* inode (on disk) */
struct sfs_disk_inode {
uint32_t size; /* size of the file (in bytes) */
uint16_t type; /* one of SYS_TYPE_* above */
uint16_t nlinks; /* # of hard links to this file */
uint32_t blocks; /* # of blocks */
uint32_t direct[SFS_NDIRECT]; /* direct blocks */
uint32_t indirect; /* indirect blocks */
// uint32_t db_indirect; /* double indirect blocks */
// unused
};
/* file entry (on disk) */
struct sfs_disk_entry {
uint32_t ino; /* inode number */
char name[SFS_MAX_FNAME_LEN + 1]; /* file name */
};
#define sfs_dentry_size \
sizeof(((struct sfs_disk_entry *)0)->name)
/* inode for sfs */
struct sfs_inode {
struct sfs_disk_inode *din; /* on-disk inode */
uint32_t ino; /* inode number */
bool dirty; /* true if inode modified */
int reclaim_count; /* kill inode if it hits zero */
semaphore_t sem; /* semaphore for din */
list_entry_t inode_link; /* entry for linked-list in sfs_fs */
list_entry_t hash_link; /* entry for hash linked-list in sfs_fs */
};
#define le2sin(le, member) \
to_struct((le), struct sfs_inode, member)
/* filesystem for sfs */
struct sfs_fs {
struct sfs_super super; /* on-disk superblock */
struct device *dev; /* device mounted on */
struct bitmap *freemap; /* blocks in use are mared 0 */
bool super_dirty; /* true if super/freemap modified */
void *sfs_buffer; /* buffer for non-block aligned io */
semaphore_t fs_sem; /* semaphore for fs */
semaphore_t io_sem; /* semaphore for io */
semaphore_t mutex_sem; /* semaphore for link/unlink and rename */
list_entry_t inode_list; /* inode linked-list */
list_entry_t *hash_list; /* inode hash linked-list */
};
/* hash for sfs */
#define SFS_HLIST_SHIFT 10
#define SFS_HLIST_SIZE (1 << SFS_HLIST_SHIFT)
#define sin_hashfn(x) (hash32(x, SFS_HLIST_SHIFT))
/* size of freemap (in bits) */
#define sfs_freemap_bits(super) ROUNDUP((super)->blocks, SFS_BLKBITS)
/* size of freemap (in blocks) */
#define sfs_freemap_blocks(super) ROUNDUP_DIV((super)->blocks, SFS_BLKBITS)
struct fs;
struct inode;
void sfs_init(void);
int sfs_mount(const char *devname);
void lock_sfs_fs(struct sfs_fs *sfs);
void lock_sfs_io(struct sfs_fs *sfs);
void unlock_sfs_fs(struct sfs_fs *sfs);
void unlock_sfs_io(struct sfs_fs *sfs);
int sfs_rblock(struct sfs_fs *sfs, void *buf, uint32_t blkno, uint32_t nblks);
int sfs_wblock(struct sfs_fs *sfs, void *buf, uint32_t blkno, uint32_t nblks);
int sfs_rbuf(struct sfs_fs *sfs, void *buf, size_t len, uint32_t blkno, off_t offset);
int sfs_wbuf(struct sfs_fs *sfs, void *buf, size_t len, uint32_t blkno, off_t offset);
int sfs_sync_super(struct sfs_fs *sfs);
int sfs_sync_freemap(struct sfs_fs *sfs);
int sfs_clear_block(struct sfs_fs *sfs, uint32_t blkno, uint32_t nblks);
int sfs_load_inode(struct sfs_fs *sfs, struct inode **node_store, uint32_t ino);
#endif /* !__KERN_FS_SFS_SFS_H__ */

View File

@@ -0,0 +1,258 @@
#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);
}

View File

@@ -0,0 +1,987 @@
#include <defs.h>
#include <string.h>
#include <stdlib.h>
#include <list.h>
#include <stat.h>
#include <kmalloc.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>
static const struct inode_ops sfs_node_dirops; // dir operations
static const struct inode_ops sfs_node_fileops; // file operations
/*
* lock_sin - lock the process of inode Rd/Wr
*/
static void
lock_sin(struct sfs_inode *sin) {
down(&(sin->sem));
}
/*
* unlock_sin - unlock the process of inode Rd/Wr
*/
static void
unlock_sin(struct sfs_inode *sin) {
up(&(sin->sem));
}
/*
* sfs_get_ops - return function addr of fs_node_dirops/sfs_node_fileops
*/
static const struct inode_ops *
sfs_get_ops(uint16_t type) {
switch (type) {
case SFS_TYPE_DIR:
return &sfs_node_dirops;
case SFS_TYPE_FILE:
return &sfs_node_fileops;
}
panic("invalid file type %d.\n", type);
}
/*
* sfs_hash_list - return inode entry in sfs->hash_list
*/
static list_entry_t *
sfs_hash_list(struct sfs_fs *sfs, uint32_t ino) {
return sfs->hash_list + sin_hashfn(ino);
}
/*
* sfs_set_links - link inode sin in sfs->linked-list AND sfs->hash_link
*/
static void
sfs_set_links(struct sfs_fs *sfs, struct sfs_inode *sin) {
list_add(&(sfs->inode_list), &(sin->inode_link));
list_add(sfs_hash_list(sfs, sin->ino), &(sin->hash_link));
}
/*
* sfs_remove_links - unlink inode sin in sfs->linked-list AND sfs->hash_link
*/
static void
sfs_remove_links(struct sfs_inode *sin) {
list_del(&(sin->inode_link));
list_del(&(sin->hash_link));
}
/*
* sfs_block_inuse - check the inode with NO. ino inuse info in bitmap
*/
static bool
sfs_block_inuse(struct sfs_fs *sfs, uint32_t ino) {
if (ino != 0 && ino < sfs->super.blocks) {
return !bitmap_test(sfs->freemap, ino);
}
panic("sfs_block_inuse: called out of range (0, %u) %u.\n", sfs->super.blocks, ino);
}
/*
* sfs_block_alloc - check and get a free disk block
*/
static int
sfs_block_alloc(struct sfs_fs *sfs, uint32_t *ino_store) {
int ret;
if ((ret = bitmap_alloc(sfs->freemap, ino_store)) != 0) {
return ret;
}
assert(sfs->super.unused_blocks > 0);
sfs->super.unused_blocks --, sfs->super_dirty = 1;
assert(sfs_block_inuse(sfs, *ino_store));
return sfs_clear_block(sfs, *ino_store, 1);
}
/*
* sfs_block_free - set related bits for ino block to 1(means free) in bitmap, add sfs->super.unused_blocks, set superblock dirty *
*/
static void
sfs_block_free(struct sfs_fs *sfs, uint32_t ino) {
assert(sfs_block_inuse(sfs, ino));
bitmap_free(sfs->freemap, ino);
sfs->super.unused_blocks ++, sfs->super_dirty = 1;
}
/*
* sfs_create_inode - alloc a inode in memroy, and init din/ino/dirty/reclian_count/sem fields in sfs_inode in inode
*/
static int
sfs_create_inode(struct sfs_fs *sfs, struct sfs_disk_inode *din, uint32_t ino, struct inode **node_store) {
struct inode *node;
if ((node = alloc_inode(sfs_inode)) != NULL) {
vop_init(node, sfs_get_ops(din->type), info2fs(sfs, sfs));
struct sfs_inode *sin = vop_info(node, sfs_inode);
sin->din = din, sin->ino = ino, sin->dirty = 0, sin->reclaim_count = 1;
sem_init(&(sin->sem), 1);
*node_store = node;
return 0;
}
return -E_NO_MEM;
}
/*
* lookup_sfs_nolock - according ino, find related inode
*
* NOTICE: le2sin, info2node MACRO
*/
static struct inode *
lookup_sfs_nolock(struct sfs_fs *sfs, uint32_t ino) {
struct inode *node;
list_entry_t *list = sfs_hash_list(sfs, ino), *le = list;
while ((le = list_next(le)) != list) {
struct sfs_inode *sin = le2sin(le, hash_link);
if (sin->ino == ino) {
node = info2node(sin, sfs_inode);
if (vop_ref_inc(node) == 1) {
sin->reclaim_count ++;
}
return node;
}
}
return NULL;
}
/*
* sfs_load_inode - If the inode isn't existed, load inode related ino disk block data into a new created inode.
* If the inode is in memory alreadily, then do nothing
*/
int
sfs_load_inode(struct sfs_fs *sfs, struct inode **node_store, uint32_t ino) {
lock_sfs_fs(sfs);
struct inode *node;
if ((node = lookup_sfs_nolock(sfs, ino)) != NULL) {
goto out_unlock;
}
int ret = -E_NO_MEM;
struct sfs_disk_inode *din;
if ((din = kmalloc(sizeof(struct sfs_disk_inode))) == NULL) {
goto failed_unlock;
}
assert(sfs_block_inuse(sfs, ino));
if ((ret = sfs_rbuf(sfs, din, sizeof(struct sfs_disk_inode), ino, 0)) != 0) {
goto failed_cleanup_din;
}
assert(din->nlinks != 0);
if ((ret = sfs_create_inode(sfs, din, ino, &node)) != 0) {
goto failed_cleanup_din;
}
sfs_set_links(sfs, vop_info(node, sfs_inode));
out_unlock:
unlock_sfs_fs(sfs);
*node_store = node;
return 0;
failed_cleanup_din:
kfree(din);
failed_unlock:
unlock_sfs_fs(sfs);
return ret;
}
/*
* sfs_bmap_get_sub_nolock - according entry pointer entp and index, find the index of indrect disk block
* return the index of indrect disk block to ino_store. no lock protect
* @sfs: sfs file system
* @entp: the pointer of index of entry disk block
* @index: the index of block in indrect block
* @create: BOOL, if the block isn't allocated, if create = 1 the alloc a block, otherwise just do nothing
* @ino_store: 0 OR the index of already inused block or new allocated block.
*/
static int
sfs_bmap_get_sub_nolock(struct sfs_fs *sfs, uint32_t *entp, uint32_t index, bool create, uint32_t *ino_store) {
assert(index < SFS_BLK_NENTRY);
int ret;
uint32_t ent, ino = 0;
off_t offset = index * sizeof(uint32_t); // the offset of entry in entry block
// if entry block is existd, read the content of entry block into sfs->sfs_buffer
if ((ent = *entp) != 0) {
if ((ret = sfs_rbuf(sfs, &ino, sizeof(uint32_t), ent, offset)) != 0) {
return ret;
}
if (ino != 0 || !create) {
goto out;
}
}
else {
if (!create) {
goto out;
}
//if entry block isn't existd, allocated a entry block (for indrect block)
if ((ret = sfs_block_alloc(sfs, &ent)) != 0) {
return ret;
}
}
if ((ret = sfs_block_alloc(sfs, &ino)) != 0) {
goto failed_cleanup;
}
if ((ret = sfs_wbuf(sfs, &ino, sizeof(uint32_t), ent, offset)) != 0) {
sfs_block_free(sfs, ino);
goto failed_cleanup;
}
out:
if (ent != *entp) {
*entp = ent;
}
*ino_store = ino;
return 0;
failed_cleanup:
if (ent != *entp) {
sfs_block_free(sfs, ent);
}
return ret;
}
/*
* sfs_bmap_get_nolock - according sfs_inode and index of block, find the NO. of disk block
* no lock protect
* @sfs: sfs file system
* @sin: sfs inode in memory
* @index: the index of block in inode
* @create: BOOL, if the block isn't allocated, if create = 1 the alloc a block, otherwise just do nothing
* @ino_store: 0 OR the index of already inused block or new allocated block.
*/
static int
sfs_bmap_get_nolock(struct sfs_fs *sfs, struct sfs_inode *sin, uint32_t index, bool create, uint32_t *ino_store) {
struct sfs_disk_inode *din = sin->din;
int ret;
uint32_t ent, ino;
// the index of disk block is in the fist SFS_NDIRECT direct blocks
if (index < SFS_NDIRECT) {
if ((ino = din->direct[index]) == 0 && create) {
if ((ret = sfs_block_alloc(sfs, &ino)) != 0) {
return ret;
}
din->direct[index] = ino;
sin->dirty = 1;
}
goto out;
}
// the index of disk block is in the indirect blocks.
index -= SFS_NDIRECT;
if (index < SFS_BLK_NENTRY) {
ent = din->indirect;
if ((ret = sfs_bmap_get_sub_nolock(sfs, &ent, index, create, &ino)) != 0) {
return ret;
}
if (ent != din->indirect) {
assert(din->indirect == 0);
din->indirect = ent;
sin->dirty = 1;
}
goto out;
} else {
panic ("sfs_bmap_get_nolock - index out of range");
}
out:
assert(ino == 0 || sfs_block_inuse(sfs, ino));
*ino_store = ino;
return 0;
}
/*
* sfs_bmap_free_sub_nolock - set the entry item to 0 (free) in the indirect block
*/
static int
sfs_bmap_free_sub_nolock(struct sfs_fs *sfs, uint32_t ent, uint32_t index) {
assert(sfs_block_inuse(sfs, ent) && index < SFS_BLK_NENTRY);
int ret;
uint32_t ino, zero = 0;
off_t offset = index * sizeof(uint32_t);
if ((ret = sfs_rbuf(sfs, &ino, sizeof(uint32_t), ent, offset)) != 0) {
return ret;
}
if (ino != 0) {
if ((ret = sfs_wbuf(sfs, &zero, sizeof(uint32_t), ent, offset)) != 0) {
return ret;
}
sfs_block_free(sfs, ino);
}
return 0;
}
/*
* sfs_bmap_free_nolock - free a block with logical index in inode and reset the inode's fields
*/
static int
sfs_bmap_free_nolock(struct sfs_fs *sfs, struct sfs_inode *sin, uint32_t index) {
struct sfs_disk_inode *din = sin->din;
int ret;
uint32_t ent, ino;
if (index < SFS_NDIRECT) {
if ((ino = din->direct[index]) != 0) {
// free the block
sfs_block_free(sfs, ino);
din->direct[index] = 0;
sin->dirty = 1;
}
return 0;
}
index -= SFS_NDIRECT;
if (index < SFS_BLK_NENTRY) {
if ((ent = din->indirect) != 0) {
// set the entry item to 0 in the indirect block
if ((ret = sfs_bmap_free_sub_nolock(sfs, ent, index)) != 0) {
return ret;
}
}
return 0;
}
return 0;
}
/*
* sfs_bmap_load_nolock - according to the DIR's inode and the logical index of block in inode, find the NO. of disk block.
* @sfs: sfs file system
* @sin: sfs inode in memory
* @index: the logical index of disk block in inode
* @ino_store:the NO. of disk block
*/
static int
sfs_bmap_load_nolock(struct sfs_fs *sfs, struct sfs_inode *sin, uint32_t index, uint32_t *ino_store) {
struct sfs_disk_inode *din = sin->din;
assert(index <= din->blocks);
int ret;
uint32_t ino;
bool create = (index == din->blocks);
if ((ret = sfs_bmap_get_nolock(sfs, sin, index, create, &ino)) != 0) {
return ret;
}
assert(sfs_block_inuse(sfs, ino));
if (create) {
din->blocks ++;
}
if (ino_store != NULL) {
*ino_store = ino;
}
return 0;
}
/*
* sfs_bmap_truncate_nolock - free the disk block at the end of file
*/
static int
sfs_bmap_truncate_nolock(struct sfs_fs *sfs, struct sfs_inode *sin) {
struct sfs_disk_inode *din = sin->din;
assert(din->blocks != 0);
int ret;
if ((ret = sfs_bmap_free_nolock(sfs, sin, din->blocks - 1)) != 0) {
return ret;
}
din->blocks --;
sin->dirty = 1;
return 0;
}
/*
* sfs_dirent_read_nolock - read the file entry from disk block which contains this entry
* @sfs: sfs file system
* @sin: sfs inode in memory
* @slot: the index of file entry
* @entry: file entry
*/
static int
sfs_dirent_read_nolock(struct sfs_fs *sfs, struct sfs_inode *sin, int slot, struct sfs_disk_entry *entry) {
assert(sin->din->type == SFS_TYPE_DIR && (slot >= 0 && slot < sin->din->blocks));
int ret;
uint32_t ino;
// according to the DIR's inode and the slot of file entry, find the index of disk block which contains this file entry
if ((ret = sfs_bmap_load_nolock(sfs, sin, slot, &ino)) != 0) {
return ret;
}
assert(sfs_block_inuse(sfs, ino));
// read the content of file entry in the disk block
if ((ret = sfs_rbuf(sfs, entry, sizeof(struct sfs_disk_entry), ino, 0)) != 0) {
return ret;
}
entry->name[SFS_MAX_FNAME_LEN] = '\0';
return 0;
}
#define sfs_dirent_link_nolock_check(sfs, sin, slot, lnksin, name) \
do { \
int err; \
if ((err = sfs_dirent_link_nolock(sfs, sin, slot, lnksin, name)) != 0) { \
warn("sfs_dirent_link error: %e.\n", err); \
} \
} while (0)
#define sfs_dirent_unlink_nolock_check(sfs, sin, slot, lnksin) \
do { \
int err; \
if ((err = sfs_dirent_unlink_nolock(sfs, sin, slot, lnksin)) != 0) { \
warn("sfs_dirent_unlink error: %e.\n", err); \
} \
} while (0)
/*
* sfs_dirent_search_nolock - read every file entry in the DIR, compare file name with each entry->name
* If equal, then return slot and NO. of disk of this file's inode
* @sfs: sfs file system
* @sin: sfs inode in memory
* @name: the filename
* @ino_store: NO. of disk of this file (with the filename)'s inode
* @slot: logical index of file entry (NOTICE: each file entry ocupied one disk block)
* @empty_slot: the empty logical index of file entry.
*/
static int
sfs_dirent_search_nolock(struct sfs_fs *sfs, struct sfs_inode *sin, const char *name, uint32_t *ino_store, int *slot, int *empty_slot) {
assert(strlen(name) <= SFS_MAX_FNAME_LEN);
struct sfs_disk_entry *entry;
if ((entry = kmalloc(sizeof(struct sfs_disk_entry))) == NULL) {
return -E_NO_MEM;
}
#define set_pvalue(x, v) do { if ((x) != NULL) { *(x) = (v); } } while (0)
int ret, i, nslots = sin->din->blocks;
set_pvalue(empty_slot, nslots);
for (i = 0; i < nslots; i ++) {
if ((ret = sfs_dirent_read_nolock(sfs, sin, i, entry)) != 0) {
goto out;
}
if (entry->ino == 0) {
set_pvalue(empty_slot, i);
continue ;
}
if (strcmp(name, entry->name) == 0) {
set_pvalue(slot, i);
set_pvalue(ino_store, entry->ino);
goto out;
}
}
#undef set_pvalue
ret = -E_NOENT;
out:
kfree(entry);
return ret;
}
/*
* sfs_dirent_findino_nolock - read all file entries in DIR's inode and find a entry->ino == ino
*/
static int
sfs_dirent_findino_nolock(struct sfs_fs *sfs, struct sfs_inode *sin, uint32_t ino, struct sfs_disk_entry *entry) {
int ret, i, nslots = sin->din->blocks;
for (i = 0; i < nslots; i ++) {
if ((ret = sfs_dirent_read_nolock(sfs, sin, i, entry)) != 0) {
return ret;
}
if (entry->ino == ino) {
return 0;
}
}
return -E_NOENT;
}
/*
* 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;
}
// sfs_opendir - just check the opne_flags, now support readonly
static int
sfs_opendir(struct inode *node, uint32_t open_flags) {
switch (open_flags & O_ACCMODE) {
case O_RDONLY:
break;
case O_WRONLY:
case O_RDWR:
default:
return -E_ISDIR;
}
if (open_flags & O_APPEND) {
return -E_ISDIR;
}
return 0;
}
// sfs_openfile - open file (no use)
static int
sfs_openfile(struct inode *node, uint32_t open_flags) {
return 0;
}
// sfs_close - close file
static int
sfs_close(struct inode *node) {
return vop_fsync(node);
}
/*
* sfs_io_nolock - Rd/Wr a file contentfrom offset position to offset+ length disk blocks<-->buffer (in memroy)
* @sfs: sfs file system
* @sin: sfs inode in memory
* @buf: the buffer Rd/Wr
* @offset: the offset of file
* @alenp: the length need to read (is a pointer). and will RETURN the really Rd/Wr lenght
* @write: BOOL, 0 read, 1 write
*/
static int
sfs_io_nolock(struct sfs_fs *sfs, struct sfs_inode *sin, void *buf, off_t offset, size_t *alenp, bool write) {
struct sfs_disk_inode *din = sin->din;
assert(din->type != SFS_TYPE_DIR);
off_t endpos = offset + *alenp, blkoff;
*alenp = 0;
// calculate the Rd/Wr end position
if (offset < 0 || offset >= SFS_MAX_FILE_SIZE || offset > endpos) {
return -E_INVAL;
}
if (offset == endpos) {
return 0;
}
if (endpos > SFS_MAX_FILE_SIZE) {
endpos = SFS_MAX_FILE_SIZE;
}
if (!write) {
if (offset >= din->size) {
return 0;
}
if (endpos > din->size) {
endpos = din->size;
}
}
int (*sfs_buf_op)(struct sfs_fs *sfs, void *buf, size_t len, uint32_t blkno, off_t offset);
int (*sfs_block_op)(struct sfs_fs *sfs, void *buf, uint32_t blkno, uint32_t nblks);
if (write) {
sfs_buf_op = sfs_wbuf, sfs_block_op = sfs_wblock;
}
else {
sfs_buf_op = sfs_rbuf, sfs_block_op = sfs_rblock;
}
int ret = 0;
size_t size, alen = 0;
uint32_t ino;
uint32_t blkno = offset / SFS_BLKSIZE; // The NO. of Rd/Wr begin block
uint32_t nblks = endpos / SFS_BLKSIZE - blkno; // The size of Rd/Wr blocks
//LAB8:EXERCISE1 YOUR CODE HINT: call sfs_bmap_load_nolock, sfs_rbuf, sfs_rblock,etc. read different kind of blocks in file
/*
* (1) If offset isn't aligned with the first block, Rd/Wr some content from offset to the end of the first block
* NOTICE: useful function: sfs_bmap_load_nolock, sfs_buf_op
* Rd/Wr size = (nblks != 0) ? (SFS_BLKSIZE - blkoff) : (endpos - offset)
* (2) Rd/Wr aligned blocks
* NOTICE: useful function: sfs_bmap_load_nolock, sfs_block_op
* (3) If end position isn't aligned with the last block, Rd/Wr some content from begin to the (endpos % SFS_BLKSIZE) of the last block
* NOTICE: useful function: sfs_bmap_load_nolock, sfs_buf_op
*/
out:
*alenp = alen;
if (offset + alen > sin->din->size) {
sin->din->size = offset + alen;
sin->dirty = 1;
}
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;
}
// sfs_read - read file
static int
sfs_read(struct inode *node, struct iobuf *iob) {
return sfs_io(node, iob, 0);
}
// sfs_write - write file
static int
sfs_write(struct inode *node, struct iobuf *iob) {
return sfs_io(node, iob, 1);
}
/*
* sfs_fstat - Return nlinks/block/size, etc. info about a file. The pointer is a pointer to struct stat;
*/
static int
sfs_fstat(struct inode *node, struct stat *stat) {
int ret;
memset(stat, 0, sizeof(struct stat));
if ((ret = vop_gettype(node, &(stat->st_mode))) != 0) {
return ret;
}
struct sfs_disk_inode *din = vop_info(node, sfs_inode)->din;
stat->st_nlinks = din->nlinks;
stat->st_blocks = din->blocks;
stat->st_size = din->size;
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_namefile -Compute pathname relative to filesystem root of the file and copy to the specified io buffer.
*
*/
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;
char *ptr = iob->io_base + iob->io_resid;
size_t alen, resid = iob->io_resid - 2;
vop_ref_inc(node);
while (1) {
struct inode *parent;
if ((ret = sfs_lookup_once(sfs, sin, "..", &parent, NULL)) != 0) {
goto failed;
}
uint32_t ino = sin->ino;
vop_ref_dec(node);
if (node == parent) {
vop_ref_dec(node);
break;
}
node = parent, sin = vop_info(node, sfs_inode);
assert(ino != sin->ino && sin->din->type == SFS_TYPE_DIR);
lock_sin(sin);
{
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] = '/';
}
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;
}
/*
* sfs_getdirentry_sub_noblock - get the content of file entry in DIR
*/
static int
sfs_getdirentry_sub_nolock(struct sfs_fs *sfs, struct sfs_inode *sin, int slot, struct sfs_disk_entry *entry) {
int ret, i, nslots = sin->din->blocks;
for (i = 0; i < nslots; i ++) {
if ((ret = sfs_dirent_read_nolock(sfs, sin, i, entry)) != 0) {
return ret;
}
if (entry->ino != 0) {
if (slot == 0) {
return 0;
}
slot --;
}
}
return -E_NOENT;
}
/*
* 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;
}
/*
* 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;
}
/*
* sfs_gettype - Return type of file. The values for file types are in sfs.h.
*/
static int
sfs_gettype(struct inode *node, uint32_t *type_store) {
struct sfs_disk_inode *din = vop_info(node, sfs_inode)->din;
switch (din->type) {
case SFS_TYPE_DIR:
*type_store = S_IFDIR;
return 0;
case SFS_TYPE_FILE:
*type_store = S_IFREG;
return 0;
case SFS_TYPE_LINK:
*type_store = S_IFLNK;
return 0;
}
panic("invalid file type %d.\n", din->type);
}
/*
* sfs_tryseek - Check if seeking to the specified position within the file is legal.
*/
static int
sfs_tryseek(struct inode *node, off_t pos) {
if (pos < 0 || pos >= SFS_MAX_FILE_SIZE) {
return -E_INVAL;
}
struct sfs_inode *sin = vop_info(node, sfs_inode);
if (pos > sin->din->size) {
return vop_truncate(node, pos);
}
return 0;
}
/*
* 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;
}
/*
* 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;
}
// The sfs specific DIR operations correspond to the abstract operations on a inode.
static const struct inode_ops sfs_node_dirops = {
.vop_magic = VOP_MAGIC,
.vop_open = sfs_opendir,
.vop_close = sfs_close,
.vop_fstat = sfs_fstat,
.vop_fsync = sfs_fsync,
.vop_namefile = sfs_namefile,
.vop_getdirentry = sfs_getdirentry,
.vop_reclaim = sfs_reclaim,
.vop_gettype = sfs_gettype,
.vop_lookup = sfs_lookup,
};
/// The sfs specific FILE operations correspond to the abstract operations on a inode.
static const struct inode_ops sfs_node_fileops = {
.vop_magic = VOP_MAGIC,
.vop_open = sfs_openfile,
.vop_close = sfs_close,
.vop_read = sfs_read,
.vop_write = sfs_write,
.vop_fstat = sfs_fstat,
.vop_fsync = sfs_fsync,
.vop_reclaim = sfs_reclaim,
.vop_gettype = sfs_gettype,
.vop_tryseek = sfs_tryseek,
.vop_truncate = sfs_truncfile,
};

View File

@@ -0,0 +1,167 @@
#include <defs.h>
#include <string.h>
#include <dev.h>
#include <sfs.h>
#include <iobuf.h>
#include <bitmap.h>
#include <assert.h>
//Basic block-level I/O routines
/* sfs_rwblock_nolock - Basic block-level I/O routine for Rd/Wr one disk block,
* without lock protect for mutex process on Rd/Wr disk block
* @sfs: sfs_fs which will be process
* @buf: the buffer uesed for Rd/Wr
* @blkno: the NO. of disk block
* @write: BOOL: Read or Write
* @check: BOOL: if check (blono < sfs super.blocks)
*/
static int
sfs_rwblock_nolock(struct sfs_fs *sfs, void *buf, uint32_t blkno, bool write, bool check) {
assert((blkno != 0 || !check) && blkno < sfs->super.blocks);
struct iobuf __iob, *iob = iobuf_init(&__iob, buf, SFS_BLKSIZE, blkno * SFS_BLKSIZE);
return dop_io(sfs->dev, iob, write);
}
/* sfs_rwblock - Basic block-level I/O routine for Rd/Wr N disk blocks ,
* with lock protect for mutex process on Rd/Wr disk block
* @sfs: sfs_fs which will be process
* @buf: the buffer uesed for Rd/Wr
* @blkno: the NO. of disk block
* @nblks: Rd/Wr number of disk block
* @write: BOOL: Read - 0 or Write - 1
*/
static int
sfs_rwblock(struct sfs_fs *sfs, void *buf, uint32_t blkno, uint32_t nblks, bool write) {
int ret = 0;
lock_sfs_io(sfs);
{
while (nblks != 0) {
if ((ret = sfs_rwblock_nolock(sfs, buf, blkno, write, 1)) != 0) {
break;
}
blkno ++, nblks --;
buf += SFS_BLKSIZE;
}
}
unlock_sfs_io(sfs);
return ret;
}
/* sfs_rblock - The Wrap of sfs_rwblock function for Rd N disk blocks ,
*
* @sfs: sfs_fs which will be process
* @buf: the buffer uesed for Rd/Wr
* @blkno: the NO. of disk block
* @nblks: Rd/Wr number of disk block
*/
int
sfs_rblock(struct sfs_fs *sfs, void *buf, uint32_t blkno, uint32_t nblks) {
return sfs_rwblock(sfs, buf, blkno, nblks, 0);
}
/* sfs_wblock - The Wrap of sfs_rwblock function for Wr N disk blocks ,
*
* @sfs: sfs_fs which will be process
* @buf: the buffer uesed for Rd/Wr
* @blkno: the NO. of disk block
* @nblks: Rd/Wr number of disk block
*/
int
sfs_wblock(struct sfs_fs *sfs, void *buf, uint32_t blkno, uint32_t nblks) {
return sfs_rwblock(sfs, buf, blkno, nblks, 1);
}
/* sfs_rbuf - The Basic block-level I/O routine for Rd( non-block & non-aligned io) one disk block(using sfs->sfs_buffer)
* with lock protect for mutex process on Rd/Wr disk block
* @sfs: sfs_fs which will be process
* @buf: the buffer uesed for Rd
* @len: the length need to Rd
* @blkno: the NO. of disk block
* @offset: the offset in the content of disk block
*/
int
sfs_rbuf(struct sfs_fs *sfs, void *buf, size_t len, uint32_t blkno, off_t offset) {
assert(offset >= 0 && offset < SFS_BLKSIZE && offset + len <= SFS_BLKSIZE);
int ret;
lock_sfs_io(sfs);
{
if ((ret = sfs_rwblock_nolock(sfs, sfs->sfs_buffer, blkno, 0, 1)) == 0) {
memcpy(buf, sfs->sfs_buffer + offset, len);
}
}
unlock_sfs_io(sfs);
return ret;
}
/* sfs_wbuf - The Basic block-level I/O routine for Wr( non-block & non-aligned io) one disk block(using sfs->sfs_buffer)
* with lock protect for mutex process on Rd/Wr disk block
* @sfs: sfs_fs which will be process
* @buf: the buffer uesed for Wr
* @len: the length need to Wr
* @blkno: the NO. of disk block
* @offset: the offset in the content of disk block
*/
int
sfs_wbuf(struct sfs_fs *sfs, void *buf, size_t len, uint32_t blkno, off_t offset) {
assert(offset >= 0 && offset < SFS_BLKSIZE && offset + len <= SFS_BLKSIZE);
int ret;
lock_sfs_io(sfs);
{
if ((ret = sfs_rwblock_nolock(sfs, sfs->sfs_buffer, blkno, 0, 1)) == 0) {
memcpy(sfs->sfs_buffer + offset, buf, len);
ret = sfs_rwblock_nolock(sfs, sfs->sfs_buffer, blkno, 1, 1);
}
}
unlock_sfs_io(sfs);
return ret;
}
/*
* sfs_sync_super - write sfs->super (in memory) into disk (SFS_BLKN_SUPER, 1) with lock protect.
*/
int
sfs_sync_super(struct sfs_fs *sfs) {
int ret;
lock_sfs_io(sfs);
{
memset(sfs->sfs_buffer, 0, SFS_BLKSIZE);
memcpy(sfs->sfs_buffer, &(sfs->super), sizeof(sfs->super));
ret = sfs_rwblock_nolock(sfs, sfs->sfs_buffer, SFS_BLKN_SUPER, 1, 0);
}
unlock_sfs_io(sfs);
return ret;
}
/*
* sfs_sync_freemap - write sfs bitmap into disk (SFS_BLKN_FREEMAP, nblks) without lock protect.
*/
int
sfs_sync_freemap(struct sfs_fs *sfs) {
uint32_t nblks = sfs_freemap_blocks(&(sfs->super));
return sfs_wblock(sfs, bitmap_getdata(sfs->freemap, NULL), SFS_BLKN_FREEMAP, nblks);
}
/*
* sfs_clear_block - write zero info into disk (blkno, nblks) with lock protect.
* @sfs: sfs_fs which will be process
* @blkno: the NO. of disk block
* @nblks: Rd/Wr number of disk block
*/
int
sfs_clear_block(struct sfs_fs *sfs, uint32_t blkno, uint32_t nblks) {
int ret;
lock_sfs_io(sfs);
{
memset(sfs->sfs_buffer, 0, SFS_BLKSIZE);
while (nblks != 0) {
if ((ret = sfs_rwblock_nolock(sfs, sfs->sfs_buffer, blkno, 1, 1)) != 0) {
break;
}
blkno ++, nblks --;
}
}
unlock_sfs_io(sfs);
return ret;
}

View File

@@ -0,0 +1,44 @@
#include <defs.h>
#include <sem.h>
#include <sfs.h>
/*
* lock_sfs_fs - lock the process of SFS Filesystem Rd/Wr Disk Block
*
* called by: sfs_load_inode, sfs_sync, sfs_reclaim
*/
void
lock_sfs_fs(struct sfs_fs *sfs) {
down(&(sfs->fs_sem));
}
/*
* lock_sfs_io - lock the process of SFS File Rd/Wr Disk Block
*
* called by: sfs_rwblock, sfs_clear_block, sfs_sync_super
*/
void
lock_sfs_io(struct sfs_fs *sfs) {
down(&(sfs->io_sem));
}
/*
* unlock_sfs_fs - unlock the process of SFS Filesystem Rd/Wr Disk Block
*
* called by: sfs_load_inode, sfs_sync, sfs_reclaim
*/
void
unlock_sfs_fs(struct sfs_fs *sfs) {
up(&(sfs->fs_sem));
}
/*
* unlock_sfs_io - unlock the process of sfs Rd/Wr Disk Block
*
* called by: sfs_rwblock sfs_clear_block sfs_sync_super
*/
void
unlock_sfs_io(struct sfs_fs *sfs) {
up(&(sfs->io_sem));
}