首页 > 编程语言 >实验三·bdev原理和源码分析

实验三·bdev原理和源码分析

时间:2022-11-26 19:04:02浏览次数:123  
标签:io SPDK lab3 spdk 源码 context 原理 bdev

任务

  • 配置bdev运行环境

  • 运行hello_bdev程序并分析源码

  • 通过bdev接口写入数据并读取

Bdev是在物理设备上的进一步抽象,物理层有NVM、 NVMeOF、CEPH RBD等,通过bdev向上提供统一接口,应用层可屏蔽底层细节,直接面向bdev读写数据。 SPDK bdev对ZNS SSD支持不完善,bug较多,调试需要花费大量时间,后续实验采用普通NVMe进行。

实验过程

运行并分析hello_bdev.c源码

新建虚拟盘并启动

新建虚拟盘

qemu-img create -f qcow2 nvme.qcow2 10G

启动虚拟机

sudo qemu-system-x86_64 -name qemucsd -m 2G --enable-kvm -cpu host -smp 4 -hda ./ubuntu.qcow2 -net user,hostfwd=tcp:127.0.0.1:7777-:22,hostfwd=tcp:127.0.0.1:2222-:2000 -net nic -drive file=nvme.qcow2,if=none,id=nvm -device nvme,serial=deadbeef,drive=nvm -nographic -fsdev local,id=fsdev0,path=./work/,security_model=none  -device virtio-9p-pci,id=fs0,fsdev=fsdev0,mount_tag=hostshare

挂载共享目录

sudo mount hostshare -t 9p ./work

报错bad option; for several filesystems (e.g. nfs***, cifs) you might need a /sbin/mount. helper program.***

可能是因为启动时没有加参数-fsdev local,id=fsdev0,path=./work/,security_model=none -device virtio-9p-pci,id=fs0,fsdev=fsdev0,mount_tag=hostshare

初始化环境

sudo HUGEMEM=1024 scripts/setup.sh

生成配置文件

./scripts/gen_nvme.sh --json-with-subsystems > ./build/examples/nvme.json

运行hello_bdev程序

cd build/examples/
sudo ./hello_bdev -c nvme.json -b Nvme0n1

img

分析hello_bdev.c源码

文件目录:spdk/examples/bdev/hello_world/hello_bdev.c

主函数 main

暂时无法在飞书文档外展示此内容

函数hello_start

暂时无法在飞书文档外展示此内容

函数hello_write

暂时无法在飞书文档外展示此内容

函数write_complete

本函数中首先释放io,然后清空缓冲区,再调用hello_read函数。

函数hello_read

和hello_write类似,只是调用了读取相关的函数,读取成功后调用read_complete

函数read_complete

打印出读出的内容并且释放io和缓冲区、关闭服务等。

修改hello_bdev.c源码

要求:生成256KB字符串数据,修改hello_bdev.c源码将字符串数据通过bdev写入,之后再读取,验证结果是否正确

这部分参考了https://miracle24.site/other/cs-exp-zns-3/

/*   SPDX-License-Identifier: BSD-3-Clause
 *   Copyright (C) 2018 Intel Corporation.
 *   All rights reserved.
 */

#include "spdk/stdinc.h"
#include "spdk/thread.h"
#include "spdk/bdev.h"
#include "spdk/env.h"
#include "spdk/event.h"
#include "spdk/log.h"
#include "spdk/string.h"
#include "spdk/bdev_zone.h"

//生成随机数
#include "time.h"
#include "stdlib.h"

static char *g_bdev_name = "Nvme0n1";
const int STRING_LEN = 256*1024*8 // 随机生成字符串的长度为256KB

struct lab3_context_t {
    struct spdk_bdev *bdev;
    struct spdk_bdev_desc *bdev_desc;
    struct spdk_io_channel *bdev_io_channel;
    char *buff;
    uint32_t buff_size;
    char *bdev_name;
    struct spdk_bdev_io_wait_entry bdev_io_wait;
};

/*
 * 生成随机256KB数据
 */

static char* random_str(void)
{
    //开辟字符串空间并清零
    char *str = (char*)malloc(STRING_LEN);
    memset(str, 0 , STRING_LEN);
    if(str)
    {
        //生成随机种子
        srand((unsigned int)time(0));
        //在字符串每一位填入随机可显示的ASCII码
        int i = 0;
        for(i=0;i<STRING_LEN;i++)
        {
            str[i] = (char) (32 + rand() % 93);
        }
        return str;
    }
    else
    {
        printf("字符串开辟失败\n");
            SPDK_ERRLOG("Failed to allocate buffer\n");
            spdk_put_io_channel(lab3_context->bdev_io_channel);
            spdk_bdev_close(lab3_context->bdev_desc);
            spdk_app_stop(-1);
            return NULL;
    }
}

