raid0

# Comment/uncomment the following line to disable/enable debugging
#DEBUG = y


# Add your debugging flag (or not) to CFLAGS
ifeq ($(DEBUG),y)
  DEBFLAGS = -O -g -DSBULL_DEBUG # "-O" is needed to expand inlines
else
  DEBFLAGS = -O2
endif

EXTRA_CFLAGS += $(DEBFLAGS)
EXTRA_CFLAGS += -I..

ifneq ($(KERNELRELEASE),)
# call from kernel build system

obj-m	:= nss_md.o
	
else

KERNELDIR ?= /lib/modules/$(shell uname -r)/build
PWD       := $(shell pwd)

default:
	$(MAKE) -C $(KERNELDIR) M=$(PWD) modules

endif



clean:
	rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions

depend .depend dep:
	$(CC) $(EXTRA_CFLAGS) -M *.c > .depend


ifeq (.depend,$(wildcard .depend))
include .depend
endif
typedef struct request_queue request_queue_t;  //由于这个内核里面没有这个定义,所以自己添加。
struct member_disk
{
	struct block_device* bdev;
	struct member_disk * next;
};
struct nss_md_dev{
	char *name;
	unsigned char *data;
	short users;
	unsigned long  long size;
	unsigned long  array_sectors; 
	int level;
	int chunk_sectors;		//每个chunk所包含的扇区数
	int raid_disks;
	struct list_head disks;
	short media_change;
	spinlock_t lock;
	struct request_queue* queue;
	struct gendisk *gd;
	struct timer_list timer; 	
	struct member_disk * mdisk;
	int status;					//标识设备是否准备好
};
typedef struct nss_md_dev nss_md_dev_t;
struct strip_zone
{
	sector_t zone_end;
	sector_t dev_start;
	int nb_dev;
};
typedef struct __Disk_T
{
	int major;
	int minor;
	int number;
	int raid_disks;
}Disk_T;

typedef struct array_info_s
{
	int level;
	int raid_disks;
	int chunk_size;
	unsigned long  sectors;
}array_info_t;
#define READY 0X0005
#define NOT_READY 0x0006

#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/timer.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 <linux/mutex.h>
#include <linux/math64.h>
#include "nss_md.h"
MODULE_LICENSE("Dual BSD/GPL");
static int nss_md_major=0;
module_param(nss_md_major,int,0);
static int hardsect_size = 512;
module_param(hardsect_size,int,0);
static int nsectors = 1024;
module_param(nsectors, int, 0);
static int ndevices = 1;
module_param(ndevices,int,0);
enum{
	RM_SIMPLE = 0,
	RM_FULL =1 ,
	RM_NOQUEUE = 2,
};
static int request_mode = RM_SIMPLE;
module_param(request_mode,int,0);
#define NSS_MD_MINORS   16

#define KERNEL_SECTOR_SIZE 512
#define INVALIDATE_DELAY 	30*HZ

#define TEST_CMD 				0x000666
#define ADD_NEW_DISK 			0x000667
#define SET_ARRAY_INFO 			0x000668
#define GET_ARRAY_INFO			0x000669
#define GET_DISK_INFO			0x000670
#define is_power_of_2(x)	((x) != 0 && (((x) & ((x) - 1)) == 0))
static struct nss_md_dev *Devices = NULL;

//dev_t dev0,dev1,dev2;
//struct block_device * bdev0,*bdev1,*bdev2;
/*static void nss_md_transfer(struct nss_md_dev *dev,unsigned long sector,
			unsigned long nsect,char *buffer,int write)
{
	printk("nss_md_transfer begin\n");
	unsigned long offset =sector *KERNEL_SECTOR_SIZE;
	unsigned long nbytes =nsect*KERNEL_SECTOR_SIZE;
	if((offset+nbytes)>dev->size){
		printk(KERN_NOTICE "Beyond-end write (%ld %ld)\n",offset,nbytes);
		return ;
	}
	if(write)
		memcpy(dev->data+offset,buffer,nbytes);
	else
		memcpy(buffer,dev->data+offset,nbytes);
	printk("nss_md_transfer finished\n");
}*/

