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
|
// manager must be locked
|
||||||
status_t AddJobQueue(KDiskDeviceJobQueue *jobQueue);
|
status_t AddJobQueue(KDiskDeviceJobQueue *jobQueue);
|
||||||
|
// the device must be write locked
|
||||||
status_t RemoveJobQueue(KDiskDeviceJobQueue *jobQueue);
|
status_t RemoveJobQueue(KDiskDeviceJobQueue *jobQueue);
|
||||||
status_t DeleteJobQueue(KDiskDeviceJobQueue *jobQueue);
|
status_t DeleteJobQueue(KDiskDeviceJobQueue *jobQueue);
|
||||||
// called when the execution is done
|
// called when the execution is done
|
||||||
|
@ -89,6 +90,11 @@ public:
|
||||||
|
|
||||||
KDiskDeviceJobFactory *JobFactory() const;
|
KDiskDeviceJobFactory *JobFactory() const;
|
||||||
|
|
||||||
|
// manager must *not* be locked
|
||||||
|
status_t UpdateBusyPartitions(KDiskDevice *device);
|
||||||
|
status_t UpdateJobStatus(KDiskDeviceJob *job, uint32 status,
|
||||||
|
bool updateBusyPartitions);
|
||||||
|
|
||||||
// Disk Systems
|
// Disk Systems
|
||||||
|
|
||||||
// manager must be locked
|
// manager must be locked
|
||||||
|
@ -118,8 +124,13 @@ private:
|
||||||
|
|
||||||
bool _RemoveJobQueue(KDiskDeviceJobQueue *jobQueue);
|
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 _Scan(const char *path);
|
||||||
status_t _ScanPartition(KPartition *partition);
|
status_t _ScanPartition(KPartition *partition);
|
||||||
|
// the manager must be locked and the device write locked
|
||||||
|
|
||||||
struct DeviceMap;
|
struct DeviceMap;
|
||||||
struct DiskSystemMap;
|
struct DiskSystemMap;
|
||||||
|
|
|
@ -187,9 +187,8 @@ KDiskDeviceJobQueue::Execute()
|
||||||
fSyncSemaphore = -1;
|
fSyncSemaphore = -1;
|
||||||
return fThread;
|
return fThread;
|
||||||
}
|
}
|
||||||
|
fFlags |= JOB_QUEUE_EXECUTING;
|
||||||
resume_thread(fThread);
|
resume_thread(fThread);
|
||||||
// wait till the thread has resumed its work
|
|
||||||
acquire_sem(fSyncSemaphore);
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -301,45 +300,45 @@ KDiskDeviceJobQueue::IsPauseRequested() const
|
||||||
int32
|
int32
|
||||||
KDiskDeviceJobQueue::_ThreadLoop()
|
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();
|
KDiskDeviceManager *manager = KDiskDeviceManager::Default();
|
||||||
// main loop: process all jobs
|
// main loop: process all jobs
|
||||||
|
bool failed = false;
|
||||||
while (KDiskDeviceJob *activeJob = ActiveJob()) {
|
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();
|
status_t error = activeJob->Do();
|
||||||
if (error == B_OK) {
|
if (error == B_OK) {
|
||||||
if (ManagerLocker locker = manager) {
|
if (ManagerLocker locker = manager) {
|
||||||
// if canceled, mark this and all succeeding jobs canceled
|
// if canceled, simply bail out -- this and all succeeding
|
||||||
if (IsCanceled()) {
|
// jobs will be canceled
|
||||||
for (int32 i = fActiveJob; KDiskDeviceJob *job = JobAt(i);
|
if (IsCanceled())
|
||||||
i++) {
|
|
||||||
job->SetStatus(B_DISK_DEVICE_JOB_CANCELED);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
// if pause was requested ignore the request
|
// if pause was requested ignore the request
|
||||||
if (IsPauseRequested())
|
if (IsPauseRequested())
|
||||||
Continue();
|
Continue();
|
||||||
// mark the job succeeded and go to the next one
|
// go to the next job
|
||||||
activeJob->SetStatus(B_DISK_DEVICE_JOB_SUCCEEDED);
|
|
||||||
fActiveJob++;
|
fActiveJob++;
|
||||||
} else
|
} else
|
||||||
break;
|
break;
|
||||||
|
// mark the job succeeded
|
||||||
|
manager->UpdateJobStatus(activeJob, B_DISK_DEVICE_JOB_SUCCEEDED,
|
||||||
|
true);
|
||||||
} else {
|
} else {
|
||||||
// job failed: mark this and all succeeding jobs failed
|
// job failed: this and all succeeding jobs will be marked failed
|
||||||
if (ManagerLocker locker = manager) {
|
failed = true;
|
||||||
for (int32 i = fActiveJob; KDiskDeviceJob *job = JobAt(i); i++)
|
|
||||||
job->SetStatus(B_DISK_DEVICE_JOB_FAILED);
|
|
||||||
}
|
|
||||||
break;
|
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.
|
// tell the manager, that we are done.
|
||||||
if (ManagerLocker locker = manager) {
|
if (ManagerLocker locker = manager) {
|
||||||
fFlags &= ~(uint32)JOB_QUEUE_EXECUTING;
|
fFlags &= ~(uint32)JOB_QUEUE_EXECUTING;
|
||||||
|
|
|
@ -22,6 +22,8 @@
|
||||||
#include "KFileSystem.h"
|
#include "KFileSystem.h"
|
||||||
#include "KPartition.h"
|
#include "KPartition.h"
|
||||||
#include "KPartitioningSystem.h"
|
#include "KPartitioningSystem.h"
|
||||||
|
#include "KPartitionVisitor.h"
|
||||||
|
#include "KShadowPartition.h"
|
||||||
|
|
||||||
// debugging
|
// debugging
|
||||||
//#define DBG(x)
|
//#define DBG(x)
|
||||||
|
@ -36,6 +38,15 @@ using BPrivate::DiskDevice::KDiskDeviceJobQueue;
|
||||||
static const char *kPartitioningSystemPrefix = "partitioning_systems";
|
static const char *kPartitioningSystemPrefix = "partitioning_systems";
|
||||||
static const char *kFileSystemPrefix = "file_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
|
// GetPartitionID
|
||||||
struct GetPartitionID {
|
struct GetPartitionID {
|
||||||
inline partition_id operator()(const KPartition *partition) const
|
inline partition_id operator()(const KPartition *partition) const
|
||||||
|
@ -494,6 +505,11 @@ KDiskDeviceManager::CreateFileDevice(const char *filePath)
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
// initialize and add the device
|
// initialize and add the device
|
||||||
error = device->SetTo(filePath);
|
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))
|
if (error == B_OK && !_AddDevice(device))
|
||||||
error = B_NO_MEMORY;
|
error = B_NO_MEMORY;
|
||||||
// scan device
|
// scan device
|
||||||
|
@ -650,11 +666,20 @@ KDiskDeviceManager::AddJobQueue(KDiskDeviceJobQueue *jobQueue)
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO: mark the concerned partitions busy /descendant busy
|
// mark the jobs scheduled
|
||||||
// start its execution
|
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();
|
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);
|
_RemoveJobQueue(jobQueue);
|
||||||
|
_UpdateBusyPartitions(jobQueue->Device());
|
||||||
|
}
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -704,6 +729,39 @@ KDiskDeviceManager::JobFactory() const
|
||||||
return fJobFactory;
|
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
|
// FindDiskSystem
|
||||||
KDiskSystem *
|
KDiskSystem *
|
||||||
KDiskDeviceManager::FindDiskSystem(const char *name)
|
KDiskDeviceManager::FindDiskSystem(const char *name)
|
||||||
|
@ -801,13 +859,20 @@ KDiskDeviceManager::InitialDeviceScan()
|
||||||
error = _Scan("/dev/disk");
|
error = _Scan("/dev/disk");
|
||||||
if (error != B_OK)
|
if (error != B_OK)
|
||||||
return error;
|
return error;
|
||||||
// scan the devices for partitions
|
}
|
||||||
int32 cookie = 0;
|
// scan the devices for partitions
|
||||||
while (KDiskDevice *device = NextDevice(&cookie)) {
|
int32 cookie = 0;
|
||||||
error = _ScanPartition(device);
|
while (KDiskDevice *device = RegisterNextDevice(&cookie)) {
|
||||||
if (error != B_OK)
|
PartitionRegistrar _(device, true);
|
||||||
break;
|
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;
|
return error;
|
||||||
}
|
}
|
||||||
|
@ -893,6 +958,88 @@ KDiskDeviceManager::_RemoveJobQueue(KDiskDeviceJobQueue *jobQueue)
|
||||||
return true;
|
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
|
// _Scan
|
||||||
status_t
|
status_t
|
||||||
KDiskDeviceManager::_Scan(const char *path)
|
KDiskDeviceManager::_Scan(const char *path)
|
||||||
|
|
Loading…
Reference in New Issue