[haiku-commits] haiku: hrev45208 - src/add-ons/kernel/partitioning_systems/gpt

  • From: axeld@xxxxxxxxxxxxxxxx
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Sun, 27 Jan 2013 14:16:35 +0100 (CET)

hrev45208 adds 1 changeset to branch 'master'
old head: 90308ec327dce4e1894b4507f9197ba92512926c
new head: 953d310a47372bb97f2b1154d032aa344dbbcb69
overview: http://cgit.haiku-os.org/haiku/log/?qt=range&q=953d310+%5E90308ec

----------------------------------------------------------------------------

953d310: gpt: Added support for the backup header/entries.

                                   [ Axel Dörfler <axeld@xxxxxxxxxxxxxxxx> ]

----------------------------------------------------------------------------

Revision:    hrev45208
Commit:      953d310a47372bb97f2b1154d032aa344dbbcb69
URL:         http://cgit.haiku-os.org/haiku/commit/?id=953d310
Author:      Axel Dörfler <axeld@xxxxxxxxxxxxxxxx>
Date:        Sun Jan 27 13:16:01 2013 UTC

----------------------------------------------------------------------------

2 files changed, 103 insertions(+), 42 deletions(-)
.../kernel/partitioning_systems/gpt/Header.cpp   | 131 +++++++++++++------
.../kernel/partitioning_systems/gpt/Header.h     |  14 +-

----------------------------------------------------------------------------

