From: Lawrence S. <ljs...@us...> - 2013-03-27 20:04:23
|
This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "A pseudo Operating System for the Dreamcast.". The branch, master has been updated via 62369bab2ddeee094bade538f2e88e10c2ebfa67 (commit) from 85d151011bf46a9d06faa3a6d24abea603b792c2 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 62369bab2ddeee094bade538f2e88e10c2ebfa67 Author: Lawrence Sebald <ljs...@us...> Date: Wed Mar 27 16:02:46 2013 -0400 A few changes in libkosext2fs: 1. Clean up the caches. There is now only one block cache, rather than separate directory block, inode block, and data block caches. 2. Clean up compilation outside of KOS and add a Makefile to facilitate that. ----------------------------------------------------------------------- Summary of changes: addons/libkosext2fs/Makefile.nonkos | 14 ++++ addons/libkosext2fs/ext2fs.c | 125 +++++++++++++---------------------- addons/libkosext2fs/ext2fs.h | 47 ++++++++++++- addons/libkosext2fs/ext2internal.h | 25 +++++-- addons/libkosext2fs/inode.c | 68 ++++++++----------- addons/libkosext2fs/superblock.c | 1 + addons/libkosext2fs/superblock.h | 4 + 7 files changed, 154 insertions(+), 130 deletions(-) create mode 100644 addons/libkosext2fs/Makefile.nonkos diff --git a/addons/libkosext2fs/Makefile.nonkos b/addons/libkosext2fs/Makefile.nonkos new file mode 100644 index 0000000..e415374 --- /dev/null +++ b/addons/libkosext2fs/Makefile.nonkos @@ -0,0 +1,14 @@ +# libkosext2fs Makefile +# This one is for building everything except the VFS glue outside of KOS. + +OBJS = ext2fs.o bitops.o block.o inode.o superblock.o symlink.o directory.o + +# Make sure everything compiles nice and cleanly (or not at all). +CFLAGS += -W -pedantic -Werror -std=gnu99 -DEXT2_NOT_IN_KOS + +libkosext2fs.a: $(OBJS) + $(AR) rcs $@ $^ + +clean: + -rm -f $(OBJS) + -rm -f libkosext2fs.a diff --git a/addons/libkosext2fs/ext2fs.c b/addons/libkosext2fs/ext2fs.c index fc5a255..5a27a98 100644 --- a/addons/libkosext2fs/ext2fs.c +++ b/addons/libkosext2fs/ext2fs.c @@ -41,13 +41,14 @@ static void make_mru(ext2_fs_t *fs, ext2_cache_t **cache, int block) { } /* XXXX: This needs locking! */ -static uint8_t *read_cache(ext2_fs_t *fs, ext2_cache_t **cache, uint32_t bl) { +uint8_t *ext2_block_read(ext2_fs_t *fs, uint32_t bl) { int i; uint8_t *rv; + ext2_cache_t **cache = fs->bcache; /* Look through the cache from the most recently used to the least recently used entry. */ - for(i = fs->cache_size - 1; i >= 0 && cache[i]->valid; --i) { + for(i = fs->cache_size - 1; i >= 0 && cache[i]->flags; --i) { if(cache[i]->block == bl) { rv = cache[i]->data; make_mru(fs, cache, i); @@ -57,15 +58,30 @@ static uint8_t *read_cache(ext2_fs_t *fs, ext2_cache_t **cache, uint32_t bl) { /* If we didn't get anything, did we end up with an invalid entry or do we need to boot someone out? */ - if(i < 0) + if(i < 0) { i = 0; + /* Make sure that if the block is dirty, we write it back out. */ + if(cache[0]->flags & EXT2_CACHE_FLAG_DIRTY) { + if(ext2_block_write_nc(fs, cache[0]->block, cache[0]->data)) { + /* XXXX: Uh oh... */ + errno = EIO; + return NULL; + } + } + + printf("Throwing out block %" PRIu32 " flags: %08" PRIx32 "\n", + cache[0]->block, cache[0]->flags); + } + /* Try to read the block in question. */ - if(ext2_block_read_nc(fs, bl, cache[i]->data)) + if(ext2_block_read_nc(fs, bl, cache[i]->data)) { + errno = EIO; return NULL; + } cache[i]->block = bl; - cache[i]->valid = 1; + cache[i]->flags = EXT2_CACHE_FLAG_VALID; rv = cache[i]->data; make_mru(fs, cache, i); @@ -91,36 +107,22 @@ int ext2_block_read_nc(ext2_fs_t *fs, uint32_t block_num, uint8_t *rv) { return 0; } -uint8_t *ext2_block_read(ext2_fs_t *fs, uint32_t block_num, int cache) { - uint8_t *rv; - ext2_cache_t **cb; - - /* Figure out what cache we're looking at */ - switch(cache) { - case EXT2_CACHE_INODE: - cb = fs->icache; - break; - - case EXT2_CACHE_DIR: - cb = fs->dcache; - break; +int ext2_block_write_nc(ext2_fs_t *fs, uint32_t block_num, uint8_t *rv) { + int fs_per_block = fs->sb.s_log_block_size - fs->dev->l_block_size + 10; - case EXT2_CACHE_DATA: - cb = fs->bcache; - break; + if(fs_per_block < 0) + /* This should never happen, as the ext2 block size must be at least + as large as the sector size of the block device itself. */ + return -EINVAL; - default: - errno = EINVAL; - return NULL; - } + if(fs->sb.s_blocks_count <= block_num) + return -EINVAL; - /* Try to read from it. */ - if(!(rv = read_cache(fs, cb, block_num))) { - errno = EIO; - return NULL; - } + if(fs->dev->write_blocks(fs->dev, block_num << fs_per_block, + 1 << fs_per_block, rv)) + return -EIO; - return rv; + return 0; } uint32_t ext2_block_size(const ext2_fs_t *fs) { @@ -139,6 +141,10 @@ int ext2_init(void) { } ext2_fs_t *ext2_fs_init(kos_blockdev_t *bd) { + return ext2_fs_init_ex(bd, EXT2_CACHE_BLOCKS); +} + +ext2_fs_t *ext2_fs_init_ex(kos_blockdev_t *bd, int cache_sz) { ext2_fs_t *rv; uint32_t bc; int j; @@ -266,77 +272,43 @@ ext2_fs_t *ext2_fs_init(kos_blockdev_t *bd) { } #endif /* EXT2FS_DEBUG */ - /* Make space for the caches. */ - if(!(rv->icache = (ext2_cache_t **)malloc(sizeof(ext2_cache_t *) * 16))) { - free(rv->bg); - free(rv); - bd->shutdown(bd); - return NULL; - } - - if(!(rv->dcache = (ext2_cache_t **)malloc(sizeof(ext2_cache_t *) * 16))) { - free(rv->icache); - free(rv->bg); - free(rv); - bd->shutdown(bd); - return NULL; - } - - if(!(rv->bcache = (ext2_cache_t **)malloc(sizeof(ext2_cache_t *) * 16))) { - free(rv->dcache); - free(rv->icache); + /* Make space for the block cache. */ + if(!(rv->bcache = (ext2_cache_t **)malloc(sizeof(ext2_cache_t *) * + cache_sz))) { free(rv->bg); free(rv); bd->shutdown(bd); return NULL; } - - for(j = 0; j < 16; ++j) { - if(!(rv->icache[j] = (ext2_cache_t *)malloc(sizeof(ext2_cache_t)))) - goto out_cache; - - if(!(rv->dcache[j] = (ext2_cache_t *)malloc(sizeof(ext2_cache_t)))) - goto out_cache; + for(j = 0; j < cache_sz; ++j) { if(!(rv->bcache[j] = (ext2_cache_t *)malloc(sizeof(ext2_cache_t)))) goto out_cache; } - for(j = 0; j < 16; ++j) { - if(!(rv->icache[j]->data = (uint8_t *)malloc(block_size))) - goto out_bcache; - - if(!(rv->dcache[j]->data = (uint8_t *)malloc(block_size))) - goto out_bcache; - + for(j = 0; j < cache_sz; ++j) { if(!(rv->bcache[j]->data = (uint8_t *)malloc(block_size))) goto out_bcache; - rv->icache[j]->valid = rv->dcache[j]->valid = rv->bcache[j]->valid = 0; + rv->bcache[j]->flags = 0; } - rv->cache_size = 16; + rv->cache_size = cache_sz; return rv; out_bcache: for(; j >= 0; --j) { free(rv->bcache[j]->data); - free(rv->dcache[j]->data); - free(rv->icache[j]->data); } - j = 15; + j = cache_sz - 1; out_cache: for(; j >= 0; --j) { free(rv->bcache[j]); - free(rv->dcache[j]); - free(rv->icache[j]); } free(rv->bcache); - free(rv->dcache); - free(rv->icache); free(rv->bg); free(rv); bd->shutdown(bd); @@ -347,18 +319,11 @@ void ext2_fs_shutdown(ext2_fs_t *fs) { int i; for(i = 0; i < fs->cache_size; ++i) { - free(fs->icache[i]->data); - free(fs->icache[i]); - free(fs->dcache[i]->data); - free(fs->dcache[i]); free(fs->bcache[i]->data); free(fs->bcache[i]); } free(fs->bcache); - free(fs->dcache); - free(fs->icache); - fs->dev->shutdown(fs->dev); free(fs->bg); free(fs); diff --git a/addons/libkosext2fs/ext2fs.h b/addons/libkosext2fs/ext2fs.h index 8a906f8..215680a 100644 --- a/addons/libkosext2fs/ext2fs.h +++ b/addons/libkosext2fs/ext2fs.h @@ -10,7 +10,11 @@ #include <sys/cdefs.h> __BEGIN_DECLS +#include <stdint.h> + +#ifndef EXT2_NOT_IN_KOS #include <kos/blockdev.h> +#endif /* Tunable filesystem parameters. These must be set at compile time. */ @@ -30,8 +34,44 @@ __BEGIN_DECLS constant. */ #define EXT2_LOG_INODE_HASH (EXT2_LOG_MAX_INODES - 2) +/* Size of the block cache, in filesystem blocks. When reading from the + filesystem, all data is read in block-sized units. The size of a block can + generally range from 1024 bytes to 4096 bytes, and is dependent on the + parameters the filesystem was formatted with. Increasing this value should + ensure that more accesses can be handled by the cache, but also increases the + latency at which data is written back to the block device itself. Setting + this to 32 should work well enough, but if you have more memory to spare, + feel free to set it larger. + + Note that this is a default value for filesystems initialized/mounted with + ext2_fs_init(). If you wish to specify your own value that differs from this + one, you can do so with the ext2_fs_init_ex() function. +*/ +#define EXT2_CACHE_BLOCKS 32 + /* End tunable filesystem parameters. */ +/* Convenience stuff, for in case you want to use this outside of KOS. */ +#ifdef EXT2_NOT_IN_KOS + +typedef struct kos_blockdev { + void *dev_data; + uint32_t l_block_size; + int (*init)(struct kos_blockdev *d); + int (*shutdown)(struct kos_blockdev *d); + int (*read_blocks)(struct kos_blockdev *d, uint32_t block, size_t count, + void *buf); + int (*write_blocks)(struct kos_blockdev *d, uint32_t block, size_t count, + const void *buf); + uint32_t (*count_blocks)(struct kos_blockdev *d); +} kos_blockdev_t; + +#ifndef SYMLOOP_MAX +#define SYMLOOP_MAX 16 +#endif + +#endif /* EXT2_NOT_IN_KOS */ + /* Opaque ext2 filesystem type */ struct ext2fs_struct; typedef struct ext2fs_struct ext2_fs_t; @@ -45,14 +85,13 @@ uint32_t ext2_log_block_size(const ext2_fs_t *fs); int ext2_init(void); ext2_fs_t *ext2_fs_init(kos_blockdev_t *bd); +ext2_fs_t *ext2_fs_init_ex(kos_blockdev_t *bd, int cache_sz); void ext2_fs_shutdown(ext2_fs_t *fs); int ext2_block_read_nc(ext2_fs_t *fs, uint32_t block_num, uint8_t *rv); -uint8_t *ext2_block_read(ext2_fs_t *fs, uint32_t block_num, int cache); +uint8_t *ext2_block_read(ext2_fs_t *fs, uint32_t block_num); -#define EXT2_CACHE_INODE 0 -#define EXT2_CACHE_DIR 1 -#define EXT2_CACHE_DATA 2 +int ext2_block_write_nc(ext2_fs_t *fs, uint32_t block_num, uint8_t *rv); __END_DECLS diff --git a/addons/libkosext2fs/ext2internal.h b/addons/libkosext2fs/ext2internal.h index ff69130..afe25a7 100644 --- a/addons/libkosext2fs/ext2internal.h +++ b/addons/libkosext2fs/ext2internal.h @@ -1,34 +1,45 @@ /* KallistiOS ##version## ext2internal.h - Copyright (C) 2012 Lawrence Sebald + Copyright (C) 2012, 2013 Lawrence Sebald */ #include "block.h" #include "superblock.h" + +#ifndef EXT2_NOT_IN_KOS #include <kos/blockdev.h> +#else +#include "ext2fs.h" +#endif #ifndef __EXT2_EXT2INTERNAL_H #define __EXT2_EXT2INTERNAL_H +#define EXT2_CACHE_FLAG_VALID 1 +#define EXT2_CACHE_FLAG_DIRTY 2 + typedef struct ext2_cache { - int valid; - uint8_t *data; + uint32_t flags; uint32_t block; + uint8_t *data; } ext2_cache_t; struct ext2fs_struct { kos_blockdev_t *dev; ext2_superblock_t sb; uint32_t block_size; - + uint32_t bg_count; ext2_bg_desc_t *bg; - - ext2_cache_t **icache; - ext2_cache_t **dcache; + ext2_cache_t **bcache; int cache_size; }; +#ifdef EXT2_NOT_IN_KOS +#include <stdio.h> +#define dbglog(x, ...) printf(__VA_ARGS__) +#endif + #endif /* !__EXT2_EXT2INTERNAL_H */ diff --git a/addons/libkosext2fs/inode.c b/addons/libkosext2fs/inode.c index 9303d82..48a15db 100644 --- a/addons/libkosext2fs/inode.c +++ b/addons/libkosext2fs/inode.c @@ -87,12 +87,12 @@ void ext2_inode_init(void) { } ext2_inode_t *ext2_inode_get(ext2_fs_t *fs, uint32_t inode_num, int *err) { - int entry = inode_num & (INODE_HASH_SZ - 1); + int ent = inode_num & (INODE_HASH_SZ - 1); struct int_inode *i; ext2_inode_t *rinode; /* Figure out if this inode is already in the hash table. */ - LIST_FOREACH(i, &inode_hash[entry], entry) { + LIST_FOREACH(i, &inode_hash[ent], entry) { if(i->fs == fs && i->inode_num == inode_num) { /* Increase the reference count, and see if it was free before. */ if(!i->refcnt++) { @@ -117,6 +117,11 @@ ext2_inode_t *ext2_inode_get(ext2_fs_t *fs, uint32_t inode_num, int *err) { /* Ok, at this point, we have a free inode, remove it from the free pool. */ TAILQ_REMOVE(&free_inodes, i, qentry); + + /* Remove it from any old hash table lists it was in */ + if(i->inode_num) + LIST_REMOVE(i, entry); + i->refcnt = 1; i->inode_num = inode_num; i->fs = fs; @@ -127,13 +132,14 @@ ext2_inode_t *ext2_inode_get(ext2_fs_t *fs, uint32_t inode_num, int *err) { i->refcnt = 0; i->inode_num = 0; i->fs = NULL; + TAILQ_INSERT_HEAD(&free_inodes, i, qentry); *err = -EIO; return NULL; } /* Add it to the hash table. */ i->inode = *rinode; - LIST_INSERT_HEAD(&inode_hash[entry], i, entry); + LIST_INSERT_HEAD(&inode_hash[ent], i, entry); #ifdef EXT2FS_DEBUG dbglog(DBG_KDEBUG, "ext2_inode_get: %" PRIu32 " (%" PRIu32 " refs)\n", @@ -184,8 +190,7 @@ static ext2_inode_t *ext2_inode_read(ext2_fs_t *fs, uint32_t inode_num) { if(inode_num > fs->sb.s_inodes_count) return NULL; - if(!(buf = ext2_block_read(fs, fs->bg[bg].bg_inode_bitmap, - EXT2_CACHE_INODE))) + if(!(buf = ext2_block_read(fs, fs->bg[bg].bg_inode_bitmap))) return NULL; if(!ext2_bit_is_set((uint32_t *)buf, index)) @@ -196,7 +201,7 @@ static ext2_inode_t *ext2_inode_read(ext2_fs_t *fs, uint32_t inode_num) { inode_block = fs->bg[bg].bg_inode_table + (index / in_per_block); index %= in_per_block; - if(!(buf = ext2_block_read(fs, inode_block, EXT2_CACHE_INODE))) + if(!(buf = ext2_block_read(fs, inode_block))) return NULL; /* Return the inode in question */ @@ -331,7 +336,7 @@ int ext2_inode_by_path(ext2_fs_t *fs, const char *path, ext2_inode_t **rv, char *ipath, *cxt, *token; int blocks, i, block_size; uint8_t *buf; - uint32_t *iblock; + uint32_t *ib; ext2_dirent_t *dent; int err = 0; size_t tmp_sz; @@ -383,8 +388,7 @@ int ext2_inode_by_path(ext2_fs_t *fs, const char *path, ext2_inode_t **rv, /* Run through any direct blocks in the inode. */ for(i = 0; i < blocks && inode->i_block[i] && i < 12; ++i) { /* Grab the block, looking in the directory cache. */ - if(!(buf = ext2_block_read(fs, inode->i_block[i], - EXT2_CACHE_DIR))) { + if(!(buf = ext2_block_read(fs, inode->i_block[i]))) { free(ipath); ext2_inode_put(inode); return -EIO; @@ -406,14 +410,13 @@ int ext2_inode_by_path(ext2_fs_t *fs, const char *path, ext2_inode_t **rv, goto out; /* Next, look through the indirect block. */ - if(!(iblock = (uint32_t *)ext2_block_read(fs, inode->i_block[12], - EXT2_CACHE_DIR))) { + if(!(ib = (uint32_t *)ext2_block_read(fs, inode->i_block[12]))) { free(ipath); ext2_inode_put(inode); return -EIO; } - if((dent = search_indir(fs, iblock, block_size, token, &err))) { + if((dent = search_indir(fs, ib, block_size, token, &err))) { goto next_token; } else if(err) { @@ -425,15 +428,13 @@ int ext2_inode_by_path(ext2_fs_t *fs, const char *path, ext2_inode_t **rv, /* Next, look through the doubly-indirect block. */ if(inode->i_block[13]) { /* Grab the block, looking in the directory cache. */ - if(!(iblock = (uint32_t *)ext2_block_read(fs, inode->i_block[13], - EXT2_CACHE_DIR))) { + if(!(ib = (uint32_t *)ext2_block_read(fs, inode->i_block[13]))) { free(ipath); ext2_inode_put(inode); return -EIO; } - if((dent = search_indir_23(fs, iblock, block_size, token, &err, - 0))) { + if((dent = search_indir_23(fs, ib, block_size, token, &err, 0))) { goto next_token; } else if(err) { @@ -447,15 +448,13 @@ int ext2_inode_by_path(ext2_fs_t *fs, const char *path, ext2_inode_t **rv, have to look all the way through one of these... */ if(inode->i_block[14]) { /* Grab the block, looking in the directory cache. */ - if(!(iblock = (uint32_t *)ext2_block_read(fs, inode->i_block[14], - EXT2_CACHE_DIR))) { ...<truncated>... hooks/post-receive -- A pseudo Operating System for the Dreamcast. |