存储学习

文件:数据与磁盘扇区之间的映射关系
文件系统,实现posix接口的vfs接口

文件系统

  1. fastdfs,tfs,gfs,glustersfs, ceph

  2. ext4/ext3, tmpfs, debugfs, ntfs, fat32

  3. vfs, fuse,

  4. dpdk

  5. rdma

  6. 内核网络

  7. 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打印