packagefs: Remove support for multiple package domains per volume

That also get rid of the job stuff and the package loader thread.
This commit is contained in:
Ingo Weinhold
2013-04-07 13:52:41 +02:00
parent af5c10ab19
commit 6978941aac
10 changed files with 203 additions and 439 deletions
@@ -28,7 +28,6 @@ HAIKU_PACKAGE_FS_SOURCES =
Query.cpp Query.cpp
Package.cpp Package.cpp
PackageDirectory.cpp PackageDirectory.cpp
PackageDomain.cpp
PackageFile.cpp PackageFile.cpp
PackageFSRoot.cpp PackageFSRoot.cpp
PackageLeafNode.cpp PackageLeafNode.cpp
@@ -21,10 +21,10 @@
#include "DebugSupport.h" #include "DebugSupport.h"
#include "PackageDirectory.h" #include "PackageDirectory.h"
#include "PackageDomain.h"
#include "PackageFile.h" #include "PackageFile.h"
#include "PackageSymlink.h" #include "PackageSymlink.h"
#include "Version.h" #include "Version.h"
#include "Volume.h"
using namespace BPackageKit; using namespace BPackageKit;
@@ -300,9 +300,9 @@ private:
// #pragma mark - Package // #pragma mark - Package
Package::Package(PackageDomain* domain, dev_t deviceID, ino_t nodeID) Package::Package(::Volume* volume, dev_t deviceID, ino_t nodeID)
: :
fDomain(domain), fVolume(volume),
fFileName(NULL), fFileName(NULL),
fName(NULL), fName(NULL),
fInstallPath(NULL), fInstallPath(NULL),
@@ -461,7 +461,7 @@ Package::Open()
} }
// open the file // open the file
fFD = openat(fDomain->DirectoryFD(), fFileName, O_RDONLY); fFD = openat(fVolume->PackagesDirectoryFD(), fFileName, O_RDONLY);
if (fFD < 0) { if (fFD < 0) {
ERROR("Failed to open package file \"%s\"\n", fFileName); ERROR("Failed to open package file \"%s\"\n", fFileName);
return errno; return errno;
@@ -24,22 +24,22 @@
using BPackageKit::BPackageArchitecture; using BPackageKit::BPackageArchitecture;
class PackageDomain;
class PackageLinkDirectory; class PackageLinkDirectory;
class Volume;
class Version; class Version;
class Package : public BReferenceable, class Package : public BReferenceable,
public DoublyLinkedListLinkImpl<Package> { public DoublyLinkedListLinkImpl<Package> {
public: public:
Package(PackageDomain* domain, dev_t deviceID, Package(::Volume* volume, dev_t deviceID,
ino_t nodeID); ino_t nodeID);
~Package(); ~Package();
status_t Init(const char* fileName); status_t Init(const char* fileName);
status_t Load(); status_t Load();
PackageDomain* Domain() const { return fDomain; } ::Volume* Volume() const { return fVolume; }
const char* FileName() const { return fFileName; } const char* FileName() const { return fFileName; }
status_t SetName(const char* name); status_t SetName(const char* name);
@@ -93,7 +93,7 @@ private:
private: private:
mutex fLock; mutex fLock;
PackageDomain* fDomain; ::Volume* fVolume;
char* fFileName; char* fFileName;
char* fName; char* fName;
char* fInstallPath; char* fInstallPath;
@@ -1,143 +0,0 @@
/*
* Copyright 2009, Ingo Weinhold, [email protected].
* Distributed under the terms of the MIT License.
*/
#include "PackageDomain.h"
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <NodeMonitor.h>
#include <AutoDeleter.h>
#include <fs/KPath.h>
#include <team.h>
#include <vfs.h>
#include "DebugSupport.h"
#include "Volume.h"
PackageDomain::PackageDomain(::Volume* volume)
:
fVolume(volume),
fPath(NULL),
fDirFD(-1)
{
}
PackageDomain::~PackageDomain()
{
PRINT("PackageDomain::~PackageDomain()\n");
Package* package = fPackages.Clear(true);
while (package != NULL) {
Package* next = package->FileNameHashTableNext();
package->ReleaseReference();
package = next;
}
if (fDirFD >= 0)
close(fDirFD);
free(fPath);
}
status_t
PackageDomain::Init(const char* path, struct stat* _st)
{
// Open the directory. We want the path be interpreted depending on from
// where it came (kernel or userland), but we always want a FD in the kernel
// I/O context. There's no VFS service method to do that for us, so we need
// to do that ourselves.
bool calledFromKernel
= team_get_current_team_id() == team_get_kernel_team_id();
// Not entirely correct, but good enough for now. The only alternative
// is to have that information passed in as well.
struct vnode* vnode;
status_t error;
if (path != NULL) {
error = vfs_get_vnode_from_path(path, calledFromKernel, &vnode);
} else {
// No path given -- use the "packages" directory at our mount point.
error = vfs_entry_ref_to_vnode(fVolume->MountPointDeviceID(),
fVolume->MountPointNodeID(), "packages", &vnode);
}
if (error != B_OK) {
ERROR("Failed to open package domain \"%s\"\n", strerror(error));
RETURN_ERROR(error);
}
fDirFD = vfs_open_vnode(vnode, O_RDONLY, true);
if (fDirFD < 0) {
ERROR("Failed to open package domain \"%s\"\n", strerror(fDirFD));
vfs_put_vnode(vnode);
RETURN_ERROR(fDirFD);
}
// Our vnode reference has been transferred to the FD.
// Is it a directory at all?
struct stat st;
if (fstat(fDirFD, &st) < 0)
RETURN_ERROR(errno);
fDeviceID = st.st_dev;
fNodeID = st.st_ino;
// get a normalized path
KPath normalizedPath;
if (normalizedPath.InitCheck() != B_OK)
RETURN_ERROR(normalizedPath.InitCheck());
char* normalizedPathBuffer = normalizedPath.LockBuffer();
error = vfs_entry_ref_to_path(fDeviceID, fNodeID, NULL,
normalizedPathBuffer, normalizedPath.BufferSize());
if (error != B_OK)
RETURN_ERROR(error);
fPath = strdup(normalizedPathBuffer);
if (fPath == NULL)
RETURN_ERROR(B_NO_MEMORY);
// init packages hash table
error = fPackages.Init();
if (error != B_OK)
return error;
if (_st != NULL)
*_st = st;
return B_OK;
}
void
PackageDomain::AddPackage(Package* package)
{
fPackages.Insert(package);
package->AcquireReference();
}
void
PackageDomain::RemovePackage(Package* package)
{
fPackages.Remove(package);
package->ReleaseReference();
}
Package*
PackageDomain::FindPackage(const char* fileName) const
{
return fPackages.Lookup(fileName);
}
@@ -1,53 +0,0 @@
/*
* Copyright 2009-2011, Ingo Weinhold, [email protected].
* Distributed under the terms of the MIT License.
*/
#ifndef PACKAGE_DOMAIN_H
#define PACKAGE_DOMAIN_H
#include <Referenceable.h>
#include <util/DoublyLinkedList.h>
#include "Package.h"
struct stat;
class Volume;
class PackageDomain : public BReferenceable,
public DoublyLinkedListLinkImpl<PackageDomain> {
public:
PackageDomain(::Volume* volume);
~PackageDomain();
::Volume* Volume() const { return fVolume; }
const char* Path() const { return fPath; }
int DirectoryFD() { return fDirFD; }
dev_t DeviceID() { return fDeviceID; }
ino_t NodeID() { return fNodeID; }
status_t Init(const char* path, struct stat* _st);
void AddPackage(Package* package);
void RemovePackage(Package* package);
Package* FindPackage(const char* fileName) const;
const PackageFileNameHashTable& Packages() const
{ return fPackages; }
private:
::Volume* fVolume;
char* fPath;
int fDirFD;
dev_t fDeviceID;
ino_t fNodeID;
PackageFileNameHashTable fPackages;
};
#endif // PACKAGE_DOMAIN_H
@@ -99,11 +99,11 @@ PackageLinkDirectory::AddPackage(Package* package,
// Find the insertion point in the list. We sort by mount type -- the more // Find the insertion point in the list. We sort by mount type -- the more
// specific the higher the priority. // specific the higher the priority.
MountType mountType = package->Domain()->Volume()->MountType(); MountType mountType = package->Volume()->MountType();
Package* otherPackage = NULL; Package* otherPackage = NULL;
for (PackageList::Iterator it = fPackages.GetIterator(); for (PackageList::Iterator it = fPackages.GetIterator();
(otherPackage = it.Next()) != NULL;) { (otherPackage = it.Next()) != NULL;) {
if (otherPackage->Domain()->Volume()->MountType() <= mountType) if (otherPackage->Volume()->MountType() <= mountType)
break; break;
} }
@@ -94,7 +94,7 @@ PackageLinkSymlink::Update(Package* package, PackageLinksListener* listener)
fLinkPath = package->InstallPath(); fLinkPath = package->InstallPath();
if (fLinkPath == NULL) { if (fLinkPath == NULL) {
fLinkPath = link_path_for_mount_type( fLinkPath = link_path_for_mount_type(
package->Domain()->Volume()->MountType()); package->Volume()->MountType());
} }
} else } else
fLinkPath = kUnknownLinkTarget; fLinkPath = kUnknownLinkTarget;
@@ -17,11 +17,11 @@ ResolvableFamily::AddResolvable(Resolvable* resolvable,
// Find the insertion point in the list. We sort by mount type -- the more // Find the insertion point in the list. We sort by mount type -- the more
// specific the higher the priority. // specific the higher the priority.
MountType mountType MountType mountType
= resolvable->Package()->Domain()->Volume()->MountType(); = resolvable->Package()->Volume()->MountType();
Resolvable* otherResolvable = NULL; Resolvable* otherResolvable = NULL;
for (FamilyResolvableList::Iterator it = fResolvables.GetIterator(); for (FamilyResolvableList::Iterator it = fResolvables.GetIterator();
(otherResolvable = it.Next()) != NULL;) { (otherResolvable = it.Next()) != NULL;) {
if (otherResolvable->Package()->Domain()->Volume()->MountType() if (otherResolvable->Package()->Volume()->MountType()
<= mountType) { <= mountType) {
break; break;
} }
@@ -1,5 +1,5 @@
/* /*
* Copyright 2009-2011, Ingo Weinhold, [email protected]. * Copyright 2009-2013, Ingo Weinhold, [email protected].
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
*/ */
@@ -23,6 +23,8 @@
#include <AutoDeleter.h> #include <AutoDeleter.h>
#include <fs/KPath.h>
#include <team.h>
#include <vfs.h> #include <vfs.h>
#include "AttributeIndex.h" #include "AttributeIndex.h"
@@ -63,51 +65,112 @@ const char* const* kHomeShineThroughDirectories
const size_t kMaxActivationRequestSize = 10 * 1024 * 1024; const size_t kMaxActivationRequestSize = 10 * 1024 * 1024;
// #pragma mark - Job // #pragma mark - ShineThroughDirectory
struct Volume::Job : DoublyLinkedListLinkImpl<Job> { struct Volume::PackagesDirectory {
Job(Volume* volume) PackagesDirectory()
: :
fVolume(volume) fPath(NULL),
fDirFD(-1)
{ {
} }
virtual ~Job()
~PackagesDirectory()
{ {
if (fDirFD >= 0)
close(fDirFD);
free(fPath);
} }
virtual void Do() = 0; const char* Path() const
protected:
Volume* fVolume;
};
// #pragma mark - AddPackageDomainJob
struct Volume::AddPackageDomainJob : Job {
AddPackageDomainJob(Volume* volume, PackageDomain* domain)
:
Job(volume),
fDomain(domain)
{ {
fDomain->AcquireReference(); return fPath;
} }
virtual ~AddPackageDomainJob() int DirectoryFD() const
{ {
fDomain->ReleaseReference(); return fDirFD;
} }
virtual void Do() dev_t DeviceID() const
{ {
fVolume->_AddPackageDomain(fDomain, true); return fDeviceID;
}
ino_t NodeID() const
{
return fNodeID;
}
status_t Init(const char* path, dev_t mountPointDeviceID,
ino_t mountPointNodeID, struct stat& _st)
{
// Open the directory. We want the path be interpreted depending on from
// where it came (kernel or userland), but we always want a FD in the
// kernel I/O context. There's no VFS service method to do that for us,
// so we need to do that ourselves.
bool calledFromKernel
= team_get_current_team_id() == team_get_kernel_team_id();
// Not entirely correct, but good enough for now. The only
// alternative is to have that information passed in as well.
struct vnode* vnode;
status_t error;
if (path != NULL) {
error = vfs_get_vnode_from_path(path, calledFromKernel, &vnode);
} else {
// No path given -- use the "packages" directory at our mount point.
error = vfs_entry_ref_to_vnode(mountPointDeviceID, mountPointNodeID,
"packages", &vnode);
}
if (error != B_OK) {
ERROR("Failed to open package domain \"%s\"\n", strerror(error));
RETURN_ERROR(error);
}
fDirFD = vfs_open_vnode(vnode, O_RDONLY, true);
if (fDirFD < 0) {
ERROR("Failed to open package domain \"%s\"\n", strerror(fDirFD));
vfs_put_vnode(vnode);
RETURN_ERROR(fDirFD);
}
// Our vnode reference has been transferred to the FD.
// Is it a directory at all?
struct stat& st = _st;
if (fstat(fDirFD, &st) < 0)
RETURN_ERROR(errno);
fDeviceID = st.st_dev;
fNodeID = st.st_ino;
// get a normalized path
KPath normalizedPath;
if (normalizedPath.InitCheck() != B_OK)
RETURN_ERROR(normalizedPath.InitCheck());
char* normalizedPathBuffer = normalizedPath.LockBuffer();
error = vfs_entry_ref_to_path(fDeviceID, fNodeID, NULL,
normalizedPathBuffer, normalizedPath.BufferSize());
if (error != B_OK)
RETURN_ERROR(error);
fPath = strdup(normalizedPathBuffer);
if (fPath == NULL)
RETURN_ERROR(B_NO_MEMORY);
return B_OK;
} }
private: private:
PackageDomain* fDomain; char* fPath;
int fDirFD;
dev_t fDeviceID;
ino_t fNodeID;
}; };
@@ -264,22 +327,32 @@ Volume::Volume(fs_volume* fsVolume)
fFSVolume(fsVolume), fFSVolume(fsVolume),
fRootDirectory(NULL), fRootDirectory(NULL),
fPackageFSRoot(NULL), fPackageFSRoot(NULL),
fPackageLoader(-1), fPackagesDirectory(NULL),
fNextNodeID(kRootDirectoryID + 1), fNextNodeID(kRootDirectoryID + 1)
fTerminating(false)
{ {
rw_lock_init(&fLock, "packagefs volume"); rw_lock_init(&fLock, "packagefs volume");
mutex_init(&fJobQueueLock, "packagefs volume job queue");
fJobQueueCondition.Init(this, "packagefs volume job queue");
} }
Volume::~Volume() Volume::~Volume()
{ {
_TerminatePackageLoader(); // remove the packages from the node tree
{
VolumeWriteLocker systemVolumeLocker(_SystemVolumeIfNotSelf());
VolumeWriteLocker volumeLocker(this);
for (PackageFileNameHashTable::Iterator it = fPackages.GetIterator();
Package* package = it.Next();) {
_RemovePackageContent(package, NULL, false);
}
}
while (PackageDomain* packageDomain = fPackageDomains.Head()) // delete the packages
_RemovePackageDomain(packageDomain); Package* package = fPackages.Clear(true);
while (package != NULL) {
Package* next = package->FileNameHashTableNext();
package->ReleaseReference();
package = next;
}
// delete all indices // delete all indices
Index* index = fIndices.Clear(true); Index* index = fIndices.Clear(true);
@@ -307,11 +380,17 @@ Volume::~Volume()
if (fRootDirectory != NULL) if (fRootDirectory != NULL)
fRootDirectory->ReleaseReference(); fRootDirectory->ReleaseReference();
mutex_destroy(&fJobQueueLock);
rw_lock_destroy(&fLock); rw_lock_destroy(&fLock);
} }
int
Volume::PackagesDirectoryFD() const
{
return fPackagesDirectory->DirectoryFD();
}
status_t status_t
Volume::Mount(const char* parameterString) Volume::Mount(const char* parameterString)
{ {
@@ -324,6 +403,10 @@ Volume::Mount(const char* parameterString)
if (error != B_OK) if (error != B_OK)
RETURN_ERROR(error); RETURN_ERROR(error);
error = fPackages.Init();
if (error != B_OK)
RETURN_ERROR(error);
error = fIndices.Init(); error = fIndices.Init();
if (error != B_OK) if (error != B_OK)
RETURN_ERROR(error); RETURN_ERROR(error);
@@ -425,14 +508,14 @@ Volume::Mount(const char* parameterString)
if (error != B_OK) if (error != B_OK)
RETURN_ERROR(error); RETURN_ERROR(error);
// create initial package domain // create package domain
PackageDomain* packageDomain = new(std::nothrow) PackageDomain(this); fPackagesDirectory = new(std::nothrow) PackagesDirectory;
if (packageDomain == NULL) if (fPackagesDirectory == NULL)
RETURN_ERROR(B_NO_MEMORY); RETURN_ERROR(B_NO_MEMORY);
BReference<PackageDomain> packageDomainReference(packageDomain, true);
struct stat st; struct stat st;
error = packageDomain->Init(packages, &st); error = fPackagesDirectory->Init(packages, fMountPoint.deviceID,
fMountPoint.nodeID, st);
if (error != B_OK) if (error != B_OK)
RETURN_ERROR(error); RETURN_ERROR(error);
@@ -481,17 +564,11 @@ Volume::Mount(const char* parameterString)
if (error != B_OK) if (error != B_OK)
RETURN_ERROR(error); RETURN_ERROR(error);
// add initial package domain // add initial packages
error = _AddPackageDomain(packageDomain, false); error = _AddInitialPackages();
if (error != B_OK) if (error != B_OK)
RETURN_ERROR(error); RETURN_ERROR(error);
// spawn package loader thread
fPackageLoader = spawn_kernel_thread(&_PackageLoaderEntry,
"package loader", B_NORMAL_PRIORITY, this);
if (fPackageLoader < 0)
RETURN_ERROR(fPackageLoader);
// publish the root node // publish the root node
fRootDirectory->AcquireReference(); fRootDirectory->AcquireReference();
error = PublishVNode(fRootDirectory); error = PublishVNode(fRootDirectory);
@@ -505,9 +582,6 @@ Volume::Mount(const char* parameterString)
if (error != B_OK) if (error != B_OK)
RETURN_ERROR(error); RETURN_ERROR(error);
// run the package loader
resume_thread(fPackageLoader);
return B_OK; return B_OK;
} }
@@ -515,7 +589,6 @@ Volume::Mount(const char* parameterString)
void void
Volume::Unmount() Volume::Unmount()
{ {
_TerminatePackageLoader();
} }
@@ -534,10 +607,8 @@ Volume::IOCtl(Node* node, uint32 operation, void* buffer, size_t size)
info.mountType = fMountType; info.mountType = fMountType;
info.rootDeviceID = fPackageFSRoot->DeviceID(); info.rootDeviceID = fPackageFSRoot->DeviceID();
info.rootDirectoryID = fPackageFSRoot->NodeID(); info.rootDirectoryID = fPackageFSRoot->NodeID();
info.packagesDeviceID = fPackagesDirectory->DeviceID();
PackageDomain* domain = fPackageDomains.Head(); info.packagesDirectoryID = fPackagesDirectory->NodeID();
info.packagesDeviceID = domain != NULL ? domain->DeviceID() : -1;
info.packagesDirectoryID = domain != NULL ? domain->NodeID() : -1;
RETURN_ERROR(user_memcpy(buffer, &info, sizeof(info))); RETURN_ERROR(user_memcpy(buffer, &info, sizeof(info)));
} }
@@ -552,13 +623,9 @@ Volume::IOCtl(Node* node, uint32 operation, void* buffer, size_t size)
VolumeReadLocker volumeReadLocker(this); VolumeReadLocker volumeReadLocker(this);
PackageDomain* domain = fPackageDomains.Head();
if (domain == NULL)
RETURN_ERROR(B_BAD_VALUE);
uint32 packageIndex = 0; uint32 packageIndex = 0;
for (PackageFileNameHashTable::Iterator it for (PackageFileNameHashTable::Iterator it
= domain->Packages().GetIterator(); it.HasNext(); = fPackages.GetIterator(); it.HasNext();
packageIndex++) { packageIndex++) {
Package* package = it.Next(); Package* package = it.Next();
PackageFSPackageInfo info; PackageFSPackageInfo info;
@@ -572,7 +639,7 @@ Volume::IOCtl(Node* node, uint32 operation, void* buffer, size_t size)
return B_BAD_ADDRESS; return B_BAD_ADDRESS;
} }
uint32 packageCount = domain->Packages().CountElements(); uint32 packageCount = fPackages.CountElements();
RETURN_ERROR(user_memcpy(&request->packageCount, &packageCount, RETURN_ERROR(user_memcpy(&request->packageCount, &packageCount,
sizeof(packageCount))); sizeof(packageCount)));
} }
@@ -685,28 +752,6 @@ Volume::PublishVNode(Node* node)
} }
status_t
Volume::AddPackageDomain(const char* path)
{
PackageDomain* packageDomain = new(std::nothrow) PackageDomain(this);
if (packageDomain == NULL)
RETURN_ERROR(B_NO_MEMORY);
BReference<PackageDomain> packageDomainReference(packageDomain, true);
status_t error = packageDomain->Init(path, NULL);
if (error != B_OK)
RETURN_ERROR(error);
Job* job = new(std::nothrow) AddPackageDomainJob(this, packageDomain);
if (job == NULL)
RETURN_ERROR(B_NO_MEMORY);
_PushJob(job);
return B_OK;
}
void void
Volume::PackageLinkNodeAdded(Node* node) Volume::PackageLinkNodeAdded(Node* node)
{ {
@@ -736,84 +781,23 @@ Volume::PackageLinkNodeChanged(Node* node, uint32 statFields,
} }
/*static*/ status_t
Volume::_PackageLoaderEntry(void* data)
{
return ((Volume*)data)->_PackageLoader();
}
status_t status_t
Volume::_PackageLoader() Volume::_AddInitialPackages()
{ {
while (!fTerminating) { dprintf("packagefs: Adding packages from \"%s\"\n",
MutexLocker jobQueueLocker(fJobQueueLock); fPackagesDirectory->Path());
Job* job = fJobQueue.RemoveHead();
if (job == NULL) {
// no job yet -- wait for someone notifying us
ConditionVariableEntry waitEntry;
fJobQueueCondition.Add(&waitEntry);
jobQueueLocker.Unlock();
waitEntry.Wait();
continue;
}
// do the job
jobQueueLocker.Unlock();
job->Do();
delete job;
}
return B_OK;
}
void
Volume::_TerminatePackageLoader()
{
fTerminating = true;
if (fPackageLoader >= 0) {
MutexLocker jobQueueLocker(fJobQueueLock);
fJobQueueCondition.NotifyOne();
jobQueueLocker.Unlock();
wait_for_thread(fPackageLoader, NULL);
fPackageLoader = -1;
}
// empty the job queue
while (Job* job = fJobQueue.RemoveHead())
delete job;
}
void
Volume::_PushJob(Job* job)
{
MutexLocker jobQueueLocker(fJobQueueLock);
fJobQueue.Add(job);
fJobQueueCondition.NotifyOne();
}
status_t
Volume::_AddPackageDomain(PackageDomain* domain, bool notify)
{
dprintf("packagefs: Adding package domain \"%s\"\n", domain->Path());
// iterate through the dir and create packages // iterate through the dir and create packages
int fd = dup(domain->DirectoryFD()); int fd = dup(fPackagesDirectory->DirectoryFD());
if (fd < 0) { if (fd < 0) {
ERROR("Failed to dup() package domain FD: %s\n", strerror(errno)); ERROR("Failed to dup() packages directory FD: %s\n", strerror(errno));
RETURN_ERROR(errno); RETURN_ERROR(errno);
} }
DIR* dir = fdopendir(fd); DIR* dir = fdopendir(fd);
if (dir == NULL) { if (dir == NULL) {
ERROR("Failed to open package domain directory \"%s\": %s\n", ERROR("Failed to open packages directory \"%s\": %s\n",
domain->Path(), strerror(errno)); fPackagesDirectory->Path(), strerror(errno));
RETURN_ERROR(errno); RETURN_ERROR(errno);
} }
CObjectDeleter<DIR, int> dirCloser(dir, closedir); CObjectDeleter<DIR, int> dirCloser(dir, closedir);
@@ -824,53 +808,56 @@ Volume::_AddPackageDomain(PackageDomain* domain, bool notify)
continue; continue;
Package* package; Package* package;
if (_LoadPackage(domain, entry->d_name, package) != B_OK) if (_LoadPackage(entry->d_name, package) != B_OK)
continue; continue;
BReference<Package> packageReference(package, true); BReference<Package> packageReference(package, true);
VolumeWriteLocker systemVolumeLocker(_SystemVolumeIfNotSelf()); VolumeWriteLocker systemVolumeLocker(_SystemVolumeIfNotSelf());
VolumeWriteLocker volumeLocker(this); VolumeWriteLocker volumeLocker(this);
domain->AddPackage(package); _AddPackage(package);
} }
// add the packages to the node tree // add the packages to the node tree
VolumeWriteLocker systemVolumeLocker(_SystemVolumeIfNotSelf()); VolumeWriteLocker systemVolumeLocker(_SystemVolumeIfNotSelf());
VolumeWriteLocker volumeLocker(this); VolumeWriteLocker volumeLocker(this);
for (PackageFileNameHashTable::Iterator it for (PackageFileNameHashTable::Iterator it = fPackages.GetIterator();
= domain->Packages().GetIterator(); Package* package = it.Next();) { Package* package = it.Next();) {
status_t error = _AddPackageContent(package, notify); status_t error = _AddPackageContent(package, false);
if (error != B_OK) { if (error != B_OK) {
for (it.Rewind(); Package* activePackage = it.Next();) { for (it.Rewind(); Package* activePackage = it.Next();) {
if (activePackage == package) if (activePackage == package)
break; break;
_RemovePackageContent(activePackage, NULL, notify); _RemovePackageContent(activePackage, NULL, false);
} }
RETURN_ERROR(error); RETURN_ERROR(error);
} }
} }
fPackageDomains.Add(domain);
domain->AcquireReference();
return B_OK; return B_OK;
} }
void inline void
Volume::_RemovePackageDomain(PackageDomain* domain) Volume::_AddPackage(Package* package)
{ {
// remove the domain's packages from the node tree fPackages.Insert(package);
VolumeWriteLocker systemVolumeLocker(_SystemVolumeIfNotSelf()); package->AcquireReference();
VolumeWriteLocker volumeLocker(this); }
for (PackageFileNameHashTable::Iterator it
= domain->Packages().GetIterator(); Package* package = it.Next();) {
_RemovePackageContent(package, NULL, false);
}
// remove the domain
fPackageDomains.Remove(domain); inline void
domain->ReleaseReference(); Volume::_RemovePackage(Package* package)
{
fPackages.Remove(package);
package->ReleaseReference();
}
inline Package*
Volume::_FindPackage(const char* fileName) const
{
return fPackages.Lookup(fileName);
} }
@@ -1336,19 +1323,18 @@ Volume::_RemoveNodeAndVNode(Node* node)
} }
/*static*/ status_t status_t
Volume::_LoadPackage(PackageDomain* domain, const char* name, Volume::_LoadPackage(const char* name, Package*& _package)
Package*& _package)
{ {
// check whether the entry is a file // check whether the entry is a file
struct stat st; struct stat st;
if (fstatat(domain->DirectoryFD(), name, &st, 0) < 0 if (fstatat(fPackagesDirectory->DirectoryFD(), name, &st, 0) < 0
|| !S_ISREG(st.st_mode)) { || !S_ISREG(st.st_mode)) {
return B_BAD_VALUE; return B_BAD_VALUE;
} }
// create a package // create a package
Package* package = new(std::nothrow) Package(domain, st.st_dev, st.st_ino); Package* package = new(std::nothrow) Package(this, st.st_dev, st.st_ino);
if (package == NULL) if (package == NULL)
RETURN_ERROR(B_NO_MEMORY); RETURN_ERROR(B_NO_MEMORY);
BReference<Package> packageReference(package, true); BReference<Package> packageReference(package, true);
@@ -1369,12 +1355,6 @@ Volume::_LoadPackage(PackageDomain* domain, const char* name,
status_t status_t
Volume::_ChangeActivation(ActivationChangeRequest& request) Volume::_ChangeActivation(ActivationChangeRequest& request)
{ {
// TODO: Would need locking, but will be irrelevant when removing the support
// for multiple package domains.
PackageDomain* domain = fPackageDomains.Head();
if (domain == NULL)
RETURN_ERROR(B_BAD_VALUE);
// first check the request // first check the request
int32 newPackageCount = 0; int32 newPackageCount = 0;
int32 oldPackageCount = 0; int32 oldPackageCount = 0;
@@ -1384,14 +1364,14 @@ Volume::_ChangeActivation(ActivationChangeRequest& request)
for (ActivationChangeRequest::Iterator it = request.GetIterator(); for (ActivationChangeRequest::Iterator it = request.GetIterator();
it.HasNext();) { it.HasNext();) {
PackageFSActivationChangeItem* item = it.Next(); PackageFSActivationChangeItem* item = it.Next();
if (item->parentDeviceID != domain->DeviceID() if (item->parentDeviceID != fPackagesDirectory->DeviceID()
|| item->parentDirectoryID != domain->NodeID()) { || item->parentDirectoryID != fPackagesDirectory->NodeID()) {
ERROR("Volume::_ChangeActivation(): mismatching packages " ERROR("Volume::_ChangeActivation(): mismatching packages "
"domain\n"); "directory\n");
RETURN_ERROR(B_BAD_VALUE); RETURN_ERROR(B_BAD_VALUE);
} }
Package* package = domain->FindPackage(item->name); Package* package = _FindPackage(item->name);
// TODO: We should better look up the package by node_ref! // TODO: We should better look up the package by node_ref!
if (item->type == PACKAGE_FS_ACTIVATE_PACKAGE) { if (item->type == PACKAGE_FS_ACTIVATE_PACKAGE) {
if (package != NULL) { if (package != NULL) {
@@ -1449,7 +1429,7 @@ INFORM("Volume::_ChangeActivation(): %" B_PRId32 " new packages, %" B_PRId32 " o
} }
Package* package; Package* package;
status_t error = _LoadPackage(domain, item->name, package); status_t error = _LoadPackage(item->name, package);
if (error != B_OK) { if (error != B_OK) {
ERROR("Volume::_ChangeActivation(): failed to load package " ERROR("Volume::_ChangeActivation(): failed to load package "
"\"%s\"\n", item->name); "\"%s\"\n", item->name);
@@ -1476,11 +1456,11 @@ INFORM("Volume::_ChangeActivation(): %" B_PRId32 " new packages, %" B_PRId32 " o
continue; continue;
} }
Package* package = domain->FindPackage(item->name); Package* package = _FindPackage(item->name);
// TODO: We should better look up the package by node_ref! // TODO: We should better look up the package by node_ref!
oldPackageReferences[oldPackageIndex++].SetTo(package); oldPackageReferences[oldPackageIndex++].SetTo(package);
_RemovePackageContent(package, NULL, true); _RemovePackageContent(package, NULL, true);
domain->RemovePackage(package); _RemovePackage(package);
INFORM("package \"%s\" deactivated\n", package->FileName()); INFORM("package \"%s\" deactivated\n", package->FileName());
} }
// TODO: Since package removal cannot fail, consider adding the new packages // TODO: Since package removal cannot fail, consider adding the new packages
@@ -1492,12 +1472,12 @@ INFORM("package \"%s\" deactivated\n", package->FileName());
for (newPackageIndex = 0; newPackageIndex < newPackageCount; for (newPackageIndex = 0; newPackageIndex < newPackageCount;
newPackageIndex++) { newPackageIndex++) {
Package* package = newPackageReferences[newPackageIndex]; Package* package = newPackageReferences[newPackageIndex];
domain->AddPackage(package); _AddPackage(package);
// add the package to the node tree // add the package to the node tree
error = _AddPackageContent(package, true); error = _AddPackageContent(package, true);
if (error != B_OK) { if (error != B_OK) {
domain->RemovePackage(package); _RemovePackage(package);
break; break;
} }
INFORM("package \"%s\" activated\n", package->FileName()); INFORM("package \"%s\" activated\n", package->FileName());
@@ -1508,19 +1488,19 @@ INFORM("package \"%s\" activated\n", package->FileName());
for (int32 i = newPackageIndex - 1; i >= 0; i--) { for (int32 i = newPackageIndex - 1; i >= 0; i--) {
Package* package = newPackageReferences[i]; Package* package = newPackageReferences[i];
_RemovePackageContent(package, NULL, true); _RemovePackageContent(package, NULL, true);
domain->RemovePackage(package); _RemovePackage(package);
} }
for (int32 i = oldPackageCount - 1; i >= 0; i--) { for (int32 i = oldPackageCount - 1; i >= 0; i--) {
Package* package = oldPackageReferences[i]; Package* package = oldPackageReferences[i];
domain->AddPackage(package); _AddPackage(package);
if (_AddPackageContent(package, true) != B_OK) { if (_AddPackageContent(package, true) != B_OK) {
// nothing we can do here // nothing we can do here
ERROR("Volume::_ChangeActivation(): failed to roll back " ERROR("Volume::_ChangeActivation(): failed to roll back "
"deactivation of package \"%s\" after error\n", "deactivation of package \"%s\" after error\n",
package->FileName()); package->FileName());
domain->RemovePackage(package); _RemovePackage(package);
} }
} }
} }
@@ -1,5 +1,5 @@
/* /*
* Copyright 2009-2011, Ingo Weinhold, [email protected]. * Copyright 2009-2013, Ingo Weinhold, [email protected].
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
*/ */
#ifndef VOLUME_H #ifndef VOLUME_H
@@ -19,7 +19,7 @@
#include "Index.h" #include "Index.h"
#include "Node.h" #include "Node.h"
#include "NodeListener.h" #include "NodeListener.h"
#include "PackageDomain.h" #include "Package.h"
#include "PackageLinksListener.h" #include "PackageLinksListener.h"
#include "Query.h" #include "Query.h"
@@ -51,6 +51,8 @@ public:
::MountType MountType() const { return fMountType; } ::MountType MountType() const { return fMountType; }
int PackagesDirectoryFD() const;
void SetPackageFSRoot(::PackageFSRoot* root) void SetPackageFSRoot(::PackageFSRoot* root)
{ fPackageFSRoot = root; } { fPackageFSRoot = root; }
::PackageFSRoot* PackageFSRoot() const ::PackageFSRoot* PackageFSRoot() const
@@ -94,8 +96,6 @@ public:
status_t RemoveVNode(ino_t nodeID); status_t RemoveVNode(ino_t nodeID);
status_t PublishVNode(Node* node); status_t PublishVNode(Node* node);
status_t AddPackageDomain(const char* path);
private: private:
// PackageLinksListener // PackageLinksListener
virtual void PackageLinkNodeAdded(Node* node); virtual void PackageLinkNodeAdded(Node* node);
@@ -105,29 +105,16 @@ private:
const OldNodeAttributes& oldAttributes); const OldNodeAttributes& oldAttributes);
private: private:
struct Job; struct PackagesDirectory;
struct AddPackageDomainJob;
struct DomainDirectoryEventJob;
struct ShineThroughDirectory; struct ShineThroughDirectory;
struct ActivationChangeRequest; struct ActivationChangeRequest;
friend struct AddPackageDomainJob;
typedef DoublyLinkedList<Job> JobList;
typedef DoublyLinkedList<PackageDomain> PackageDomainList;
private: private:
static status_t _PackageLoaderEntry(void* data); status_t _AddInitialPackages();
status_t _PackageLoader();
void _TerminatePackageLoader(); inline void _AddPackage(Package* package);
inline void _RemovePackage(Package* package);
void _PushJob(Job* job); inline Package* _FindPackage(const char* fileName) const;
status_t _AddInitialPackageDomain(const char* path);
status_t _AddPackageDomain(PackageDomain* domain,
bool notify);
void _RemovePackageDomain(PackageDomain* domain);
status_t _AddPackageContent(Package* package, status_t _AddPackageContent(Package* package,
bool notify); bool notify);
@@ -155,8 +142,8 @@ private:
void _RemoveNodeAndVNode(Node* node); void _RemoveNodeAndVNode(Node* node);
// caller must hold a reference // caller must hold a reference
static status_t _LoadPackage(PackageDomain* domain, status_t _LoadPackage(const char* name,
const char* name, Package*& _package); Package*& _package);
status_t _ChangeActivation( status_t _ChangeActivation(
ActivationChangeRequest& request); ActivationChangeRequest& request);
@@ -187,8 +174,7 @@ private:
Directory* fRootDirectory; Directory* fRootDirectory;
::PackageFSRoot* fPackageFSRoot; ::PackageFSRoot* fPackageFSRoot;
::MountType fMountType; ::MountType fMountType;
thread_id fPackageLoader; PackagesDirectory* fPackagesDirectory;
PackageDomainList fPackageDomains;
struct { struct {
dev_t deviceID; dev_t deviceID;
@@ -197,16 +183,11 @@ private:
NodeIDHashTable fNodes; NodeIDHashTable fNodes;
NodeListenerHashTable fNodeListeners; NodeListenerHashTable fNodeListeners;
PackageFileNameHashTable fPackages;
QueryList fQueries; QueryList fQueries;
IndexHashTable fIndices; IndexHashTable fIndices;
JobList fJobQueue;
mutex fJobQueueLock;
ConditionVariable fJobQueueCondition;
ino_t fNextNodeID; ino_t fNextNodeID;
volatile bool fTerminating;
}; };