diff --git a/src/add-ons/kernel/partitioning_systems/gpt/Header.cpp 
b/src/add-ons/kernel/partitioning_systems/gpt/Header.cpp
index c47b64c..55ccb82 100644
--- a/src/add-ons/kernel/partitioning_systems/gpt/Header.cpp
+++ b/src/add-ons/kernel/partitioning_systems/gpt/Header.cpp
@@ -44,27 +44,37 @@ Header::Header(int fd, uint64 lastBlock, uint32 blockSize)
        fStatus(B_NO_INIT),
        fEntries(NULL)
 {
-       // TODO: check the correctness of the protective MBR
+       // TODO: check the correctness of the protective MBR and warn if invalid
 
-       // read and check the partition table header
+       // Read and check the partition table header
 
-       ssize_t bytesRead = read_pos(fd, (uint64)EFI_HEADER_LOCATION * 
blockSize,
+       fStatus = _Read(fd, (uint64)EFI_HEADER_LOCATION * blockSize,
                &fHeader, sizeof(efi_table_header));
-       if (bytesRead != (ssize_t)sizeof(efi_table_header)) {
-               if (bytesRead < B_OK)
-                       fStatus = bytesRead;
-               else
-                       fStatus = B_IO_ERROR;
+       if (fStatus == B_OK) {
+               if (!_IsHeaderValid(fHeader, EFI_HEADER_LOCATION))
+                       fStatus = B_BAD_DATA;
+       }
 
-               return;
+       // Read backup header, too
+       status_t status = _Read(fd, lastBlock * blockSize, &fBackupHeader,
+               sizeof(efi_table_header));
+       if (status == B_OK) {
+               if (!_IsHeaderValid(fBackupHeader, lastBlock))
+                       status = B_BAD_DATA;
        }
 
-       if (memcmp(fHeader.header, EFI_PARTITION_HEADER, sizeof(fHeader.header))
-               || !_ValidateHeaderCRC()
-               || fHeader.AbsoluteBlock() != EFI_HEADER_LOCATION) {
-               // TODO: check that partition counts are in valid bounds
-               fStatus = B_BAD_DATA;
+       // If both headers are invalid, bail out -- this is probably not a GPT 
disk
+       if (status != B_OK && fStatus != B_OK)
                return;
+
+       if (fStatus != B_OK) {
+               // Recreate primary header from the backup
+               fHeader = fBackupHeader;
+               fHeader.SetAbsoluteBlock(EFI_HEADER_LOCATION);
+               fHeader.SetEntriesBlock(EFI_PARTITION_ENTRIES_BLOCK);
+       } else if (status != B_OK) {
+               // Recreate backup header from primary
+               _SetBackupHeaderFromPrimary(lastBlock);
        }
 
        // allocate, read, and check partition entry array
@@ -77,22 +87,22 @@ Header::Header(int fd, uint64 lastBlock, uint32 blockSize)
                return;
        }
 
-       bytesRead = read_pos(fd, fHeader.EntriesBlock() * blockSize,
+       fStatus = _Read(fd, fHeader.EntriesBlock() * blockSize,
                fEntries, _EntryArraySize());
-       if (bytesRead != (ssize_t)_EntryArraySize()) {
-               if (bytesRead < B_OK)
-                       fStatus = bytesRead;
-               else
-                       fStatus = B_IO_ERROR;
-
-               return;
+       if (fStatus != B_OK || !_ValidateEntriesCRC()) {
+               // Read backup entries instead
+               fStatus = _Read(fd, fBackupHeader.EntriesBlock() * blockSize,
+                       fEntries, _EntryArraySize());
+               if (fStatus != B_OK)
+                       return;
+
+               if (!_ValidateEntriesCRC()) {
+                       fStatus = B_BAD_DATA;
+                       return;
+               }
        }
 
-       if (!_ValidateEntriesCRC()) {
-               // TODO: check overlapping or out of range partitions
-               fStatus = B_BAD_DATA;
-               return;
-       }
+       // TODO: check overlapping or out of range partitions
 
 #ifdef TRACE_EFI_GPT
        _Dump();
@@ -140,6 +150,8 @@ Header::Header(uint64 lastBlock, uint32 blockSize)
        fHeader.SetFirstUsableBlock(EFI_PARTITION_ENTRIES_BLOCK + entryBlocks);
        fHeader.SetLastUsableBlock(lastBlock - 1 - entryBlocks);
 
+       _SetBackupHeaderFromPrimary(lastBlock);
+
 #ifdef TRACE_EFI_GPT
        _Dump();
        _DumpPartitions();
@@ -168,19 +180,25 @@ status_t
 Header::WriteEntry(int fd, uint32 entryIndex)
 {
        // Determine block to write
-       off_t block = fHeader.EntriesBlock()
+       off_t blockOffset =
                + entryIndex * fHeader.EntrySize() / fBlockSize;
        uint32 entryOffset = entryIndex * fHeader.EntrySize() % fBlockSize;
 
-       status_t status = _Write(fd, block * fBlockSize, fEntries + entryOffset,
-               fBlockSize);
+       status_t status = _Write(fd,
+               (fHeader.EntriesBlock() + blockOffset) * fBlockSize,
+               fEntries + entryOffset, fBlockSize);
        if (status != B_OK)
                return status;
 
-       // TODO: write mirror at the end
-
        // Update header, too -- the entries CRC changed
-       return _WriteHeader(fd);
+       status = _WriteHeader(fd);
+
+       // Write backup
+       status_t backupStatus = _Write(fd,
+               (fBackupHeader.EntriesBlock() + blockOffset) * fBlockSize,
+               fEntries + entryOffset, fBlockSize);
+
+       return status == B_OK ? backupStatus : status;
 }
 
 
@@ -192,9 +210,15 @@ Header::Write(int fd)
        if (status != B_OK)
                return status;
 
-       // TODO: write mirror at the end
+       // First write the header, so that we have at least one completely 
correct
+       // data set
+       status = _WriteHeader(fd);
+
+       // Write backup entries
+       status_t backupStatus = _Write(fd,
+               fBackupHeader.EntriesBlock() * fBlockSize, fEntries, 
_EntryArraySize());
 
-       return _WriteHeader(fd);
+       return status == B_OK ? backupStatus : status;
 }
 
 
@@ -208,9 +232,8 @@ Header::_WriteHeader(int fd)
        if (status != B_OK)
                return status;
 
-       // TODO: write mirror at the end
-
-       return B_OK;
+       return _Write(fd, fBackupHeader.AbsoluteBlock() * fBlockSize,
+               &fBackupHeader, sizeof(efi_table_header));
 }
 
 
@@ -227,6 +250,19 @@ Header::_Write(int fd, off_t offset, const void* data, 
size_t size) const
 }
 
 
+status_t
+Header::_Read(int fd, off_t offset, void* data, size_t size) const
+{
+       ssize_t bytesRead = read_pos(fd, offset, data, size);
+       if (bytesRead < 0)
+               return bytesRead;
+       if (bytesRead != (ssize_t)size)
+               return B_IO_ERROR;
+
+       return B_OK;
+}
+
+
 void
 Header::_UpdateCRC()
 {
@@ -238,6 +274,15 @@ Header::_UpdateCRC()
 
 
 bool
+Header::_IsHeaderValid(const efi_table_header& header, uint64 block)
+{
+       return !memcmp(fHeader.header, EFI_PARTITION_HEADER, 
sizeof(fHeader.header))
+               && _ValidateHeaderCRC()
+               && fHeader.AbsoluteBlock() == block;
+}
+
+
+bool
 Header::_ValidateHeaderCRC()
 {
        uint32 originalCRC = fHeader.HeaderCRC();
@@ -258,6 +303,16 @@ Header::_ValidateEntriesCRC() const
 }
 
 
+void
+Header::_SetBackupHeaderFromPrimary(uint64 lastBlock)
+{
+       fBackupHeader = fHeader;
+       fBackupHeader.SetAbsoluteBlock(lastBlock);
+       fBackupHeader.SetEntriesBlock(
+               lastBlock - _EntryArraySize() / fBlockSize);
+}
+
+
 #ifdef TRACE_EFI_GPT
 const char *
 Header::_PrintGUID(const guid_t &id)
diff --git a/src/add-ons/kernel/partitioning_systems/gpt/Header.h 
b/src/add-ons/kernel/partitioning_systems/gpt/Header.h
index 486a5e2..f3681df 100644
--- a/src/add-ons/kernel/partitioning_systems/gpt/Header.h
+++ b/src/add-ons/kernel/partitioning_systems/gpt/Header.h
@@ -43,27 +43,33 @@ public:
 #endif
 
 private:
-                       const char*                     _PrintGUID(const 
guid_t& id);
-                       void                            _Dump();
-                       void                            _DumpPartitions();
-
 #ifndef _BOOT_MODE
                        status_t                        _WriteHeader(int fd);
                        status_t                        _Write(int fd, off_t 
offset, const void* data,
                                                                        size_t 
size) const;
+                       status_t                        _Read(int fd, off_t 
offset, void* data,
+                                                                       size_t 
size) const;
                        void                            _UpdateCRC();
 #endif
 
+                       bool                            _IsHeaderValid(const 
efi_table_header& header,
+                                                                       uint64 
block);
                        bool                            _ValidateHeaderCRC();
                        bool                            _ValidateEntriesCRC() 
const;
+                       void                            
_SetBackupHeaderFromPrimary(uint64 lastBlock);
                        size_t                          _EntryArraySize() const
                                                                        { 
return fHeader.EntrySize()
                                                                                
* fHeader.EntryCount(); }
 
+                       const char*                     _PrintGUID(const 
guid_t& id);
+                       void                            _Dump();
+                       void                            _DumpPartitions();
+
 private:
                        uint32                          fBlockSize;
                        status_t                        fStatus;
                        efi_table_header        fHeader;
+                       efi_table_header        fBackupHeader;
                        uint8*                          fEntries;
 };
 


Other related posts: