Implemented write support in the file system and added fiotest, and stat

This commit is contained in:
Ali Mashtizadeh 2023-11-21 21:37:17 -05:00
parent bd44784c5f
commit d4fb02e2b4
12 changed files with 472 additions and 32 deletions

View File

@ -180,6 +180,7 @@ SConscript('bin/ethinject/SConscript', variant_dir='build/bin/ethinject')
SConscript('bin/false/SConscript', variant_dir='build/bin/false')
SConscript('bin/ls/SConscript', variant_dir='build/bin/ls')
SConscript('bin/shell/SConscript', variant_dir='build/bin/shell')
SConscript('bin/stat/SConscript', variant_dir='build/bin/stat')
SConscript('bin/true/SConscript', variant_dir='build/bin/true')
SConscript('sbin/ifconfig/SConscript', variant_dir='build/sbin/ifconfig')
SConscript('sbin/init/SConscript', variant_dir='build/sbin/init')
@ -212,12 +213,14 @@ if env["BOOTDISK"] == "1":
Depends(bootdisk, "#build/bin/false/false")
Depends(bootdisk, "#build/bin/ls/ls")
Depends(bootdisk, "#build/bin/shell/shell")
Depends(bootdisk, "#build/bin/stat/stat")
Depends(bootdisk, "#build/bin/true/true")
Depends(bootdisk, "#build/sbin/ifconfig/ifconfig")
Depends(bootdisk, "#build/sbin/init/init")
Depends(bootdisk, "#build/sbin/sysctl/sysctl")
Depends(bootdisk, "#build/sys/castor")
#Depends(bootdisk, "#build/tests/lwiptest")
Depends(bootdisk, "#build/tests/fiotest")
Depends(bootdisk, "#build/tests/pthreadtest")
Depends(bootdisk, "#build/tests/spawnanytest")
Depends(bootdisk, "#build/tests/spawnmultipletest")

23
bin/stat/SConscript Normal file
View File

@ -0,0 +1,23 @@
import sys
Import('env')
init_env = env.Clone()
src = [ ]
src_common = [
"stat.c"
]
src.append(env["CRTBEGIN"])
src.append(src_common)
src.append(env["CRTEND"])
init_env.Append(LINKFLAGS = ['-nostdlib'])
init_env.Append(CPPFLAGS = ['-fno-builtin', '-nostdinc'])
init_env.Append(CPPPATH = ['#build/include'])
init_env.Append(LIBPATH = ['#build/lib/libc'], LIBS = ['c'])
init_env.Program("stat", src)

42
bin/stat/stat.c Normal file
View File

@ -0,0 +1,42 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/stat.h>
// Castor Only
#include <syscall.h>
int
main(int argc, const char *argv[])
{
int i;
int status, fd;
struct stat sb;
char buf[256];
if (argc < 2) {
fputs("Requires an argument\n", stdout);
return 1;
}
if (argc > 2) {
fputs("Too many arguments, expected one\n", stdout);
return 1;
}
status = OSStat(argv[1], &sb);
if (status != 0) {
fputs("Cannot stat file\n", stdout);
return 0;
}
printf(" File: \"%s\"\n", argv[1]);
printf(" Size: %d\n", sb.st_size);
printf("Blocks: %d\n", sb.st_blocks);
printf(" Inode: %d\n", sb.st_ino);
return 0;
}

View File

@ -11,6 +11,7 @@ DIR /
FILE false build/bin/false/false
FILE ls build/bin/ls/ls
FILE shell build/bin/shell/shell
FILE stat build/bin/stat/stat
FILE true build/bin/true/true
END
DIR sbin
@ -21,6 +22,7 @@ DIR /
FILE sysctl build/sbin/sysctl/sysctl
END
DIR tests
FILE fiotest build/tests/fiotest
FILE pthreadtest build/tests/pthreadtest
FILE spawnsingletest build/tests/spawnsingletest
FILE spawnmultipletest build/tests/spawnmultipletest

