#include<linux/module.h>
#include<linux/genhd.h>
#include<linux/vmalloc.h>
#include<linux/fs.h>
#include<linux/bio.h>
#include<linux/blkdev.h>
static unsigned long long mem = 409600;
module_param(mem,ullong,0644);
MODULE_PARM_DESC(mem,"parameter");
static int sector_size = 512;
static int major = 0;
static struct sbd_struct
{
struct gendisk *gd;
void *memory;
} sbd_dev;
static inline int transfer_single_bio(struct bio *bio)
{
struct bvec_iter iter;
struct bio_vec vector;
sector_t sector = bio->bi_iter.bi_sector;
bool wirte = bio_data_dir(bio) == WRITE;
bio_for_each_segment(vector,bio,iter) {
unsigned int len = vector.bv_len;
void *addr = kmap(vector.bv_page);
if(wirte)
memcpy(sbd_dev.
memory+sector
*sector_size
,addr
+vector.
bv_offset,len
);
else
memcpy(addr
+vector.
bv_offset,sbd_dev.
memory+sector
*sector_size
,len
);
kunmap(addr);
sector += len >> 9;
}
return 0;
}
static blk_qc_t make_request(struct request_queue *q, struct bio *bio)
{
int result=0;
if(bio_end_sector(bio)>get_capacity(bio->bi_bdev->bd_disk))
goto mrerr0;
result = transfer_single_bio(bio);
if(unlikely(result!=0))
goto mrerr0;
bio_endio(bio);
return BLK_QC_T_NONE;
mrerr0:
bio_io_error(bio);
return BLK_QC_T_NONE;
}
static struct block_device_operations block_methods = {
.owner = THIS_MODULE
};
static int __init sbd_constructor(void)
{
pr_info("mem= %lld \n",mem);
sbd_dev.memory = vmalloc(mem);
if(!sbd_dev.memory) {
pr_alert("Memory allocation error!\n");
goto ier1;
}
sbd_dev.gd = alloc_disk(1);
if(!sbd_dev.gd) {
pr_alert("General disk structure allocation error!\n");
goto ier2;
}
major = register_blkdev(major,"sbd");
if(major<=0) {
pr_alert("Major number allocation error!\n");
goto ier3;
}
pr_info("[sbd] Major number allocated: %d.\n",major);
sbd_dev.gd->major = major;
sbd_dev.gd->first_minor = 0;
sbd_dev.gd->fops = &block_methods;
sbd_dev.gd->private_data = NULL;
sbd_dev.gd->flags|=GENHD_FL_SUPPRESS_PARTITION_INFO;
strcpy(sbd_dev.
gd->disk_name
,"sbd");
set_capacity(sbd_dev.gd,(mem)>>9);
sbd_dev.gd->queue = blk_alloc_queue(GFP_KERNEL);
if(!sbd_dev.gd->queue) {
pr_alert("Request queue allocation error!\n");
goto ier4;
}
blk_queue_make_request(sbd_dev.gd->queue,make_request);
pr_info("[sbd] Gendisk initialized.\n");
add_disk(sbd_dev.gd);
return 0;
ier4:
unregister_blkdev(major,"sbd");
ier3:
put_disk(sbd_dev.gd);
ier2:
vfree(sbd_dev.memory);
ier1:
return -ENOMEM;
}
static void __exit sbd_desctructor(void)
{
del_gendisk(sbd_dev.gd);
blk_cleanup_queue(sbd_dev.gd->queue);
unregister_blkdev(major,"sbd");
put_disk(sbd_dev.gd);
vfree(sbd_dev.memory);
}
module_init(sbd_constructor);
module_exit(sbd_desctructor);
MODULE_LICENSE("GPL");
MODULE_VERSION("1.0");