* Moved the checksum device driver to subdir "driver".

* Created a file system module and a disk system add-on. Currently only
  initializing and identifying/scanning is supported.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@37300 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold 2010-06-29 10:52:16 +00:00
parent 06237dd800
commit 952d6c8cc4
14 changed files with 840 additions and 14 deletions

View File

@ -1,16 +1,5 @@
SubDir HAIKU_TOP src tests system kernel file_corruption ;
SubDirHdrs $(HAIKU_TOP) src system kernel device_manager ;
UsePrivateKernelHeaders ;
KernelAddon <test_driver>checksum_device :
checksum_device.cpp
# from src/kits/shared
SHA256.cpp
;
SEARCH on [ FGristFiles SHA256.cpp ]
= [ FDirName $(HAIKU_TOP) src kits shared ] ;
HaikuSubInclude disk_system ;
HaikuSubInclude driver ;
HaikuSubInclude fs ;

View File

@ -0,0 +1,41 @@
/*
* Copyright 2010, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#ifndef CHECK_SUM_FS_H
#define CHECK_SUM_FS_H
#include <OS.h>
#define CHECK_SUM_FS_PRETTY_NAME "CheckSum File System"
static const uint64 kCheckSumFSSuperBlockOffset = 16 * B_PAGE_SIZE;
static const uint64 kCheckSumFSMinSize
= kCheckSumFSSuperBlockOffset + 16 * B_PAGE_SIZE;
static const uint32 kCheckSumFSNameLength = 256;
static const uint32 kCheckSumFSSignatureLength = 16;
#define CHECK_SUM_FS_SIGNATURE_1 "_1!cHEcKsUmfS!1_"
#define CHECK_SUM_FS_SIGNATURE_2 "-2@ChECkSumFs@2-"
static const uint32 kCheckSumFSVersion = 1;
struct checksumfs_super_block {
char signature1[kCheckSumFSSignatureLength];
uint32 version;
uint32 pad1;
uint64 totalBlocks;
uint64 freeBlocks;
uint64 rootDir;
uint64 blockBitmap;
char name[kCheckSumFSNameLength];
char signature2[kCheckSumFSSignatureLength];
} _PACKED;
#endif // CHECK_SUM_FS_H

View File

@ -0,0 +1,13 @@
SubDir HAIKU_TOP src tests system kernel file_corruption disk_system ;
UsePrivateHeaders shared storage ;
UseHeaders [ FDirName $(SUBDIR) $(DOTDOT) ] ;
Addon <disk_system>checksumfs :
checksumfs.cpp
: be $(TARGET_LIBSTDC++)
;

View File

@ -0,0 +1,212 @@
/*
* Copyright 2010, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#include <new>
#include <DiskDeviceDefs.h>
#include <DiskSystemAddOn.h>
#include <AutoDeleter.h>
#include <MutablePartition.h>
#include "checksumfs.h"
static const uint32 kDiskSystemFlags =
0
// | B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_NAME
// | B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_PARAMETERS
| B_DISK_SYSTEM_SUPPORTS_INITIALIZING
| B_DISK_SYSTEM_SUPPORTS_CONTENT_NAME
// | B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_NAME_WHILE_MOUNTED
// | B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_PARAMETERS_WHILE_MOUNTED
;
class CheckSumFSAddOn : public BDiskSystemAddOn {
public:
CheckSumFSAddOn();
virtual status_t CreatePartitionHandle(
BMutablePartition* partition,
BPartitionHandle** _handle);
virtual bool CanInitialize(
const BMutablePartition* partition);
virtual status_t GetInitializationParameterEditor(
const BMutablePartition* partition,
BPartitionParameterEditor** _editor);
virtual status_t ValidateInitialize(
const BMutablePartition* partition,
BString* name, const char* parameters);
virtual status_t Initialize(BMutablePartition* partition,
const char* name, const char* parameters,
BPartitionHandle** _handle);
};
class CheckSumFSPartitionHandle : public BPartitionHandle {
public:
CheckSumFSPartitionHandle(
BMutablePartition* partition);
~CheckSumFSPartitionHandle();
status_t Init();
virtual uint32 SupportedOperations(uint32 mask);
};
// #pragma mark - CheckSumFSAddOn
CheckSumFSAddOn::CheckSumFSAddOn()
:
BDiskSystemAddOn(CHECK_SUM_FS_PRETTY_NAME, kDiskSystemFlags)
{
}
status_t
CheckSumFSAddOn::CreatePartitionHandle(BMutablePartition* partition,
BPartitionHandle** _handle)
{
debug_printf("CheckSumFSAddOn::CreatePartitionHandle()\n");
CheckSumFSPartitionHandle* handle
= new(std::nothrow) CheckSumFSPartitionHandle(partition);
if (handle == NULL)
return B_NO_MEMORY;
status_t error = handle->Init();
if (error != B_OK) {
delete handle;
return error;
}
*_handle = handle;
return B_OK;
}
bool
CheckSumFSAddOn::CanInitialize(const BMutablePartition* partition)
{
debug_printf("CheckSumFSAddOn::CanInitialize()\n");
return (uint64)partition->Size() >= kCheckSumFSMinSize;
}
status_t
CheckSumFSAddOn::GetInitializationParameterEditor(
const BMutablePartition* partition, BPartitionParameterEditor** _editor)
{
debug_printf("CheckSumFSAddOn::GetInitializationParameterEditor()\n");
*_editor = NULL;
return B_OK;
}
status_t
CheckSumFSAddOn::ValidateInitialize(const BMutablePartition* partition,
BString* name, const char* parameters)
{
debug_printf("CheckSumFSAddOn::ValidateInitialize()\n");
if (!CanInitialize(partition) || name == NULL)
return B_BAD_VALUE;
// truncate name, if too long
if ((uint64)name->Length() >= kCheckSumFSNameLength)
name->Truncate(kCheckSumFSNameLength - 1);
// replace '/' by '-'
name->ReplaceAll('/', '-');
return B_OK;
}
status_t
CheckSumFSAddOn::Initialize(BMutablePartition* partition, const char* name,
const char* parameters, BPartitionHandle** _handle)
{
debug_printf("CheckSumFSAddOn::Initialize()\n");
if (!CanInitialize(partition) || name == NULL
|| strlen(name) >= kCheckSumFSNameLength) {
return B_BAD_VALUE;
}
CheckSumFSPartitionHandle* handle
= new(std::nothrow) CheckSumFSPartitionHandle(partition);
if (handle == NULL)
return B_NO_MEMORY;
ObjectDeleter<CheckSumFSPartitionHandle> handleDeleter(handle);
status_t error = partition->SetContentType(Name());
if (error != B_OK)
return error;
partition->SetContentName(name);
partition->SetContentParameters(parameters);
partition->SetBlockSize(B_PAGE_SIZE);
partition->SetContentSize(partition->Size() / B_PAGE_SIZE * B_PAGE_SIZE);
partition->Changed(B_PARTITION_CHANGED_INITIALIZATION);
*_handle = handleDeleter.Detach();
return B_OK;
}
// #pragma mark - CheckSumFSPartitionHandle
CheckSumFSPartitionHandle::CheckSumFSPartitionHandle(
BMutablePartition* partition)
:
BPartitionHandle(partition)
{
}
CheckSumFSPartitionHandle::~CheckSumFSPartitionHandle()
{
}
status_t
CheckSumFSPartitionHandle::Init()
{
return B_OK;
}
uint32
CheckSumFSPartitionHandle::SupportedOperations(uint32 mask)
{
return kDiskSystemFlags & mask;
}
// #pragma mark -
status_t
get_disk_system_add_ons(BList* addOns)
{
debug_printf("checksumfs: get_disk_system_add_ons()\n");
CheckSumFSAddOn* addOn = new(std::nothrow) CheckSumFSAddOn;
if (addOn == NULL)
return B_NO_MEMORY;
if (!addOns->AddItem(addOn)) {
delete addOn;
return B_NO_MEMORY;
}
debug_printf("checksumfs: get_disk_system_add_ons() done ok\n");
return B_OK;
}

View File

@ -0,0 +1,19 @@
SubDir HAIKU_TOP src tests system kernel file_corruption driver ;
SubDirHdrs $(HAIKU_TOP) src system kernel device_manager ;
UsePrivateKernelHeaders ;
UseHeaders [ FDirName $(SUBDIR) $(DOTDOT) ] ;
KernelAddon checksum_device :
checksum_device.cpp
# from src/kits/shared
SHA256.cpp
;
SEARCH on [ FGristFiles SHA256.cpp ]
= [ FDirName $(HAIKU_TOP) src kits shared ] ;

View File

@ -0,0 +1,101 @@
/*
* Copyright 2010, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#ifndef BLOCK_H
#define BLOCK_H
#include <fs_cache.h>
#include "Volume.h"
class Block {
public:
Block()
:
fVolume(NULL),
fData(NULL)
{
}
~Block()
{
Put();
}
bool GetReadable(Volume* volume, uint64 blockIndex)
{
Put();
return _Init(volume, blockIndex,
block_cache_get(volume->BlockCache(), blockIndex));
}
bool GetWritable(Volume* volume, uint64 blockIndex)
{
Put();
return _Init(volume, blockIndex,
block_cache_get_writable(volume->BlockCache(), blockIndex, -1));
}
bool GetZero(Volume* volume, uint64 blockIndex)
{
Put();
return _Init(volume, blockIndex,
block_cache_get_empty(volume->BlockCache(), blockIndex, -1));
}
void Put()
{
if (fVolume != NULL) {
block_cache_put(fVolume->BlockCache(), fIndex);
fVolume = NULL;
fData = NULL;
}
}
void Discard()
{
if (fVolume != NULL) {
block_cache_discard(fVolume->BlockCache(), fIndex, 1);
fVolume = NULL;
fData = NULL;
}
}
void* Data() const
{
return fData;
}
uint64 Index() const
{
return fIndex;
}
private:
bool _Init(Volume* volume, uint64 blockIndex, const void* data)
{
if (data == NULL)
return false;
fVolume = volume;
fData = const_cast<void*>(data);
fIndex = blockIndex;
return true;
}
private:
Volume* fVolume;
void* fData;
uint64 fIndex;
};
#endif // BLOCK_H

View File

@ -0,0 +1,20 @@
SubDir HAIKU_TOP src tests system kernel file_corruption fs ;
UsePrivateHeaders shared ;
UseHeaders [ FDirName $(SUBDIR) $(DOTDOT) ] ;
KernelAddon checksumfs :
checksumfs.cpp
SuperBlock.cpp
Volume.cpp
# from src/kits/shared
SHA256.cpp
;
SEARCH on [ FGristFiles SHA256.cpp ]
= [ FDirName $(HAIKU_TOP) src kits shared ] ;

View File

@ -0,0 +1,45 @@
/*
* Copyright 2010, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#include "SuperBlock.h"
#include <string.h>
#include "Volume.h"
bool
SuperBlock::Check(uint64 totalBlocks) const
{
if (strncmp(signature1, CHECK_SUM_FS_SIGNATURE_1,
kCheckSumFSSignatureLength) != 0
|| strncmp(signature2, CHECK_SUM_FS_SIGNATURE_2,
kCheckSumFSSignatureLength) != 0
|| Version() != kCheckSumFSVersion
|| TotalBlocks() < kCheckSumFSMinSize / B_PAGE_SIZE
|| TotalBlocks() > totalBlocks
|| strnlen(name, kCheckSumFSNameLength) >= kCheckSumFSNameLength) {
return false;
}
// TODO: Check free blocks and location of root directory and block bitmap.
return true;
}
void
SuperBlock::Initialize(Volume* volume)
{
memcpy(signature1, CHECK_SUM_FS_SIGNATURE_1, kCheckSumFSSignatureLength);
memcpy(signature2, CHECK_SUM_FS_SIGNATURE_2, kCheckSumFSSignatureLength);
version = kCheckSumFSVersion;
totalBlocks = volume->TotalBlocks();
// freeBlocks = volume->BlockAllocator()->FreeBlocks();
// blockBitmap = volume->BlockAllocator()->BlockBitmap();
// rootDir = volume->RootDirBlock();
strlcpy(name, volume->Name(), kCheckSumFSNameLength);
}

View File

@ -0,0 +1,29 @@
/*
* Copyright 2010, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#ifndef SUPER_BLOCK_H
#define SUPER_BLOCK_H
#include "checksumfs.h"
class Volume;
struct SuperBlock : private checksumfs_super_block {
public:
uint64 TotalBlocks() const { return totalBlocks; }
uint64 FreeBlocks() const { return freeBlocks; }
uint32 Version() const { return version; }
const char* Name() const { return name; }
uint64 BlockBitmap() const { return blockBitmap; }
uint64 RootDir() const { return rootDir; }
bool Check(uint64 totalBlocks) const;
void Initialize(Volume* volume);
};
#endif // SUPER_BLOCK_H

View File

@ -0,0 +1,116 @@
/*
* Copyright 2010, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#include "Volume.h"
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <fs_cache.h>
#include "Block.h"
#include "checksumfs.h"
#include "SuperBlock.h"
Volume::Volume(uint32 flags)
:
fFD(-1),
fFlags(flags),
fBlockCache(NULL),
fTotalBlocks(0),
fName(NULL)
{
}
Volume::~Volume()
{
if (fBlockCache != NULL)
block_cache_delete(fBlockCache, false);
if (fFD >= 0)
close(fFD);
free(fName);
}
status_t
Volume::Init(const char* device)
{
// open the device
fFD = open(device, IsReadOnly() ? O_RDONLY : O_RDWR);
if (fFD < 0)
return errno;
// get the size
struct stat st;
if (fstat(fFD, &st) < 0)
return errno;
return _Init(st.st_size / B_PAGE_SIZE);
}
status_t
Volume::Init(int fd, uint64 totalBlocks)
{
fFD = dup(fd);
if (fFD < 0)
return errno;
return _Init(totalBlocks);
}
status_t
Volume::Mount()
{
// TODO:...
return B_UNSUPPORTED;
}
status_t
Volume::Initialize(const char* name)
{
fName = strdup(name);
if (fName == NULL)
return B_NO_MEMORY;
Block block;
if (!block.GetZero(this, kCheckSumFSSuperBlockOffset / B_PAGE_SIZE))
return B_ERROR;
SuperBlock* superBlock = (SuperBlock*)block.Data();
superBlock->Initialize(this);
block.Put();
return block_cache_sync(fBlockCache);
}
status_t
Volume::_Init(uint64 totalBlocks)
{
fTotalBlocks = totalBlocks;
if (fTotalBlocks * B_PAGE_SIZE < kCheckSumFSMinSize)
return B_BAD_VALUE;
// create a block cache
fBlockCache = block_cache_create(fFD, fTotalBlocks, B_PAGE_SIZE,
IsReadOnly());
if (fBlockCache == NULL)
return B_NO_MEMORY;
return B_OK;
}

View File

@ -0,0 +1,48 @@
/*
* Copyright 2010, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#ifndef VOLUME_H
#define VOLUME_H
#include <fs_interface.h>
#include <fs_volume.h>
class Volume {
public:
Volume(uint32 flags);
~Volume();
status_t Init(const char* device);
status_t Init(int fd, uint64 totalBlocks);
status_t Mount();
status_t Initialize(const char* name);
inline bool IsReadOnly() const;
inline uint64 TotalBlocks() const { return fTotalBlocks; }
inline void* BlockCache() const { return fBlockCache; }
inline const char* Name() const { return fName; }
private:
status_t _Init(uint64 totalBlocks);
private:
int fFD;
uint32 fFlags;
void* fBlockCache;
uint64 fTotalBlocks;
char* fName;
};
bool
Volume::IsReadOnly() const
{
return (fFlags & B_MOUNT_READ_ONLY) != 0;
}
#endif // VOLUME_H

View File

@ -0,0 +1,193 @@
/*
* Copyright 2010, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#include <string.h>
#include <new>
#include <fs_interface.h>
#include <AutoDeleter.h>
#include "checksumfs.h"
#include "SuperBlock.h"
#include "Volume.h"
static const char* const kCheckSumFSModuleName = "file_systems/checksumfs"
B_CURRENT_FS_API_VERSION;
static const char* const kCheckSumFSShortName = "checksumfs";
// #pragma mark -
static float
checksumfs_identify_partition(int fd, partition_data* partition,
void** _cookie)
{
if ((uint64)partition->size < kCheckSumFSMinSize)
return -1;
SuperBlock* superBlock = new(std::nothrow) SuperBlock;
if (superBlock == NULL)
return -1;
ObjectDeleter<SuperBlock> superBlockDeleter(superBlock);
if (pread(fd, superBlock, sizeof(*superBlock), kCheckSumFSSuperBlockOffset)
!= sizeof(*superBlock)) {
return -1;
}
if (!superBlock->Check((uint64)partition->size / B_PAGE_SIZE))
return -1;
*_cookie = superBlockDeleter.Detach();
return 0.8f;
}
static status_t
checksumfs_scan_partition(int fd, partition_data* partition, void* cookie)
{
SuperBlock* superBlock = (SuperBlock*)cookie;
partition->status = B_PARTITION_VALID;
partition->flags |= B_PARTITION_FILE_SYSTEM;
partition->content_size = superBlock->TotalBlocks() * B_PAGE_SIZE;
partition->block_size = B_PAGE_SIZE;
partition->content_name = strdup(superBlock->Name());
if (partition->content_name == NULL)
return B_NO_MEMORY;
return B_OK;
}
static void
checksumfs_free_identify_partition_cookie(partition_data* partition,
void* cookie)
{
SuperBlock* superBlock = (SuperBlock*)cookie;
delete superBlock;
}
static status_t
checksumfs_mount(fs_volume* volume, const char* device, uint32 flags,
const char* args, ino_t* _rootVnodeID)
{
// TODO: Implement!
return B_UNSUPPORTED;
}
static status_t
checksumfs_set_content_name(int fd, partition_id partition, const char* name,
disk_job_id job)
{
// TODO: Implement!
return B_UNSUPPORTED;
}
static status_t
checksumfs_initialize(int fd, partition_id partition, const char* name,
const char* parameters, off_t partitionSize, disk_job_id job)
{
if (name == NULL || strlen(name) >= kCheckSumFSNameLength)
return B_BAD_VALUE;
// TODO: Forcing a non-empty name here. Superfluous when the userland disk
// system add-on has a parameter editor for it.
if (*name == '\0')
name = "Unnamed";
update_disk_device_job_progress(job, 0);
Volume volume(0);
status_t error = volume.Init(fd, partitionSize / B_PAGE_SIZE);
if (error != B_OK)
return error;
error = volume.Initialize(name);
if (error != B_OK)
return error;
// rescan partition
error = scan_partition(partition);
if (error != B_OK)
return error;
update_disk_device_job_progress(job, 1);
return B_OK;
}
static status_t
checksumfs_std_ops(int32 operation, ...)
{
switch (operation) {
case B_MODULE_INIT:
case B_MODULE_UNINIT:
return B_OK;
default:
return B_BAD_VALUE;
}
}
static file_system_module_info sFSModule = {
{
kCheckSumFSModuleName,
0,
checksumfs_std_ops
},
kCheckSumFSShortName,
CHECK_SUM_FS_PRETTY_NAME,
// DDM flags
B_DISK_SYSTEM_SUPPORTS_INITIALIZING
| B_DISK_SYSTEM_SUPPORTS_CONTENT_NAME
| B_DISK_SYSTEM_SUPPORTS_WRITING,
/* scanning (the device is write locked) */
checksumfs_identify_partition,
checksumfs_scan_partition,
checksumfs_free_identify_partition_cookie,
NULL, // free_partition_content_cookie
/* general operations */
checksumfs_mount,
/* capability querying (the device is read locked) */
NULL, // get_supported_operations
NULL, // validate_resize
NULL, // validate_move
NULL, // validate_set_content_name
NULL, // validate_set_content_parameters
NULL, // validate_initialize
/* shadow partition modification (device is write locked) */
NULL, // shadow_changed
/* writing (the device is NOT locked) */
NULL, // defragment
NULL, // repair
NULL, // resize
NULL, // move
checksumfs_set_content_name,
NULL, // set_content_parameters
checksumfs_initialize
};
const module_info* modules[] = {
(module_info*)&sFSModule,
NULL
};