[haiku-commits] r37300 - in haiku/trunk/src/tests/system/kernel/file_corruption: . disk_system driver fs

  • From: ingo_weinhold@xxxxxx
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Tue, 29 Jun 2010 12:52:16 +0200 (CEST)

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 ...]

Other related posts:

  • » [haiku-commits] r37300 - in haiku/trunk/src/tests/system/kernel/file_corruption: . disk_system driver fs - ingo_weinhold