View File

@ -15,6 +15,8 @@
#include <o2fs.h>
#define ROUND_UP(_a, _b) (((_a) + (_b) - 1)/(_b))
#define MAXBLOCKSIZE (64*1024*1024)
char tempbuf[MAXBLOCKSIZE];
@ -25,6 +27,7 @@ bool hasManifest = false;
uint64_t diskSize = 0;
uint64_t diskOffset = 0;
uint64_t blockSize = 16*1024;
uint64_t bitmapSize;
int diskfd;
struct stat diskstat;
@ -230,6 +233,30 @@ ObjID *AddDirectory()
return id;
}
void BlockBitmap()
{
off_t off = lseek(diskfd, 0, SEEK_CUR) / blockSize;
/* Code below only supports using the first 16K blocks */
assert(off < blockSize);
memset(tempbuf, 0, MAXBLOCKSIZE);
/* Mark the blocks in use up to the current offset */
assert(off > 8);
for (off_t i = 0; i < (off / 8); i++) {
tempbuf[i] = 0xFF;
}
for (off_t i = 0; i < (off % 8); i++) {
tempbuf[off / 8] |= 1 << i;
}
lseek(diskfd, blockSize, SEEK_SET);
for (int i = 0; i < bitmapSize; i++)
AppendBlock(tempbuf + (blockSize * i), blockSize);
}
void Superblock(ObjID *objid)
{
SuperBlock sb;
@ -242,6 +269,8 @@ void Superblock(ObjID *objid)
sb.versionMinor = O2FS_VERSION_MINOR;
sb.blockCount = diskSize / blockSize;
sb.blockSize = blockSize;
sb.bitmapSize = sb.blockCount;
sb.bitmapOffset = 1;
if (objid)
memcpy(&sb.root, objid, sizeof(ObjID));
@ -332,10 +361,16 @@ int main(int argc, char * const *argv)
lseek(diskfd, 0, SEEK_SET);
}
/* Skip superblock */
diskOffset = blockSize;
lseek(diskfd, diskOffset, SEEK_SET);
memset(zerobuf, 0, MAXBLOCKSIZE);
/* Zero the bitmap (and skip past it) */
bitmapSize = ROUND_UP(diskSize / (blockSize * 8), blockSize);
for (int i = 0; i < bitmapSize; i++)
AppendBlock(zerobuf, blockSize);
ObjID *root = NULL;
if (hasManifest) {
int tok;
@ -359,6 +394,9 @@ int main(int argc, char * const *argv)
}
}
/* Write bitmap */
BlockBitmap();
Superblock(root);
free(root);

View File

