Implemented write support in the file system and added fiotest, and stat
This commit is contained in:
parent
bd44784c5f
commit
d4fb02e2b4
@ -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
23
bin/stat/SConscript
Normal 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
42
bin/stat/stat.c
Normal 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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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 */
|
||||
|
@ -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__ */
|
||||
|
@ -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
|
||||
|
@ -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
24
tests/fiotest.c
Normal 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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user