"auth_service_required": "cephx", "auth_service_ticket_ttl": "3600.000000", "auth_supported": "", "bdev_aio ": "true", "bdev_aio_max_queue_depth": "1024", "bdev_aio_poll_ms": "250", "bdev_aio_reap_max": "16", "bdev_async_discard": "false", "bdev_block_size": "4096", "bdev_debug_aio": "false", "bdev_debug_aio_suicide_timeout ": "60.000000", "bdev_debug_inflight_ios": "false", "bdev_enable_discard": "false", "bdev_inject_crash ": "0", "bdev_inject_crash_flush_delay": "2", "bdev_nvme_retry_count": "-1", "bdev_nvme_unbind_from_kernel
cb, cb_arg)bdev_io = bdev_channel_get_io(channel)bdev_io->u.bdev.iovs = iov...bdev->fn_table->submit_request (bdev_io, bdev_iscsi_get_buf_cb, bdev_io->u.bdev.num_blocks * bdev_io->bdev->blocklen) alignment = spdk_bdev_get_buf_align(bdev) _are_iovs_aligned(bdev_io->u.bdev.iovs, bdev_io_get_buf(bdev_io, len) max_len = bdev_io_get_max_buf_len(bdev_io, len) bdev_io_pull_data(bdev_io)bdev_iscsi_get_buf_cb bdev_iscsi_readv task = iscsi_read16_task(lun
) rpc_bdev_daos_create -> module/bdev/daos/bdev_daos_rpc.c create_bdev_daos block_size % 512 512 -> lib/bdev/bdev.c -> spdk_bdev_register(struct spdk_bdev *bdev) bdev_register(bdev) -> lib/bdev /bdev.c -> bdev_register(struct spdk_bdev *bdev) spdk_bdev_get_memory_domains 获取给定 bdev 使用的 SPDK bdev.c 当前使用 spdk_bdev 指针作为其 io_device 句柄,强制 bdev 模块选择不同的东西。 注册 bdev 时,bdev 模块会在通知 bdev 寄存器之前对其进行检查。
"auth_service_required": "cephx", "auth_service_ticket_ttl": "3600.000000", "auth_supported": "", "bdev_aio ": "true", "bdev_aio_max_queue_depth": "1024", "bdev_aio_poll_ms": "250", "bdev_aio_reap_max": "16", "bdev_async_discard": "false", "bdev_block_size": "4096", "bdev_debug_aio": "false", "bdev_debug_aio_suicide_timeout ": "60.000000", "bdev_debug_inflight_ios": "false", "bdev_enable_discard": "false", "bdev_inject_crash ": "0", "bdev_inject_crash_flush_delay": "2", "bdev_nvme_retry_count": "-1", "bdev_nvme_unbind_from_kernel
endpoint->ops.attach_device(endpoint) vfu_virtio_blk_add_bdev(req.name, req.bdev_name, req.num_queues , req.qsize, req.packed_ring) spdk_bdev_open_ext(bdev_name, true, bdev_event_cb, blk_endpoint , &blk_endpoint->bdev_desc) -> open and set bdev_desc -> 关联bdev virtio_blk_update_config(&blk_endpoint ->blk_cfg, blk_endpoint->bdev, blk_endpoint->virtio.num_queues) blk_cfg->blk_size = spdk_bdev_get_block_size case VIRTIO_BLK_T_FLUSH spdk_bdev_flush(blk_endpoint->bdev_desc, blk_endpoint->io_channel
到SPDK框架,让virtio设备对外呈现为bdev提供服务。 SPDK应用主要通过呈现的bdev对virtio 设备进行访问,IO读写及控制类接口与其它普通bdev无异,其后台由前述的virtio_fn_table中的函数来进行转化处理。 比如可以通过json配置文件或者rpc命令指定要使用的virtio block device的pci addr信息及对应创建的spdk_bdev设备名称,然后对该bdev设备跑测试。 到SPDK框架,让virtio设备对外呈现为bdev提供服务。 设备实现时没有经过SPDK bdev的框架,且目前代码中仅实现了一种通过申请的内存模拟的bdev类型。
(fs_type, flags, dev_name, data, ext4_fill_super,mnt);4236 } 这里面一共调用了两个接口get_sb_bdev和ext4_fill_super 后面涉及到了对块设备操作的很多工作,文件系统最关键的就是管理文件,并且是块设备上的,这个块设备就是在get_sb_bdev里面得到的 747 int get_sb_bdev(struct file_system_type (flags & MS_RDONLY)) 758 mode |= FMODE_WRITE; 759 760 bdev = open_bdev_exclusive(dev_name, mode, fs_type ); 761 if (IS_ERR(bdev)) 762 return PTR_ERR(bdev);…… 799 800 s->s_flags = flags; 801 s->s_mode = mode ; 802 strlcpy(s->s_id, bdevname(bdev, b), sizeof(s->s_id)); 803 sb_set_blocksize(s, block_size(bdev))
(block device)实现,mount_bdev判断两次挂载是否为同一个文件系统的依据是:是否为同一个块设备(test_bdev_super),也就是同一个块设备只有一个super_block与之对应 ); if (IS_ERR(bdev)) return ERR_CAST(bdev); /* * once the super is inserted into the list by ->bd_fsfreeze_mutex); if (bdev->bd_fsfreeze_count > 0) { mutex_unlock(&bdev->bd_fsfreeze_mutex); error = -EBUSY; goto error_bdev; } s = sget(fs_type, test_bdev_super, set_bdev_super, flags | MS_NOSEC , bdev); mutex_unlock(&bdev->bd_fsfreeze_mutex); if (IS_ERR(s)) goto error_s; if (s->s_root
_bdev_io_submit_ext(desc, bdev_io) -> bdev:从 spdk_bdev_io 中删除 spdk_bdev_ext_io_opts spdk_bdev_ext_io_opts 3. spdk_bdev_ext_io_opts有一个metadata字段,而spdk_bdev_io已经有u.bdev.md_buf,这意味着我们在spdk_bdev_io中的几个不同的地方存储相同的东西 不幸的是,此更改破坏了 API,并需要更改支持 spdk_bdev_io.u.bdev.ext_opts 的 bdev 模块 bdev_io_needs_sequence_exec , bdev_io, internal.ch_link) _bdev_io_submit(bdev_io) bdev_io_do_submit bdev_submit_request(bdev, ch, bdev_io) -> bdev->fn_table->submit_request(ioch, bdev_io) -> bdev_malloc_submit_request
Mount_bdev()函数主要完成superblock对象的内存初始化,并且加入到全局superblock链表中。 (flags & MS_RDONLY)) mode |= FMODE_WRITE; /* 通过设备名字获取被mount设备的bdev对象 */ bdev = blkdev_get_by_path (dev_name, mode, fs_type); if (IS_ERR(bdev)) return ERR_CAST(bdev); /* * once ->bd_fsfreeze_mutex); if (bdev->bd_fsfreeze_count > 0) { mutex_unlock(&bdev->bd_fsfreeze_mutex (fs_type, test_bdev_super, set_bdev_super, bdev); mutex_unlock(&bdev->bd_fsfreeze_mutex); if
; long ret = 0; spin_lock(&bdev_lock); list_for_each_entry(bdev, &all_bdevs, bd_list) { ret += bdev->bd_inode->i_mapping->nrpages; } spin_unlock(& 首先是块设备本身,打开时使用 bdev->bd_inode->i_mapping。 = bdev->bd_inode->i_mapping; return blkdev_get(bdev, filp->f_mode, filp); } 其次,文件系统的Superblock if (sb->s_bdev) { struct backing_dev_info *bdi; bdi = sb->s_bdev->bd_inode
,在SPDK上创建bdev就相当于物理机理硬盘槽位上插入硬盘,数据到了SPDK的bdev,再通过SPDK的driver落的本地或者远端真正的硬件上。 #创建一个spdk bdev spdk_rpc.py bdev_null_create Snap1 200000 512 #把这个nvme controller和SPDK关联起来,执行这一步之后 裸金属写到硬盘里的数据就能被 virtio-blk #spdk创建bdev Snap0 spdk_rpc.py bdev_null_create Snap0 100000 512 #创建一个device snap_rpc.py emulation_device_attach --bdev_type spdk --bdev Snap0 mlx5_0 virtio_blk image.png #创建controller,把device加到这个controller上 snap_rpc.py controller_virtio_blk_create -d 61:00.0 --bdev_type spdk --bdev Snap0 mlx5_0 ?
它们之间的关系如下所示(以NVMe bdev为例): ? BlobFS在管理文件时,主要依赖于Blobstore对blob的分配与管理。 在Blobstore下层,与SPDK bdev层对接。 SPDK bdev层类似于内核中的通用块设备层,是对底层不同类型设备的统一抽象管理,例如NVMe bdev、Malloc bdev、AIO bdev等。 注意: Blob的persistent主要是针对NVMe这类bdev。对于Malloc bdev,由于其本身的性质,是无法保证Blob的persistent,需要重启后进行重新配置。 最后向SPDK bdev层发送异步的读请求,并等待I/O完成。
的一个函数指针作为参数传递给get_sb_bdev。 我们来看下mount_bdev的实现(**它执行完成之后会创建vfs的三大数据结构 super_block、根inode和根dentry **): 2)mount_bdev源码分析 //fs/super.c mount_bdev ->bdev = blkdev_get_by_path(dev_name, mode, fs_type) //通过要挂载的块设备路径名 获得它的块设备描述符block_device (会涉及到路径名查找和通过设备号在bdev文件系统查找block_device,block_device是添加块设备到系统时创建的) -> s = sget(fs_type, test_bdev_super , set_bdev_super, flags | SB_NOSEC, ¦bdev); //查找或创建vfs的超级块 (会首先在文件系统类型的fs_supers链表查找是否已经读取过指定的超级块
,在SPDK上创建bdev就相当于物理机理硬盘槽位上插入硬盘, 数据到了SPDK的bdev,再通过SPDK的driver落的本地或者远端真正的硬件上。 spdk_rpc.py bdev_null_create Snap1 200000 512 #把这个nvme controller和SPDK关联起来,执行这一步之后 裸金属写到硬盘里的数据就能被SPDK virtio-blk #spdk创建bdev Snap0 spdk_rpc.py bdev_null_create Snap0 100000 512 #创建一个device snap_rpc.py emulation_device_attach --bdev_type spdk --bdev Snap0 mlx5_0 virtio_blk #创建controller,把device加到这个controller上 snap_rpc.py controller_virtio_blk_create -d 61:00.0 --bdev_type spdk --bdev Snap0 mlx5_0 #此时裸金属上就能看到一个virtio-blk类型的硬盘 Full Offload Mode 只支持
scm_mount: /mnt/daos # map to -s /mnt/daos scm_class: ram scm_size: 4 #内存模拟scm # When bdev_class # The size of file that will be created is specified by bdev_size in GB units. # The location of the files that will be created is specified in bdev_list. bdev_class: file bdev_size: 16 #文件模拟nvme bdev_list: [/tmp/daos-bdev]启动集群启动集群:.
CPU+DPU 协同处理 (CXL)去掉获取IO通道的流程图片存储节点:使用 SPDK 软件堆栈的 CPU+DPU 协同处理 (CXL)优点由于简化了存储数据访问和操作,因此 IOPS 更高,例如 • bdev_write :sequence_encrypt + serial_compress + Storage_write • bdev_read:Storage_read + serial_decompress + serial_decrypt
demo-host ceph]# tail -100 /var/log/ceph/ceph-osd.20.log 2019-02-27 16:31:34.492858 7fc0f33aed80 1 bdev /var/lib/ceph/osd/ceph-20/block: (5) Input/output error 2019-02-27 16:31:34.492917 7fc0f33aed80 1 bdev /var/lib/ceph/osd/ceph-20/block: (5) Input/output error 2019-02-27 16:31:34.751776 7fc0f33aed80 1 bdev create path /var/lib/ceph/osd/ceph-20/block type kernel 2019-02-27 16:31:34.751779 7fc0f33aed80 1 bdev ceph-20/block) open path /var/lib/ceph/osd/ceph-20/block 2019-02-27 16:31:34.751978 7fc0f33aed80 1 bdev
bio结构 bio = bio_alloc(GFP_NOIO, 1); bio->bi_sector = bh->b_blocknr * (bh->b_size >> 9); bio->bi_bdev = bh->b_bdev; bio->bi_io_vec[0].bv_page = bh->b_page; bio->bi_io_vec[0].bv_len = bh->b_size; bio- deactivate */ } static inline void __generic_make_request(struct bio *bio) { do { //获得请求队列 q = bdev_get_queue (bio->bi_bdev); //调用队列中的"构造请求函数" ret = q->make_request_fn(q, bio); //当我们写驱动程序时,不提供request函数时,系统有一个默认的函数
数据流图解: 应用侧发起块读取请求 SPDK Fastpath bdev:首先检查缓存的映射。 如果命中,fastpath bdev直接从驱动器读取。 NVMf网关-RBD路径:客户端通过NVMe-oF协议发送块请求,经过网关节点并与存储节点交互,涉及RBD bdev。 Olympia路径(hit):如果缓存命中,客户端请求直接通过fastpath bdev和aio bdev进行处理,数据存储在NVMe驱动器中。 深入理解 fastpath bdev 具体来说,fastpath bdev是一个优化的数据路径,它可以将块数据的映射信息缓存到内存中,从而加速后续的数据访问。 缓存命中:如果缓存中已有该数据的映射,fastpath bdev会直接使用缓存中的数据进行读取,从而提高了访问速度。