]> git.proxmox.com Git - ceph.git/blobdiff - ceph/src/spdk/lib/bdev/gpt/vbdev_gpt.c
import 15.2.0 Octopus source
[ceph.git] / ceph / src / spdk / lib / bdev / gpt / vbdev_gpt.c
index 751af0ea862c3b61221e788deb276fb8468b88fb..7f1f6d641466f13da05a8fc9795ee1bbe04ce860 100644 (file)
@@ -60,12 +60,13 @@ static struct spdk_bdev_module gpt_if = {
        .examine_disk = vbdev_gpt_examine,
 
 };
-SPDK_BDEV_MODULE_REGISTER(&gpt_if)
+SPDK_BDEV_MODULE_REGISTER(gpt, &gpt_if)
 
 /* Base block device gpt context */
 struct gpt_base {
        struct spdk_gpt                 gpt;
        struct spdk_bdev_part_base      *part_base;
+       SPDK_BDEV_PART_TAILQ            parts;
 
        /* This channel is only used for reading the partition table. */
        struct spdk_io_channel          *ch;
@@ -89,8 +90,6 @@ struct gpt_io {
        struct spdk_bdev_io_wait_entry bdev_io_wait;
 };
 
-static SPDK_BDEV_PART_TAILQ g_gpt_disks = TAILQ_HEAD_INITIALIZER(g_gpt_disks);
-
 static bool g_gpt_disabled;
 
 static void
@@ -98,14 +97,17 @@ spdk_gpt_base_free(void *ctx)
 {
        struct gpt_base *gpt_base = ctx;
 
-       spdk_dma_free(gpt_base->gpt.buf);
+       spdk_free(gpt_base->gpt.buf);
        free(gpt_base);
 }
 
 static void
-spdk_gpt_base_bdev_hotremove_cb(void *_base_bdev)
+spdk_gpt_base_bdev_hotremove_cb(void *_part_base)
 {
-       spdk_bdev_part_base_hotremove(_base_bdev, &g_gpt_disks);
+       struct spdk_bdev_part_base *part_base = _part_base;
+       struct gpt_base *gpt_base = spdk_bdev_part_base_get_ctx(part_base);
+
+       spdk_bdev_part_base_hotremove(part_base, &gpt_base->parts);
 }
 
 static int vbdev_gpt_destruct(void *ctx);
@@ -130,10 +132,11 @@ spdk_gpt_base_bdev_init(struct spdk_bdev *bdev)
                return NULL;
        }
 
+       TAILQ_INIT(&gpt_base->parts);
        gpt_base->part_base = spdk_bdev_part_base_construct(bdev,
                              spdk_gpt_base_bdev_hotremove_cb,
                              &gpt_if, &vbdev_gpt_fn_table,
-                             &g_gpt_disks, spdk_gpt_base_free, gpt_base,
+                             &gpt_base->parts, spdk_gpt_base_free, gpt_base,
                              sizeof(struct gpt_channel), NULL, NULL);
        if (!gpt_base->part_base) {
                free(gpt_base);
@@ -142,8 +145,10 @@ spdk_gpt_base_bdev_init(struct spdk_bdev *bdev)
        }
 
        gpt = &gpt_base->gpt;
+       gpt->parse_phase = SPDK_GPT_PARSE_PHASE_PRIMARY;
        gpt->buf_size = spdk_max(SPDK_GPT_BUFFER_SIZE, bdev->blocklen);
-       gpt->buf = spdk_dma_zmalloc(gpt->buf_size, spdk_bdev_get_buf_align(bdev), NULL);
+       gpt->buf = spdk_zmalloc(gpt->buf_size, spdk_bdev_get_buf_align(bdev), NULL,
+                               SPDK_ENV_LCORE_ID_ANY, SPDK_MALLOC_DMA);
        if (!gpt->buf) {
                SPDK_ERRLOG("Cannot alloc buf\n");
                spdk_bdev_part_base_free(gpt_base->part_base);
@@ -248,14 +253,11 @@ vbdev_gpt_dump_info_json(void *ctx, struct spdk_json_write_ctx *w)
        struct spdk_gpt_partition_entry *gpt_entry = &gpt->partitions[gpt_disk->partition_index];
        uint64_t offset_blocks = spdk_bdev_part_get_offset_blocks(&gpt_disk->part);
 
-       spdk_json_write_name(w, "gpt");
-       spdk_json_write_object_begin(w);
+       spdk_json_write_named_object_begin(w, "gpt");
 
-       spdk_json_write_name(w, "base_bdev");
-       spdk_json_write_string(w, spdk_bdev_get_name(part_base_bdev));
+       spdk_json_write_named_string(w, "base_bdev", spdk_bdev_get_name(part_base_bdev));
 
-       spdk_json_write_name(w, "offset_blocks");
-       spdk_json_write_uint64(w, offset_blocks);
+       spdk_json_write_named_uint64(w, "offset_blocks", offset_blocks);
 
        spdk_json_write_name(w, "partition_type_guid");
        write_guid(w, &gpt_entry->part_type_guid);
@@ -336,7 +338,7 @@ vbdev_gpt_create_bdevs(struct gpt_base *gpt_base)
 }
 
 static void
