Memory efficiently extract the initrd.

This commit is contained in:
Jonas 'Sortie' Termansen 2014-04-29 23:52:52 +02:00
parent 34c65265d0
commit 152d768112
4 changed files with 73 additions and 34 deletions

View File

@ -1,6 +1,6 @@
/******************************************************************************* /*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013. Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014.
This file is part of Sortix. This file is part of Sortix.
@ -31,6 +31,7 @@
#include <string.h> #include <string.h>
#include <timespec.h> #include <timespec.h>
#include <sortix/dirent.h>
#include <sortix/fcntl.h> #include <sortix/fcntl.h>
#include <sortix/initrd.h> #include <sortix/initrd.h>
#include <sortix/mman.h> #include <sortix/mman.h>
@ -258,11 +259,11 @@ void Init(addr_t phys, size_t size)
CheckSum(); CheckSum();
} }
static bool ExtractDir(ioctx_t* ctx, uint32_t ino, Ref<Descriptor> node); static bool ExtractDir(ioctx_t* ctx, uint32_t ino, Ref<Descriptor> node, Ref<Descriptor> links);
static bool ExtractFile(ioctx_t* ctx, uint32_t ino, Ref<Descriptor> file); static bool ExtractFile(ioctx_t* ctx, uint32_t ino, Ref<Descriptor> file);
static bool ExtractNode(ioctx_t* ctx, uint32_t ino, Ref<Descriptor> node); static bool ExtractNode(ioctx_t* ctx, uint32_t ino, Ref<Descriptor> node, Ref<Descriptor> links);
static bool ExtractDir(ioctx_t* ctx, uint32_t ino, Ref<Descriptor> dir) static bool ExtractDir(ioctx_t* ctx, uint32_t ino, Ref<Descriptor> dir, Ref<Descriptor> links)
{ {
size_t numfiles = GetNumFiles(ino); size_t numfiles = GetNumFiles(ino);
for ( size_t i = 0; i < numfiles; i++ ) for ( size_t i = 0; i < numfiles; i++ )
@ -275,7 +276,7 @@ static bool ExtractDir(ioctx_t* ctx, uint32_t ino, Ref<Descriptor> dir)
uint32_t childino = Traverse(ino, name); uint32_t childino = Traverse(ino, name);
if ( !childino ) if ( !childino )
return false; return false;
const initrd_inode_t* child = GetInode(childino); initrd_inode_t* child = (initrd_inode_t*) GetInode(childino);
mode_t mode = InitRDModeToHost(child->mode); mode_t mode = InitRDModeToHost(child->mode);
if ( INITRD_S_ISDIR(child->mode) ) if ( INITRD_S_ISDIR(child->mode) )
{ {
@ -284,16 +285,41 @@ static bool ExtractDir(ioctx_t* ctx, uint32_t ino, Ref<Descriptor> dir)
Ref<Descriptor> desc = dir->open(ctx, name, O_SEARCH | O_DIRECTORY, 0); Ref<Descriptor> desc = dir->open(ctx, name, O_SEARCH | O_DIRECTORY, 0);
if ( !desc ) if ( !desc )
return false; return false;
if ( !ExtractNode(ctx, childino, desc) ) if ( !ExtractNode(ctx, childino, desc, links) )
return false; return false;
} }
if ( INITRD_S_ISREG(child->mode) ) if ( INITRD_S_ISREG(child->mode) )
{ {
Ref<Descriptor> desc = dir->open(ctx, name, O_WRITE | O_CREATE, mode); assert(child->nlink != 0);
if ( !desc ) char link_path[sizeof(childino) * 3];
return false; snprintf(link_path, sizeof(link_path), "%ju", (uintmax_t) childino);
if ( !ExtractNode(ctx, childino, desc) ) Ref<Descriptor> existing(links->open(ctx, link_path, O_READ, 0));
return false; if ( !existing || dir->link(ctx, name, existing) != 0 )
{
Ref<Descriptor> desc(dir->open(ctx, name, O_WRITE | O_CREATE, mode));
if ( !desc )
return false;
if ( !ExtractNode(ctx, childino, desc, links) )
return false;
if ( 2 <= child->nlink )
links->link(ctx, link_path, desc);
}
if ( --child->nlink == 0 && INITRD_S_ISREG(child->mode) )
{
size_t filesize;
const uint8_t* data = Open(childino, &filesize);
uintptr_t from = (uintptr_t) data;
uintptr_t size = filesize;
uintptr_t from_aligned = Page::AlignUp(from);
uintptr_t from_distance = from_aligned - from;
if ( from_distance <= size )
{
uintptr_t size_aligned = Page::AlignDown(size - from_distance);
for ( size_t i = 0; i < size_aligned; i += Page::Size() )
Page::Put(Memory::Unmap(from_aligned + i));
Memory::Flush();
}
}
} }
} }
return true; return true;
@ -318,7 +344,7 @@ static bool ExtractFile(ioctx_t* ctx, uint32_t ino, Ref<Descriptor> file)
return true; return true;
} }
static bool ExtractNode(ioctx_t* ctx, uint32_t ino, Ref<Descriptor> node) static bool ExtractNode(ioctx_t* ctx, uint32_t ino, Ref<Descriptor> node, Ref<Descriptor> links)
{ {
const initrd_inode_t* inode = GetInode(ino); const initrd_inode_t* inode = GetInode(ino);
if ( !inode ) if ( !inode )
@ -328,7 +354,7 @@ static bool ExtractNode(ioctx_t* ctx, uint32_t ino, Ref<Descriptor> node)
if ( node->chown(ctx, inode->uid, inode->gid) < 0 ) if ( node->chown(ctx, inode->uid, inode->gid) < 0 )
return false; return false;
if ( INITRD_S_ISDIR(inode->mode) ) if ( INITRD_S_ISDIR(inode->mode) )
if ( !ExtractDir(ctx, ino, node) ) if ( !ExtractDir(ctx, ino, node, links) )
return false; return false;
if ( INITRD_S_ISREG(inode->mode) ) if ( INITRD_S_ISREG(inode->mode) )
if ( !ExtractFile(ctx, ino, node) ) if ( !ExtractFile(ctx, ino, node) )
@ -340,36 +366,55 @@ static bool ExtractNode(ioctx_t* ctx, uint32_t ino, Ref<Descriptor> node)
return true; return true;
} }
bool ExtractInto(Ref<Descriptor> desc)
{
ioctx_t ctx; SetupKernelIOCtx(&ctx);
return ExtractNode(&ctx, sb->root, desc);
}
bool ExtractFromPhysicalInto(addr_t physaddr, size_t size, Ref<Descriptor> desc) bool ExtractFromPhysicalInto(addr_t physaddr, size_t size, Ref<Descriptor> desc)
{ {
Init(physaddr, size); Init(physaddr, size);
return ExtractInto(desc);
}
void Delete() ioctx_t ctx; SetupKernelIOCtx(&ctx);
{ if ( desc->mkdir(&ctx, ".initrd-links", 0777) != 0 )
size_t size = initrdsize; return false;
initrd = NULL; Ref<Descriptor> links(desc->open(&ctx, ".initrd-links", O_READ | O_DIRECTORY, 0));
initrdsize = 0; if ( !links )
return false;
if ( !ExtractNode(&ctx, sb->root, desc, links) )
return false;
union
{
struct kernel_dirent dirent;
uint8_t dirent_data[sizeof(struct kernel_dirent) + sizeof(uintmax_t) * 3];
};
while ( 0 < links->readdirents(&ctx, &dirent, sizeof(dirent_data), 1) &&
((const char*) dirent.d_name)[0] )
{
if ( ((const char*) dirent.d_name)[0] == '.' )
continue;
links->unlink(&ctx, dirent.d_name);
links->lseek(&ctx, 0, SEEK_SET);
}
desc->rmdir(&ctx, ".initrd-links");
// Unmap the pages and return the physical frames for reallocation. // Unmap the pages and return the physical frames for reallocation.
addr_t mapat = initrd_addr_alloc.from; addr_t mapat = initrd_addr_alloc.from;
for ( size_t i = 0; i < size; i += Page::Size() ) for ( size_t i = 0; i < initrdsize; i += Page::Size() )
{ {
if ( !Memory::LookUp(mapat + i, NULL, NULL) )
continue;
addr_t addr = Memory::Unmap(mapat + i); addr_t addr = Memory::Unmap(mapat + i);
Page::Put(addr); Page::Put(addr);
} }
Memory::Flush(); Memory::Flush();
initrdsize = 0;
// Free the used virtual address space. // Free the used virtual address space.
FreeKernelAddress(&initrd_addr_alloc); FreeKernelAddress(&initrd_addr_alloc);
return true;
} }
} // namespace InitRD } // namespace InitRD

View File

@ -1,6 +1,6 @@
/******************************************************************************* /*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012. Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014.
This file is part of Sortix. This file is part of Sortix.
@ -33,9 +33,7 @@ class Descriptor;
namespace InitRD { namespace InitRD {
bool ExtractInto(Ref<Descriptor> desc);
bool ExtractFromPhysicalInto(addr_t physaddr, size_t size, Ref<Descriptor> desc); bool ExtractFromPhysicalInto(addr_t physaddr, size_t size, Ref<Descriptor> desc);
void Delete();
} // namespace InitRD } // namespace InitRD

View File

@ -547,9 +547,6 @@ static void BootThread(void* /*user*/)
"needs more memory to boot using this initrd, as a rule of thumb " "needs more memory to boot using this initrd, as a rule of thumb "
"you need twice as much memory as the size of the initrd device."); "you need twice as much memory as the size of the initrd device.");
// We no longer need the initrd, so free its resources.
InitRD::Delete();
// //
// Stage 5. Loading and Initializing Core Drivers. // Stage 5. Loading and Initializing Core Drivers.
// //

View File

@ -65,7 +65,6 @@
#include <sortix/kernel/worker.h> #include <sortix/kernel/worker.h>
#include "elf.h" #include "elf.h"
#include "initrd.h"
#if defined(__i386__) || defined(__x86_64__) #if defined(__i386__) || defined(__x86_64__)
#include "x86-family/float.h" #include "x86-family/float.h"