/*static void nss_md_request(request_queue_t *q)
{
	printk("nss_md_request begin\n");
	struct request *req;
	req=blk_fetch_request(q);
	while(req){
		struct nss_md_dev *dev=req->rq_disk->private_data;
		if(!blk_fs_request(req)){
			printk(KERN_NOTICE "Skip non-fs request\n");
			blk_end_request_all(req,0);
			
			continue;
		}
//		nss_md_transfer(dev,blk_rq_pos(req),blk_rq_cur_sectors(req),
//				req->buffer,rq_data_dir(req));
		unsigned long offset =blk_rq_pos(req)<<9;		//偏移字节数	
		unsigned long nbytes=blk_rq_cur_bytes(req);		//剩余字节数	
		int err=0;
		if((offset+nbytes)>dev->size){
			printk("bad access:block=%lu,count=%u\n",
				blk_rq_pos(req),blk_rq_cur_sectors(req));
			err=-EIO;
			goto done;
		}
		if(rq_data_dir(req)==WRITE)
		{
			memcpy(dev->data+offset,req->buffer,nbytes);
			printk(" WRITE finished\n");
		}
		else
		{
			memcpy(req->buffer,dev->data+offset,nbytes);
			printk("READ finished\n");
		}
		done:
			if(!__blk_end_request_cur(req,err))
				req=blk_fetch_request(q);
	}
	printk("nss_md_request finished\n");
}*/

/*static int nss_md_xfer_bio(struct nss_md_dev *dev,struct bio *bio)
{
	int i;
	struct bio_vec *bvec;
	sector_t sector = bio->bi_sector;
	bio_for_each_segment(bvec,bio,i){
		char *buffer = __bio_kmap_atomic(bio,i,KM_USER0);
		nss_md_transfer(dev,sector,bio_cur_bytes(bio)>>9,
					buffer,bio_data_dir(bio)==WRITE);
		sector +=bio_cur_bytes(bio)>>9;
		__bio_kunmap_atomic(bio,KM_USER0);
	}
	return 0;
}*/

/*static int nss_md_xfer_request(struct nss_md_dev *dev,struct request *req)
{
	struct bio *bio;
	int nsect =0;
	__rq_for_each_bio(bio,req){
		nss_md_xfer_bio(dev,bio);
		nsect +=bio->bi_size/KERNEL_SECTOR_SIZE;
	}
	return nsect;
}*/

/*static void nss_md_full_request(request_queue_t *q)
{
	struct request *req;
	int sectors_xferred;
	struct nss_md_dev *dev=q->queuedata;
	while((req=blk_fetch_request(q))!=NULL){
		if(!blk_fs_request(req)){
			printk(KERN_NOTICE "Skip non-fs request\n");
			blk_end_request_all(req,0);
			continue;
		}
		sectors_xferred=nss_md_xfer_request(dev,req);
		if (!__blk_end_request_cur(req, 0)) {
			blk_start_request(req);
			blk_fetch_request(q);
		}	
	}
}*/

static inline int is_io_in_chunk_boundary(struct nss_md_dev *mddev,
			unsigned int chunk_sects, struct bio *bio)
{
	if (likely(is_power_of_2(chunk_sects))) {
		return chunk_sects >= ((bio->bi_sector & (chunk_sects-1))
					+ (bio->bi_size >> 9));
	} else{
		sector_t sector = bio->bi_sector;
		return chunk_sects >= (sector_div(sector, chunk_sects)
						+ (bio->bi_size >> 9));
	}
}