/*
 * Usage function for printing parameters that are specific to this application
 */
static void
lab3_bdev_usage(void)
{
    printf(" -b <bdev>                 name of the bdev to use\n");
}

/*
 * This function is called to parse the parameters that are specific to this application
 */
static int
lab3_bdev_parse_arg(int ch, char *arg)
{
    switch (ch) {
    case 'b':
        g_bdev_name = arg;
        break;
    default:
        return -EINVAL;
    }
    return 0;
}

/*
 * Callback function for read io completion.
 */
static void
read_complete(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg)
{
    struct lab3_context_t *lab3_context = cb_arg;

    if (success) {
        SPDK_NOTICELOG("Read string from bdev : %s\n", lab3_context->buff);
    } else {
        SPDK_ERRLOG("bdev io read error\n");
    }

    /* Complete the bdev io and close the channel */
    spdk_bdev_free_io(bdev_io);
    spdk_put_io_channel(lab3_context->bdev_io_channel);
    spdk_bdev_close(lab3_context->bdev_desc);
    SPDK_NOTICELOG("Stopping app\n");
    spdk_app_stop(success ? 0 : -1);
}

static void
lab3_read(void *arg)
{
    struct lab3_context_t *lab3_context = arg;
    int rc = 0;

    SPDK_NOTICELOG("Reading io\n");
    rc = spdk_bdev_read(lab3_context->bdev_desc, lab3_context->bdev_io_channel,
                lab3_context->buff, 0, lab3_context->buff_size, read_complete,
                lab3_context);

    if (rc == -ENOMEM) {
        SPDK_NOTICELOG("Queueing io\n");
        /* In case we cannot perform I/O now, queue I/O */
        lab3_context->bdev_io_wait.bdev = lab3_context->bdev;
        lab3_context->bdev_io_wait.cb_fn = lab3_read;
        lab3_context->bdev_io_wait.cb_arg = lab3_context;
        spdk_bdev_queue_io_wait(lab3_context->bdev, lab3_context->bdev_io_channel,
                    &lab3_context->bdev_io_wait);
    } else if (rc) {
        SPDK_ERRLOG("%s error while reading from bdev: %d\n", spdk_strerror(-rc), rc);
        spdk_put_io_channel(lab3_context->bdev_io_channel);
        spdk_bdev_close(lab3_context->bdev_desc);
        spdk_app_stop(-1);
    }
}

/*
 * Callback function for write io completion.
 */
static void
write_complete(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg)
{
    struct lab3_context_t *lab3_context = cb_arg;

    /* Complete the I/O */
    spdk_bdev_free_io(bdev_io);

    if (success) {
        SPDK_NOTICELOG("bdev io write completed successfully\n");
    } else {
        SPDK_ERRLOG("bdev io write error: %d\n", EIO);
        spdk_put_io_channel(lab3_context->bdev_io_channel);
        spdk_bdev_close(lab3_context->bdev_desc);
        spdk_app_stop(-1);
        return;
    }

    /* Zero the buffer so that we can use it for reading */
    memset(lab3_context->buff, 0, lab3_context->buff_size);

    lab3_read(lab3_context);
}

static void
lab3_write(void *arg)
{
    struct lab3_context_t *lab3_context = arg;
    int rc = 0;

    SPDK_NOTICELOG("Writing to the bdev\n");
    rc = spdk_bdev_write(lab3_context->bdev_desc, lab3_context->bdev_io_channel,
                 lab3_context->buff, 0, lab3_context->buff_size, write_complete,
                 lab3_context);

    if (rc == -ENOMEM) {
        SPDK_NOTICELOG("Queueing io\n");
        lab3_context->bdev_io_wait.bdev = lab3_context->bdev;
        lab3_context->bdev_io_wait.cb_fn = lab3_write;
        lab3_context->bdev_io_wait.cb_arg = lab3_context;
        spdk_bdev_queue_io_wait(lab3_context->bdev, lab3_context->bdev_io_channel,
                    &lab3_context->bdev_io_wait);
    } else if (rc) {
        SPDK_ERRLOG("%s error while writing to bdev: %d\n", spdk_strerror(-rc), rc);
        spdk_put_io_channel(lab3_context->bdev_io_channel);
        spdk_bdev_close(lab3_context->bdev_desc);
        spdk_app_stop(-1);
    }
}

static void
lab3_bdev_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev,
            void *event_ctx)
{
    SPDK_NOTICELOG("Unsupported bdev event: type %d\n", type);
}

