test

obj-m := sbull.o
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)

default:
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
clean:
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) clean
rm -rf Module.markers modules.order Module.symvers

include <linux/module.h>

include <linux/moduleparam.h>

include <linux/init.h>

include <linux/sched.h>

include <linux/kernel.h>

include <linux/slab.h>

include <linux/fs.h>

include <linux/errno.h>

include <linux/types.h>

include <linux/fcntl.h>

include <linux/hdreg.h>

include <linux/kdev_t.h>

include <linux/vmalloc.h>

include <linux/genhd.h>

include <linux/blkdev.h>

include <linux/buffer_head.h>

include <linux/bio.h>

include "sbull.h"

static int sbull_major = SBULL_MAJOR; //主设备号 0
static int nsectors = 16384; //设备大小
static int hardsect_size = 512; //扇区大小

module_param(sbull_major,int,0);
module_param(nsectors,int,0);
module_param(hardsect_size,int,0);

struct sbull_dev
{
int size; //以扇区为单位设备的大小
u8 *data; //数据数组(存储磁盘数据队列)
struct request_queue *queue; //请求队列(用于互斥)
struct gendisk *gd; //gendisk结构
spinlock_t lock; //设备自旋锁
};

static struct sbull_dev *Devices = NULL;

static int sbull_open(struct inode *inode,struct file *filp)
{
return 0;
}

static int sbull_release(struct inode *inode,struct file *filp)
{
return 0;
}

static int sbull_ioctl(struct inode inode,struct file filp,unsigned int cmd,unsigned long arg)
{
int ret = 0;
int err = 0;
//检测命令的有效性
if(_IOC_TYPE(cmd) != SBULL_IOC_MAGIC)
{
return -EINVAL;
}
if(_IOC_NR(cmd) > SBULL_IOC_MAXNR)
{
return -EINVAL;
}
//根据命令类型,检测用户空间是否可以访问
if(_IOC_DIR(cmd) & _IOC_READ)
{
err = !access_ok(VERIFY_WRITE,(void
)arg,_IOC_SIZE(cmd));
}
else if(_IOC_DIR(cmd) & _IOC_WRITE)
{
err = !access_ok(VERIFY_READ,(void
)arg,_IOC_SIZE(cmd));
}
if(err)
{
return -EFAULT;
}
switch(cmd)
{
case SBULL_IOCGETMAJOR: //得到主设备号
ret = __put_user(sbull_major,(int __user)arg);
break;
case SBULL_IOCGETSECTORS: //得到扇区总数
ret = __put_user(nsectors,(int __user
)arg);
break;
case SBULL_IOCGETSIZE: //得到块设备大小
ret = __put_user(nsectors * hardsect_size,(int __user*)arg);
break;
default:
return -EFAULT;
}
return ret;
}

static void sbull_transfer(struct sbull_dev *dev,sector_t sector,unsigned long nsect,char *buffer,int write)
{
unsigned long offset = sector << 9;
unsigned long nbytes = nsect << 9;
if( (offset + nbytes) > dev->size )
{
printk(KERN_NOTICE "Beyond-end write (%ld %ld) ",offset,nbytes);
return;
}
if(write)
{
printk(KERN_NOTICE "writing to disk ");
memcpy(dev->data + offset,buffer,nbytes);
}
else
{
printk(KERN_NOTICE "readding from disk ");
memcpy(buffer,dev->data + offset,nbytes);
}

}

static void sbull_request(struct request_queue *q)
{
struct request *req;
req = blk_fetch_request(q);
while( req != NULL )
{
struct sbull_dev *dev = req->rq_disk->private_data;
if(!blk_fs_request(req))
{
printk(KERN_NOTICE "Skip non-fs request ");
__blk_end_request_all(req,0);
continue;
}
sbull_transfer(dev,blk_rq_pos(req),blk_rq_cur_sectors(req),req->buffer,rq_data_dir(req));
if( !__blk_end_request_cur(req,0))
{
req = blk_fetch_request(q);
}
}
}

static struct block_device_operations sbull_ops =
{
.owner = THIS_MODULE,
.open = sbull_open,
.release= sbull_release,
.ioctl = sbull_ioctl,
};

static int __init sbull_init(void)
{
//注册块设备驱动程序
sbull_major = register_blkdev(sbull_major,"sbull");
if(sbull_major <= 0)
{
printk(KERN_WARNING "unable to get major number ");
return -EBUSY;
}

Devices = kmalloc(sizeof(struct sbull_dev),GFP_KERNEL);
if(Devices == NULL)
goto out_unregister;
memset(Devices,0,sizeof(struct sbull_dev));

//初始化sbull_dev数据结构
Devices->size = nsectors * hardsect_size;
Devices->data = vmalloc(Devices->size);
if(Devices->data == NULL)
{
printk(KERN_NOTICE "vmalloc failure. ");
goto out_kfree;
}
memset(Devices->data,0,Devices->size);
//对自旋锁进行分配和初始化
spin_lock_init(&Devices->lock);

//分配请求队列
Devices->queue = blk_init_queue(sbull_request,&Devices->lock);
if(Devices->queue == NULL)
{
printk(KERN_NOTICE "request queue error");
goto out_vfree;
}
//设置扇区大小
blk_queue_logical_block_size(Devices->queue, hardsect_size);
//分配、初始化及安装相应的gendisk结构
Devices->gd = alloc_disk(1);
if( !Devices->gd )
{
printk(KERN_NOTICE "alloc_disk failure ");
goto out_vfree;
}
Devices->gd->major = sbull_major;
Devices->gd->first_minor = 0;
Devices->gd->fops = &sbull_ops;
Devices->gd->queue = Devices->queue;
Devices->gd->private_data = Devices;
strcpy(Devices->gd->disk_name,"sbull0");
set_capacity(Devices->gd,nsectors * (hardsect_size / KERN_SECTOR_SIZE));
add_disk(Devices->gd);
return 0;

out_vfree:
vfree(Devices->data);
out_kfree:
kfree(Devices);
out_unregister:
unregister_blkdev(sbull_major,"sbull");
return -ENOMEM;
}

static void __exit sbull_exit(void)
{
struct sbull_dev *dev = Devices;
if(dev->gd)
{
del_gendisk(dev->gd);
put_disk(dev->gd);
printk("Release gendisk success. ");
}
if(dev->queue)
{
blk_cleanup_queue(dev->queue);
printk("rmmod module success. ");
}
if(dev->data)
{
vfree(dev->data);
printk("Release diskdata success. ");
}
unregister_blkdev(sbull_major,"sbull");
printk("Blockdevice unregister success. ");
kfree(Devices);
}

MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("LvYongQiang");
module_init(sbull_init);
module_exit(sbull_exit);

ifndef _SBULL_H

define _SBULL_H

include <linux/types.h>

include <linux/ioctl.h>

include <linux/fcntl.h>

define SBULL_MAJOR 0

define KERN_SECTOR_SIZE 512

//定义幻数

define SBULL_IOC_MAGIC 'x'

//定义命令

define SBULL_IOCGETMAJOR _IOR(SBULL_IOC_MAGIC,1,int)

define SBULL_IOCGETSECTORS _IOR(SBULL_IOC_MAGIC,2,int)

define SBULL_IOCGETSIZE _IOR(SBULL_IOC_MAGIC,3,int)

define SBULL_IOC_MAXNR 3

endif

原文地址:https://www.cnblogs.com/xiaoran991/p/13678210.html