static int nss_md_make_request(request_queue_t *q,struct bio *bio)
{
	nss_md_dev_t *dev=q->queuedata;
	unsigned int chunk_sects;
	const int rw =bio_data_dir(bio);
	int cpu,tmp;
	struct member_disk* tmp_disk;
	
	sector_t  strip=0;
	unsigned int   disknum=0;
	sector_t chunk_num=0;
	unsigned int  chunk_offset=0;
	
	printk("nss_md_make_request begin\n");
	printk("bio->bi_sector:%llu\n",bio->bi_sector);
	printk("dev->status:%d\n",dev->status);
	if(dev->status==NOT_READY)
	{
		printk("status of device is not READY\n");
		bio_io_error(bio);
		return 0;
	}
	
	/*if(unlikely(bio_barrier(bio)))
	{
		bio_endio(bio,-EOPNOTSUPP);
		return 0;
	}*/
	
	cpu=part_stat_lock();
	part_stat_inc(cpu,&dev->gd->part0,ios[rw]);
	part_stat_add(cpu,&dev->gd->part0,sectors[rw],bio_sectors(bio));
	part_stat_unlock();
	chunk_sects=dev->chunk_sectors;
	printk("chunk_sects:%d\n",chunk_sects);
	if(unlikely(!is_io_in_chunk_boundary(dev,chunk_sects,bio)))
	{
		sector_t sector=bio->bi_sector;
		struct bio_pair *bp;
		if(bio->bi_vcnt!=1 || bio->bi_idx!=0)
			goto bad_map;
		if(likely(is_power_of_2(chunk_sects)))
			bp=bio_split(bio,chunk_sects-(sector & 
			(chunk_sects-1)));
		else
			bp=bio_split(bio,chunk_sects-
				sector_div(sector,chunk_sects));
		if(nss_md_make_request(q,&bp->bio1))
			generic_make_request(&bp->bio1);
		if(nss_md_make_request(q,&bp->bio2))
			generic_make_request(&bp->bio2);
		bio_pair_release(bp);
		return 0;
	}
//	sector_t tmp=bio->bi_sector;
//	chunk_num=div_u64(tmp,128);
//	chunk_num=tmp>>7;
	chunk_num=div_u64_rem(bio->bi_sector,chunk_sects,&chunk_offset);
	printk("bio->bi_sector:%llu,chunk_offset:%u,chunk_num:%llu\n",bio->bi_sector,chunk_offset,chunk_num);
//	strip=div_u64(chunk_num,3);
	strip=div_u64_rem(chunk_num,dev->raid_disks,&disknum);
	printk("chunk_offset:%u---strip:%llu---disknum:%u\n",chunk_offset,strip,disknum);
	for(tmp_disk=dev->mdisk,tmp=0;tmp<disknum;tmp++)
	{
		tmp_disk=tmp_disk->next;
	}
	bio->bi_bdev=tmp_disk->bdev;
	bio->bi_sector=(strip*chunk_sects)+chunk_offset;
/*	if(disknum==0)
	{
		bio->bi_bdev=bdev0;
//		bio->bi_sector=(strip<<7)+chunk_offset;
	}
	else if(disknum==1)
	{
		bio->bi_bdev=bdev1;
//		bio->bi_sector=(strip<<7)+chunk_offset;
	}
	else
	{
		bio->bi_bdev=bdev2;
//		bio->bi_sector=(strip<<7)+chunk_offset;

	}*/
//	bio->bi_bdev=bdev1;
//	generic_make_request(bio);
//	printk("nss_md_make_request finished\n");
	return 1;
bad_map:
	printk("raid0_make_request bug: can't convert block across chunks"
		" or bigger than %dk %llu %d\n", chunk_sects / 2,
		(unsigned long long)bio->bi_sector, bio->bi_size >> 10);

	bio_io_error(bio);
	return 0;
}

static int nss_md_open(struct block_device *bdev,fmode_t  mode)
{
	struct nss_md_dev* dev=bdev->bd_disk->private_data;
	printk("open\n");
	printk("open2\n");
	del_timer_sync(&dev->timer);
	printk("open3\n");
	printk("open4\n");
	spin_lock(&dev->lock);
	printk("open5\n");
	if(!dev->users)
	{
		printk("open6\n");
		check_disk_change(bdev);
		printk("open7\n");
	}
	dev->users++;
	spin_unlock(&dev->lock);
	printk("open8\n");
	return 0;
}

