1488570ebSJim Harris /* SPDX-License-Identifier: BSD-3-Clause 2a6dbe372Spaul luse * Copyright (C) 2017 Intel Corporation. 307fe6a43SSeth Howell * All rights reserved. 407fe6a43SSeth Howell */ 507fe6a43SSeth Howell 607fe6a43SSeth Howell /* 707fe6a43SSeth Howell * This driver reads a GPT partition table from a bdev and exposes a virtual block device for 807fe6a43SSeth Howell * each partition. 907fe6a43SSeth Howell */ 1007fe6a43SSeth Howell 113a39d90bSJim Harris #define REGISTER_GUID_DEPRECATION 1207fe6a43SSeth Howell #include "gpt.h" 1307fe6a43SSeth Howell 1407fe6a43SSeth Howell #include "spdk/endian.h" 1507fe6a43SSeth Howell #include "spdk/env.h" 1607fe6a43SSeth Howell #include "spdk/thread.h" 1707fe6a43SSeth Howell #include "spdk/rpc.h" 1807fe6a43SSeth Howell #include "spdk/string.h" 1907fe6a43SSeth Howell #include "spdk/util.h" 2007fe6a43SSeth Howell 2107fe6a43SSeth Howell #include "spdk/bdev_module.h" 224e8e97c8STomasz Zawadzki #include "spdk/log.h" 2307fe6a43SSeth Howell 2407fe6a43SSeth Howell static int vbdev_gpt_init(void); 2507fe6a43SSeth Howell static void vbdev_gpt_examine(struct spdk_bdev *bdev); 2607fe6a43SSeth Howell static int vbdev_gpt_get_ctx_size(void); 2707fe6a43SSeth Howell 2807fe6a43SSeth Howell static struct spdk_bdev_module gpt_if = { 2907fe6a43SSeth Howell .name = "gpt", 3007fe6a43SSeth Howell .module_init = vbdev_gpt_init, 3107fe6a43SSeth Howell .get_ctx_size = vbdev_gpt_get_ctx_size, 3207fe6a43SSeth Howell .examine_disk = vbdev_gpt_examine, 3307fe6a43SSeth Howell 3407fe6a43SSeth Howell }; 3507fe6a43SSeth Howell SPDK_BDEV_MODULE_REGISTER(gpt, &gpt_if) 3607fe6a43SSeth Howell 3707fe6a43SSeth Howell /* Base block device gpt context */ 3807fe6a43SSeth Howell struct gpt_base { 3907fe6a43SSeth Howell struct spdk_gpt gpt; 4007fe6a43SSeth Howell struct spdk_bdev_part_base *part_base; 4107fe6a43SSeth Howell SPDK_BDEV_PART_TAILQ parts; 4207fe6a43SSeth Howell 4307fe6a43SSeth Howell /* This channel is only used for reading the partition table. */ 4407fe6a43SSeth Howell struct spdk_io_channel *ch; 4507fe6a43SSeth Howell }; 4607fe6a43SSeth Howell 4707fe6a43SSeth Howell /* Context for each gpt virtual bdev */ 4807fe6a43SSeth Howell struct gpt_disk { 4907fe6a43SSeth Howell struct spdk_bdev_part part; 5007fe6a43SSeth Howell uint32_t partition_index; 5107fe6a43SSeth Howell }; 5207fe6a43SSeth Howell 5307fe6a43SSeth Howell struct gpt_channel { 5407fe6a43SSeth Howell struct spdk_bdev_part_channel part_ch; 5507fe6a43SSeth Howell }; 5607fe6a43SSeth Howell 5707fe6a43SSeth Howell struct gpt_io { 5807fe6a43SSeth Howell struct spdk_io_channel *ch; 5907fe6a43SSeth Howell struct spdk_bdev_io *bdev_io; 6007fe6a43SSeth Howell 6107fe6a43SSeth Howell /* for bdev_io_wait */ 6207fe6a43SSeth Howell struct spdk_bdev_io_wait_entry bdev_io_wait; 6307fe6a43SSeth Howell }; 6407fe6a43SSeth Howell 6507fe6a43SSeth Howell static void 661d2faf6dSSeth Howell gpt_base_free(void *ctx) 6707fe6a43SSeth Howell { 6807fe6a43SSeth Howell struct gpt_base *gpt_base = ctx; 6907fe6a43SSeth Howell 7007fe6a43SSeth Howell spdk_free(gpt_base->gpt.buf); 7107fe6a43SSeth Howell free(gpt_base); 7207fe6a43SSeth Howell } 7307fe6a43SSeth Howell 7407fe6a43SSeth Howell static void 751d2faf6dSSeth Howell gpt_base_bdev_hotremove_cb(void *_part_base) 7607fe6a43SSeth Howell { 7707fe6a43SSeth Howell struct spdk_bdev_part_base *part_base = _part_base; 7807fe6a43SSeth Howell struct gpt_base *gpt_base = spdk_bdev_part_base_get_ctx(part_base); 7907fe6a43SSeth Howell 8007fe6a43SSeth Howell spdk_bdev_part_base_hotremove(part_base, &gpt_base->parts); 8107fe6a43SSeth Howell } 8207fe6a43SSeth Howell 8307fe6a43SSeth Howell static int vbdev_gpt_destruct(void *ctx); 8407fe6a43SSeth Howell static void vbdev_gpt_submit_request(struct spdk_io_channel *_ch, struct spdk_bdev_io *bdev_io); 8507fe6a43SSeth Howell static int vbdev_gpt_dump_info_json(void *ctx, struct spdk_json_write_ctx *w); 86cff525d3SAlexey Marchuk static int vbdev_gpt_get_memory_domains(void *ctx, struct spdk_memory_domain **domains, 87cff525d3SAlexey Marchuk int array_size); 8807fe6a43SSeth Howell 8907fe6a43SSeth Howell static struct spdk_bdev_fn_table vbdev_gpt_fn_table = { 9007fe6a43SSeth Howell .destruct = vbdev_gpt_destruct, 9107fe6a43SSeth Howell .submit_request = vbdev_gpt_submit_request, 9207fe6a43SSeth Howell .dump_info_json = vbdev_gpt_dump_info_json, 93cff525d3SAlexey Marchuk .get_memory_domains = vbdev_gpt_get_memory_domains, 9407fe6a43SSeth Howell }; 9507fe6a43SSeth Howell 9607fe6a43SSeth Howell static struct gpt_base * 971d2faf6dSSeth Howell gpt_base_bdev_init(struct spdk_bdev *bdev) 9807fe6a43SSeth Howell { 9907fe6a43SSeth Howell struct gpt_base *gpt_base; 10007fe6a43SSeth Howell struct spdk_gpt *gpt; 10199935996STomasz Zawadzki int rc; 10207fe6a43SSeth Howell 10307fe6a43SSeth Howell gpt_base = calloc(1, sizeof(*gpt_base)); 10407fe6a43SSeth Howell if (!gpt_base) { 10507fe6a43SSeth Howell SPDK_ERRLOG("Cannot alloc memory for gpt_base pointer\n"); 10607fe6a43SSeth Howell return NULL; 10707fe6a43SSeth Howell } 10807fe6a43SSeth Howell 10907fe6a43SSeth Howell TAILQ_INIT(&gpt_base->parts); 11099935996STomasz Zawadzki rc = spdk_bdev_part_base_construct_ext(spdk_bdev_get_name(bdev), 1111d2faf6dSSeth Howell gpt_base_bdev_hotremove_cb, 11207fe6a43SSeth Howell &gpt_if, &vbdev_gpt_fn_table, 1131d2faf6dSSeth Howell &gpt_base->parts, gpt_base_free, gpt_base, 11499935996STomasz Zawadzki sizeof(struct gpt_channel), NULL, NULL, &gpt_base->part_base); 11599935996STomasz Zawadzki if (rc != 0) { 11607fe6a43SSeth Howell free(gpt_base); 11707fe6a43SSeth Howell SPDK_ERRLOG("cannot construct gpt_base"); 11807fe6a43SSeth Howell return NULL; 11907fe6a43SSeth Howell } 12007fe6a43SSeth Howell 12107fe6a43SSeth Howell gpt = &gpt_base->gpt; 12207fe6a43SSeth Howell gpt->parse_phase = SPDK_GPT_PARSE_PHASE_PRIMARY; 12307fe6a43SSeth Howell gpt->buf_size = spdk_max(SPDK_GPT_BUFFER_SIZE, bdev->blocklen); 12407fe6a43SSeth Howell gpt->buf = spdk_zmalloc(gpt->buf_size, spdk_bdev_get_buf_align(bdev), NULL, 12507fe6a43SSeth Howell SPDK_ENV_LCORE_ID_ANY, SPDK_MALLOC_DMA); 12607fe6a43SSeth Howell if (!gpt->buf) { 12707fe6a43SSeth Howell SPDK_ERRLOG("Cannot alloc buf\n"); 12807fe6a43SSeth Howell spdk_bdev_part_base_free(gpt_base->part_base); 12907fe6a43SSeth Howell return NULL; 13007fe6a43SSeth Howell } 13107fe6a43SSeth Howell 13207fe6a43SSeth Howell gpt->sector_size = bdev->blocklen; 13307fe6a43SSeth Howell gpt->total_sectors = bdev->blockcnt; 13407fe6a43SSeth Howell gpt->lba_start = 0; 13507fe6a43SSeth Howell gpt->lba_end = gpt->total_sectors - 1; 13607fe6a43SSeth Howell 13707fe6a43SSeth Howell return gpt_base; 13807fe6a43SSeth Howell } 13907fe6a43SSeth Howell 14007fe6a43SSeth Howell static int 14107fe6a43SSeth Howell vbdev_gpt_destruct(void *ctx) 14207fe6a43SSeth Howell { 14307fe6a43SSeth Howell struct gpt_disk *gpt_disk = ctx; 14407fe6a43SSeth Howell 14507fe6a43SSeth Howell return spdk_bdev_part_free(&gpt_disk->part); 14607fe6a43SSeth Howell } 14707fe6a43SSeth Howell 1488dd1cd21SBen Walker static void _vbdev_gpt_submit_request(struct spdk_io_channel *_ch, struct spdk_bdev_io *bdev_io); 14907fe6a43SSeth Howell 15007fe6a43SSeth Howell static void 15107fe6a43SSeth Howell vbdev_gpt_resubmit_request(void *arg) 15207fe6a43SSeth Howell { 15307fe6a43SSeth Howell struct gpt_io *io = (struct gpt_io *)arg; 15407fe6a43SSeth Howell 15507fe6a43SSeth Howell _vbdev_gpt_submit_request(io->ch, io->bdev_io); 15607fe6a43SSeth Howell } 15707fe6a43SSeth Howell 15807fe6a43SSeth Howell static void 15907fe6a43SSeth Howell vbdev_gpt_queue_io(struct gpt_io *io) 16007fe6a43SSeth Howell { 161017f8751Spaul luse struct gpt_channel *ch = spdk_io_channel_get_ctx(io->ch); 16207fe6a43SSeth Howell int rc; 16307fe6a43SSeth Howell 16407fe6a43SSeth Howell io->bdev_io_wait.bdev = io->bdev_io->bdev; 16507fe6a43SSeth Howell io->bdev_io_wait.cb_fn = vbdev_gpt_resubmit_request; 16607fe6a43SSeth Howell io->bdev_io_wait.cb_arg = io; 16707fe6a43SSeth Howell 16807fe6a43SSeth Howell rc = spdk_bdev_queue_io_wait(io->bdev_io->bdev, 169017f8751Spaul luse ch->part_ch.base_ch, &io->bdev_io_wait); 17007fe6a43SSeth Howell if (rc != 0) { 17107fe6a43SSeth Howell SPDK_ERRLOG("Queue io failed in vbdev_gpt_queue_io, rc=%d.\n", rc); 17207fe6a43SSeth Howell spdk_bdev_io_complete(io->bdev_io, SPDK_BDEV_IO_STATUS_FAILED); 17307fe6a43SSeth Howell } 17407fe6a43SSeth Howell } 17507fe6a43SSeth Howell 17607fe6a43SSeth Howell static void 17707fe6a43SSeth Howell vbdev_gpt_get_buf_cb(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io, bool success) 17807fe6a43SSeth Howell { 17907fe6a43SSeth Howell if (!success) { 18007fe6a43SSeth Howell spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED); 18107fe6a43SSeth Howell return; 18207fe6a43SSeth Howell } 18307fe6a43SSeth Howell 18407fe6a43SSeth Howell _vbdev_gpt_submit_request(ch, bdev_io); 18507fe6a43SSeth Howell } 18607fe6a43SSeth Howell 18707fe6a43SSeth Howell static void 18807fe6a43SSeth Howell _vbdev_gpt_submit_request(struct spdk_io_channel *_ch, struct spdk_bdev_io *bdev_io) 18907fe6a43SSeth Howell { 19007fe6a43SSeth Howell struct gpt_channel *ch = spdk_io_channel_get_ctx(_ch); 19107fe6a43SSeth Howell struct gpt_io *io = (struct gpt_io *)bdev_io->driver_ctx; 19207fe6a43SSeth Howell int rc; 19307fe6a43SSeth Howell 19407fe6a43SSeth Howell rc = spdk_bdev_part_submit_request(&ch->part_ch, bdev_io); 19507fe6a43SSeth Howell if (rc) { 19607fe6a43SSeth Howell if (rc == -ENOMEM) { 1972172c432STomasz Zawadzki SPDK_DEBUGLOG(vbdev_gpt, "gpt: no memory, queue io\n"); 19807fe6a43SSeth Howell io->ch = _ch; 19907fe6a43SSeth Howell io->bdev_io = bdev_io; 20007fe6a43SSeth Howell vbdev_gpt_queue_io(io); 20107fe6a43SSeth Howell } else { 20207fe6a43SSeth Howell SPDK_ERRLOG("gpt: error on bdev_io submission, rc=%d.\n", rc); 20307fe6a43SSeth Howell spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED); 20407fe6a43SSeth Howell } 20507fe6a43SSeth Howell } 20607fe6a43SSeth Howell } 20707fe6a43SSeth Howell 20807fe6a43SSeth Howell static void 20907fe6a43SSeth Howell vbdev_gpt_submit_request(struct spdk_io_channel *_ch, struct spdk_bdev_io *bdev_io) 21007fe6a43SSeth Howell { 21107fe6a43SSeth Howell switch (bdev_io->type) { 21207fe6a43SSeth Howell case SPDK_BDEV_IO_TYPE_READ: 21307fe6a43SSeth Howell spdk_bdev_io_get_buf(bdev_io, vbdev_gpt_get_buf_cb, 21407fe6a43SSeth Howell bdev_io->u.bdev.num_blocks * bdev_io->bdev->blocklen); 21507fe6a43SSeth Howell break; 21607fe6a43SSeth Howell default: 21707fe6a43SSeth Howell _vbdev_gpt_submit_request(_ch, bdev_io); 21807fe6a43SSeth Howell break; 21907fe6a43SSeth Howell } 22007fe6a43SSeth Howell } 22107fe6a43SSeth Howell 22207fe6a43SSeth Howell static void 223ff12a5edSMike Gerdts gpt_guid_to_uuid(const struct spdk_gpt_guid *guid, struct spdk_uuid *uuid) 224ff12a5edSMike Gerdts { 225ff12a5edSMike Gerdts #pragma pack(push, 1) 226ff12a5edSMike Gerdts struct tmp_uuid { 227ff12a5edSMike Gerdts uint32_t b0; 228ff12a5edSMike Gerdts uint16_t b4; 229ff12a5edSMike Gerdts uint16_t b6; 230ff12a5edSMike Gerdts uint16_t b8; 231ff12a5edSMike Gerdts uint16_t b10; 232ff12a5edSMike Gerdts uint32_t b12; 233ff12a5edSMike Gerdts } *ret = (struct tmp_uuid *)uuid; 234ff12a5edSMike Gerdts #pragma pack(pop) 235ff12a5edSMike Gerdts SPDK_STATIC_ASSERT(sizeof(*ret) == sizeof(*uuid), "wrong size"); 236ff12a5edSMike Gerdts 237ff12a5edSMike Gerdts ret->b0 = from_be32(&guid->raw[0]); 238ff12a5edSMike Gerdts ret->b4 = from_be16(&guid->raw[4]); 239ff12a5edSMike Gerdts ret->b6 = from_be16(&guid->raw[6]); 240ff12a5edSMike Gerdts ret->b8 = from_le16(&guid->raw[8]); 241ff12a5edSMike Gerdts ret->b10 = from_le16(&guid->raw[10]); 242ff12a5edSMike Gerdts ret->b12 = from_le32(&guid->raw[12]); 243ff12a5edSMike Gerdts } 244ff12a5edSMike Gerdts 245ff12a5edSMike Gerdts static void 24607fe6a43SSeth Howell write_guid(struct spdk_json_write_ctx *w, const struct spdk_gpt_guid *guid) 24707fe6a43SSeth Howell { 24807fe6a43SSeth Howell spdk_json_write_string_fmt(w, "%08x-%04x-%04x-%04x-%04x%08x", 24907fe6a43SSeth Howell from_le32(&guid->raw[0]), 25007fe6a43SSeth Howell from_le16(&guid->raw[4]), 25107fe6a43SSeth Howell from_le16(&guid->raw[6]), 25207fe6a43SSeth Howell from_be16(&guid->raw[8]), 25307fe6a43SSeth Howell from_be16(&guid->raw[10]), 25407fe6a43SSeth Howell from_be32(&guid->raw[12])); 25507fe6a43SSeth Howell } 25607fe6a43SSeth Howell 25707fe6a43SSeth Howell static void 25807fe6a43SSeth Howell write_string_utf16le(struct spdk_json_write_ctx *w, const uint16_t *str, size_t max_len) 25907fe6a43SSeth Howell { 26007fe6a43SSeth Howell size_t len; 26107fe6a43SSeth Howell const uint16_t *p; 26207fe6a43SSeth Howell 26307fe6a43SSeth Howell for (len = 0, p = str; len < max_len && *p; p++) { 26407fe6a43SSeth Howell len++; 26507fe6a43SSeth Howell } 26607fe6a43SSeth Howell 26707fe6a43SSeth Howell spdk_json_write_string_utf16le_raw(w, str, len); 26807fe6a43SSeth Howell } 26907fe6a43SSeth Howell 27007fe6a43SSeth Howell static int 27107fe6a43SSeth Howell vbdev_gpt_dump_info_json(void *ctx, struct spdk_json_write_ctx *w) 27207fe6a43SSeth Howell { 27307fe6a43SSeth Howell struct gpt_disk *gpt_disk = SPDK_CONTAINEROF(ctx, struct gpt_disk, part); 27407fe6a43SSeth Howell struct spdk_bdev_part_base *base_bdev = spdk_bdev_part_get_base(&gpt_disk->part); 27507fe6a43SSeth Howell struct gpt_base *gpt_base = spdk_bdev_part_base_get_ctx(base_bdev); 27607fe6a43SSeth Howell struct spdk_bdev *part_base_bdev = spdk_bdev_part_base_get_bdev(base_bdev); 27707fe6a43SSeth Howell struct spdk_gpt *gpt = &gpt_base->gpt; 27807fe6a43SSeth Howell struct spdk_gpt_partition_entry *gpt_entry = &gpt->partitions[gpt_disk->partition_index]; 27907fe6a43SSeth Howell uint64_t offset_blocks = spdk_bdev_part_get_offset_blocks(&gpt_disk->part); 28007fe6a43SSeth Howell 28107fe6a43SSeth Howell spdk_json_write_named_object_begin(w, "gpt"); 28207fe6a43SSeth Howell 28307fe6a43SSeth Howell spdk_json_write_named_string(w, "base_bdev", spdk_bdev_get_name(part_base_bdev)); 28407fe6a43SSeth Howell 28507fe6a43SSeth Howell spdk_json_write_named_uint64(w, "offset_blocks", offset_blocks); 28607fe6a43SSeth Howell 28707fe6a43SSeth Howell spdk_json_write_name(w, "partition_type_guid"); 28807fe6a43SSeth Howell write_guid(w, &gpt_entry->part_type_guid); 28907fe6a43SSeth Howell 29007fe6a43SSeth Howell spdk_json_write_name(w, "unique_partition_guid"); 29107fe6a43SSeth Howell write_guid(w, &gpt_entry->unique_partition_guid); 29207fe6a43SSeth Howell 29307fe6a43SSeth Howell spdk_json_write_name(w, "partition_name"); 29407fe6a43SSeth Howell write_string_utf16le(w, gpt_entry->partition_name, SPDK_COUNTOF(gpt_entry->partition_name)); 29507fe6a43SSeth Howell 29607fe6a43SSeth Howell spdk_json_write_object_end(w); 29707fe6a43SSeth Howell 29807fe6a43SSeth Howell return 0; 29907fe6a43SSeth Howell } 30007fe6a43SSeth Howell 30107fe6a43SSeth Howell static int 302cff525d3SAlexey Marchuk vbdev_gpt_get_memory_domains(void *ctx, struct spdk_memory_domain **domains, int array_size) 303cff525d3SAlexey Marchuk { 304cff525d3SAlexey Marchuk struct gpt_disk *gpt_disk = SPDK_CONTAINEROF(ctx, struct gpt_disk, part); 305cff525d3SAlexey Marchuk struct spdk_bdev_part_base *part_base = spdk_bdev_part_get_base(&gpt_disk->part); 306cff525d3SAlexey Marchuk struct spdk_bdev *part_base_bdev = spdk_bdev_part_base_get_bdev(part_base); 307cff525d3SAlexey Marchuk 308cff525d3SAlexey Marchuk if (part_base_bdev->dif_check_flags & SPDK_DIF_FLAGS_REFTAG_CHECK) { 309cff525d3SAlexey Marchuk /* bdev_part remaps reftag and touches metadata buffer, that means it can't support memory domains 310cff525d3SAlexey Marchuk * if dif is enabled */ 311cff525d3SAlexey Marchuk return 0; 312cff525d3SAlexey Marchuk } 313cff525d3SAlexey Marchuk 314cff525d3SAlexey Marchuk return spdk_bdev_get_memory_domains(part_base_bdev, domains, array_size); 315cff525d3SAlexey Marchuk } 316cff525d3SAlexey Marchuk 317cff525d3SAlexey Marchuk static int 31807fe6a43SSeth Howell vbdev_gpt_create_bdevs(struct gpt_base *gpt_base) 31907fe6a43SSeth Howell { 32007fe6a43SSeth Howell uint32_t num_partition_entries; 32107fe6a43SSeth Howell uint64_t i, head_lba_start, head_lba_end; 32207fe6a43SSeth Howell uint32_t num_partitions; 32307fe6a43SSeth Howell struct spdk_gpt_partition_entry *p; 32407fe6a43SSeth Howell struct gpt_disk *d; 32507fe6a43SSeth Howell struct spdk_gpt *gpt; 32607fe6a43SSeth Howell char *name; 32707fe6a43SSeth Howell struct spdk_bdev *base_bdev; 32807fe6a43SSeth Howell int rc; 32907fe6a43SSeth Howell 33007fe6a43SSeth Howell gpt = &gpt_base->gpt; 33107fe6a43SSeth Howell num_partition_entries = from_le32(&gpt->header->num_partition_entries); 33207fe6a43SSeth Howell head_lba_start = from_le64(&gpt->header->first_usable_lba); 33307fe6a43SSeth Howell head_lba_end = from_le64(&gpt->header->last_usable_lba); 33407fe6a43SSeth Howell num_partitions = 0; 33507fe6a43SSeth Howell 33607fe6a43SSeth Howell for (i = 0; i < num_partition_entries; i++) { 33707fe6a43SSeth Howell p = &gpt->partitions[i]; 33807fe6a43SSeth Howell uint64_t lba_start = from_le64(&p->starting_lba); 33907fe6a43SSeth Howell uint64_t lba_end = from_le64(&p->ending_lba); 3403a39d90bSJim Harris uint64_t partition_size = lba_end - lba_start + 1; 341ff12a5edSMike Gerdts struct spdk_bdev_part_construct_opts opts; 34207fe6a43SSeth Howell 3433a39d90bSJim Harris if (lba_start == 0) { 34407fe6a43SSeth Howell continue; 34507fe6a43SSeth Howell } 3463a39d90bSJim Harris 3473a39d90bSJim Harris if (SPDK_GPT_GUID_EQUAL(&gpt->partitions[i].part_type_guid, 3483a39d90bSJim Harris &SPDK_GPT_PART_TYPE_GUID_OLD)) { 3493a39d90bSJim Harris /* GitHub issue #2801 - we continue to report these partitions with 3503a39d90bSJim Harris * off-by-one sizing error to ensure we don't break layouts based 3513a39d90bSJim Harris * on that smaller size. */ 3523a39d90bSJim Harris partition_size -= 1; 3533a39d90bSJim Harris } else if (!SPDK_GPT_GUID_EQUAL(&gpt->partitions[i].part_type_guid, 3543a39d90bSJim Harris &SPDK_GPT_PART_TYPE_GUID)) { 3553a39d90bSJim Harris /* Partition type isn't TYPE_GUID or TYPE_GUID_OLD, so this isn't 356*34edd9f1SKamil Godzwon * an SPDK partition. Continue to the next partition. 3573a39d90bSJim Harris */ 3583a39d90bSJim Harris continue; 3593a39d90bSJim Harris } 3603a39d90bSJim Harris 36107fe6a43SSeth Howell if (lba_start < head_lba_start || lba_end > head_lba_end) { 36207fe6a43SSeth Howell continue; 36307fe6a43SSeth Howell } 36407fe6a43SSeth Howell 36507fe6a43SSeth Howell d = calloc(1, sizeof(*d)); 36607fe6a43SSeth Howell if (!d) { 36707fe6a43SSeth Howell SPDK_ERRLOG("Memory allocation failure\n"); 36807fe6a43SSeth Howell return -1; 36907fe6a43SSeth Howell } 37007fe6a43SSeth Howell 37107fe6a43SSeth Howell /* index start at 1 instead of 0 to match the existing style */ 37207fe6a43SSeth Howell base_bdev = spdk_bdev_part_base_get_bdev(gpt_base->part_base); 37307fe6a43SSeth Howell name = spdk_sprintf_alloc("%sp%" PRIu64, spdk_bdev_get_name(base_bdev), i + 1); 37407fe6a43SSeth Howell if (!name) { 37507fe6a43SSeth Howell SPDK_ERRLOG("name allocation failure\n"); 37607fe6a43SSeth Howell free(d); 37707fe6a43SSeth Howell return -1; 37807fe6a43SSeth Howell } 37907fe6a43SSeth Howell 380ff12a5edSMike Gerdts spdk_bdev_part_construct_opts_init(&opts, sizeof(opts)); 381ff12a5edSMike Gerdts gpt_guid_to_uuid(&p->unique_partition_guid, &opts.uuid); 382ff12a5edSMike Gerdts rc = spdk_bdev_part_construct_ext(&d->part, gpt_base->part_base, name, lba_start, 383ff12a5edSMike Gerdts partition_size, "GPT Disk", &opts); 38407fe6a43SSeth Howell free(name); 38507fe6a43SSeth Howell if (rc) { 38607fe6a43SSeth Howell SPDK_ERRLOG("could not construct bdev part\n"); 38707fe6a43SSeth Howell /* spdk_bdev_part_construct will free name on failure */ 38807fe6a43SSeth Howell free(d); 38907fe6a43SSeth Howell return -1; 39007fe6a43SSeth Howell } 39107fe6a43SSeth Howell num_partitions++; 39207fe6a43SSeth Howell d->partition_index = i; 39307fe6a43SSeth Howell } 39407fe6a43SSeth Howell 39507fe6a43SSeth Howell return num_partitions; 39607fe6a43SSeth Howell } 39707fe6a43SSeth Howell 39807fe6a43SSeth Howell static void 39985119e68SAlex Michon gpt_read_secondary_table_complete(struct spdk_bdev_io *bdev_io, bool success, void *arg) 40007fe6a43SSeth Howell { 40107fe6a43SSeth Howell struct gpt_base *gpt_base = (struct gpt_base *)arg; 40207fe6a43SSeth Howell struct spdk_bdev *bdev = spdk_bdev_part_base_get_bdev(gpt_base->part_base); 40307fe6a43SSeth Howell int rc, num_partitions = 0; 40407fe6a43SSeth Howell 40507fe6a43SSeth Howell spdk_bdev_free_io(bdev_io); 40607fe6a43SSeth Howell spdk_put_io_channel(gpt_base->ch); 40707fe6a43SSeth Howell gpt_base->ch = NULL; 40807fe6a43SSeth Howell 40985119e68SAlex Michon if (!success) { 41085119e68SAlex Michon SPDK_ERRLOG("Gpt: bdev=%s io error\n", spdk_bdev_get_name(bdev)); 41107fe6a43SSeth Howell goto end; 41207fe6a43SSeth Howell } 41307fe6a43SSeth Howell 4141d2faf6dSSeth Howell rc = gpt_parse_partition_table(&gpt_base->gpt); 41507fe6a43SSeth Howell if (rc) { 4162172c432STomasz Zawadzki SPDK_DEBUGLOG(vbdev_gpt, "Failed to parse secondary partition table\n"); 41707fe6a43SSeth Howell goto end; 41807fe6a43SSeth Howell } 41907fe6a43SSeth Howell 42007fe6a43SSeth Howell SPDK_WARNLOG("Gpt: bdev=%s primary partition table broken, use the secondary\n", 42107fe6a43SSeth Howell spdk_bdev_get_name(bdev)); 42207fe6a43SSeth Howell 42307fe6a43SSeth Howell num_partitions = vbdev_gpt_create_bdevs(gpt_base); 42407fe6a43SSeth Howell if (num_partitions < 0) { 4252172c432STomasz Zawadzki SPDK_DEBUGLOG(vbdev_gpt, "Failed to split dev=%s by gpt table\n", 42607fe6a43SSeth Howell spdk_bdev_get_name(bdev)); 42707fe6a43SSeth Howell } 42807fe6a43SSeth Howell 42907fe6a43SSeth Howell end: 43007fe6a43SSeth Howell spdk_bdev_module_examine_done(&gpt_if); 43107fe6a43SSeth Howell if (num_partitions <= 0) { 43207fe6a43SSeth Howell /* If no gpt_disk instances were created, free the base context */ 43307fe6a43SSeth Howell spdk_bdev_part_base_free(gpt_base->part_base); 43407fe6a43SSeth Howell } 43507fe6a43SSeth Howell } 43607fe6a43SSeth Howell 43707fe6a43SSeth Howell static int 43807fe6a43SSeth Howell vbdev_gpt_read_secondary_table(struct gpt_base *gpt_base) 43907fe6a43SSeth Howell { 44007fe6a43SSeth Howell struct spdk_gpt *gpt; 44107fe6a43SSeth Howell struct spdk_bdev_desc *part_base_desc; 44207fe6a43SSeth Howell uint64_t secondary_offset; 44307fe6a43SSeth Howell 44407fe6a43SSeth Howell gpt = &gpt_base->gpt; 44507fe6a43SSeth Howell gpt->parse_phase = SPDK_GPT_PARSE_PHASE_SECONDARY; 44607fe6a43SSeth Howell gpt->header = NULL; 44707fe6a43SSeth Howell gpt->partitions = NULL; 44807fe6a43SSeth Howell 44907fe6a43SSeth Howell part_base_desc = spdk_bdev_part_base_get_desc(gpt_base->part_base); 45007fe6a43SSeth Howell 45107fe6a43SSeth Howell secondary_offset = gpt->total_sectors * gpt->sector_size - gpt->buf_size; 45207fe6a43SSeth Howell return spdk_bdev_read(part_base_desc, gpt_base->ch, gpt_base->gpt.buf, secondary_offset, 4531d2faf6dSSeth Howell gpt_base->gpt.buf_size, gpt_read_secondary_table_complete, 45407fe6a43SSeth Howell gpt_base); 45507fe6a43SSeth Howell } 45607fe6a43SSeth Howell 45707fe6a43SSeth Howell static void 45885119e68SAlex Michon gpt_bdev_complete(struct spdk_bdev_io *bdev_io, bool success, void *arg) 45907fe6a43SSeth Howell { 46007fe6a43SSeth Howell struct gpt_base *gpt_base = (struct gpt_base *)arg; 46107fe6a43SSeth Howell struct spdk_bdev *bdev = spdk_bdev_part_base_get_bdev(gpt_base->part_base); 46207fe6a43SSeth Howell int rc, num_partitions = 0; 46307fe6a43SSeth Howell 46407fe6a43SSeth Howell spdk_bdev_free_io(bdev_io); 46507fe6a43SSeth Howell 46685119e68SAlex Michon if (!success) { 46785119e68SAlex Michon SPDK_ERRLOG("Gpt: bdev=%s io error\n", spdk_bdev_get_name(bdev)); 46807fe6a43SSeth Howell goto end; 46907fe6a43SSeth Howell } 47007fe6a43SSeth Howell 4711d2faf6dSSeth Howell rc = gpt_parse_mbr(&gpt_base->gpt); 47207fe6a43SSeth Howell if (rc) { 4732172c432STomasz Zawadzki SPDK_DEBUGLOG(vbdev_gpt, "Failed to parse mbr\n"); 47407fe6a43SSeth Howell goto end; 47507fe6a43SSeth Howell } 47607fe6a43SSeth Howell 4771d2faf6dSSeth Howell rc = gpt_parse_partition_table(&gpt_base->gpt); 47807fe6a43SSeth Howell if (rc) { 4792172c432STomasz Zawadzki SPDK_DEBUGLOG(vbdev_gpt, "Failed to parse primary partition table\n"); 48007fe6a43SSeth Howell rc = vbdev_gpt_read_secondary_table(gpt_base); 48107fe6a43SSeth Howell if (rc) { 48207fe6a43SSeth Howell SPDK_ERRLOG("Failed to read secondary table\n"); 48307fe6a43SSeth Howell goto end; 48407fe6a43SSeth Howell } 48507fe6a43SSeth Howell return; 48607fe6a43SSeth Howell } 48707fe6a43SSeth Howell 48807fe6a43SSeth Howell num_partitions = vbdev_gpt_create_bdevs(gpt_base); 48907fe6a43SSeth Howell if (num_partitions < 0) { 4902172c432STomasz Zawadzki SPDK_DEBUGLOG(vbdev_gpt, "Failed to split dev=%s by gpt table\n", 49107fe6a43SSeth Howell spdk_bdev_get_name(bdev)); 49207fe6a43SSeth Howell } 49307fe6a43SSeth Howell 49407fe6a43SSeth Howell end: 49507fe6a43SSeth Howell spdk_put_io_channel(gpt_base->ch); 49607fe6a43SSeth Howell gpt_base->ch = NULL; 49707fe6a43SSeth Howell /* 49807fe6a43SSeth Howell * Notify the generic bdev layer that the actions related to the original examine 49907fe6a43SSeth Howell * callback are now completed. 50007fe6a43SSeth Howell */ 50107fe6a43SSeth Howell spdk_bdev_module_examine_done(&gpt_if); 50207fe6a43SSeth Howell 50307fe6a43SSeth Howell /* 50407fe6a43SSeth Howell * vbdev_gpt_create_bdevs returns the number of bdevs created upon success. 50507fe6a43SSeth Howell * We can branch on this value. 50607fe6a43SSeth Howell */ 50707fe6a43SSeth Howell if (num_partitions <= 0) { 50807fe6a43SSeth Howell /* If no gpt_disk instances were created, free the base context */ 50907fe6a43SSeth Howell spdk_bdev_part_base_free(gpt_base->part_base); 51007fe6a43SSeth Howell } 51107fe6a43SSeth Howell } 51207fe6a43SSeth Howell 51307fe6a43SSeth Howell static int 51407fe6a43SSeth Howell vbdev_gpt_read_gpt(struct spdk_bdev *bdev) 51507fe6a43SSeth Howell { 51607fe6a43SSeth Howell struct gpt_base *gpt_base; 51707fe6a43SSeth Howell struct spdk_bdev_desc *part_base_desc; 51807fe6a43SSeth Howell int rc; 51907fe6a43SSeth Howell 5201d2faf6dSSeth Howell gpt_base = gpt_base_bdev_init(bdev); 52107fe6a43SSeth Howell if (!gpt_base) { 52207fe6a43SSeth Howell SPDK_ERRLOG("Cannot allocated gpt_base\n"); 52307fe6a43SSeth Howell return -1; 52407fe6a43SSeth Howell } 52507fe6a43SSeth Howell 52607fe6a43SSeth Howell part_base_desc = spdk_bdev_part_base_get_desc(gpt_base->part_base); 52707fe6a43SSeth Howell gpt_base->ch = spdk_bdev_get_io_channel(part_base_desc); 52807fe6a43SSeth Howell if (gpt_base->ch == NULL) { 52907fe6a43SSeth Howell SPDK_ERRLOG("Failed to get an io_channel.\n"); 53007fe6a43SSeth Howell spdk_bdev_part_base_free(gpt_base->part_base); 53107fe6a43SSeth Howell return -1; 53207fe6a43SSeth Howell } 53307fe6a43SSeth Howell 53407fe6a43SSeth Howell rc = spdk_bdev_read(part_base_desc, gpt_base->ch, gpt_base->gpt.buf, 0, 5351d2faf6dSSeth Howell gpt_base->gpt.buf_size, gpt_bdev_complete, gpt_base); 53607fe6a43SSeth Howell if (rc < 0) { 53707fe6a43SSeth Howell spdk_put_io_channel(gpt_base->ch); 53807fe6a43SSeth Howell spdk_bdev_part_base_free(gpt_base->part_base); 53907fe6a43SSeth Howell SPDK_ERRLOG("Failed to send bdev_io command\n"); 54007fe6a43SSeth Howell return -1; 54107fe6a43SSeth Howell } 54207fe6a43SSeth Howell 54307fe6a43SSeth Howell return 0; 54407fe6a43SSeth Howell } 54507fe6a43SSeth Howell 54607fe6a43SSeth Howell static int 54707fe6a43SSeth Howell vbdev_gpt_init(void) 54807fe6a43SSeth Howell { 54907fe6a43SSeth Howell return 0; 55007fe6a43SSeth Howell } 55107fe6a43SSeth Howell 55207fe6a43SSeth Howell static int 55307fe6a43SSeth Howell vbdev_gpt_get_ctx_size(void) 55407fe6a43SSeth Howell { 55507fe6a43SSeth Howell return sizeof(struct gpt_io); 55607fe6a43SSeth Howell } 55707fe6a43SSeth Howell 55807fe6a43SSeth Howell static void 55907fe6a43SSeth Howell vbdev_gpt_examine(struct spdk_bdev *bdev) 56007fe6a43SSeth Howell { 56107fe6a43SSeth Howell int rc; 56207fe6a43SSeth Howell 56307fe6a43SSeth Howell /* A bdev with fewer than 2 blocks cannot have a GPT. Block 0 has 56407fe6a43SSeth Howell * the MBR and block 1 has the GPT header. 56507fe6a43SSeth Howell */ 566ccdbe656STomasz Zawadzki if (spdk_bdev_get_num_blocks(bdev) < 2) { 56707fe6a43SSeth Howell spdk_bdev_module_examine_done(&gpt_if); 56807fe6a43SSeth Howell return; 56907fe6a43SSeth Howell } 57007fe6a43SSeth Howell 57107fe6a43SSeth Howell if (spdk_bdev_get_block_size(bdev) % 512 != 0) { 5722172c432STomasz Zawadzki SPDK_DEBUGLOG(vbdev_gpt, 573aeb693caSShuhei Matsumoto "GPT module does not support block size %" PRIu32 " for bdev %s\n", 57407fe6a43SSeth Howell spdk_bdev_get_block_size(bdev), spdk_bdev_get_name(bdev)); 57507fe6a43SSeth Howell spdk_bdev_module_examine_done(&gpt_if); 57607fe6a43SSeth Howell return; 57707fe6a43SSeth Howell } 57807fe6a43SSeth Howell 57907fe6a43SSeth Howell rc = vbdev_gpt_read_gpt(bdev); 58007fe6a43SSeth Howell if (rc) { 58107fe6a43SSeth Howell spdk_bdev_module_examine_done(&gpt_if); 58207fe6a43SSeth Howell SPDK_ERRLOG("Failed to read info from bdev %s\n", spdk_bdev_get_name(bdev)); 58307fe6a43SSeth Howell } 58407fe6a43SSeth Howell } 58507fe6a43SSeth Howell 5862172c432STomasz Zawadzki SPDK_LOG_REGISTER_COMPONENT(vbdev_gpt) 587