mirror of
https://github.com/Mathewnd/Astral.git
synced 2026-11-01 15:08:21 +00:00
ext2: change allocateblock to work with inodes and add freestructure
This commit is contained in:
+112
-23
@@ -145,9 +145,11 @@ typedef struct {
|
|||||||
|
|
||||||
typedef uint32_t blockptr_t;
|
typedef uint32_t blockptr_t;
|
||||||
|
|
||||||
|
#define GROUP_GETINODE(fs, x) ((x) * (fs)->superblock.inodespergroup + 1)
|
||||||
#define GROUP_GETBLOCK(fs, x) ((x) * (fs)->superblock.blockspergroup + (fs)->superblock.superblockstart)
|
#define GROUP_GETBLOCK(fs, x) ((x) * (fs)->superblock.blockspergroup + (fs)->superblock.superblockstart)
|
||||||
#define BLOCK_GETDISKOFFSET(fs, x) ((fs)->blocksize * (x))
|
#define BLOCK_GETDISKOFFSET(fs, x) ((fs)->blocksize * (x))
|
||||||
#define BLOCK_GETGROUP(fs, x) (((x) - (fs)->superblock.superblockstart) / (fs)->superblock.blockspergroup)
|
#define BLOCK_GETGROUP(fs, x) (((x) - (fs)->superblock.superblockstart) / (fs)->superblock.blockspergroup)
|
||||||
|
#define BLOCK_GETINDEX(fs, x) (((x) - (fs)->superblock.superblockstart) % (fs)->superblock.blockspergroup)
|
||||||
#define INODE_GETGROUP(fs, x) (((x) - 1) / (fs)->superblock.inodespergroup)
|
#define INODE_GETGROUP(fs, x) (((x) - 1) / (fs)->superblock.inodespergroup)
|
||||||
#define INODE_GETINDEX(fs, x) (((x) - 1) % (fs)->superblock.inodespergroup)
|
#define INODE_GETINDEX(fs, x) (((x) - 1) % (fs)->superblock.inodespergroup)
|
||||||
#define INODE_GETDISKOFFSET(fs, table, x) ((table) + INODE_GETINDEX(fs, x) * (fs)->superblock.inodesize)
|
#define INODE_GETDISKOFFSET(fs, table, x) ((table) + INODE_GETINDEX(fs, x) * (fs)->superblock.inodesize)
|
||||||
@@ -170,32 +172,36 @@ static int syncsuperblock(ext2fs_t *fs) {
|
|||||||
return vfs_write(fs->backing, &fs->superblock, sizeof(ext2superblock_t), SUPERBLOCK_OFFSET, &tmp, 0);
|
return vfs_write(fs->backing, &fs->superblock, sizeof(ext2superblock_t), SUPERBLOCK_OFFSET, &tmp, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int allocateblock(ext2fs_t *fs, uintmax_t *block) {
|
// allocates either a block or an inode
|
||||||
|
static int allocatestructure(ext2fs_t *fs, uintmax_t *retid, bool inode) {
|
||||||
MUTEX_ACQUIRE(&fs->descriptorlock, false);
|
MUTEX_ACQUIRE(&fs->descriptorlock, false);
|
||||||
uintmax_t bg = fs->lowestfreeblockbg;
|
uintmax_t bg = inode ? fs->lowestfreeinodebg : fs->lowestfreeblockbg;
|
||||||
|
|
||||||
int e = 0;
|
int e = 0;
|
||||||
blockgroupdesc_t desc;
|
blockgroupdesc_t desc;
|
||||||
|
|
||||||
// safe to check outside of the superblock lock, as nothing that doesn't already
|
// safe to check outside of the superblock lock, as nothing that doesn't already
|
||||||
// hold the descriptorlock would change this variable
|
// hold the descriptorlock would change this variable
|
||||||
if (fs->superblock.unallocatedblocks == 0) {
|
if (inode ? fs->superblock.unallocatedinodes == 0 : fs->superblock.unallocatedblocks == 0) {
|
||||||
e = ENOSPC;
|
e = ENOSPC;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
// iterate through block groups to find one with a free descriptor
|
// iterate through block groups to find one with free structures
|
||||||
for (; bg < fs->bgcount; ++bg) {
|
for (; bg < fs->bgcount; ++bg) {
|
||||||
size_t readc;
|
size_t readc;
|
||||||
e = vfs_read(fs->backing, &desc, sizeof(blockgroupdesc_t), DESC_GETDISKOFFSET(fs, bg), &readc, 0);
|
e = vfs_read(fs->backing, &desc, sizeof(blockgroupdesc_t), DESC_GETDISKOFFSET(fs, bg), &readc, 0);
|
||||||
if (e)
|
if (e)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
if (desc.freeblocks)
|
if (inode ? desc.freeinodes : desc.freeblocks)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
fs->lowestfreeblockbg = bg;
|
if (inode)
|
||||||
|
fs->lowestfreeinodebg = bg;
|
||||||
|
else
|
||||||
|
fs->lowestfreeblockbg = bg;
|
||||||
|
|
||||||
if (bg == fs->bgcount) {
|
if (bg == fs->bgcount) {
|
||||||
e = ENOSPC;
|
e = ENOSPC;
|
||||||
@@ -203,58 +209,141 @@ static int allocateblock(ext2fs_t *fs, uintmax_t *block) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// XXX maybe it shouldn't be assumed this will always be a power of 2?
|
// XXX maybe it shouldn't be assumed this will always be a power of 2?
|
||||||
size_t bmsize = fs->superblock.blockspergroup / 8;
|
size_t bmsize = (inode ? fs->superblock.inodespergroup : fs->superblock.blockspergroup) / 8;
|
||||||
uint8_t *bm = alloc(bmsize);
|
uint8_t *bm = alloc(bmsize);
|
||||||
if (bm == NULL) {
|
if (bm == NULL) {
|
||||||
e = ENOMEM;
|
e = ENOMEM;
|
||||||
goto cleanup;;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
// read bitmap into buffer
|
// read bitmap into buffer
|
||||||
size_t readc;
|
size_t readc;
|
||||||
e = vfs_read(fs->backing, bm, bmsize, BLOCK_GETDISKOFFSET(fs, desc.blockbitmap), &readc, 0);
|
e = vfs_read(fs->backing, bm, bmsize, BLOCK_GETDISKOFFSET(fs, inode ? desc.inodebitmap : desc.blockbitmap), &readc, 0);
|
||||||
if (e)
|
if (e)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
uintmax_t blockfound = 0;
|
uintmax_t structurefound = 0;
|
||||||
int i;
|
int i;
|
||||||
// find free block in it
|
// find free block in it
|
||||||
for (i = 0; i < bmsize; ++i) {
|
for (i = 0; i < bmsize; ++i) {
|
||||||
// in ext2, a 1 means an used entry and a 0 means a free entry.
|
// in ext2, a 1 means an used entry and a 0 means a free entry.
|
||||||
// this is bad for iterating and finding free blocks and getting a free block using __builtin_ctz
|
// this is bad for iterating and finding free structures and getting a free structure using __builtin_ctz
|
||||||
// therefore we do a logical NOT in it. now 0 means an used entry and 1 means a free entry.
|
// therefore we do a logical NOT in it. now 0 means an used entry and 1 means a free entry.
|
||||||
uint8_t v = ~bm[i];
|
uint8_t v = ~bm[i];
|
||||||
if (v) {
|
if (v) {
|
||||||
int offset = __builtin_ctz(v);
|
int offset = __builtin_ctz(v);
|
||||||
bm[i] |= 1 << offset; //set as used
|
bm[i] |= 1 << offset; //set as used
|
||||||
blockfound = GROUP_GETBLOCK(fs, bg) + i * 8 + offset;
|
structurefound = (inode ? GROUP_GETINODE(fs, bg) : GROUP_GETBLOCK(fs, bg)) + i * 8 + offset;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
__assert(blockfound);
|
__assert(structurefound);
|
||||||
|
|
||||||
// sync bitmap back into disk
|
// sync bitmap back into disk
|
||||||
size_t writec;
|
size_t writec;
|
||||||
e = vfs_write(fs->backing, bm, bmsize, BLOCK_GETDISKOFFSET(fs, desc.blockbitmap), &writec, 0);
|
e = vfs_write(fs->backing, bm, bmsize, BLOCK_GETDISKOFFSET(fs, inode ? desc.inodebitmap : desc.blockbitmap), &writec, 0);
|
||||||
if (e)
|
if (e)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
// update block group desc free block count
|
// update block group desc free structure count
|
||||||
// TODO if an error happens here, the filesystem should probably be marked to be in an unclean state.
|
// TODO if an error happens here, the filesystem should probably be marked to be in an unclean state.
|
||||||
--desc.freeblocks;
|
if (inode)
|
||||||
|
desc.freeinodes -= 1;
|
||||||
|
else
|
||||||
|
desc.freeblocks -= 1;
|
||||||
|
|
||||||
e = vfs_write(fs->backing, &desc, sizeof(blockgroupdesc_t), DESC_GETDISKOFFSET(fs, bg), &writec, 0);
|
e = vfs_write(fs->backing, &desc, sizeof(blockgroupdesc_t), DESC_GETDISKOFFSET(fs, bg), &writec, 0);
|
||||||
if (e)
|
if (e)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
if (desc.freeblocks == 0)
|
// update lowest free block group if there are no more free structures in the current one
|
||||||
++fs->lowestfreeblockbg;
|
if ((inode ? desc.freeinodes : desc.freeblocks) == 0) {
|
||||||
|
if (inode)
|
||||||
|
fs->lowestfreeinodebg += 1;
|
||||||
|
else
|
||||||
|
fs->lowestfreeblockbg += 1;
|
||||||
|
}
|
||||||
|
|
||||||
*block = blockfound;
|
*retid = structurefound;
|
||||||
|
|
||||||
// update superblock unallocated block count
|
// update superblock unallocated structure count
|
||||||
MUTEX_ACQUIRE(&fs->superblocklock, false);
|
MUTEX_ACQUIRE(&fs->superblocklock, false);
|
||||||
--fs->superblock.unallocatedblocks;
|
if (inode)
|
||||||
|
fs->superblock.unallocatedinodes -= 1;
|
||||||
|
else
|
||||||
|
fs->superblock.unallocatedblocks -= 1;
|
||||||
|
e = syncsuperblock(fs);
|
||||||
|
MUTEX_RELEASE(&fs->superblocklock);
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
MUTEX_RELEASE(&fs->descriptorlock);
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
// frees a block or an inode
|
||||||
|
static int freestructure(ext2fs_t *fs, uintmax_t id, bool inode) {
|
||||||
|
int e = 0;
|
||||||
|
int bg = inode ? INODE_GETGROUP(fs, id) : BLOCK_GETGROUP(fs, id);
|
||||||
|
MUTEX_ACQUIRE(&fs->descriptorlock, false);
|
||||||
|
|
||||||
|
blockgroupdesc_t desc;
|
||||||
|
size_t readc;
|
||||||
|
e = vfs_read(fs->backing, &desc, sizeof(blockgroupdesc_t), DESC_GETDISKOFFSET(fs, bg), &readc, 0);
|
||||||
|
if (e)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
// XXX maybe it shouldn't be assumed this will always be a power of 2?
|
||||||
|
size_t bmsize = (inode ? fs->superblock.inodespergroup : fs->superblock.blockspergroup) / 8;
|
||||||
|
uint8_t *bm = alloc(bmsize);
|
||||||
|
if (bm == NULL) {
|
||||||
|
e = ENOMEM;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
// read bitmap into buffer
|
||||||
|
e = vfs_read(fs->backing, bm, bmsize, BLOCK_GETDISKOFFSET(fs, inode ? desc.inodebitmap : desc.blockbitmap), &readc, 0);
|
||||||
|
if (e)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
int index = inode ? INODE_GETINDEX(fs, id) : BLOCK_GETINDEX(fs, id);
|
||||||
|
int bmoffset = index / 8;
|
||||||
|
int bmindex = index % 8;
|
||||||
|
|
||||||
|
// 0 means free
|
||||||
|
bm[bmoffset] &= ~(1 << bmindex);
|
||||||
|
|
||||||
|
// sync bitmap back into disk
|
||||||
|
size_t writec;
|
||||||
|
e = vfs_write(fs->backing, bm, bmsize, BLOCK_GETDISKOFFSET(fs, inode ? desc.inodebitmap : desc.blockbitmap), &writec, 0);
|
||||||
|
if (e)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
// update block group desc free structure count
|
||||||
|
// TODO if an error happens here, the filesystem should probably be marked to be in an unclean state.
|
||||||
|
if (inode)
|
||||||
|
desc.freeinodes += 1;
|
||||||
|
else
|
||||||
|
desc.freeblocks += 1;
|
||||||
|
|
||||||
|
e = vfs_write(fs->backing, &desc, sizeof(blockgroupdesc_t), DESC_GETDISKOFFSET(fs, bg), &writec, 0);
|
||||||
|
if (e)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
// update lowest free block group if block group is lower
|
||||||
|
if (bg < (inode ? fs->lowestfreeinodebg : fs->lowestfreeblockbg)) {
|
||||||
|
if (inode)
|
||||||
|
fs->lowestfreeinodebg = bg;
|
||||||
|
else
|
||||||
|
fs->lowestfreeblockbg = bg;
|
||||||
|
}
|
||||||
|
|
||||||
|
// update superblock unallocated structure count
|
||||||
|
MUTEX_ACQUIRE(&fs->superblocklock, false);
|
||||||
|
if (inode)
|
||||||
|
fs->superblock.unallocatedinodes += 1;
|
||||||
|
else
|
||||||
|
fs->superblock.unallocatedblocks += 1;
|
||||||
e = syncsuperblock(fs);
|
e = syncsuperblock(fs);
|
||||||
MUTEX_RELEASE(&fs->superblocklock);
|
MUTEX_RELEASE(&fs->superblocklock);
|
||||||
|
|
||||||
@@ -609,7 +698,7 @@ static int ext2_getdents(vnode_t *vnode, dent_t *buffer, size_t count, uintmax_t
|
|||||||
buffer[i].d_type = vfs_getposixtype(ext2denttovfstypetable[dent->type]);
|
buffer[i].d_type = vfs_getposixtype(ext2denttovfstypetable[dent->type]);
|
||||||
memcpy(buffer[i].d_name, dent->name, dent->namelen);
|
memcpy(buffer[i].d_name, dent->name, dent->namelen);
|
||||||
buffer[i].d_name[dent->namelen] = '\0';
|
buffer[i].d_name[dent->namelen] = '\0';
|
||||||
++i;
|
i += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
offset += dent->size;
|
offset += dent->size;
|
||||||
@@ -794,7 +883,7 @@ static int ext2_mount(vfs_t **vfs, vnode_t *mountpoint, vnode_t *backing, void *
|
|||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
VFS_INIT(&fs->vfs, &vfsops, 0);
|
VFS_INIT(&fs->vfs, &vfsops, 0);
|
||||||
++fs->superblock.mountsaftercheck;
|
fs->superblock.mountsaftercheck += 1;
|
||||||
fs->superblock.timeoflastmount = timekeeper_time().s;
|
fs->superblock.timeoflastmount = timekeeper_time().s;
|
||||||
fs->backing = backing;
|
fs->backing = backing;
|
||||||
err = syncsuperblock(fs);
|
err = syncsuperblock(fs);
|
||||||
|
|||||||
Reference in New Issue
Block a user