static int nss_md_release(struct gendisk *gd ,fmode_t mode)
{
	struct nss_md_dev *dev=gd->private_data;
	spin_lock(&dev->lock);
	dev->users--;
	if(!dev->users){
		dev->timer.expires=jiffies+INVALIDATE_DELAY;
		add_timer(&dev->timer);
	}
	spin_unlock(&dev->lock);
	return 0;
}

int nss_md_media_changed(struct gendisk *gd)
{
	struct nss_md_dev *dev=gd->private_data;
	return dev->media_change;
}

int nss_md_revalidate(struct gendisk *gd)
{
	struct nss_md_dev *dev =gd->private_data;
	if(dev->media_change){
		dev->media_change=0;
		memset(dev->data,0,dev->size);
	}
	return 0;
}

void nss_md_invalidate(unsigned long ldev)
{
	struct nss_md_dev *dev=(struct nss_md_dev *)ldev;
	spin_lock(&dev->lock);
	if(dev->users ||!dev->data)
		printk(KERN_WARNING "sbull:timer sanity check failed\n");
	else
		dev->media_change=1;
	spin_unlock(&dev->lock);
}
static int set_array_info(nss_md_dev_t* dev, array_info_t*array)
{
	dev->level=array->level;
	dev->chunk_sectors=array->chunk_size>>9;
	dev->raid_disks=array->raid_disks;
	dev->array_sectors=array->sectors;
	return 0;
}
static int add_new_disk(nss_md_dev_t* dev, Disk_T* disk)
{
	dev_t kdev;
	struct block_device * bdev;
	struct member_disk* memdisk;
	printk("come to add_new_disk()\n");
	kdev=MKDEV(disk->major,disk->minor);
	printk("after mkdev\n");
	if(disk->major!=MAJOR(kdev) || disk->minor!=MINOR(kdev))
	{
		printk("overflow\n");
		return -EOVERFLOW;
	}
	bdev=open_by_devnum(kdev,FMODE_READ|FMODE_WRITE);
	memdisk=(struct member_disk*)kmalloc(sizeof(struct member_disk),0);
	memdisk->bdev=bdev;
	memdisk->next=(*dev).mdisk;
	(*dev).mdisk=memdisk;
	printk("after operation of list\n");
	if(disk->number==disk->raid_disks)
	{
		set_capacity(dev->gd,dev->array_sectors);
		(*dev).status=READY;
		printk("status set to READY\n");
	}
	printk("add new disk finished\n");
	return 0;
}
int nss_md_ioctl(struct block_device *bdev,fmode_t mode,
			unsigned int cmd,unsigned long arg)
{
	void __user *argp = (void __user *)arg;
	struct nss_md_dev *dev = bdev->bd_disk->private_data;
	array_info_t array;
	struct member_disk * tmp_mdisk;
			Disk_T disk;
	switch(cmd){
/*		case HDIO_GETGEO:
			printk("received cmd :HDIO_GETGEO\n");
			size =dev->size*(hardsect_size/KERNEL_SECTOR_SIZE);
			geo.cylinders=(size &~0x3f)>>6;
			geo.heads =4;
			geo.sectors =16;
			geo.start=4;
			if(copy_to_user((void __user *)arg,&geo,sizeof(geo)))
				return -EFAULT;
			return 0;*/
		case TEST_CMD:
			printk("cmd TEST has been received~\n");
			break;
		case SET_ARRAY_INFO:
			printk("cmd SET_ARRAY_INFO has been received~\n");
			if(copy_from_user(&array,argp,sizeof(array)))
				printk("copy from user error\n");
			else
			{
				printk("level:%d,raid_disks:%d,chunk-size:%d,size:%lu\n",array.level,array.raid_disks,array.chunk_size,array.sectors);
				set_array_info(dev,&array);
			}
			break;
		case ADD_NEW_DISK:
			printk("cmd ADD_NEW_DISK has been received~\n");
			if(copy_from_user(&disk,argp,sizeof(disk)))
				printk("copy from user error\n");
			else
			{
				printk("major:%d,minor:%d,number:%d,raid_disks:%d\n",disk.major,disk.minor,disk.number,disk.raid_disks);
				if(disk.number>disk.raid_disks)
				{
					printk("the number of disks is more than raid_disks\n");
					break;
				}
				else
				{
					add_new_disk(dev,&disk);
					for(tmp_mdisk=dev->mdisk;tmp_mdisk!=NULL;)
					{
						printk("dev:%s\n",tmp_mdisk->bdev->bd_disk->disk_name);	
						tmp_mdisk=tmp_mdisk->next;
					}
				}
			}
			break;
//		case GET_ARRAY_INFO:
//			break;
//		case GET_DISK_INFO:
//			break;
	}
	return 0;
}

