Files
haiku-beta6/src/system/kernel/disk_device_manager/KPartitioningSystem.cpp
T
Ingo Weinhold db5c68ca46 * Added the partition size as parameter to the file and partitioning
system initialize() hooks. It's often the only info about the
  partition one needs and thus locking the partition just to get it is
  no longer necessary.
* intel partitioning system:
  - Removed passing around block sizes. We require 512 byte sectors
    anyway. In fact using the parent partition's block size was even
    wrong.
  - Simplified writing the partition map sector.
  - Simplified and corrected the partition map initialization.
  - We don't fail identifying a partition anymore, if the partition map
    contains no partitions. We would never identify a freshly
    initialized partition map before.
  - Made pm_identify() more intelligent: It determines the priority to
    return depending on whether the partition is the device itself and
    whether we have recognized child partitions.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@22447 a95241bf-73f2-0310-859d-f6bbb57e9c96
2007-10-04 23:48:18 +00:00

899 lines
23 KiB
C++

/*
* Copyright 2003-2007, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Ingo Weinhold <[email protected]>
* Lubos Kulic <[email protected]>
*/
/** \file KPartitioningSystem.cpp
*
* \brief Implementation of \ref KPartitioningSystem class
*/
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <ddm_modules.h>
#include <KDiskDevice.h>
#include <KDiskDeviceJob.h>
#include <KDiskDeviceManager.h>
#include <KDiskDeviceUtils.h>
#include <KPartition.h>
#include <KPartitioningSystem.h>
// constructor
KPartitioningSystem::KPartitioningSystem(const char *name)
: KDiskSystem(name),
fModule(NULL)
{
}
// destructor
KPartitioningSystem::~KPartitioningSystem()
{
}
// Init
status_t
KPartitioningSystem::Init()
{
status_t error = KDiskSystem::Init();
if (error != B_OK)
return error;
error = Load();
if (error != B_OK)
return error;
error = SetPrettyName(fModule->pretty_name);
SetFlags(fModule->flags & ~(uint32)B_DISK_SYSTEM_IS_FILE_SYSTEM);
Unload();
return error;
}
// Identify
//! Try to identify a given partition
float
KPartitioningSystem::Identify(KPartition *partition, void **cookie)
{
if (!partition || !cookie || !fModule || !fModule->identify_partition)
return -1;
int fd = -1;
if (partition->Open(O_RDONLY, &fd) != B_OK)
return -1;
float result = fModule->identify_partition(fd, partition->PartitionData(),
cookie);
close(fd);
return result;
}
// Scan
//! Scan the partition
status_t
KPartitioningSystem::Scan(KPartition *partition, void *cookie)
{
if (!partition || !fModule || !fModule->scan_partition)
return B_ERROR;
int fd = -1;
status_t result = partition->Open(O_RDONLY, &fd);
if (result != B_OK)
return result;
result = fModule->scan_partition(fd, partition->PartitionData(), cookie);
close(fd);
return result;
}
// FreeIdentifyCookie
void
KPartitioningSystem::FreeIdentifyCookie(KPartition *partition, void *cookie)
{
if (!partition || !fModule || !fModule->free_identify_partition_cookie)
return;
fModule->free_identify_partition_cookie(partition->PartitionData(),
cookie);
}
// FreeCookie
void
KPartitioningSystem::FreeCookie(KPartition *partition)
{
if (!partition || !fModule || !fModule->free_partition_cookie
|| partition->ParentDiskSystem() != this) {
return;
}
fModule->free_partition_cookie(partition->PartitionData());
partition->SetCookie(NULL);
}
// FreeContentCookie
void
KPartitioningSystem::FreeContentCookie(KPartition *partition)
{
if (!partition || !fModule || !fModule->free_partition_content_cookie
|| partition->DiskSystem() != this) {
return;
}
fModule->free_partition_content_cookie(partition->PartitionData());
partition->SetContentCookie(NULL);
}
// GetSupportedOperations
uint32
KPartitioningSystem::GetSupportedOperations(KPartition* partition, uint32 mask)
{
ASSERT(partition != NULL);
// Note, that for initialization, the partition's disk system does not
// need to be this disk system.
if (!fModule)
return 0;
if (!fModule->get_supported_operations)
return (Flags() & mask);
return fModule->get_supported_operations(partition->PartitionData(), mask)
& mask;
}
// GetSupportedChildOperations
uint32
KPartitioningSystem::GetSupportedChildOperations(KPartition* child, uint32 mask)
{
ASSERT(child != NULL);
ASSERT(child->Parent() != NULL);
ASSERT(child->Parent()->DiskSystem() == this);
if (!fModule)
return 0;
if (!fModule->get_supported_child_operations)
return (Flags() & mask);
return fModule->get_supported_child_operations(
child->Parent()->PartitionData(), child->PartitionData(), mask)
& mask;
}
// SupportsInitializingChild
/*! Check whether the child partition managed by this partitioning system can
be initialized with the given disk system.
*/
bool
KPartitioningSystem::SupportsInitializingChild(KPartition *child,
const char *diskSystem)
{
if (!child || child->ParentDiskSystem() != this || !diskSystem
|| !fModule)
return false;
// If the hook is not implemented, the parent disk system doesn't want a
// veto.
if (!fModule->supports_initializing_child)
return true;
return fModule->supports_initializing_child(child->PartitionData(),
diskSystem);
}
// IsSubSystemFor
//! Check whether the add-on is a subsystem for a given partition.
bool
KPartitioningSystem::IsSubSystemFor(KPartition *partition)
{
return (partition && fModule && fModule->is_sub_system_for
&& fModule->is_sub_system_for(partition->PartitionData()));
}
// ValidateResize
//! Validates parameters for resizing a partition
bool
KPartitioningSystem::ValidateResize(KPartition *partition, off_t *size)
{
return (partition && size && partition->DiskSystem() == this && fModule
&& fModule->validate_resize
&& fModule->validate_resize(partition->PartitionData(), size));
}
// ValidateResizeChild
//! Validates parameters for resizing a child partition
bool
KPartitioningSystem::ValidateResizeChild(KPartition *child, off_t *size)
{
return (child && size && child->Parent()
&& child->ParentDiskSystem() == this && fModule
&& fModule->validate_resize_child
&& fModule->validate_resize_child(child->Parent()->PartitionData(),
child->PartitionData(), size));
}
// ValidateMove
//! Validates parameters for moving a partition
bool
KPartitioningSystem::ValidateMove(KPartition *partition, off_t *start)
{
return (partition && start && partition->DiskSystem() == this && fModule
&& fModule->validate_move
&& fModule->validate_move(partition->PartitionData(), start));
}
// ValidateMoveChild
//! Validates parameters for moving a child partition
bool
KPartitioningSystem::ValidateMoveChild(KPartition *child, off_t *start)
{
return (child && start && child->Parent()
&& child->ParentDiskSystem() == this && fModule
&& fModule->validate_move_child
&& fModule->validate_move_child(child->Parent()->PartitionData(),
child->PartitionData(), start));
}
// ValidateSetName
//! Validates parameters for setting name of a partition
bool
KPartitioningSystem::ValidateSetName(KPartition *partition, char *name)
{
return (partition && name && partition->Parent()
&& partition->ParentDiskSystem() == this && fModule
&& fModule->validate_set_name
&& fModule->validate_set_name(partition->PartitionData(), name));
}
// ValidateSetContentName
//! Validates parameters for setting name of the content of a partition
bool
KPartitioningSystem::ValidateSetContentName(KPartition *partition, char *name)
{
return (partition && name && partition->DiskSystem() == this
&& fModule && fModule->validate_set_content_name
&& fModule->validate_set_content_name(partition->PartitionData(),
name));
}
// ValidateSetType
//! Validates parameters for setting type of a partition
bool
KPartitioningSystem::ValidateSetType(KPartition *partition, const char *type)
{
return (partition && type && partition->ParentDiskSystem() == this
&& fModule && fModule->validate_set_type
&& fModule->validate_set_type(partition->PartitionData(), type));
}
// ValidateSetParameters
//! Validates parameters for setting parameters of a partition
bool
KPartitioningSystem::ValidateSetParameters(KPartition *partition,
const char *parameters)
{
return (partition && partition->ParentDiskSystem() == this
&& fModule && fModule->validate_set_parameters
&& fModule->validate_set_parameters(partition->PartitionData(),
parameters));
}
// ValidateSetContentParameters
//! Validates parameters for setting parameters of the content of a partition
bool
KPartitioningSystem::ValidateSetContentParameters(KPartition *partition,
const char *parameters)
{
return (partition && partition->DiskSystem() == this && fModule
&& fModule->validate_set_content_parameters
&& fModule->validate_set_content_parameters(
partition->PartitionData(), parameters));
}
// ValidateInitialize
//! Validates parameters for initializing a partition
bool
KPartitioningSystem::ValidateInitialize(KPartition *partition, char *name,
const char *parameters)
{
return (partition && name && fModule && fModule->validate_initialize
&& fModule->validate_initialize(partition->PartitionData(), name,
parameters));
}
// ValidateCreateChild
//! Validates parameters for creating child of a partition
bool
KPartitioningSystem::ValidateCreateChild(KPartition *partition, off_t *start,
off_t *size, const char *type, const char *parameters, int32 *index)
{
int32 _index = 0;
if (!index)
index = &_index;
return (partition && start && size && type
&& partition->DiskSystem() == this && fModule
&& fModule->validate_create_child
&& fModule->validate_create_child(partition->PartitionData(), start,
size, type, parameters, index));
}
// CountPartitionableSpaces
//! Counts partitionable spaces on a partition
int32
KPartitioningSystem::CountPartitionableSpaces(KPartition *partition)
{
if (!partition || partition->DiskSystem() != this || !fModule)
return 0;
if (!fModule->get_partitionable_spaces) {
// TODO: Fallback algorithm.
return 0;
}
int32 count = 0;
status_t error = fModule->get_partitionable_spaces(
partition->PartitionData(), NULL, 0, &count);
return (error == B_OK || error == B_BUFFER_OVERFLOW ? count : 0);
}
// GetPartitionableSpaces
//! Retrieves a list of partitionable spaces on a partition
status_t
KPartitioningSystem::GetPartitionableSpaces(KPartition *partition,
partitionable_space_data *buffer, int32 count, int32 *actualCount)
{
if (!partition || partition->DiskSystem() != this || count > 0 && !buffer
|| !actualCount || !fModule) {
return B_BAD_VALUE;
}
if (!fModule->get_partitionable_spaces) {
// TODO: Fallback algorithm.
return B_ENTRY_NOT_FOUND;
}
return fModule->get_partitionable_spaces(partition->PartitionData(),
buffer, count, actualCount);
}
// GetNextSupportedType
//! Iterates through supported partition types
status_t
KPartitioningSystem::GetNextSupportedType(KPartition *partition, int32 *cookie,
char *type)
{
if (!partition || partition->DiskSystem() != this || !cookie || !type
|| !fModule) {
return B_BAD_VALUE;
}
if (!fModule->get_next_supported_type)
return B_ENTRY_NOT_FOUND;
return fModule->get_next_supported_type(partition->PartitionData(), cookie,
type);
}
// GetTypeForContentType
//! Translates the "pretty" content type to an internal type
status_t
KPartitioningSystem::GetTypeForContentType(const char *contentType, char *type)
{
if (!contentType || !type || !fModule)
return B_BAD_VALUE;
if (!fModule->get_type_for_content_type)
return B_ENTRY_NOT_FOUND;
return fModule->get_type_for_content_type(contentType, type);
}
// ShadowPartitionChanged
//! Calls for additional modifications when shadow partition is changed
status_t
KPartitioningSystem::ShadowPartitionChanged(KPartition *partition,
uint32 operation)
{
if (!partition)
return B_BAD_VALUE;
if (!fModule)
return B_ERROR;
// If not implemented, we assume, that the partitioning system doesn't
// have to make any additional changes.
if (!fModule->shadow_changed)
return B_OK;
return fModule->shadow_changed(partition->PartitionData(), operation);
}
// Repair
//! Repairs a partition
status_t
KPartitioningSystem::Repair(KPartition *partition, bool checkOnly,
KDiskDeviceJob *job)
{
// to be implemented
return B_ERROR;
}
// Resize
//! Resizes a partition
status_t
KPartitioningSystem::Resize(KPartition *partition, off_t size,
KDiskDeviceJob *job)
{
// check parameters
if (!partition || !job || size < 0)
return B_BAD_VALUE;
if (!fModule->resize)
return B_ENTRY_NOT_FOUND;
// lock partition and open partition device
KDiskDeviceManager *manager = KDiskDeviceManager::Default();
KPartition *_partition = manager->WriteLockPartition(partition->ID());
if (!_partition)
return B_ERROR;
int fd = -1;
{
PartitionRegistrar registrar(_partition, true);
PartitionRegistrar deviceRegistrar(_partition->Device(), true);
DeviceWriteLocker locker(_partition->Device(), true);
if (partition != _partition)
return B_ERROR;
status_t result = partition->Open(O_RDWR, &fd);
if (result != B_OK)
return result;
}
// let the module do its job
status_t result = fModule->resize(fd, partition->ID(), size, job->ID());
// cleanup and return
close(fd);
return result;
}
// ResizeChild
//! Resizes child of a partition
status_t
KPartitioningSystem::ResizeChild(KPartition *child, off_t size,
KDiskDeviceJob *job)
{
// check parameters
if (!child || !job || !child->Parent() || size < 0)
return B_BAD_VALUE;
if (!fModule->resize_child)
return B_ENTRY_NOT_FOUND;
// lock partition and open (parent) partition device
KDiskDeviceManager *manager = KDiskDeviceManager::Default();
KPartition *_partition = manager->WriteLockPartition(child->ID());
KPartition *_parent = manager->WriteLockPartition(child->Parent()->ID());
if (!_partition)
return B_ERROR;
int fd = -1;
{
PartitionRegistrar registrar(_partition, true);
PartitionRegistrar deviceRegistrar(_partition->Device(), true);
DeviceWriteLocker locker(_partition->Device(), true);
if (child != _partition)
return B_ERROR;
status_t result = child->Parent()->Open(O_RDWR, &fd);
if (result != B_OK)
return result;
}
// let the module do its job
status_t result = fModule->resize_child(fd, child->ID(), size, job->ID());
// cleanup and return
close(fd);
return result;
}
// Move
//! Moves a partition
status_t
KPartitioningSystem::Move(KPartition *partition, off_t offset,
KDiskDeviceJob *job)
{
// check parameters
if (!partition || !job)
return B_BAD_VALUE;
if (!fModule->move)
return B_ENTRY_NOT_FOUND;
// lock partition and open partition device
KDiskDeviceManager *manager = KDiskDeviceManager::Default();
KPartition *_partition = manager->WriteLockPartition(partition->ID());
if (!_partition)
return B_ERROR;
int fd = -1;
{
PartitionRegistrar registrar(_partition, true);
PartitionRegistrar deviceRegistrar(_partition->Device(), true);
DeviceWriteLocker locker(_partition->Device(), true);
if (partition != _partition)
return B_ERROR;
status_t result = partition->Open(O_RDWR, &fd);
if (result != B_OK)
return result;
}
// let the module do its job
status_t result = fModule->move(fd, partition->ID(), offset, job->ID());
// cleanup and return
close(fd);
return result;
}
// MoveChild
//! Moves child of a partition
status_t
KPartitioningSystem::MoveChild(KPartition *child, off_t offset,
KDiskDeviceJob *job)
{
// check parameters
if (!child || !job || !child->Parent())
return B_BAD_VALUE;
if (!fModule->move_child)
return B_ENTRY_NOT_FOUND;
// lock partition and open (parent) partition device
KDiskDeviceManager *manager = KDiskDeviceManager::Default();
KPartition *_partition = manager->WriteLockPartition(child->ID());
KPartition *_parent = manager->WriteLockPartition(child->Parent()->ID());
if (!_partition)
return B_ERROR;
int fd = -1;
{
PartitionRegistrar registrar(_partition, true);
PartitionRegistrar deviceRegistrar(_partition->Device(), true);
DeviceWriteLocker locker(_partition->Device(), true);
if (child != _partition)
return B_ERROR;
status_t result = child->Parent()->Open(O_RDWR, &fd);
if (result != B_OK)
return result;
}
// let the module do its job
status_t result = fModule->move_child(fd, child->Parent()->ID(),
child->ID(), offset, job->ID());
// cleanup and return
close(fd);
return result;
}
// SetName
//! Sets name of a partition
status_t
KPartitioningSystem::SetName(KPartition *partition, char *name,
KDiskDeviceJob *job)
{
// check parameters
if (!partition || !job || !name)
return B_BAD_VALUE;
if (!fModule->set_name)
return B_ENTRY_NOT_FOUND;
// lock partition and open partition device
KDiskDeviceManager *manager = KDiskDeviceManager::Default();
KPartition *_partition = manager->WriteLockPartition(partition->ID());
if (!_partition)
return B_ERROR;
int fd = -1;
{
PartitionRegistrar registrar(_partition, true);
PartitionRegistrar deviceRegistrar(_partition->Device(), true);
DeviceWriteLocker locker(_partition->Device(), true);
if (partition != _partition)
return B_ERROR;
status_t result = partition->Open(O_RDWR, &fd);
if (result != B_OK)
return result;
}
// let the module do its job
status_t result = fModule->set_name(fd, partition->ID(), name, job->ID());
// cleanup and return
close(fd);
return result;
}
// SetContentName
//! Sets name of the content of a partition
status_t
KPartitioningSystem::SetContentName(KPartition *partition, char *name,
KDiskDeviceJob *job)
{
// check parameters
if (!partition || !job || !name)
return B_BAD_VALUE;
if (!fModule->set_content_name)
return B_ENTRY_NOT_FOUND;
// lock partition and open partition device
KDiskDeviceManager *manager = KDiskDeviceManager::Default();
KPartition *_partition = manager->WriteLockPartition(partition->ID());
if (!_partition)
return B_ERROR;
int fd = -1;
{
PartitionRegistrar registrar(_partition, true);
PartitionRegistrar deviceRegistrar(_partition->Device(), true);
DeviceWriteLocker locker(_partition->Device(), true);
if (partition != _partition)
return B_ERROR;
status_t result = partition->Open(O_RDWR, &fd);
if (result != B_OK)
return result;
}
// let the module do its job
status_t result = fModule->set_content_name(fd, partition->ID(), name,
job->ID());
// cleanup and return
close(fd);
return result;
}
// SetType
//! Sets type of a partition
status_t
KPartitioningSystem::SetType(KPartition *partition, char *type,
KDiskDeviceJob *job)
{
// check parameters
if (!partition || !job || !type)
return B_BAD_VALUE;
if (!fModule->set_type)
return B_ENTRY_NOT_FOUND;
// lock partition and open partition device
KDiskDeviceManager *manager = KDiskDeviceManager::Default();
KPartition *_partition = manager->WriteLockPartition(partition->ID());
if (!_partition)
return B_ERROR;
int fd = -1;
{
PartitionRegistrar registrar(_partition, true);
PartitionRegistrar deviceRegistrar(_partition->Device(), true);
DeviceWriteLocker locker(_partition->Device(), true);
if (partition != _partition)
return B_ERROR;
status_t result = partition->Open(O_RDWR, &fd);
if (result != B_OK)
return result;
}
// let the module do its job
status_t result = fModule->set_type(fd, partition->ID(), type, job->ID());
// cleanup and return
close(fd);
return result;
}
// SetParameters
//! Sets parameters of a partition
status_t
KPartitioningSystem::SetParameters(KPartition *partition,
const char *parameters, KDiskDeviceJob *job)
{
// check parameters
if (!partition || !job || !parameters)
return B_BAD_VALUE;
if (!fModule->set_parameters)
return B_ENTRY_NOT_FOUND;
// lock partition and open partition device
KDiskDeviceManager *manager = KDiskDeviceManager::Default();
KPartition *_partition = manager->WriteLockPartition(partition->ID());
if (!_partition)
return B_ERROR;
int fd = -1;
{
PartitionRegistrar registrar(_partition, true);
PartitionRegistrar deviceRegistrar(_partition->Device(), true);
DeviceWriteLocker locker(_partition->Device(), true);
if (partition != _partition)
return B_ERROR;
status_t result = partition->Open(O_RDWR, &fd);
if (result != B_OK)
return result;
}
// let the module do its job
status_t result = fModule->set_parameters(fd, partition->ID(), parameters,
job->ID());
// cleanup and return
close(fd);
return result;
}
// SetContentParameters
//! Sets parameters of the content of a partition
status_t
KPartitioningSystem::SetContentParameters(KPartition *partition,
const char *parameters, KDiskDeviceJob *job)
{
// check parameters
if (!partition || !job || !parameters)
return B_BAD_VALUE;
if (!fModule->set_content_parameters)
return B_ENTRY_NOT_FOUND;
// lock partition and open partition device
KDiskDeviceManager *manager = KDiskDeviceManager::Default();
KPartition *_partition = manager->WriteLockPartition(partition->ID());
if (!_partition)
return B_ERROR;
int fd = -1;
{
PartitionRegistrar registrar(_partition, true);
PartitionRegistrar deviceRegistrar(_partition->Device(), true);
DeviceWriteLocker locker(_partition->Device(), true);
if (partition != _partition)
return B_ERROR;
status_t result = partition->Open(O_RDWR, &fd);
if (result != B_OK)
return result;
}
// let the module do its job
status_t result = fModule->set_content_parameters(fd, partition->ID(),
parameters, job->ID());
// cleanup and return
close(fd);
return result;
}
// Initialize
//! Initializes a partition with this partitioning system
status_t
KPartitioningSystem::Initialize(KPartition *partition, const char *name,
const char *parameters, KDiskDeviceJob *job)
{
// check parameters
if (!partition || !job || !name /*|| !parameters*/)
return B_BAD_VALUE;
if (!fModule->initialize)
return B_ENTRY_NOT_FOUND;
// lock partition and open partition device
KDiskDeviceManager *manager = KDiskDeviceManager::Default();
// TODO: This looks overly complicated.
KPartition *_partition = manager->WriteLockPartition(partition->ID());
if (!_partition)
return B_ERROR;
int fd = -1;
off_t partitionSize;
{
PartitionRegistrar registrar(_partition, true);
PartitionRegistrar deviceRegistrar(_partition->Device(), true);
DeviceWriteLocker locker(_partition->Device(), true);
if (partition != _partition)
return B_ERROR;
status_t result = partition->Open(O_RDWR, &fd);
if (result != B_OK)
return result;
partitionSize = partition->Size();
}
// let the module do its job
status_t result = fModule->initialize(fd, partition->ID(), name, parameters,
partitionSize, job->ID());
// cleanup and return
close(fd);
return result;
}
// CreateChild
//! Creates a child partition
status_t
KPartitioningSystem::CreateChild(KPartition *partition, off_t offset,
off_t size, const char *type, const char *parameters, KDiskDeviceJob *job,
KPartition **child, partition_id childID)
{
// check parameters
if (!partition || !job || !type /*|| !parameters*/ || !child)
return B_BAD_VALUE;
if (!fModule->create_child)
return B_ENTRY_NOT_FOUND;
// lock partition and open partition device
KDiskDeviceManager *manager = KDiskDeviceManager::Default();
KPartition *_partition = manager->WriteLockPartition(partition->ID());
if (!_partition)
return B_ERROR;
int fd = -1;
{
PartitionRegistrar registrar(_partition, true);
PartitionRegistrar deviceRegistrar(_partition->Device(), true);
DeviceWriteLocker locker(_partition->Device(), true);
if (partition != _partition)
return B_ERROR;
status_t result = partition->Open(O_RDWR, &fd);
if (result != B_OK)
return result;
}
// let the module do its job
status_t result = fModule->create_child(fd, partition->ID(), offset, size,
type, parameters, job->ID(), &childID);
// find and return the child
*child = manager->FindPartition(childID, false);
// cleanup and return
close(fd);
return result;
}
// DeleteChild
//! Deletes a child partition
status_t
KPartitioningSystem::DeleteChild(KPartition *child, KDiskDeviceJob *job)
{
// to be implemented
return B_ERROR;
}
// LoadModule
status_t
KPartitioningSystem::LoadModule()
{
if (fModule) // shouldn't happen
return B_OK;
return get_module(Name(), (module_info**)&fModule);
}
// UnloadModule
void
KPartitioningSystem::UnloadModule()
{
if (fModule) {
put_module(fModule->module.name);
fModule = NULL;
}
}