Improved the interaction between job queue and manager. Partitions should now be mark busy correctly.
git-svn-id: file:///srv/svn/repos/haiku/trunk/current@4223 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
13ab290504
commit
8d91b8087d
@ -81,6 +81,7 @@ public:
|
||||
|
||||
// manager must be locked
|
||||
status_t AddJobQueue(KDiskDeviceJobQueue *jobQueue);
|
||||
// the device must be write locked
|
||||
status_t RemoveJobQueue(KDiskDeviceJobQueue *jobQueue);
|
||||
status_t DeleteJobQueue(KDiskDeviceJobQueue *jobQueue);
|
||||
// called when the execution is done
|
||||
@ -89,6 +90,11 @@ public:
|
||||
|
||||
KDiskDeviceJobFactory *JobFactory() const;
|
||||
|
||||
// manager must *not* be locked
|
||||
status_t UpdateBusyPartitions(KDiskDevice *device);
|
||||
status_t UpdateJobStatus(KDiskDeviceJob *job, uint32 status,
|
||||
bool updateBusyPartitions);
|
||||
|
||||
// Disk Systems
|
||||
|
||||
// manager must be locked
|
||||
@ -118,8 +124,13 @@ private:
|
||||
|
||||
bool _RemoveJobQueue(KDiskDeviceJobQueue *jobQueue);
|
||||
|
||||
status_t _UpdateBusyPartitions(KDiskDevice *device);
|
||||
status_t _UpdateJobStatus(KDiskDeviceJob *job, uint32 status,
|
||||
bool updateBusyPartitions);
|
||||
|
||||
status_t _Scan(const char *path);
|
||||
status_t _ScanPartition(KPartition *partition);
|
||||
// the manager must be locked and the device write locked
|
||||
|
||||
struct DeviceMap;
|
||||
struct DiskSystemMap;
|
||||
|
@ -187,9 +187,8 @@ KDiskDeviceJobQueue::Execute()
|
||||
fSyncSemaphore = -1;
|
||||
return fThread;
|
||||
}
|
||||
fFlags |= JOB_QUEUE_EXECUTING;
|
||||
resume_thread(fThread);
|
||||
// wait till the thread has resumed its work
|
||||
acquire_sem(fSyncSemaphore);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@ -301,45 +300,45 @@ KDiskDeviceJobQueue::IsPauseRequested() const
|
||||
int32
|
||||
KDiskDeviceJobQueue::_ThreadLoop()
|
||||
{
|
||||
// TODO: notifications
|
||||
// mark all jobs scheduled
|
||||
for (int32 i = 0; KDiskDeviceJob *job = JobAt(i); i++)
|
||||
job->SetStatus(B_DISK_DEVICE_JOB_SCHEDULED);
|
||||
// mark the queue executing and notify the thread waiting in Execute()
|
||||
fFlags |= JOB_QUEUE_EXECUTING;
|
||||
release_sem(fSyncSemaphore);
|
||||
KDiskDeviceManager *manager = KDiskDeviceManager::Default();
|
||||
// main loop: process all jobs
|
||||
bool failed = false;
|
||||
while (KDiskDeviceJob *activeJob = ActiveJob()) {
|
||||
activeJob->SetStatus(B_DISK_DEVICE_JOB_IN_PROGRESS);
|
||||
manager->UpdateJobStatus(activeJob, B_DISK_DEVICE_JOB_IN_PROGRESS,
|
||||
true);
|
||||
status_t error = activeJob->Do();
|
||||
if (error == B_OK) {
|
||||
if (ManagerLocker locker = manager) {
|
||||
// if canceled, mark this and all succeeding jobs canceled
|
||||
if (IsCanceled()) {
|
||||
for (int32 i = fActiveJob; KDiskDeviceJob *job = JobAt(i);
|
||||
i++) {
|
||||
job->SetStatus(B_DISK_DEVICE_JOB_CANCELED);
|
||||
}
|
||||
// if canceled, simply bail out -- this and all succeeding
|
||||
// jobs will be canceled
|
||||
if (IsCanceled())
|
||||
break;
|
||||
}
|
||||
// if pause was requested ignore the request
|
||||
if (IsPauseRequested())
|
||||
Continue();
|
||||
// mark the job succeeded and go to the next one
|
||||
activeJob->SetStatus(B_DISK_DEVICE_JOB_SUCCEEDED);
|
||||
// go to the next job
|
||||
fActiveJob++;
|
||||
} else
|
||||
break;
|
||||
// mark the job succeeded
|
||||
manager->UpdateJobStatus(activeJob, B_DISK_DEVICE_JOB_SUCCEEDED,
|
||||
true);
|
||||
} else {
|
||||
// job failed: mark this and all succeeding jobs failed
|
||||
if (ManagerLocker locker = manager) {
|
||||
for (int32 i = fActiveJob; KDiskDeviceJob *job = JobAt(i); i++)
|
||||
job->SetStatus(B_DISK_DEVICE_JOB_FAILED);
|
||||
}
|
||||
// job failed: this and all succeeding jobs will be marked failed
|
||||
failed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// All jobs that remain need to be marked failed or canceled.
|
||||
bool updatePartitions = false;
|
||||
for (int32 i = fActiveJob; KDiskDeviceJob *job = JobAt(i); i++) {
|
||||
manager->UpdateJobStatus(job, (failed ? B_DISK_DEVICE_JOB_FAILED
|
||||
: B_DISK_DEVICE_JOB_CANCELED),
|
||||
false);
|
||||
updatePartitions = true;
|
||||
}
|
||||
if (updatePartitions)
|
||||
manager->UpdateBusyPartitions(Device());
|
||||
// tell the manager, that we are done.
|
||||
if (ManagerLocker locker = manager) {
|
||||
fFlags &= ~(uint32)JOB_QUEUE_EXECUTING;
|
||||
|
@ -22,6 +22,8 @@
|
||||
#include "KFileSystem.h"
|
||||
#include "KPartition.h"
|
||||
#include "KPartitioningSystem.h"
|
||||
#include "KPartitionVisitor.h"
|
||||
#include "KShadowPartition.h"
|
||||
|
||||
// debugging
|
||||
//#define DBG(x)
|
||||
@ -36,6 +38,15 @@ using BPrivate::DiskDevice::KDiskDeviceJobQueue;
|
||||
static const char *kPartitioningSystemPrefix = "partitioning_systems";
|
||||
static const char *kFileSystemPrefix = "file_systems";
|
||||
|
||||
// is_active_job_status
|
||||
static
|
||||
bool
|
||||
is_active_job_status(uint32 status)
|
||||
{
|
||||
return (status == B_DISK_DEVICE_JOB_SCHEDULED
|
||||
|| status == B_DISK_DEVICE_JOB_IN_PROGRESS);
|
||||
}
|
||||
|
||||
// GetPartitionID
|
||||
struct GetPartitionID {
|
||||
inline partition_id operator()(const KPartition *partition) const
|
||||
@ -494,6 +505,11 @@ KDiskDeviceManager::CreateFileDevice(const char *filePath)
|
||||
return B_NO_MEMORY;
|
||||
// initialize and add the device
|
||||
error = device->SetTo(filePath);
|
||||
// Note: Here we are allowed to lock a device although already having
|
||||
// the manager locked, since it is not yet added to the manager.
|
||||
DeviceWriteLocker deviceLocker(device);
|
||||
if (error == B_OK && !deviceLocker.IsLocked())
|
||||
error = B_ERROR;
|
||||
if (error == B_OK && !_AddDevice(device))
|
||||
error = B_NO_MEMORY;
|
||||
// scan device
|
||||
@ -650,11 +666,20 @@ KDiskDeviceManager::AddJobQueue(KDiskDeviceJobQueue *jobQueue)
|
||||
return error;
|
||||
}
|
||||
}
|
||||
// TODO: mark the concerned partitions busy /descendant busy
|
||||
// start its execution
|
||||
// mark the jobs scheduled
|
||||
for (int32 i = 0; KDiskDeviceJob *job = jobQueue->JobAt(i); i++)
|
||||
_UpdateJobStatus(job, B_DISK_DEVICE_JOB_SCHEDULED, false);
|
||||
_UpdateBusyPartitions(jobQueue->Device());
|
||||
// start the execution of the queue
|
||||
error = jobQueue->Execute();
|
||||
if (error != B_OK)
|
||||
if (error != B_OK) {
|
||||
// resuming the execution failed -- mark all jobs failed and
|
||||
// remove the queue
|
||||
for (int32 i = 0; KDiskDeviceJob *job = jobQueue->JobAt(i); i++)
|
||||
_UpdateJobStatus(job, B_DISK_DEVICE_JOB_FAILED, false);
|
||||
_RemoveJobQueue(jobQueue);
|
||||
_UpdateBusyPartitions(jobQueue->Device());
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
@ -704,6 +729,39 @@ KDiskDeviceManager::JobFactory() const
|
||||
return fJobFactory;
|
||||
}
|
||||
|
||||
// UpdateBusyPartitions
|
||||
status_t
|
||||
KDiskDeviceManager::UpdateBusyPartitions(KDiskDevice *device)
|
||||
{
|
||||
if (!device)
|
||||
return B_BAD_VALUE;
|
||||
if (DeviceWriteLocker deviceLocker = device) {
|
||||
if (ManagerLocker locker = this)
|
||||
return _UpdateBusyPartitions(device);
|
||||
}
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
// UpdateJobStatus
|
||||
status_t
|
||||
KDiskDeviceManager::UpdateJobStatus(KDiskDeviceJob *job, uint32 status,
|
||||
bool updateBusyPartitions)
|
||||
{
|
||||
// check parameters
|
||||
if (!job)
|
||||
return B_BAD_VALUE;
|
||||
KDiskDeviceJobQueue *jobQueue = job->JobQueue();
|
||||
KDiskDevice *device = (jobQueue ? jobQueue->Device() : NULL);
|
||||
if (!device)
|
||||
return B_BAD_VALUE;
|
||||
// lock device and manager
|
||||
if (DeviceWriteLocker deviceLocker = device) {
|
||||
if (ManagerLocker locker = this)
|
||||
return _UpdateJobStatus(job, status, updateBusyPartitions);
|
||||
}
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
// FindDiskSystem
|
||||
KDiskSystem *
|
||||
KDiskDeviceManager::FindDiskSystem(const char *name)
|
||||
@ -801,13 +859,20 @@ KDiskDeviceManager::InitialDeviceScan()
|
||||
error = _Scan("/dev/disk");
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
}
|
||||
// scan the devices for partitions
|
||||
int32 cookie = 0;
|
||||
while (KDiskDevice *device = NextDevice(&cookie)) {
|
||||
while (KDiskDevice *device = RegisterNextDevice(&cookie)) {
|
||||
PartitionRegistrar _(device, true);
|
||||
if (DeviceWriteLocker deviceLocker = device) {
|
||||
if (ManagerLocker locker = this) {
|
||||
error = _ScanPartition(device);
|
||||
if (error != B_OK)
|
||||
break;
|
||||
}
|
||||
} else
|
||||
return B_ERROR;
|
||||
} else
|
||||
return B_ERROR;
|
||||
}
|
||||
return error;
|
||||
}
|
||||
@ -893,6 +958,88 @@ KDiskDeviceManager::_RemoveJobQueue(KDiskDeviceJobQueue *jobQueue)
|
||||
return true;
|
||||
}
|
||||
|
||||
// _UpdateBusyPartitions
|
||||
status_t
|
||||
KDiskDeviceManager::_UpdateBusyPartitions(KDiskDevice *device)
|
||||
{
|
||||
if (!device)
|
||||
return B_BAD_VALUE;
|
||||
// mark all partitions un-busy
|
||||
struct UnmarkBusyVisitor : KPartitionVisitor {
|
||||
virtual bool VisitPre(KPartition *partition)
|
||||
{
|
||||
partition->ClearFlags(B_PARTITION_BUSY
|
||||
| B_PARTITION_DESCENDANT_BUSY);
|
||||
return false;
|
||||
}
|
||||
} visitor;
|
||||
device->VisitEachDescendant(&visitor);
|
||||
if (device->ShadowPartition())
|
||||
device->ShadowPartition()->VisitEachDescendant(&visitor);
|
||||
// Iterate through all job queues and all jobs scheduled or in
|
||||
// progress and mark their scope busy.
|
||||
for (int32 cookie = 0;
|
||||
KDiskDeviceJobQueue *jobQueue = NextJobQueue(&cookie); ) {
|
||||
if (jobQueue->Device() != device)
|
||||
continue;
|
||||
for (int32 i = jobQueue->ActiveJobIndex();
|
||||
KDiskDeviceJob *job = jobQueue->JobAt(i); i++) {
|
||||
if (job->Status() != B_DISK_DEVICE_JOB_IN_PROGRESS
|
||||
&& job->Status() == B_DISK_DEVICE_JOB_SCHEDULED) {
|
||||
continue;
|
||||
}
|
||||
KPartition *partition = FindPartition(job->ScopeID());
|
||||
if (!partition || partition->Device() != device)
|
||||
continue;
|
||||
partition->AddFlags(B_PARTITION_BUSY);
|
||||
if (KPartition *shadow = partition->ShadowPartition())
|
||||
shadow->AddFlags(B_PARTITION_BUSY);
|
||||
}
|
||||
}
|
||||
// mark all anscestors of busy partitions descendant busy
|
||||
struct MarkBusyVisitor : KPartitionVisitor {
|
||||
virtual bool VisitPost(KPartition *partition)
|
||||
{
|
||||
if ((partition->IsBusy() || partition->IsDescendantBusy())
|
||||
&& partition->Parent()) {
|
||||
partition->Parent()->AddFlags(
|
||||
B_PARTITION_DESCENDANT_BUSY);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
} visitor2;
|
||||
device->VisitEachDescendant(&visitor2);
|
||||
if (device->ShadowPartition())
|
||||
device->ShadowPartition()->VisitEachDescendant(&visitor2);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// _UpdateJobStatus
|
||||
status_t
|
||||
KDiskDeviceManager::_UpdateJobStatus(KDiskDeviceJob *job, uint32 status,
|
||||
bool updateBusyPartitions)
|
||||
{
|
||||
// check parameters
|
||||
if (!job)
|
||||
return B_BAD_VALUE;
|
||||
KDiskDeviceJobQueue *jobQueue = job->JobQueue();
|
||||
KDiskDevice *device = (jobQueue ? jobQueue->Device() : NULL);
|
||||
if (!device)
|
||||
return B_BAD_VALUE;
|
||||
if (job->Status() == status)
|
||||
return B_OK;
|
||||
// check migration of a schedule/in progress to a terminal state
|
||||
// or vice versa
|
||||
updateBusyPartitions &= (is_active_job_status(job->Status())
|
||||
!= is_active_job_status(status));
|
||||
// set new state and update the partitions' busy flags
|
||||
job->SetStatus(status);
|
||||
if (updateBusyPartitions)
|
||||
return _UpdateBusyPartitions(device);
|
||||
// TODO: notifications
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// _Scan
|
||||
status_t
|
||||
KDiskDeviceManager::_Scan(const char *path)
|
||||
|
Loading…
Reference in New Issue
Block a user