存储学习
文件:数据与磁盘扇区之间的映射关系
文件系统,实现posix接口的vfs接口
文件系统
-
fastdfs,tfs,gfs,glustersfs, ceph
-
ext4/ext3, tmpfs, debugfs, ntfs, fat32
-
vfs, fuse,
-
dpdk
-
rdma
-
内核网络
-
ebpf,bpf
1. 应用程序直接操作裸盘
#include <linux/nvme_ioctl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
int main() {
int fd = open("/dev/nvme1n1", O_RDWR);
if(fd < 0) {
return -1;
}
char * buffer = malloc(4096);
if(!buffer) {
perror("malloc failed\n");
return -1;
}
memset(buffer, 0, 4096);
struct nvme_user_io io;
io.addr = (__u64) buffer; // 源数据地址
io.slba = 0; // start logic block address
io.nblocks = 1; // 要读取或者写入的块数
io.opcode = 1; //write // 操作码,1表示写,2表示读
strcpy(buffer, "hello world!");
if(-1==ioctl(fd, NVME_IOCTL_SUBMIT_IO, &io)) {
perror("ioctl failed\n");
goto Clean;
}
printf("write successfully\n");
memset(buffer, 0, 4096);
io.opcode = 2;
if(-1==ioctl(fd, NVME_IOCTL_SUBMIT_IO, &io)) {
perror("ioctl failed");
goto Clean;
}
printf("read successfuly\n");
printf("buffer: %s\n", buffer);
Clean:
close(fd);
free(buffer);
return 0;
}
往磁盘写入数据之后可以直接cat /dev/nvme0n1查看数据,注意使用空磁盘测试防止覆盖数据
2. 内核操作磁盘
内核插入自己实现的模块module
insmod kernel_nvme.ko
Makefile:
obj-m := kernel_nvme.o
KERNELBUILD := /lib/modules/$(shell uname -r)/build
default:
make -C $(KERNELBUILD) M=$(shell pwd) modules
#include <linux/module.h>
#include <linux/bio.h>
#include <linux/blkdev.h>
#define DISK_NAME "/dev/nvme0n1"
#define DISK_SECTOR_SIZE 4096
static int king_nvme_write(struct block_device* bdev, char* buffer, int length) {
//maximum number of segments or vectors that can be associated with the I/O operation. It allows you to describe the I/O operation in terms of multiple discontiguous memory regions. The `BIO_MAX_VECS` macro is often used to specify the maximum number of vectors a `struct bio` can contain.
struct bio* bio = bio_alloc(bdev, BIO_MAX_VECS, REQ_OP_WRITE, GFP_NOIO);
if(!bio)
return -1;
bio->bi_iter.bi_sector = 0; //
// GFP_KERNEL: get free page for kernel
struct page* page = alloc_page(GFP_KERNEL); // alloca kernel page
if(!page)
return -1;
memcpy(page_address(page), buffer, length);
bio_add_page(bio, page, length, 0);
submit_bio_wait(bio);
__free_page(page);
// decrement the reference count of bio
bio_put(bio);
return 0;
}
static int king_nvme_read(struct block_device* bdev, char* buffer, int length) {
return 0;
}
static int __init king_nvme_init(void) {
printk("king nvme_init\n");
char* buffer = kmalloc(DISK_SECTOR_SIZE, GFP_KERNEL);
if(!buffer) {
printk("kmalloc failed\n");
return -1;
}
memset(buffer, 0, DISK_SECTOR_SIZE);
strcpy(buffer, "hello world");
struct block_device * bdev = blkdev_get_by_path(DISK_NAME, FMODE_READ|FMODE_WRITE, NULL);
if(IS_ERROR(bdev)) {
printk("blkdev_get_by_device failed\n");
return -1;
}
king_nvme_write(bdev, buffer, DISK_SECTOR_SIZE);
memset(buffer, 0 , DISK_SECTOR_SIZE);
printk("write successfully\n");
king_nvme_read(bdev, buffer, DISK_SECTOR_SIZE);
printk("write successfully\n");
return 0;
}
static int __exit king_nvme_exit(void) {
printk("king_nvme_exit\n");
return 0;
}
module_init(king_nvme_init);
module_exit(king_nvme_exit);
MODULE_LICENSE("GPL");
chatgpt的答案
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/blkdev.h>
#include <linux/bio.h>
#define NVME_DEVICE_PATH "/dev/nvme0n1"
#define DATA_SIZE 4096
static struct block_device *nvme_bdev = NULL;
static int __init nvme_write_init(void) {
struct bio *bio;
char data[DATA_SIZE] = "Hello, NVMe!"; // Data to be written
nvme_bdev = blkdev_get_by_path(NVME_DEVICE_PATH, FMODE_READ | FMODE_WRITE, NULL);
if (IS_ERR(nvme_bdev)) {
printk(KERN_ERR "Error: Unable to open NVMe device\n");
return -1;
}
bio = bio_alloc(GFP_NOIO, 1);
if (!bio) {
printk(KERN_ERR "Error: bio_alloc failed\n");
blkdev_put(nvme_bdev, FMODE_READ | FMODE_WRITE);
return -1;
}
bio->bi_iter.bi_sector = 0; // LBA
bio_add_page(bio, virt_to_page(data), DATA_SIZE, 0);
submit_bio(REQ_OP_WRITE, bio);
blkdev_put(nvme_bdev, FMODE_READ | FMODE_WRITE);
return 0;
}
static void __exit nvme_write_exit(void) {
printk(KERN_INFO "NVMe Write Module Unloaded\n");
}
module_init(nvme_write_init);
module_exit(nvme_write_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("NVMe Write Kernel Module");
MODULE_VERSION("1.0");
编译生成ko文件我们直接
insmod kernel_nvme.ko
dmesg // 查看init打印
rmmod kernel_nvme.ko
dmesg // 查看exit打印