模拟块设备的c++代码,支持压缩
时间: 2023-08-11 11:35:12 浏览: 44
下面是一个简单的模拟块设备的C代码,它支持压缩和解压缩:
```c
#include <linux/module.h>
#include <linux/blkdev.h>
#include <linux/genhd.h>
#include <linux/completion.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/bio.h>
#include <linux/crypto.h>
#include <crypto/hash.h>
#include <crypto/aead.h>
#define DEVICE_NAME "mydevice"
#define SECTOR_SIZE 512
#define NUM_SECTORS 1024
#define COMPRESSED_SECTOR_SIZE 256
#define MAX_CRYPTO_KEY_SIZE 32
#define MAX_CRYPTO_IV_SIZE 16
struct mydevice {
struct request_queue *queue;
struct gendisk *disk;
unsigned char *data;
unsigned char *compressed_data;
unsigned char *crypto_key;
unsigned char *crypto_iv;
struct crypto_aead *aead;
struct completion completion;
};
static int mydevice_open(struct block_device *bdev, fmode_t mode)
{
printk(KERN_INFO "mydevice: device opened\n");
return 0;
}
static void mydevice_release(struct gendisk *disk, fmode_t mode)
{
printk(KERN_INFO "mydevice: device released\n");
}
static int mydevice_transfer(struct mydevice *dev, sector_t sector,
unsigned int num_sectors, char *buffer, int write)
{
unsigned int i;
unsigned int offset;
unsigned int compressed_size;
struct bio *bio;
struct bio_vec bvec;
struct scatterlist sg;
struct crypto_aead *aead;
struct aead_request *req;
char *src;
char *dst;
char *iv;
char *tag;
int err;
if (write) {
/* Compression */
compressed_size = COMPRESSED_SECTOR_SIZE;
err = crypto_aead_setauthsize(dev->aead, COMPRESSED_SECTOR_SIZE);
if (err) {
printk(KERN_ERR "mydevice: failed to set authsize\n");
return -EIO;
}
err = crypto_aead_encrypt(dev->aead, dev->crypto_iv, MAX_CRYPTO_IV_SIZE,
dev->compressed_data, compressed_size,
dev->data + sector * SECTOR_SIZE,
num_sectors * SECTOR_SIZE, dev->crypto_key);
if (err) {
printk(KERN_ERR "mydevice: encryption failed\n");
return -EIO;
}
src = dev->compressed_data;
dst = buffer;
} else {
/* Decompression */
compressed_size = num_sectors * COMPRESSED_SECTOR_SIZE;
err = crypto_aead_setauthsize(dev->aead, COMPRESSED_SECTOR_SIZE);
if (err) {
printk(KERN_ERR "mydevice: failed to set authsize\n");
return -EIO;
}
err = crypto_aead_decrypt(dev->aead, dev->crypto_iv, MAX_CRYPTO_IV_SIZE,
dev->data + sector * SECTOR_SIZE, compressed_size,
dev->compressed_data, COMPRESSED_SECTOR_SIZE,
dev->crypto_key);
if (err) {
printk(KERN_ERR "mydevice: decryption failed\n");
return -EIO;
}
src = dev->compressed_data;
dst = buffer;
}
/* Scatter-gather I/O */
bio = bio_alloc(GFP_KERNEL, 1);
if (!bio)
return -EIO;
bvec.bv_page = virt_to_page(dst);
offset = offset_in_page(dst);
bvec.bv_len = min_t(unsigned int, num_sectors * SECTOR_SIZE, PAGE_SIZE - offset);
bvec.bv_offset = offset;
sg_init_one(&sg, src, compressed_size);
bio_add_page(bio, bvec.bv_page, bvec.bv_len, bvec.bv_offset);
bio_add_page(bio, &sg, compressed_size, 0);
req = aead_request_alloc(dev->aead, GFP_KERNEL);
if (!req) {
bio_put(bio);
return -EIO;
}
aead_request_set_callback(req, 0, NULL, NULL);
aead_request_set_crypt(req, bio, bio, bvec.bv_len, iv);
if (write)
err = crypto_aead_encrypt(req);
else
err = crypto_aead_decrypt(req);
if (err == -EINPROGRESS) {
wait_for_completion(&dev->completion);
err = req->base.error;
}
aead_request_free(req);
bio_put(bio);
return err ? -EIO : 0;
}
static void mydevice_request(struct request_queue *queue)
{
struct request *req;
struct mydevice *dev;
dev = queue->queuedata;
while ((req = blk_fetch_request(queue)) != NULL) {
if (req->cmd_type != REQ_TYPE_FS) {
printk(KERN_ERR "mydevice: unknown request\n");
__blk_end_request_all(req, -EIO);
continue;
}
if (req->sector + req->current_nr_sectors > NUM_SECTORS) {
printk(KERN_ERR "mydevice: invalid request\n");
__blk_end_request_all(req, -EIO);
continue;
}
if (blk_rq_is_passthrough(req)) {
printk(KERN_INFO "mydevice: passthrough request\n");
__blk_end_request_all(req, -EIO);
continue;
}
if (blk_rq_map_kern(dev->disk, req, dev->data)) {
printk(KERN_ERR "mydevice: rq_map_kern failed\n");
__blk_end_request_all(req, -EIO);
continue;
}
if (mydevice_transfer(dev, blk_rq_pos(req), blk_rq_cur_sectors(req),
bio_data(req->bio), rq_data_dir(req))) {
printk(KERN_ERR "mydevice: transfer failed\n");
__blk_end_request_all(req, -EIO);
continue;
}
__blk_end_request_all(req, 0);
}
}
static int mydevice_init(void)
{
int err;
struct mydevice *dev;
dev = kzalloc(sizeof(struct mydevice), GFP_KERNEL);
if (!dev)
return -ENOMEM;
dev->data = vmalloc(NUM_SECTORS * SECTOR_SIZE);
if (!dev->data) {
kfree(dev);
return -ENOMEM;
}
dev->compressed_data = vmalloc(NUM_SECTORS * COMPRESSED_SECTOR_SIZE);
if (!dev->compressed_data) {
vfree(dev->data);
kfree(dev);
return -ENOMEM;
}
dev->crypto_key = kzalloc(MAX_CRYPTO_KEY_SIZE, GFP_KERNEL);
if (!dev->crypto_key) {
vfree(dev->compressed_data);
vfree(dev->data);
kfree(dev);
return -ENOMEM;
}
dev->crypto_iv = kzalloc(MAX_CRYPTO_IV_SIZE, GFP_KERNEL);
if (!dev->crypto_iv) {
kfree(dev->crypto_key);
vfree(dev->compressed_data);
vfree(dev->data);
kfree(dev);
return -ENOMEM;
}
err = crypto_alloc_aead("gcm(aes)", 0, CRYPTO_ALG_ASYNC);
if (err) {
kfree(dev->crypto_iv);
kfree(dev->crypto_key);
vfree(dev->compressed_data);
vfree(dev->data);
kfree(dev);
return err;
}
dev->aead = crypto_alloc_aead("gcm(aes)", 0, CRYPTO_ALG_ASYNC);
if (IS_ERR(dev->aead)) {
crypto_free_aead(dev->aead);
kfree(dev->crypto_iv);
kfree(dev->crypto_key);
vfree(dev->compressed_data);
vfree(dev->data);
kfree(dev);
return PTR_ERR(dev->aead);
}
dev->queue = blk_init_queue(mydevice_request, NULL);
if (!dev->queue) {
crypto_free_aead(dev->aead);
kfree(dev->crypto_iv);
kfree(dev->crypto_key);
vfree(dev->compressed_data);
vfree(dev->data);
kfree(dev);
return -ENOMEM;
}
blk_queue_logical_block_size(dev->queue, SECTOR_SIZE);
blk_queue_physical_block_size(dev->queue, SECTOR_SIZE);
dev->queue->queuedata = dev;
dev->disk = alloc_disk(1);
if (!dev->disk) {
blk_cleanup_queue(dev->queue);
crypto_free_aead(dev->aead);
kfree(dev->crypto_iv);
kfree(dev->crypto_key);
vfree(dev->compressed_data);
vfree(dev->data);
kfree(dev);
return -ENOMEM;
}
dev->disk->major = 0;
dev->disk->first_minor = 0;
dev->disk->fops = &(struct file_operations) {
.owner = THIS_MODULE,
.open = mydevice_open,
.release = mydevice_release,
};
dev->disk->queue = dev->queue;
dev->disk->private_data = dev;
sprintf(dev->disk->disk_name, DEVICE_NAME);
set_capacity(dev->disk, NUM_SECTORS);
init_completion(&dev->completion);
add_disk(dev->disk);
printk(KERN_INFO "mydevice: device initialized\n");
return 0;
}
static void mydevice_exit(void)
{
struct mydevice *dev;
dev = disk->private_data;
del_gendisk(dev->disk);
put_disk(dev->disk);
blk_cleanup_queue(dev->queue);
crypto_free_aead(dev->aead);
kfree(dev->crypto_iv);
kfree(dev->crypto_key);
vfree(dev->compressed_data);
vfree(dev->data);
kfree(dev);
printk(KERN_INFO "mydevice: device removed\n");
}
module_init(mydevice_init);
module_exit(mydevice_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("A simple simulated block device driver with compression and encryption");
```
在此示例中,我们使用结构体`mydevice`来保存设备的状态信息。我们为设备分配了内存,并使用`crypto_alloc_aead()`函数为设备分配了一个GCM(AES)加密算法。我们还定义了一个`mydevice_transfer()`函数,该函数在读取和写入请求期间执行压缩和解压缩操作,并使用散列-聚合I/O进行数据传输。我们在`mydevice_request()`函数中处理请求,将它们映射到设备数据上,并使用`mydevice_transfer()`函数执行实际的读取和写入操作。
此外,我们使用`blk_queue_logical_block_size()`和`blk_queue_physical_block_size()`函数设置设备的逻辑和物理块大小,并使用`aead_request_alloc()`函数和`aead_request_free()`函数分配和释放AED请求。我们还使用`blk_init_queue()`函数为设备分配请求队列,并使用`add_disk()`函数将设备添加到系统中。最后,我们在模块初始化函数中注册设备驱动程序,并在模块退出函数中注销它。