@ -34,10 +34,10 @@
#define IDE_COMMAND 7 /* Write */
#define IDE_STATUS 7 /* Read */
// IDE Commands
// IDE Commands (PIO)
#define IDE_CMD_READ 0x20
#define IDE_CMD_READ_EXT 0x24
#define IDE_CMD_WRITE
#define IDE_CMD_WRITE 0x30
#define IDE_CMD_WRITE_EXT 0x34
#define IDE_CMD_FLUSH 0xE7
#define IDE_CMD_IDENTIFY 0xEC
@ -77,6 +77,7 @@ int IDE_Read(Disk *disk, void *buf, SGArray *sga, DiskCB, void *arg);
int IDE_Write(Disk *disk, void *buf, SGArray *sga, DiskCB, void *arg);
int IDE_Flush(Disk *disk, void *buf, SGArray *sga, DiskCB, void *arg);
int IDE_ReadOne(IDEDrive *drive, void *buf, uint64_t off, uint64_t len);
int IDE_WriteOne(IDEDrive *drive, void *buf, uint64_t off, uint64_t len);
IDE primary;
IDEDrive primaryDrives[2];
@ -291,7 +292,23 @@ IDE_Read(Disk *disk, void *buf, SGArray *sga, DiskCB cb, void *arg)
int
IDE_Write(Disk *disk, void *buf, SGArray *sga, DiskCB cb, void *arg)
{
return -1;
int i;
int status;
IDEDrive *idedrive;
idedrive = disk->handle;
for (i = 0; i < sga->len; i++) {
status = IDE_WriteOne(idedrive,
buf,
sga->entries[i].offset / 512,
sga->entries[i].length / 512);
buf += sga->entries[i].length;
if (status < 0)
return status;
}
return 0;
}
int
@ -401,7 +418,7 @@ IDE_WriteOne(IDEDrive *drive, void *buf, uint64_t off, uint64_t len)
uint8_t status;
IDE *ide = drive->ide;
Log(ide, "Write %llx %llx\n", off, len);
DLOG(ide, "read %llx %llx\n", off, len);
ASSERT(drive->drive == 0 || drive->drive == 1);
@ -425,33 +442,46 @@ IDE_WriteOne(IDEDrive *drive, void *buf, uint64_t off, uint64_t len)
}
ide->lastDriveCode = driveCode;
}
outb(ide->base + IDE_SECTORCOUNT, len >> 8);
outb(ide->base + IDE_LBALOW, off >> 24);
outb(ide->base + IDE_LBAMID, off >> 32);
outb(ide->base + IDE_LBAHIGH, off >> 40);
outb(ide->base + IDE_SECTORCOUNT, len);
outb(ide->base + IDE_LBALOW, off);
outb(ide->base + IDE_LBAMID, off >> 8);
outb(ide->base + IDE_LBAHIGH, off >> 16);
outb(ide->base + IDE_COMMAND, IDE_CMD_WRITE_EXT);
// XXX: Need timeout
while (1) {
status = inb(ide->base + IDE_STATUS);
if ((status & IDE_STATUS_BSY) == 0)
break;
if (lba48) {
outb(ide->base + IDE_SECTORCOUNT, len >> 8);
outb(ide->base + IDE_LBALOW, off >> 24);
outb(ide->base + IDE_LBAMID, off >> 32);
outb(ide->base + IDE_LBAHIGH, off >> 40);
}
outb(ide->base + IDE_SECTORCOUNT, len);
outb(ide->base + IDE_LBALOW, off & 0xff);
outb(ide->base + IDE_LBAMID, (off >> 8) & 0xff);
outb(ide->base + IDE_LBAHIGH, (off >> 16) & 0xff);
if (lba48)
outb(ide->base + IDE_COMMAND, IDE_CMD_WRITE_EXT);
else
outb(ide->base + IDE_COMMAND, IDE_CMD_WRITE);
status = IDEWaitForBusy(ide, false);
if ((status & IDE_STATUS_ERR) != 0) {
Spinlock_Unlock(&ide->lock);
Log(ide, "Error trying write from drive %d\n", drive);
Log(ide, "Error trying read from drive %d\n", drive->drive);
return -1;
}
int sectors;
for (sectors = 0; sectors < len; sectors++)
{
uint8_t *b = buf + sectors * IDE_SECTOR_SIZE;
outsw(ide->base + IDE_DATAPORT, b, 256);
status = IDEWaitForBusy(ide, true);
if ((status & IDE_STATUS_ERR) != 0) {
Spinlock_Unlock(&ide->lock);
Log(ide, "Error reading from drive %d\n", drive->drive);
return -1;
}
}
Spinlock_Unlock(&ide->lock);
// XXX: Loop on outw(ide->base, b + sectorOffset);
// XXX: CACHE FLUSH
// XXX: Flush cache ...
return 0;
}

View File