/*
* the device operations structure.
*/
static struct block_device_operations nss_md_ops={
	.owner			=THIS_MODULE,
	.open			=nss_md_open,
	.release			=nss_md_release,
	.media_changed	=nss_md_media_changed,
	.revalidate_disk	=nss_md_revalidate,
	.ioctl			=nss_md_ioctl
};

/*static int  get_diskinfo(void)
{
	dev0=MKDEV(8,16);
	if(8!=MAJOR(dev0) || 16!=MINOR(dev0))
		return -EOVERFLOW;
	bdev0=open_by_devnum(dev0,FMODE_READ|FMODE_WRITE);
	printk("disk0 name:%s\n",bdev0->bd_disk->disk_name);

	dev1=MKDEV(8,32);
	if(8!=MAJOR(dev1) || 32!=MINOR(dev1))
		return -EOVERFLOW;
	bdev1=open_by_devnum(dev1,FMODE_READ|FMODE_WRITE);
	printk("disk1 name:%s\n",bdev1->bd_disk->disk_name);

	dev2=MKDEV(8,48);
	if(8!=MAJOR(dev2) || 48!=MINOR(dev2))
		return -EOVERFLOW;
	bdev2=open_by_devnum(dev2,FMODE_READ|FMODE_WRITE);
	printk("disk2 name:%s\n",bdev2->bd_disk->disk_name);
	return 0;
}*/
static void setup_device(struct nss_md_dev *dev,int which)
{
	printk(KERN_ALERT "hello2\n");
	
//	get_diskinfo();
	memset(dev,0,sizeof(struct nss_md_dev));
//	dev->size=nsectors*hardsect_size;					//指定设备的大小
	dev->size=8<<30;
//	dev->data =vmalloc(dev->size);
	printk(KERN_ALERT "hello3\n");
//	if(dev->data ==NULL){
//		printk(KERN_NOTICE "vmalloc failure.\n");
//		return;
//	}
	printk(KERN_ALERT "hello4\n");
	spin_lock_init(&dev->lock);
	printk(KERN_ALERT "hello5\n");
	init_timer(&dev->timer);
	printk(KERN_ALERT "hello6\n");
	dev->timer.data=(unsigned long)dev;
	dev->timer.function=nss_md_invalidate;
/*	switch(request_mode){
		case RM_NOQUEUE:*/
			dev->queue=blk_alloc_queue(GFP_KERNEL);
			if(dev->queue==NULL)
				goto out_vfree;
			blk_queue_make_request(dev->queue,nss_md_make_request);
//			break;
/*		case RM_FULL:
			dev->queue=blk_init_queue(nss_md_full_request,&dev->lock);
			if(dev->queue==NULL)
				goto out_vfree;
			break;
		case RM_SIMPLE:
			printk(KERN_ALERT "hello7\n");
			dev->queue=blk_init_queue(nss_md_request,&dev->lock);
			printk(KERN_ALERT "hello8\n");
			if(dev->queue==NULL)
				goto out_vfree;*/
//			break;
//		default:
//			printk(KERN_NOTICE "Bad request mode %d,using simple\n",request_mode);
//		}
		printk(KERN_ALERT "hello9\n");
		blk_queue_logical_block_size(dev->queue,hardsect_size);
		printk(KERN_ALERT "hello10\n");
		dev->status=NOT_READY;
		printk("dev->status:%d\n",dev->status);
		dev->queue->queuedata=dev;
		dev->gd=alloc_disk(NSS_MD_MINORS);
		printk(KERN_ALERT "hello11\n");
		if(!dev->gd){
			printk(KERN_NOTICE "alloc_disk failure\n");
			goto out_vfree;
		}
		dev->gd->major=nss_md_major;
		dev->gd->first_minor=which*NSS_MD_MINORS;
		dev->gd->fops=&nss_md_ops;
		dev->gd->queue =dev->queue;
		dev->gd->private_data=dev;
		printk(KERN_ALERT "hello12\n");
		snprintf(dev->gd->disk_name,32,"nss_md%d",which);
		printk(KERN_ALERT "hello13\n");
//		set_capacity(dev->gd,nsectors*(hardsect_size/KERNEL_SECTOR_SIZE));
//		set_capacity(dev->gd,8<<21);
		dev->gd->flags |= GENHD_FL_EXT_DEVT;
		printk(KERN_ALERT "hello14\n");
		add_disk(dev->gd);
		printk(KERN_ALERT "hello15\n");
		return;
		
	out_vfree:
		if(dev->data)
			vfree(dev->data);
}