static void
reset_zone_complete(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg)
{
    struct lab3_context_t *lab3_context = cb_arg;

    /* Complete the I/O */
    spdk_bdev_free_io(bdev_io);

    if (!success) {
        SPDK_ERRLOG("bdev io reset zone error: %d\n", EIO);
        spdk_put_io_channel(lab3_context->bdev_io_channel);
        spdk_bdev_close(lab3_context->bdev_desc);
        spdk_app_stop(-1);
        return;
    }

    lab3_write(lab3_context);
}

static void
lab3_reset_zone(void *arg)
{
    struct lab3_context_t *lab3_context = arg;
    int rc = 0;

    rc = spdk_bdev_zone_management(lab3_context->bdev_desc, lab3_context->bdev_io_channel,
                       0, SPDK_BDEV_ZONE_RESET, reset_zone_complete, lab3_context);

    if (rc == -ENOMEM) {
        SPDK_NOTICELOG("Queueing io\n");
        /* In case we cannot perform I/O now, queue I/O */
        lab3_context->bdev_io_wait.bdev = lab3_context->bdev;
        lab3_context->bdev_io_wait.cb_fn = lab3_reset_zone;
        lab3_context->bdev_io_wait.cb_arg = lab3_context;
        spdk_bdev_queue_io_wait(lab3_context->bdev, lab3_context->bdev_io_channel,
                    &lab3_context->bdev_io_wait);
    } else if (rc) {
        SPDK_ERRLOG("%s error while resetting zone: %d\n", spdk_strerror(-rc), rc);
        spdk_put_io_channel(lab3_context->bdev_io_channel);
        spdk_bdev_close(lab3_context->bdev_desc);
        spdk_app_stop(-1);
    }
}

static void
lab3_start(void *arg1)
{
    struct lab3_context_t *lab3_context = arg1;
    uint32_t buf_align;
    int rc = 0;
    lab3_context->bdev = NULL;
    lab3_context->bdev_desc = NULL;

    SPDK_NOTICELOG("Successfully started the application\n");

    SPDK_NOTICELOG("Opening the bdev %s\n", lab3_context->bdev_name);
    rc = spdk_bdev_open_ext(lab3_context->bdev_name, true, lab3_bdev_event_cb, NULL,
                &lab3_context->bdev_desc);
    if (rc) {
        SPDK_ERRLOG("Could not open bdev: %s\n", lab3_context->bdev_name);
        spdk_app_stop(-1);
        return;
    }

    lab3_context->bdev = spdk_bdev_desc_get_bdev(lab3_context->bdev_desc);

    SPDK_NOTICELOG("Opening io channel\n");

    lab3_context->bdev_io_channel = spdk_bdev_get_io_channel(lab3_context->bdev_desc);
    if (lab3_context->bdev_io_channel == NULL) {
        SPDK_ERRLOG("Could not create bdev I/O channel!!\n");
        spdk_bdev_close(lab3_context->bdev_desc);
        spdk_app_stop(-1);
        return;
    }

    lab3_context->buff_size = spdk_bdev_get_block_size(lab3_context->bdev) *
                //    spdk_bdev_get_write_unit_size(lab3_context->bdev);
                ceil((STRING_LEN/8.0)/spdk_bdev_get_block_size(lab3_context->bdev));
    buf_align = spdk_bdev_get_buf_align(lab3_context->bdev);
    lab3_context->buff = spdk_dma_zmalloc(lab3_context->buff_size, buf_align, NULL);
    if (!lab3_context->buff) {
        SPDK_ERRLOG("Failed to allocate buffer\n");
        spdk_put_io_channel(lab3_context->bdev_io_channel);
        spdk_bdev_close(lab3_context->bdev_desc);
        spdk_app_stop(-1);
        return;
    }
    sprintf(lab3_context->buff,, "%s", random_str());

    if (spdk_bdev_is_zoned(lab3_context->bdev)) {
        lab3_reset_zone(lab3_context);
        /* If bdev is zoned, the callback, reset_zone_complete, will call lab3_write() */
        return;
    }

    lab3_write(lab3_context);
}

int
main(int argc, char **argv)
{
    struct spdk_app_opts opts = {};
    int rc = 0;
    struct lab3_context_t lab3_context = {};

    
    spdk_app_opts_init(&opts, sizeof(opts));
    opts.name = "lab3_bdev";

    /*
     * Parse built-in SPDK command line parameters as well
     * as our custom one(s).
     */
    if ((rc = spdk_app_parse_args(argc, argv, &opts, "b:", NULL, lab3_bdev_parse_arg,
                      lab3_bdev_usage)) != SPDK_APP_PARSE_ARGS_SUCCESS) {
        exit(rc);
    }
    lab3_context.bdev_name = g_bdev_name;

    /*
     * spdk_app_start() will initialize the SPDK framework, call lab3_start(),
     * and then block until spdk_app_stop() is called (or if an initialization
     * error occurs, spdk_app_start() will return with rc even without calling
     * lab3_start().
     */
    rc = spdk_app_start(&opts, lab3_start, &lab3_context);
    if (rc) {
        SPDK_ERRLOG("ERROR starting application\n");
    }

    /* At this point either spdk_app_stop() was called, or spdk_app_start()
     * failed because of internal error.
     */

    /* When the app stops, free up memory that we allocated. */
    spdk_dma_free(lab3_context.buff);

    /* Gracefully close out all of the SPDK subsystems. */
    spdk_app_fini();
    return rc;
}
SPDK_ROOT_DIR := /home/cwj/work/spdk