-spdk_gpt_bdev_complete(struct spdk_bdev_io *bdev_io, bool status, void *arg)
+spdk_gpt_read_secondary_table_complete(struct spdk_bdev_io *bdev_io, bool status, void *arg)
 {
        struct gpt_base *gpt_base = (struct gpt_base *)arg;
        struct spdk_bdev *bdev = spdk_bdev_part_base_get_bdev(gpt_base->part_base);
@@ -352,12 +354,81 @@ spdk_gpt_bdev_complete(struct spdk_bdev_io *bdev_io, bool status, void *arg)
                goto end;
        }
 
-       rc = spdk_gpt_parse(&gpt_base->gpt);
+       rc = spdk_gpt_parse_partition_table(&gpt_base->gpt);
+       if (rc) {
+               SPDK_DEBUGLOG(SPDK_LOG_VBDEV_GPT, "Failed to parse secondary partition table\n");
+               goto end;
+       }
+
+       SPDK_WARNLOG("Gpt: bdev=%s primary partition table broken, use the secondary\n",
+                    spdk_bdev_get_name(bdev));
+
+       num_partitions = vbdev_gpt_create_bdevs(gpt_base);
+       if (num_partitions < 0) {
+               SPDK_DEBUGLOG(SPDK_LOG_VBDEV_GPT, "Failed to split dev=%s by gpt table\n",
+                             spdk_bdev_get_name(bdev));
+       }
+
+end:
+       spdk_bdev_module_examine_done(&gpt_if);
+       if (num_partitions <= 0) {
+               /* If no gpt_disk instances were created, free the base context */
+               spdk_bdev_part_base_free(gpt_base->part_base);
+       }
+}
+
+static int
+vbdev_gpt_read_secondary_table(struct gpt_base *gpt_base)
+{
+       struct spdk_gpt *gpt;
+       struct spdk_bdev_desc *part_base_desc;
+       uint64_t secondary_offset;
+
+       gpt = &gpt_base->gpt;
+       gpt->parse_phase = SPDK_GPT_PARSE_PHASE_SECONDARY;
+       gpt->header = NULL;
+       gpt->partitions = NULL;
+
+       part_base_desc = spdk_bdev_part_base_get_desc(gpt_base->part_base);
+
+       secondary_offset = gpt->total_sectors * gpt->sector_size - gpt->buf_size;
+       return spdk_bdev_read(part_base_desc, gpt_base->ch, gpt_base->gpt.buf, secondary_offset,
+                             gpt_base->gpt.buf_size, spdk_gpt_read_secondary_table_complete,
+                             gpt_base);
+}
+
+static void
+spdk_gpt_bdev_complete(struct spdk_bdev_io *bdev_io, bool status, void *arg)
+{
+       struct gpt_base *gpt_base = (struct gpt_base *)arg;
+       struct spdk_bdev *bdev = spdk_bdev_part_base_get_bdev(gpt_base->part_base);
+       int rc, num_partitions = 0;
+
+       spdk_bdev_free_io(bdev_io);
+
+       if (status != SPDK_BDEV_IO_STATUS_SUCCESS) {
+               SPDK_ERRLOG("Gpt: bdev=%s io error status=%d\n",
+                           spdk_bdev_get_name(bdev), status);
+               goto end;
+       }
+
+       rc = spdk_gpt_parse_mbr(&gpt_base->gpt);
        if (rc) {
-               SPDK_DEBUGLOG(SPDK_LOG_VBDEV_GPT, "Failed to parse gpt\n");
+               SPDK_DEBUGLOG(SPDK_LOG_VBDEV_GPT, "Failed to parse mbr\n");
                goto end;
        }
 
+       rc = spdk_gpt_parse_partition_table(&gpt_base->gpt);
+       if (rc) {
+               SPDK_DEBUGLOG(SPDK_LOG_VBDEV_GPT, "Failed to parse primary partition table\n");
+               rc = vbdev_gpt_read_secondary_table(gpt_base);
+               if (rc) {
+                       SPDK_ERRLOG("Failed to read secondary table\n");
+                       goto end;
+               }
+               return;
+       }
+
        num_partitions = vbdev_gpt_create_bdevs(gpt_base);
        if (num_partitions < 0) {
                SPDK_DEBUGLOG(SPDK_LOG_VBDEV_GPT, "Failed to split dev=%s by gpt table\n",
@@ -365,6 +436,8 @@ spdk_gpt_bdev_complete(struct spdk_bdev_io *bdev_io, bool status, void *arg)
        }
 
 end:
+       spdk_put_io_channel(gpt_base->ch);
+       gpt_base->ch = NULL;
        /*
         * Notify the generic bdev layer that the actions related to the original examine
         *  callback are now completed.