static int __init nss_md_init(void)
{
	int i;
	printk(KERN_ALERT "nss_md_init begin\n");
	nss_md_major=register_blkdev(nss_md_major,"nss_md");
	if(nss_md_major<=0){
		printk(KERN_WARNING "nss_md:unable to get major number\n");
		return -EBUSY;
	}
	Devices=kmalloc(ndevices *sizeof(struct nss_md_dev),GFP_KERNEL);
	if(Devices==NULL)
		goto out_unregister;
	for(i=0;i<ndevices;i++)
		setup_device(Devices+i,i);
	printk(KERN_ALERT "nss_md_init finished\n");
	return 0;
out_unregister:
	printk(KERN_ALERT "out_unregister\n");
	unregister_blkdev(nss_md_major,"nss_md");
	return -ENOMEM;
	
}
static void __exit nss_md_exit(void)
{
	int i;
	printk(KERN_ALERT  "goodbye\n");
	for(i=0;i<ndevices;i++){
		struct nss_md_dev *dev=Devices +i;
		printk(KERN_ALERT  "goodbye2\n");
		del_timer_sync(&dev->timer);
		printk(KERN_ALERT  "goodbye3\n");
		if(dev->gd)
		{
			printk(KERN_ALERT  "goodbye4\n");
			del_gendisk(dev->gd);
			printk(KERN_ALERT  "goodbye5\n");
			put_disk(dev->gd);
			printk(KERN_ALERT  "goodbye6\n");
		}
		if(dev->queue)
		{
			printk(KERN_ALERT  "goodbye7\n");
			blk_cleanup_queue(dev->queue);
			printk(KERN_ALERT  "goodbye8\n");
				
		}
		if(dev->data)
		{
			printk(KERN_ALERT  "goodbye9\n");
			vfree(dev->data);
			printk(KERN_ALERT  "goodbye10\n");
		}
	}
	printk(KERN_ALERT  "goodbye11\n");
	unregister_blkdev(nss_md_major,"nss_md");
	printk(KERN_ALERT  "goodbye12\n");
	kfree(Devices);
}
module_init(nss_md_init);
module_exit(nss_md_exit);

你可能感兴趣的:(raid0)