LCOV - code coverage report
Current view: top level - spdk/module/bdev/gpt - gpt.c (source / functions) Hit Total Coverage
Test: Combined Lines: 129 145 89.0 %
Date: 2024-07-11 15:05:21 Functions: 10 10 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 66 89 74.2 %

           Branch data     Line data    Source code
       1                 :            : /*   SPDX-License-Identifier: BSD-3-Clause
       2                 :            :  *   Copyright (C) 2017 Intel Corporation.
       3                 :            :  *   All rights reserved.
       4                 :            :  */
       5                 :            : 
       6                 :            : #include "gpt.h"
       7                 :            : 
       8                 :            : #include "spdk/crc32.h"
       9                 :            : #include "spdk/endian.h"
      10                 :            : #include "spdk/event.h"
      11                 :            : 
      12                 :            : #include "spdk/log.h"
      13                 :            : 
      14                 :            : #define GPT_PRIMARY_PARTITION_TABLE_LBA 0x1
      15                 :            : #define PRIMARY_PARTITION_NUMBER 4
      16                 :            : #define GPT_PROTECTIVE_MBR 1
      17                 :            : #define SPDK_MAX_NUM_PARTITION_ENTRIES 128
      18                 :            : 
      19                 :            : static uint64_t
      20                 :         76 : gpt_get_expected_head_lba(struct spdk_gpt *gpt)
      21                 :            : {
      22      [ +  +  - ]:         76 :         switch (gpt->parse_phase) {
      23                 :         68 :         case SPDK_GPT_PARSE_PHASE_PRIMARY:
      24                 :         68 :                 return GPT_PRIMARY_PARTITION_TABLE_LBA;
      25                 :          8 :         case SPDK_GPT_PARSE_PHASE_SECONDARY:
      26                 :          8 :                 return gpt->lba_end;
      27                 :          0 :         default:
      28                 :          0 :                 assert(false);
      29                 :            :         }
      30                 :            :         return 0;
      31                 :            : }
      32                 :            : 
      33                 :            : static struct spdk_gpt_header *
      34                 :         96 : gpt_get_header_buf(struct spdk_gpt *gpt)
      35                 :            : {
      36      [ +  +  - ]:         96 :         switch (gpt->parse_phase) {
      37                 :         84 :         case SPDK_GPT_PARSE_PHASE_PRIMARY:
      38                 :         84 :                 return (struct spdk_gpt_header *)
      39                 :         84 :                        (gpt->buf + GPT_PRIMARY_PARTITION_TABLE_LBA * gpt->sector_size);
      40                 :         12 :         case SPDK_GPT_PARSE_PHASE_SECONDARY:
      41                 :         12 :                 return (struct spdk_gpt_header *)
      42                 :         12 :                        (gpt->buf + (gpt->buf_size - gpt->sector_size));
      43                 :          0 :         default:
      44                 :          0 :                 assert(false);
      45                 :            :         }
      46                 :            :         return NULL;
      47                 :            : }
      48                 :            : 
      49                 :            : static struct spdk_gpt_partition_entry *
      50                 :         68 : gpt_get_partitions_buf(struct spdk_gpt *gpt, uint64_t total_partition_size,
      51                 :            :                        uint64_t partition_start_lba)
      52                 :            : {
      53                 :            :         uint64_t secondary_total_size;
      54                 :            : 
      55      [ +  +  - ]:         68 :         switch (gpt->parse_phase) {
      56                 :         64 :         case SPDK_GPT_PARSE_PHASE_PRIMARY:
      57                 :         64 :                 if ((total_partition_size + partition_start_lba * gpt->sector_size) >
      58         [ +  + ]:         64 :                     gpt->buf_size) {
      59                 :          4 :                         SPDK_ERRLOG("Buffer size is not enough\n");
      60                 :          4 :                         return NULL;
      61                 :            :                 }
      62                 :         60 :                 return (struct spdk_gpt_partition_entry *)
      63                 :         60 :                        (gpt->buf + partition_start_lba * gpt->sector_size);
      64                 :          4 :         case SPDK_GPT_PARSE_PHASE_SECONDARY:
      65                 :          4 :                 secondary_total_size = (gpt->lba_end - partition_start_lba + 1) * gpt->sector_size;
      66         [ -  + ]:          4 :                 if (secondary_total_size > gpt->buf_size) {
      67                 :          0 :                         SPDK_ERRLOG("Buffer size is not enough\n");
      68                 :          0 :                         return NULL;
      69                 :            :                 }
      70                 :          4 :                 return (struct spdk_gpt_partition_entry *)
      71                 :          4 :                        (gpt->buf + (gpt->buf_size - secondary_total_size));
      72                 :          0 :         default:
      73                 :          0 :                 assert(false);
      74                 :            :         }
      75                 :            :         return NULL;
      76                 :            : }
      77                 :            : 
      78                 :            : static int
      79                 :         84 : gpt_read_partitions(struct spdk_gpt *gpt)
      80                 :            : {
      81                 :            :         uint32_t total_partition_size, num_partition_entries, partition_entry_size;
      82                 :            :         uint64_t partition_start_lba;
      83                 :         84 :         struct spdk_gpt_header *head = gpt->header;
      84                 :            :         uint32_t crc32;
      85                 :            : 
      86                 :         84 :         num_partition_entries = from_le32(&head->num_partition_entries);
      87         [ +  + ]:         84 :         if (num_partition_entries > SPDK_MAX_NUM_PARTITION_ENTRIES) {
      88                 :         12 :                 SPDK_ERRLOG("Num_partition_entries=%u which exceeds max=%u\n",
      89                 :            :                             num_partition_entries, SPDK_MAX_NUM_PARTITION_ENTRIES);
      90                 :         12 :                 return -1;
      91                 :            :         }
      92                 :            : 
      93                 :         72 :         partition_entry_size = from_le32(&head->size_of_partition_entry);
      94         [ +  + ]:         72 :         if (partition_entry_size != sizeof(struct spdk_gpt_partition_entry)) {
      95                 :          4 :                 SPDK_ERRLOG("Partition_entry_size(%x) != expected(%zx)\n",
      96                 :            :                             partition_entry_size, sizeof(struct spdk_gpt_partition_entry));
      97                 :          4 :                 return -1;
      98                 :            :         }
      99                 :            : 
     100                 :         68 :         total_partition_size = num_partition_entries * partition_entry_size;
     101                 :         68 :         partition_start_lba = from_le64(&head->partition_entry_lba);
     102                 :         68 :         gpt->partitions = gpt_get_partitions_buf(gpt, total_partition_size,
     103                 :            :                           partition_start_lba);
     104         [ +  + ]:         68 :         if (!gpt->partitions) {
     105                 :          4 :                 SPDK_ERRLOG("Failed to get gpt partitions buf\n");
     106                 :          4 :                 return -1;
     107                 :            :         }
     108                 :            : 
     109                 :         64 :         crc32 = spdk_crc32_ieee_update(gpt->partitions, total_partition_size, ~0);
     110                 :         64 :         crc32 ^= ~0;
     111                 :            : 
     112         [ +  + ]:         64 :         if (crc32 != from_le32(&head->partition_entry_array_crc32)) {
     113                 :          4 :                 SPDK_ERRLOG("GPT partition entry array crc32 did not match\n");
     114                 :          4 :                 return -1;
     115                 :            :         }
     116                 :            : 
     117                 :         60 :         return 0;
     118                 :            : }
     119                 :            : 
     120                 :            : static int
     121                 :         72 : gpt_lba_range_check(struct spdk_gpt_header *head, uint64_t lba_end)
     122                 :            : {
     123                 :            :         uint64_t usable_lba_start, usable_lba_end;
     124                 :            : 
     125                 :         72 :         usable_lba_start = from_le64(&head->first_usable_lba);
     126                 :         72 :         usable_lba_end = from_le64(&head->last_usable_lba);
     127                 :            : 
     128         [ -  + ]:         72 :         if (usable_lba_end < usable_lba_start) {
     129                 :          0 :                 SPDK_ERRLOG("Head's usable_lba_end(%" PRIu64 ") < usable_lba_start(%" PRIu64 ")\n",
     130                 :            :                             usable_lba_end, usable_lba_start);
     131                 :          0 :                 return -1;
     132                 :            :         }
     133                 :            : 
     134         [ +  + ]:         72 :         if (usable_lba_end > lba_end) {
     135                 :          4 :                 SPDK_ERRLOG("Head's usable_lba_end(%" PRIu64 ") > lba_end(%" PRIu64 ")\n",
     136                 :            :                             usable_lba_end, lba_end);
     137                 :          4 :                 return -1;
     138                 :            :         }
     139                 :            : 
     140   [ -  +  -  - ]:         68 :         if ((usable_lba_start < GPT_PRIMARY_PARTITION_TABLE_LBA) &&
     141                 :            :             (GPT_PRIMARY_PARTITION_TABLE_LBA < usable_lba_end)) {
     142                 :          0 :                 SPDK_ERRLOG("Head lba is not in the usable range\n");
     143                 :          0 :                 return -1;
     144                 :            :         }
     145                 :            : 
     146                 :         68 :         return 0;
     147                 :            : }
     148                 :            : 
     149                 :            : static int
     150                 :         96 : gpt_read_header(struct spdk_gpt *gpt)
     151                 :            : {
     152                 :            :         uint32_t head_size;
     153                 :            :         uint32_t new_crc, original_crc;
     154                 :            :         uint64_t my_lba, head_lba;
     155                 :            :         struct spdk_gpt_header *head;
     156                 :            : 
     157                 :         96 :         head = gpt_get_header_buf(gpt);
     158         [ -  + ]:         96 :         if (!head) {
     159                 :          0 :                 SPDK_ERRLOG("Failed to get gpt header buf\n");
     160                 :          0 :                 return -1;
     161                 :            :         }
     162                 :            : 
     163                 :         96 :         head_size = from_le32(&head->header_size);
     164   [ +  -  +  + ]:         96 :         if (head_size < sizeof(*head) || head_size > gpt->sector_size) {
     165                 :         12 :                 SPDK_ERRLOG("head_size=%u\n", head_size);
     166                 :         12 :                 return -1;
     167                 :            :         }
     168                 :            : 
     169                 :         84 :         original_crc = from_le32(&head->header_crc32);
     170                 :         84 :         head->header_crc32 = 0;
     171                 :         84 :         new_crc = spdk_crc32_ieee_update(head, from_le32(&head->header_size), ~0);
     172                 :         84 :         new_crc ^= ~0;
     173                 :            :         /* restore header crc32 */
     174                 :         84 :         to_le32(&head->header_crc32, original_crc);
     175                 :            : 
     176         [ +  + ]:         84 :         if (new_crc != original_crc) {
     177                 :          4 :                 SPDK_ERRLOG("head crc32 does not match, provided=%u, calculated=%u\n",
     178                 :            :                             original_crc, new_crc);
     179                 :          4 :                 return -1;
     180                 :            :         }
     181                 :            : 
     182   [ +  +  +  + ]:         80 :         if (memcmp(SPDK_GPT_SIGNATURE, head->gpt_signature,
     183                 :            :                    sizeof(head->gpt_signature))) {
     184                 :          4 :                 SPDK_ERRLOG("signature did not match\n");
     185                 :          4 :                 return -1;
     186                 :            :         }
     187                 :            : 
     188                 :         76 :         head_lba = gpt_get_expected_head_lba(gpt);
     189                 :         76 :         my_lba = from_le64(&head->my_lba);
     190         [ +  + ]:         76 :         if (my_lba != head_lba) {
     191                 :          4 :                 SPDK_ERRLOG("head my_lba(%" PRIu64 ") != expected(%" PRIu64 ")\n",
     192                 :            :                             my_lba, head_lba);
     193                 :          4 :                 return -1;
     194                 :            :         }
     195                 :            : 
     196         [ +  + ]:         72 :         if (gpt_lba_range_check(head, gpt->lba_end)) {
     197                 :          4 :                 SPDK_ERRLOG("lba range check error\n");
     198                 :          4 :                 return -1;
     199                 :            :         }
     200                 :            : 
     201                 :         68 :         gpt->header = head;
     202                 :         68 :         return 0;
     203                 :            : }
     204                 :            : 
     205                 :            : static int
     206                 :       5303 : gpt_check_mbr(struct spdk_gpt *gpt)
     207                 :            : {
     208                 :       5303 :         int i, primary_partition = 0;
     209                 :       5303 :         uint32_t total_lba_size = 0, ret = 0, expected_start_lba;
     210                 :            :         struct spdk_mbr *mbr;
     211                 :            : 
     212                 :       5303 :         mbr = (struct spdk_mbr *)gpt->buf;
     213         [ +  + ]:       5303 :         if (from_le16(&mbr->mbr_signature) != SPDK_MBR_SIGNATURE) {
     214   [ -  +  -  + ]:       5235 :                 SPDK_DEBUGLOG(gpt_parse, "Signature mismatch, provided=%x,"
     215                 :            :                               "expected=%x\n", from_le16(&mbr->disk_signature),
     216                 :            :                               SPDK_MBR_SIGNATURE);
     217                 :       5235 :                 return -1;
     218                 :            :         }
     219                 :            : 
     220         [ +  + ]:        100 :         for (i = 0; i < PRIMARY_PARTITION_NUMBER; i++) {
     221         [ +  + ]:         92 :                 if (mbr->partitions[i].os_type == SPDK_MBR_OS_TYPE_GPT_PROTECTIVE) {
     222                 :         60 :                         primary_partition = i;
     223                 :         60 :                         ret = GPT_PROTECTIVE_MBR;
     224                 :         60 :                         break;
     225                 :            :                 }
     226                 :            :         }
     227                 :            : 
     228         [ +  + ]:         68 :         if (ret == GPT_PROTECTIVE_MBR) {
     229                 :         60 :                 expected_start_lba = GPT_PRIMARY_PARTITION_TABLE_LBA;
     230         [ -  + ]:         60 :                 if (from_le32(&mbr->partitions[primary_partition].start_lba) != expected_start_lba) {
     231   [ #  #  #  # ]:          0 :                         SPDK_DEBUGLOG(gpt_parse, "start lba mismatch, provided=%u, expected=%u\n",
     232                 :            :                                       from_le32(&mbr->partitions[primary_partition].start_lba),
     233                 :            :                                       expected_start_lba);
     234                 :          0 :                         return -1;
     235                 :            :                 }
     236                 :            : 
     237                 :         60 :                 total_lba_size = from_le32(&mbr->partitions[primary_partition].size_lba);
     238   [ +  +  +  + ]:         60 :                 if ((total_lba_size != ((uint32_t) gpt->total_sectors - 1)) &&
     239                 :            :                     (total_lba_size != 0xFFFFFFFF)) {
     240   [ -  +  -  + ]:          4 :                         SPDK_DEBUGLOG(gpt_parse,
     241                 :            :                                       "GPT Primary MBR size does not equal: (record_size %u != actual_size %u)!\n",
     242                 :            :                                       total_lba_size, (uint32_t) gpt->total_sectors - 1);
     243                 :          4 :                         return -1;
     244                 :            :                 }
     245                 :            :         } else {
     246   [ -  +  -  + ]:          8 :                 SPDK_DEBUGLOG(gpt_parse, "Currently only support GPT Protective MBR format\n");
     247                 :          8 :                 return -1;
     248                 :            :         }
     249                 :            : 
     250                 :         56 :         return 0;
     251                 :            : }
     252                 :            : 
     253                 :            : int
     254                 :       5299 : gpt_parse_mbr(struct spdk_gpt *gpt)
     255                 :            : {
     256                 :            :         int rc;
     257                 :            : 
     258   [ +  +  +  + ]:       5299 :         if (!gpt || !gpt->buf) {
     259                 :         16 :                 SPDK_ERRLOG("Gpt and the related buffer should not be NULL\n");
     260                 :         16 :                 return -1;
     261                 :            :         }
     262                 :            : 
     263                 :       5283 :         rc = gpt_check_mbr(gpt);
     264         [ +  + ]:       5283 :         if (rc) {
     265   [ -  +  -  + ]:       5231 :                 SPDK_DEBUGLOG(gpt_parse, "Failed to detect gpt in MBR\n");
     266                 :       5231 :                 return rc;
     267                 :            :         }
     268                 :            : 
     269                 :         52 :         return 0;
     270                 :            : }
     271                 :            : 
     272                 :            : int
     273                 :         72 : gpt_parse_partition_table(struct spdk_gpt *gpt)
     274                 :            : {
     275                 :            :         int rc;
     276                 :            : 
     277                 :         72 :         rc = gpt_read_header(gpt);
     278         [ +  + ]:         72 :         if (rc) {
     279                 :          8 :                 SPDK_ERRLOG("Failed to read gpt header\n");
     280                 :          8 :                 return rc;
     281                 :            :         }
     282                 :            : 
     283                 :         64 :         rc = gpt_read_partitions(gpt);
     284         [ +  + ]:         64 :         if (rc) {
     285                 :          8 :                 SPDK_ERRLOG("Failed to read gpt partitions\n");
     286                 :          8 :                 return rc;
     287                 :            :         }
     288                 :            : 
     289                 :         56 :         return 0;
     290                 :            : }
     291                 :            : 
     292                 :       1898 : SPDK_LOG_REGISTER_COMPONENT(gpt_parse)

Generated by: LCOV version 1.14