@ -71,11 +71,30 @@ O2FS_Mount(Disk *disk)
return NULL;
}
// Read bitmap
for (int i = 0; i < (sb->bitmapSize / sb->blockSize); i++) {
ASSERT(i < 16);
BufCacheEntry *bentry;
uint64_t offset = (sb->bitmapOffset + i) * sb->blockSize;
if (BufCache_Read(disk, offset, &bentry) < 0) {
Alert(o2fs, "Bitmap read failed\n");
for (i = 0; i < 16; i++)
BufCache_Release(fs->bitmap[i]);
BufCache_Release(entry);
return NULL;
}
fs->bitmap[i] = bentry;
}
DLOG(o2fs, "File system mounted\n");
DLOG(o2fs, "Root @ 0x%llx\n", sb->root.offset);
fs->fsptr = entry;
fs->fsval = sb->root.offset;
fs->blksize = sb->bitmapSize;
// Setup VFS structure
fs->op = &O2FSOperations;
@ -101,6 +120,86 @@ O2FS_Unmount(VFS *fs)
return -1;
}
/**
* O2FSBAlloc --
*
* Allocate a block.
*
* @param [in] vfs VFS Instance.
*
* @return Block number.
*/
uint64_t
O2FSBAlloc(VFS *fs)
{
for (int i = 0; i < 16; i++) {
char *bitmap;
BufCacheEntry *bentry = fs->bitmap[i];
if (fs->bitmap[i] == NULL)
break;
bitmap = bentry->buffer;
// XXX: Check for end of disk
for (int b = 0; b < fs->blksize; b++) {
for (int bi = 0; bi < 8; bi++) {
if ((bitmap[b] >> bi) & 0x1) {
/* Set bit */
bitmap[b] |= (1 << bi);
/* Write bitmap */
BufCache_Write(bentry);
/*
* Block index is the sum of:
* blksize*8 blocks per bitmap entry
* 8 blocks per bitmap byte
* bit #
*/
return fs->blksize*8*i + 8*b + bi;
}
}
}
}
return 0;
}
/**
* O2FSBFree --
*
* Free a block.
*
* @param [in] vfs VFS Instance.
* @param [in] block Block number.
*/
void
O2FSBFree(VFS *fs, uint64_t block)
{
uint64_t bitoff = block & 0x7;
uint64_t bytoff = (block >> 8) % fs->blksize;
uint64_t bufoff = block / (fs->blksize*8);
BufCacheEntry *bentry = fs->bitmap[bufoff];
ASSERT(bentry != NULL);
char *bitmap = bentry->buffer;
/* Mask out the bit */
bitmap[bytoff] &= ~(1 << bitoff);
/* Write the bitmap */
BufCache_Write(bentry);
}
/**
* O2FSLoadVNode --
*
* Load a VNode from the disk given an ObjID.
*
* @param [in] vfs VFS Instance.
* @param [in] oobjid Object ID.
*/
VNode *
O2FSLoadVNode(VFS *fs, ObjID *objid)
{
@ -143,12 +242,59 @@ O2FSLoadVNode(VFS *fs, ObjID *objid)
return vn;
}
/**
* O2FSGrowVNode --
*
* Grow a VNode.
*
* @param [in] vfs VFS Instance.
* @param [in] bn BNode for the object.
* @param [in] filesz New file size.
*
* @return 0 on success, otherwise error code.
*/
int
O2FSGrowVNode(VNode *vn, uint64_t filesz)
{
VFS *vfs = vn->vfs;
BufCacheEntry *vnEntry = (BufCacheEntry *)vn->fsptr;
BNode *bn = vnEntry->buffer;
if (filesz > (vfs->blksize * 64))
return -EINVAL;
for (int i = 0; i < ((filesz + vfs->blksize - 1) / vfs->blksize); i++) {
if (bn->direct[i].offset == 0)
bn->direct[i].offset = O2FSBAlloc(vfs) * vfs->blksize;
}
bn->size = filesz;
BufCache_Write(vnEntry);
return 0;
}
/**
* O2FSRetainVNode --
*
* Increment VNode reference count.
*
* @param [in] vn VNode.
*/
void
O2FSRetainVNode(VNode *vn)
{
vn->refCount++;
}
/**
* O2FSReleaseVNode --
*
* Decrement VNode reference count and release it if reaches zero.
*
* @param [in] vn VNode.
*/
void
O2FSReleaseVNode(VNode *vn)
{
@ -160,6 +306,16 @@ O2FSReleaseVNode(VNode *vn)
}
}
/**
* O2FS_GetRoot --
*
* Read the root directory Inode.
*
* @param [in] fs VFS Instance.
* @param [out] dn VNode of the root directory.
*
* @return 0 on success, otherwise error.
*/
int
O2FS_GetRoot(VFS *fs, VNode **dn)
{
@ -212,6 +368,17 @@ O2FSDumpDirEntry(BDirEntry *entry)
VLOG(o2fs, "%16s %08llx %08llx\n", entry->name, entry->objId.offset, entry->size);
}
/**
* O2FS_Lookup --
*
* Lookup a directory entry within a given directory.
*
* @param [in] vn VNode of the directory to look through.
* @param [out] fn VNode of the entry if found.
* @param [in] name Name of the file.
*
* @return 0 on success, otherwise error.
*/
int
O2FS_Lookup(VNode *dn, VNode **fn, const char *name)
{
@ -266,6 +433,16 @@ O2FS_Close(VNode *fn)
return 0;
}
/**
* O2FS_Stat --
*
* Stat a VNode.
*
* @param [in] fn VNode of the file to stat.
* @param [out] statinfo Stat structure.
*
* @return 0 on success.
*/
int
O2FS_Stat(VNode *fn, struct stat *statinfo)
{
@ -275,14 +452,28 @@ O2FS_Stat(VNode *fn, struct stat *statinfo)
BufCacheEntry *fileEntry = (BufCacheEntry *)fn->fsptr;
BNode *fileBN = fileEntry->buffer;
DLOG(o2fs, "O2FS %p %d\n", fileBN, fileBN->size);
statinfo->st_ino = fileEntry->diskOffset;
statinfo->st_size = fileBN->size;
// XXX: support other fields
statinfo->st_blocks = (fileBN->size + sb->blockSize - 1) / sb->blockSize;
statinfo->st_blksize = sb->blockSize;
return 0;
}
/**
* O2FS_Read --
*
* Read from a VNode.
*
* @param [in] fn VNode of the file.
* @param [out] buf Buffer to read into.
* @param [in] off Offset within the file.
* @param [in] len Length of the buffer to read.
*
* @return number of bytes on success, otherwise negative error code.
*/
int
O2FS_Read(VNode *fn, void *buf, uint64_t off, uint64_t len)
{
@ -337,13 +528,89 @@ O2FS_Read(VNode *fn, void *buf, uint64_t off, uint64_t len)
return readBytes;
}
/**
* O2FS_Write --
*
* Write to a VNode.
*
* @param [in] fn VNode of the file.
* @param [in] buf Buffer to write out.
* @param [in] off Offset within the file.
* @param [in] len Length of the buffer to write.
*
* @return number of bytes on success, otherwise negative error code.
*/
int
O2FS_Write(VNode *fn, void *buf, uint64_t off, uint64_t len)
{
NOT_IMPLEMENTED();
return -EINVAL;
int status;
VFS *vfs = fn->vfs;
BufCacheEntry *sbEntry = (BufCacheEntry *)vfs->fsptr;
SuperBlock *sb = sbEntry->buffer;
BufCacheEntry *fileEntry = (BufCacheEntry *)fn->fsptr;
BNode *fileBN = fileEntry->buffer;
uint64_t blocks = (fileBN->size + sb->blockSize - 1) / sb->blockSize;
uint64_t readBytes = 0;
DLOG(o2fs, "Write %lld %d\n", fileBN->size, blocks);
if (off > fileBN->size) {
return 0;
}
// XXX: Check permissions
if (fileBN->size < (off+len)) {
status = O2FSGrowVNode(fn, off+len);
if (status < 0)
return status;
}
while (1) {
uint64_t b = off / sb->blockSize;
uint64_t bOff = off % sb->blockSize;
uint64_t bLen;
BufCacheEntry *entry;
if (bOff + len > sb->blockSize) {
bLen = sb->blockSize - bOff;
} else {
bLen = len;
}
status = BufCache_Read(fn->disk, fileBN->direct[b].offset, &entry);
if (status < 0)
return status;
DLOG(o2fs, "READ %lx %lx %lld\n", buf, entry->buffer, bLen);
memcpy(entry->buffer + bOff, buf, bLen);
BufCache_Write(entry);
BufCache_Release(entry);
readBytes += bLen;
buf += bLen;
off += bLen;
len -= bLen;
if (len == 0)
break;
}
return readBytes;
}
/**
* O2FS_ReadDir --
*
* Read a directory entry.
*
* @param [in] fn VNode of the directory.
* @param [out] buf Buffer to read the directory entry into.
* @param [in] len Length of the buffer.
* @param [inout] off Offset to start from and return the next offset.
*
* @return 0 on success, otherwise error.
*/
int
O2FS_ReadDir(VNode *fn, void *buf, uint64_t len, uint64_t *off)
{

View File

@ -44,13 +44,15 @@ typedef struct ObjID {
*/
typedef struct SuperBlock
{
uint8_t magic[8];
uint16_t versionMajor;
uint16_t versionMinor;
uint8_t magic[8]; /* Superblock Magic */
uint16_t versionMajor; /* Major Version Number */
uint16_t versionMinor; /* Minor Version Number */
uint32_t _rsvd0;
uint64_t features;
uint64_t blockCount;
uint64_t blockSize;
uint64_t features; /* Feature Flags */
uint64_t blockCount; /* Total Blocks */
uint64_t blockSize; /* Block Size in Bytes */
uint64_t bitmapSize; /* Free Bitmap Size in Bytes */
uint64_t bitmapOffset; /* Free Bitmap Offset */
uint64_t version; /* Snapshot version */
ObjID root; /* Root Tree */

View File

@ -16,7 +16,9 @@ typedef struct VFS {
// FS Fields
void *fsptr;
uint64_t fsval;
uint64_t blksize;
VNode *root;
void *bitmap[16];
} VFS;
typedef struct VNode {
@ -54,6 +56,7 @@ int VFS_Stat(const char *path, struct stat *sb);
int VFS_Open(VNode *fn);
int VFS_Close(VNode *fn);
int VFS_Read(VNode *fn, void *buf, uint64_t off, uint64_t len);
int VFS_Write(VNode *fn, void *buf, uint64_t off, uint64_t len);
int VFS_ReadDir(VNode *fn, void *buf, uint64_t len, uint64_t *off);
#endif /* __SYS_VFS_H__ */

View File

@ -29,7 +29,7 @@ VFSUIO_Write(Handle *handle, void *buf, uint64_t len, uint64_t off)
// XXX: Need to pin memory
return -EINVAL;
return VFS_Write(handle->vnode, buf, len, off);
}
static int

View File

@ -9,6 +9,12 @@ test_env.Append(CPPFLAGS = ['-fno-builtin', '-nostdinc'])
test_env.Append(CPPPATH = ['#build/include'])
test_env.Append(LIBPATH = ['#build/lib/libc'], LIBS = ['c'])
fiotest_src = []
fiotest_src.append(env["CRTBEGIN"])
fiotest_src.append(["fiotest.c"])
fiotest_src.append(env["CRTEND"])
test_env.Program("fiotest", fiotest_src)
threadtest_src = []
threadtest_src.append(env["CRTBEGIN"])
threadtest_src.append(["threadtest.c"])

24
tests/fiotest.c Normal file
View File

@ -0,0 +1,24 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
// Castor Only
#include <syscall.h>
int
main(int argc, const char *argv[])
{
printf("FIO Test\n");
uint64_t fd = OSOpen("/LICENSE", 0);
for (int i = 0; i < 100; i++) {
OSWrite(fd, "123456789\n", i*10, 10);
}
printf("Success!\n");
return 0;
}