Author: bonefish Date: 2010-06-29 12:52:16 +0200 (Tue, 29 Jun 2010) New Revision: 37300 Changeset: http://dev.haiku-os.org/changeset/37300/haiku Added: haiku/trunk/src/tests/system/kernel/file_corruption/checksumfs.h haiku/trunk/src/tests/system/kernel/file_corruption/disk_system/ haiku/trunk/src/tests/system/kernel/file_corruption/disk_system/Jamfile haiku/trunk/src/tests/system/kernel/file_corruption/disk_system/checksumfs.cpp haiku/trunk/src/tests/system/kernel/file_corruption/driver/ haiku/trunk/src/tests/system/kernel/file_corruption/driver/Jamfile haiku/trunk/src/tests/system/kernel/file_corruption/driver/checksum_device.cpp haiku/trunk/src/tests/system/kernel/file_corruption/driver/checksum_device.h haiku/trunk/src/tests/system/kernel/file_corruption/fs/ haiku/trunk/src/tests/system/kernel/file_corruption/fs/Block.h haiku/trunk/src/tests/system/kernel/file_corruption/fs/Jamfile haiku/trunk/src/tests/system/kernel/file_corruption/fs/SuperBlock.cpp haiku/trunk/src/tests/system/kernel/file_corruption/fs/SuperBlock.h haiku/trunk/src/tests/system/kernel/file_corruption/fs/Volume.cpp haiku/trunk/src/tests/system/kernel/file_corruption/fs/Volume.h haiku/trunk/src/tests/system/kernel/file_corruption/fs/checksumfs.cpp Removed: haiku/trunk/src/tests/system/kernel/file_corruption/checksum_device.cpp haiku/trunk/src/tests/system/kernel/file_corruption/checksum_device.h Modified: haiku/trunk/src/tests/system/kernel/file_corruption/Jamfile Log: * 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. Modified: haiku/trunk/src/tests/system/kernel/file_corruption/Jamfile =================================================================== --- haiku/trunk/src/tests/system/kernel/file_corruption/Jamfile 2010-06-29 10:49:03 UTC (rev 37299) +++ haiku/trunk/src/tests/system/kernel/file_corruption/Jamfile 2010-06-29 10:52:16 UTC (rev 37300) @@ -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 ; Added: haiku/trunk/src/tests/system/kernel/file_corruption/checksumfs.h =================================================================== --- haiku/trunk/src/tests/system/kernel/file_corruption/checksumfs.h (rev 0) +++ haiku/trunk/src/tests/system/kernel/file_corruption/checksumfs.h 2010-06-29 10:52:16 UTC (rev 37300) @@ -0,0 +1,41 @@ +/* + * Copyright 2010, Ingo Weinhold, ingo_weinhold@xxxxxxx + * 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 Added: haiku/trunk/src/tests/system/kernel/file_corruption/disk_system/Jamfile =================================================================== --- haiku/trunk/src/tests/system/kernel/file_corruption/disk_system/Jamfile (rev 0) +++ haiku/trunk/src/tests/system/kernel/file_corruption/disk_system/Jamfile 2010-06-29 10:52:16 UTC (rev 37300) @@ -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++) +; Added: haiku/trunk/src/tests/system/kernel/file_corruption/disk_system/checksumfs.cpp =================================================================== --- haiku/trunk/src/tests/system/kernel/file_corruption/disk_system/checksumfs.cpp (rev 0) +++ haiku/trunk/src/tests/system/kernel/file_corruption/disk_system/checksumfs.cpp 2010-06-29 10:52:16 UTC (rev 37300) @@ -0,0 +1,212 @@ +/* + * Copyright 2010, Ingo Weinhold, ingo_weinhold@xxxxxxx + * 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; +} Copied: haiku/trunk/src/tests/system/kernel/file_corruption/driver/Jamfile (from rev 37258, haiku/trunk/src/tests/system/kernel/file_corruption/Jamfile) =================================================================== --- haiku/trunk/src/tests/system/kernel/file_corruption/driver/Jamfile (rev 0) +++ haiku/trunk/src/tests/system/kernel/file_corruption/driver/Jamfile 2010-06-29 10:52:16 UTC (rev 37300) @@ -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 ] ; Copied: haiku/trunk/src/tests/system/kernel/file_corruption/driver/checksum_device.cpp (from rev 37258, haiku/trunk/src/tests/system/kernel/file_corruption/checksum_device.cpp) =================================================================== --- haiku/trunk/src/tests/system/kernel/file_corruption/driver/checksum_device.cpp (rev 0) +++ haiku/trunk/src/tests/system/kernel/file_corruption/driver/checksum_device.cpp 2010-06-29 10:52:16 UTC (rev 37300) @@ -0,0 +1,1184 @@ +/* + * Copyright 2010, Ingo Weinhold, ingo_weinhold@xxxxxxx + * Distributed under the terms of the MIT License. + */ + + +#include "checksum_device.h" + +#include <ctype.h> +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +#include <algorithm> + +#include <device_manager.h> + +#include <AutoDeleter.h> +#include <util/AutoLock.h> +#include <util/DoublyLinkedList.h> + +#include <fs/KPath.h> +#include <lock.h> +#include <vm/vm.h> + +#include "dma_resources.h" +#include "io_requests.h" +#include "IOSchedulerSimple.h" + +#include "CheckSum.h" + + +// parameters for the DMA resource +static const uint32 kDMAResourceBufferCount = 16; +static const uint32 kDMAResourceBounceBufferCount = 16; + +static const size_t kCheckSumLength = sizeof(CheckSum); +static const uint32 kCheckSumsPerBlock = B_PAGE_SIZE / sizeof(CheckSum); + +static const char* const kDriverModuleName + = "drivers/disk/virtual/checksum_device/driver_v1"; +static const char* const kControlDeviceModuleName + = "drivers/disk/virtual/checksum_device/control/device_v1"; +static const char* const kRawDeviceModuleName + = "drivers/disk/virtual/checksum_device/raw/device_v1"; + +static const char* const kControlDeviceName + = "disk/virtual/checksum_device/control"; +static const char* const kRawDeviceBaseName = "disk/virtual/checksum_device"; + +static const char* const kFilePathItem = "checksum_device/file_path"; + + +struct RawDevice; +typedef DoublyLinkedList<RawDevice> RawDeviceList; + +struct device_manager_info* sDeviceManager; + +static RawDeviceList sDeviceList; +static mutex sDeviceListLock = MUTEX_INITIALIZER("checksum device list"); + + +struct CheckSumBlock : public DoublyLinkedListLinkImpl<CheckSumBlock> { + uint64 blockIndex; + bool used; + bool dirty; + CheckSum checkSums[kCheckSumsPerBlock]; + + CheckSumBlock() + : + used(false) + { + } +}; + + +struct CheckSumCache { + CheckSumCache() + { + mutex_init(&fLock, "check sum cache"); + } + + ~CheckSumCache() + { + while (CheckSumBlock* block = fBlocks.RemoveHead()) + delete block; + + mutex_destroy(&fLock); + } + + status_t Init(int fd, uint64 blockCount, uint32 cachedBlockCount) + { + fBlockCount = blockCount; + fFD = fd; + + for (uint32 i = 0; i < cachedBlockCount; i++) { + CheckSumBlock* block = new(std::nothrow) CheckSumBlock; + if (block == NULL) + return B_NO_MEMORY; + + fBlocks.Add(block); + } + + return B_OK; + } + + status_t GetCheckSum(uint64 blockIndex, CheckSum& checkSum) + { + ASSERT(blockIndex < fBlockCount); + + MutexLocker locker(fLock); + + CheckSumBlock* block; + status_t error = _GetBlock( + fBlockCount + blockIndex / kCheckSumsPerBlock, block); + if (error != B_OK) + return error; + + checkSum = block->checkSums[blockIndex % kCheckSumsPerBlock]; + + return B_OK; + } + + status_t SetCheckSum(uint64 blockIndex, const CheckSum& checkSum) + { + ASSERT(blockIndex < fBlockCount); + + MutexLocker locker(fLock); + + CheckSumBlock* block; + status_t error = _GetBlock( + fBlockCount + blockIndex / kCheckSumsPerBlock, block); + if (error != B_OK) + return error; + + block->checkSums[blockIndex % kCheckSumsPerBlock] = checkSum; + block->dirty = true; + + return B_OK; + } + +private: + typedef DoublyLinkedList<CheckSumBlock> BlockList; + +private: + status_t _GetBlock(uint64 blockIndex, CheckSumBlock*& _block) + { + // check whether we have already cached the block + for (BlockList::Iterator it = fBlocks.GetIterator(); + CheckSumBlock* block = it.Next();) { + if (block->used && block->blockIndex) { + // we know it -- requeue and return + it.Remove(); + fBlocks.Add(block); + _block = block; + return B_OK; + } + } + + // flush the least recently used block and recycle it + CheckSumBlock* block = fBlocks.Head(); + status_t error = _FlushBlock(block); + if (error != B_OK) + return error; + + error = _ReadBlock(block, blockIndex); + if (error != B_OK) + return error; + + // requeue + fBlocks.Remove(block); + fBlocks.Add(block); + + _block = block; + return B_OK; + } + + status_t _FlushBlock(CheckSumBlock* block) + { + if (!block->used || !block->dirty) + return B_OK; + + ssize_t written = pwrite(fFD, block->checkSums, B_PAGE_SIZE, + block->blockIndex * B_PAGE_SIZE); + if (written < 0) + return errno; + if (written != B_PAGE_SIZE) + return B_ERROR; + + block->dirty = false; + return B_OK; + } + + status_t _ReadBlock(CheckSumBlock* block, uint64 blockIndex) + { + // mark unused for the failure cases -- reset later + block->used = false; + + ssize_t bytesRead = pread(fFD, block->checkSums, B_PAGE_SIZE, + blockIndex * B_PAGE_SIZE); + if (bytesRead < 0) + return errno; + if (bytesRead != B_PAGE_SIZE) + return B_ERROR; + + block->blockIndex = blockIndex; + block->used = true; + block->dirty = false; + + return B_OK; + } + +private: + mutex fLock; + uint64 fBlockCount; + int fFD; + BlockList fBlocks; // LRU first +}; + + +struct Device { + Device(device_node* node) + : + fNode(node) + { + mutex_init(&fLock, "checksum device"); + } + + virtual ~Device() + { + mutex_destroy(&fLock); + } + + bool Lock() { mutex_lock(&fLock); return true; } + void Unlock() { mutex_unlock(&fLock); } + + device_node* Node() const { return fNode; } + + virtual status_t PublishDevice() = 0; + +protected: + mutex fLock; + device_node* fNode; +}; + + +struct ControlDevice : Device { + ControlDevice(device_node* node) + : + Device(node) + { + } + + status_t Register(const char* fileName) + { + device_attr attrs[] = { + {B_DEVICE_PRETTY_NAME, B_STRING_TYPE, + {string: "Checksum Raw Device"}}, + {kFilePathItem, B_STRING_TYPE, {string: fileName}}, + {NULL} + }; + + return sDeviceManager->register_node( + sDeviceManager->get_parent_node(Node()), kDriverModuleName, attrs, + NULL, NULL); + } + + virtual status_t PublishDevice() + { + return sDeviceManager->publish_device(Node(), kControlDeviceName, + kControlDeviceModuleName); + } +}; + + +struct RawDevice : Device, DoublyLinkedListLinkImpl<RawDevice> { + RawDevice(device_node* node) + : + Device(node), + fIndex(-1), + fFD(-1), + fFileSize(0), + fDeviceSize(0), + fDeviceName(NULL), + fDMAResource(NULL), + fIOScheduler(NULL), + fTransferBuffer(NULL), + fCheckSumCache(NULL) + { + } + + virtual ~RawDevice() + { + if (fIndex >= 0) { + MutexLocker locker(sDeviceListLock); + sDeviceList.Remove(this); + } + + if (fFD >= 0) + close(fFD); + + free(fDeviceName); + } + + int32 Index() const { return fIndex; } + off_t DeviceSize() const { return fDeviceSize; } + const char* DeviceName() const { return fDeviceName; } + + status_t Init(const char* fileName) + { + // open and stat file + fFD = open(fileName, O_RDWR); + if (fFD < 0) + return errno; + + struct stat st; + if (fstat(fFD, &st) < 0) + return errno; + + fFileSize = st.st_size / B_PAGE_SIZE * B_PAGE_SIZE; + fDeviceSize = fFileSize / (B_PAGE_SIZE + kCheckSumLength) * B_PAGE_SIZE; + + // find a free slot + fIndex = 0; + RawDevice* nextDevice = NULL; + MutexLocker locker(sDeviceListLock); + for (RawDeviceList::Iterator it = sDeviceList.GetIterator(); + (nextDevice = it.Next()) != NULL;) { + if (nextDevice->Index() > fIndex) + break; + fIndex = nextDevice->Index() + 1; + } + + sDeviceList.InsertBefore(nextDevice, this); + + // construct our device path + KPath path(kRawDeviceBaseName); + char buffer[32]; + snprintf(buffer, sizeof(buffer), "%" B_PRId32 "/raw", fIndex); + + status_t error = path.Append(buffer); + if (error != B_OK) + return error; + + fDeviceName = path.DetachBuffer(); + + return B_OK; + } + + status_t Prepare() + { + fCheckSumCache = new(std::nothrow) CheckSumCache; + if (fCheckSumCache == NULL) { + Unprepare(); + return B_NO_MEMORY; + } + + status_t error = fCheckSumCache->Init(fFD, fDeviceSize / B_PAGE_SIZE, + 16); + if (error != B_OK) { + Unprepare(); + return error; + } + + // no DMA restrictions + const dma_restrictions restrictions = {}; + + fDMAResource = new(std::nothrow) DMAResource; + if (fDMAResource == NULL) { + Unprepare(); + return B_NO_MEMORY; + } + + error = fDMAResource->Init(restrictions, B_PAGE_SIZE, + kDMAResourceBufferCount, kDMAResourceBounceBufferCount); + if (error != B_OK) { + Unprepare(); + return error; + } + + fIOScheduler = new(std::nothrow) IOSchedulerSimple(fDMAResource); + if (fIOScheduler == NULL) { + Unprepare(); + return B_NO_MEMORY; + } + + error = fIOScheduler->Init("checksum device scheduler"); + if (error != B_OK) { + Unprepare(); + return error; + } + + fIOScheduler->SetCallback(&_DoIOEntry, this); + + fTransferBuffer = malloc(B_PAGE_SIZE); + if (fTransferBuffer == NULL) { + Unprepare(); + return B_NO_MEMORY; + } + + return B_OK; + } + + void Unprepare() + { + free(fTransferBuffer); + fTransferBuffer = NULL; + + delete fIOScheduler; + fIOScheduler = NULL; + + delete fDMAResource; + fDMAResource = NULL; + + delete fCheckSumCache; + fCheckSumCache = NULL; + } + + status_t DoIO(IORequest* request) + { + return fIOScheduler->ScheduleRequest(request); + } + + virtual status_t PublishDevice() + { + return sDeviceManager->publish_device(Node(), fDeviceName, + kRawDeviceModuleName); + } + + status_t SetBlockCheckSum(uint64 blockIndex, const CheckSum& checkSum) + { + return fCheckSumCache->SetCheckSum(blockIndex, checkSum); + } + +private: + static status_t _DoIOEntry(void* data, IOOperation* operation) + { + return ((RawDevice*)data)->_DoIO(operation); + } + + status_t _DoIO(IOOperation* operation) + { + off_t offset = operation->Offset(); + generic_size_t length = operation->Length(); + + ASSERT(offset % B_PAGE_SIZE == 0); + ASSERT(length % B_PAGE_SIZE == 0); + + const generic_io_vec* vecs = operation->Vecs(); + generic_size_t vecOffset = 0; + bool isWrite = operation->IsWrite(); + + while (length > 0) { + status_t error = _TransferBlock(vecs, vecOffset, offset, isWrite); + if (error != B_OK) { + fIOScheduler->OperationCompleted(operation, error, 0); + return error; + } + + offset += B_PAGE_SIZE; + length -= B_PAGE_SIZE; + } + + fIOScheduler->OperationCompleted(operation, B_OK, operation->Length()); + return B_OK; + } + + status_t _TransferBlock(const generic_io_vec*& vecs, + generic_size_t& vecOffset, off_t offset, bool isWrite) + { + if (isWrite) { + // write -- copy data to transfer buffer + status_t error = _CopyData(vecs, vecOffset, true); + if (error != B_OK) + return error; + _CheckCheckSum(offset / B_PAGE_SIZE); + } + + ssize_t transferred = isWrite + ? pwrite(fFD, fTransferBuffer, B_PAGE_SIZE, offset) + : pread(fFD, fTransferBuffer, B_PAGE_SIZE, offset); + + if (transferred < 0) + return errno; + if (transferred != B_PAGE_SIZE) + return B_ERROR; + + if (!isWrite) { + // read -- copy data from transfer buffer + status_t error =_CopyData(vecs, vecOffset, false); + if (error != B_OK) + return error; + } + + return B_OK; + } + + status_t _CopyData(const generic_io_vec*& vecs, generic_size_t& vecOffset, + bool toBuffer) + { + uint8* buffer = (uint8*)fTransferBuffer; + size_t length = B_PAGE_SIZE; + while (length > 0) { + size_t toCopy = std::min((generic_size_t)length, + vecs->length - vecOffset); + + if (toCopy == 0) { + vecs++; + vecOffset = 0; + continue; + } + + phys_addr_t vecAddress = vecs->base + vecOffset; + + status_t error = toBuffer + ? vm_memcpy_from_physical(buffer, vecAddress, toCopy, false) + : vm_memcpy_to_physical(vecAddress, buffer, toCopy, false); + if (error != B_OK) + return error; + + buffer += toCopy; + length -= toCopy; + vecOffset += toCopy; + } + + return B_OK; + } + + void _CheckCheckSum(uint64 blockIndex) + { + // get the checksum the block should have + CheckSum expectedCheckSum; + if (fCheckSumCache->GetCheckSum(blockIndex, expectedCheckSum) != B_OK) + return; + + // if the checksum is clear, we aren't supposed to check + if (expectedCheckSum.IsZero()) { + dprintf("checksum_device: skipping check sum check for block %" + B_PRIu64 "\n", blockIndex); + return; + } + + // compute the transfer buffer check sum + fSHA256.Init(); + fSHA256.Update(fTransferBuffer, B_PAGE_SIZE); + + if (expectedCheckSum != fSHA256.Digest()) + panic("Check sum mismatch for block %" B_PRIu64, blockIndex); + } + +private: + int32 fIndex; + int fFD; + off_t fFileSize; + off_t fDeviceSize; + char* fDeviceName; + DMAResource* fDMAResource; + IOScheduler* fIOScheduler; + void* fTransferBuffer; + CheckSumCache* fCheckSumCache; + SHA256 fSHA256; +}; + + +struct RawDeviceCookie { + RawDeviceCookie(RawDevice* device, int openMode) + : + fDevice(device), + fOpenMode(openMode) + { + } + + RawDevice* Device() const { return fDevice; } + int OpenMode() const { return fOpenMode; } + +private: + RawDevice* fDevice; + int fOpenMode; +}; + + +// #pragma mark - + + +static bool +parse_command_line(char* buffer, char**& _argv, int& _argc) +{ + // Process the argument string. We split at whitespace, heeding quotes and + // escaped characters. The processed arguments are written to the given + // buffer, separated by single null chars. + char* start = buffer; + char* out = buffer; + bool pendingArgument = false; + int argc = 0; + while (*start != '\0') { + // ignore whitespace + if (isspace(*start)) { + if (pendingArgument) { + *out = '\0'; + out++; + argc++; + pendingArgument = false; + } + start++; + continue; + } + + pendingArgument = true; + + if (*start == '"' || *start == '\'') { + // quoted text -- continue until closing quote + char quote = *start; + start++; + while (*start != '\0' && *start != quote) { + if (*start == '\\' && quote == '"') { + start++; + if (*start == '\0') + break; + } + *out = *start; + start++; + out++; + } + + if (*start != '\0') + start++; + } else { + // unquoted text + if (*start == '\\') { + // escaped char + start++; + if (start == '\0') + break; + } + + *out = *start; + start++; + out++; + } + } + + if (pendingArgument) { + *out = '\0'; + argc++; + } + + // allocate argument vector + char** argv = new(std::nothrow) char*[argc + 1]; + if (argv == NULL) + return false; + + // fill vector + start = buffer; + for (int i = 0; i < argc; i++) { + argv[i] = start; + start += strlen(start) + 1; + } + argv[argc] = NULL; + [... truncated: 1149 lines follow ...]