include $(SPDK_ROOT_DIR)/mk/spdk.common.mk
include $(SPDK_ROOT_DIR)/mk/spdk.modules.mk

APP = lab3_code

C_SRCS := lab3_code.c

SPDK_LIB_LIST = $(ALL_MODULES_LIST) event event_bdev

include $(SPDK_ROOT_DIR)/mk/spdk.app.mk

run: all
    @ echo "编译结束,清除中间文件"
    @ rm -f lab3_code.d lab3_code.o
    @ echo "生成配置文件"
    @ $(SPDK_ROOT_DIR)/scripts/gen_nvme.sh --json-with-subsystems > ./lab3_code.json
    @ echo "运行程序"
    @ sudo ./lab3_code -c ./lab3_code.json
    @ echo "数据大小:按照要求是256KB"
    @ echo " "
    @ du -h data.*
    @ echo " "
    @ echo "比较数据内容,没有输出则是相同"
    @ diff data.in data.out

运行修改后的程序

sudo HUGEMEM=1024 scripts/setup.sh
cd ..
cd lab3
make run

img

可见完成了实验要求。

标签:io,SPDK,lab3,spdk,源码,context,原理,bdev
From: https://www.cnblogs.com/hushrush/p/16928031.html

相关文章

  • 实验四·blobstore原理和源码分析
    实验任务学习Blob基本原理完成hello_blob程序运行修改底层bdev为nvmeBlob构建在bdev之上,是对数据存储的进一步抽象,类似于文件,但是不具备文件POSIX接口,可近似按文件形......
  • easylogging++的那些事(四)源码分析(二)日志记录宏(一)CLOG宏(四)日志信息保存
    目录writer类的输出运算符writer类的流操控符el::base::MessageBuilder类CLOG宏接口调用流程图在上一篇中我们分析完了CLOG宏日志输出的流程,在结尾的时候我们提......
  • 实验三 ORI指令设计实验【计算机组成原理】
    实验三ORI指令设计实验【计算机组成原理】​​前言​​​​推荐​​​​实验三ORI指令设计实验​​​​一、实验目的​​​​二、实验环境​​​​三、实验原理​​​​四......
  • 在CentOS编译Git源码
    Git是一个免费的开源分布式版本控制系统,旨在处理从小到小到的所有内容具有速度和效率的超大型项目。Git易于学习,占用空间很小,性能快如闪电。它超越了Subversion,CVS,Per......
  • CentOS7源码安装Nginx1.22
    CentOS7源码安装Nginx1.22一、安装下载源码包:wgethttp://nginx.org/download/nginx-1.22.1.tar.gz安装依赖:yum-yinstallgccmakepcrepcre-developensslope......
  • AFL源码分析(一)
    AFL源码分析(一)文章首发于:ChaMd5公众号​​https://mp.weixin.qq.com/s/E-D_M25xv5gIpRa6k8xOvw​​a.alf-gcc.c1.find_as这个函数的功能是获取使用的汇编器。首先获取环境......
  • 计算机组成原理习题课第一章-1(唐朔飞)
    计算机组成原理习题课第一章-1(唐朔飞)✨欢迎关注......
  • 深入剖析Java Stream底层源码
    1Stream的使用在深入学习Stream的本质之前,我们需要先熟悉Stream的使用规则。对Stream有了整体的认识之后,才能更好的理解它的本质。1.1使用步骤使用Stream只需要遵循3......
  • easylogging++的那些事(四)源码分析(二)日志记录宏(一)CLOG宏(三)日志输出
    目录Writer析构函数Writer::processDispatch接口Writer::triggerDispatch接口base::LogDispatcher::dispatch接口DefaultLogDispatchCallback::handle接口DefaultLogD......
  • JSP课设:学生选课系统(附源码+调试)
    JSP学生选课管理系统学生选课管理系统功能概述(1)登录模块分为两种角色:学生角色、教师角色(2)教师模块:选课管理功能为对课程信息(课程编号、名称、学分)进行添加、修改、删除操......