diff --git a/kernel/initrd.cpp b/kernel/initrd.cpp index c983541d..08f98c2d 100644 --- a/kernel/initrd.cpp +++ b/kernel/initrd.cpp @@ -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. @@ -31,6 +31,7 @@ #include #include +#include #include #include #include @@ -258,11 +259,11 @@ void Init(addr_t phys, size_t size) CheckSum(); } -static bool ExtractDir(ioctx_t* ctx, uint32_t ino, Ref node); +static bool ExtractDir(ioctx_t* ctx, uint32_t ino, Ref node, Ref links); static bool ExtractFile(ioctx_t* ctx, uint32_t ino, Ref file); -static bool ExtractNode(ioctx_t* ctx, uint32_t ino, Ref node); +static bool ExtractNode(ioctx_t* ctx, uint32_t ino, Ref node, Ref links); -static bool ExtractDir(ioctx_t* ctx, uint32_t ino, Ref dir) +static bool ExtractDir(ioctx_t* ctx, uint32_t ino, Ref dir, Ref links) { size_t numfiles = GetNumFiles(ino); for ( size_t i = 0; i < numfiles; i++ ) @@ -275,7 +276,7 @@ static bool ExtractDir(ioctx_t* ctx, uint32_t ino, Ref dir) uint32_t childino = Traverse(ino, name); if ( !childino ) return false; - const initrd_inode_t* child = GetInode(childino); + initrd_inode_t* child = (initrd_inode_t*) GetInode(childino); mode_t mode = InitRDModeToHost(child->mode); if ( INITRD_S_ISDIR(child->mode) ) { @@ -284,16 +285,41 @@ static bool ExtractDir(ioctx_t* ctx, uint32_t ino, Ref dir) Ref desc = dir->open(ctx, name, O_SEARCH | O_DIRECTORY, 0); if ( !desc ) return false; - if ( !ExtractNode(ctx, childino, desc) ) + if ( !ExtractNode(ctx, childino, desc, links) ) return false; } if ( INITRD_S_ISREG(child->mode) ) { - Ref desc = dir->open(ctx, name, O_WRITE | O_CREATE, mode); - if ( !desc ) - return false; - if ( !ExtractNode(ctx, childino, desc) ) - return false; + assert(child->nlink != 0); + char link_path[sizeof(childino) * 3]; + snprintf(link_path, sizeof(link_path), "%ju", (uintmax_t) childino); + Ref existing(links->open(ctx, link_path, O_READ, 0)); + if ( !existing || dir->link(ctx, name, existing) != 0 ) + { + Ref 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; @@ -318,7 +344,7 @@ static bool ExtractFile(ioctx_t* ctx, uint32_t ino, Ref file) return true; } -static bool ExtractNode(ioctx_t* ctx, uint32_t ino, Ref node) +static bool ExtractNode(ioctx_t* ctx, uint32_t ino, Ref node, Ref links) { const initrd_inode_t* inode = GetInode(ino); if ( !inode ) @@ -328,7 +354,7 @@ static bool ExtractNode(ioctx_t* ctx, uint32_t ino, Ref node) if ( node->chown(ctx, inode->uid, inode->gid) < 0 ) return false; if ( INITRD_S_ISDIR(inode->mode) ) - if ( !ExtractDir(ctx, ino, node) ) + if ( !ExtractDir(ctx, ino, node, links) ) return false; if ( INITRD_S_ISREG(inode->mode) ) if ( !ExtractFile(ctx, ino, node) ) @@ -340,36 +366,55 @@ static bool ExtractNode(ioctx_t* ctx, uint32_t ino, Ref node) return true; } -bool ExtractInto(Ref desc) -{ - ioctx_t ctx; SetupKernelIOCtx(&ctx); - return ExtractNode(&ctx, sb->root, desc); -} - bool ExtractFromPhysicalInto(addr_t physaddr, size_t size, Ref desc) { Init(physaddr, size); - return ExtractInto(desc); -} -void Delete() -{ - size_t size = initrdsize; + ioctx_t ctx; SetupKernelIOCtx(&ctx); + if ( desc->mkdir(&ctx, ".initrd-links", 0777) != 0 ) + return false; - initrd = NULL; - initrdsize = 0; + Ref links(desc->open(&ctx, ".initrd-links", O_READ | O_DIRECTORY, 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. 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); Page::Put(addr); } Memory::Flush(); + initrdsize = 0; + // Free the used virtual address space. FreeKernelAddress(&initrd_addr_alloc); + + return true; } } // namespace InitRD diff --git a/kernel/initrd.h b/kernel/initrd.h index caee0d57..a064eac6 100644 --- a/kernel/initrd.h +++ b/kernel/initrd.h @@ -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. @@ -33,9 +33,7 @@ class Descriptor; namespace InitRD { -bool ExtractInto(Ref desc); bool ExtractFromPhysicalInto(addr_t physaddr, size_t size, Ref desc); -void Delete(); } // namespace InitRD diff --git a/kernel/kernel.cpp b/kernel/kernel.cpp index 9b4d017d..19c95865 100644 --- a/kernel/kernel.cpp +++ b/kernel/kernel.cpp @@ -547,9 +547,6 @@ static void BootThread(void* /*user*/) "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."); - // We no longer need the initrd, so free its resources. - InitRD::Delete(); - // // Stage 5. Loading and Initializing Core Drivers. // diff --git a/kernel/process.cpp b/kernel/process.cpp index 861c3e61..c367cfb7 100644 --- a/kernel/process.cpp +++ b/kernel/process.cpp @@ -65,7 +65,6 @@ #include #include "elf.h" -#include "initrd.h" #if defined(__i386__) || defined(__x86_64__) #include "x86-family/float.h"