ramdisk的模拟实现

在linux系统中有一种文件系统很特殊,他便是ramdisk,当然完全的ramdisk已经由于其对内存容量的要求已经没人使用了,但是他的升级版本cramfs确实很瘦欢迎,尤其是在嵌入式设备中,当你想创建一个文件系统而又不想让人对其中的文件进行修改,那么cramfs便是很好的选择。在我的这个程序中,模仿ramdisk原理,从内存中开辟一块内存(8M),然后对其进行格式化,挂载使用。当然,这一切的任务是驱动完成的,所以本程序是一个块设备的驱动。好了废话不多说,请看程序(我已经添加了足够多的注释,基本山不用我再多解释了吧。。。。。)

/*
 * Sample disk driver for 2.6.35.
 */

//#include <linux/autoconf.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>

#include <linux/sched.h>
#include <linux/kernel.h>	/* printk() */
#include <linux/slab.h>		/* kmalloc() */
#include <linux/fs.h>		/* everything... */
#include <linux/errno.h>	/* error codes */
#include <linux/timer.h>
#include <linux/types.h>	/* size_t */
#include <linux/fcntl.h>	/* O_ACCMODE */
#include <linux/hdreg.h>	/* HDIO_GETGEO */
#include <linux/kdev_t.h>
#include <linux/vmalloc.h>
#include <linux/genhd.h>
#include <linux/blkdev.h>
//#include <linux/buffer_head.h>	/* invalidate_bdev */
#include <linux/bio.h>

MODULE_LICENSE("Dual BSD/GPL");

static int ramdisk_major = 0;
module_param(ramdisk_major, int, 0);
static int hardsect_size = 512;  /*The size of a sector*/
module_param(hardsect_size, int, 0);
static int nsectors = 8*1024*2;	/* How big the drive is */
module_param(nsectors, int, 0);
static int ndevices = 1;
module_param(ndevices, int, 0);

/*
 * The different "request modes" we can use.
 */
enum {
	RM_SIMPLE  = 0,	/* The extra-simple request function */
	RM_FULL    = 1,	/* The full-blown version */
	RM_NOQUEUE = 2,	/* Use make_request */
};
//static int request_mode = RM_FULL;
//static int request_mode = RM_SIMPLE;
static int request_mode = RM_NOQUEUE;
module_param(request_mode, int, 0);

/*
 * Minor number and partition management.
 */
#define ramdisk_MINORS	16
//#define MINOR_SHIFT	4
//#define DEVNUM(kdevnum)	(MINOR(kdev_t_to_nr(kdevnum)) >> MINOR_SHIFT

/*
 * We can tweak our hardware sector size, but the kernel talks to us
 * in terms of small sectors, always.
 */
#define KERNEL_SECTOR_SIZE	512

/*
 * The internal representation of our device.
 */
struct ramdisk_dev {
        int size;                       /* Device size in bytes */
        u8 *data;                       /* points to the space of device */
        short users;                    /* How many users */
        spinlock_t lock;                /* For mutual exclusion */
        struct request_queue *queue;    /* The device request queue */
        struct gendisk *gd;             /* The gendisk structure */
};

static struct ramdisk_dev *Devices = NULL;

/*
 * Handle an I/O request.
 * 瀹炵幇鎵囧尯鐨勮鍐? */
static void ramdisk_transfer(struct ramdisk_dev *dev, unsigned long sector,
		unsigned long nsect, char *buffer, int write)
{
	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);
}

static void ramdisk_request(struct request_queue *q)
{
	struct request *req;
	struct ramdisk_dev *dev;
	
	while ((req = blk_fetch_request(q)) != NULL) {
		dev= req->rq_disk->private_data;
		/*
		if (! blk_fs_request(req)) {
			printk (KERN_NOTICE "Skip non-  ererefs request\n");
			__blk_end_request_all(req, -EIO);
			printk("*** not blk_fs_request ***\n");
			continue;
		}
		*/
		while ( 1 )
		{
			ramdisk_transfer(dev, blk_rq_pos(req), blk_rq_cur_sectors(req),
					req->buffer, rq_data_dir(req));
		
			if ( ! __blk_end_request_cur(req, 0) )
			{ 
				break;    
			}
		}
	}
}

/*
 * Transfer a single BIO.
 */
static int ramdisk_xfer_bio(struct ramdisk_dev *dev, struct bio *bio)
{
	int i;
	struct bio_vec *bvec;
	sector_t sector = bio->bi_sector;

	/* Do each segment independently. */
	bio_for_each_segment(bvec, bio, i) {  
		char *buffer = __bio_kmap_atomic(bio, i, KM_USER0);
		ramdisk_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; /* Always "succeed" */
}

/*
 * Transfer a full request.
 */
static int ramdisk_xfer_request(struct ramdisk_dev *dev, struct request *req)
{
	struct bio *bio;
	int nsect = 0;
    
	__rq_for_each_bio(bio, req) { 
		ramdisk_xfer_bio(dev, bio);
		nsect += bio->bi_size/KERNEL_SECTOR_SIZE;
	}
	return nsect;
}

/*
 * Smarter request function that "handles clustering".*/
static void ramdisk_full_request(struct request_queue *q)
{

	struct request *req;
	int nsect;
	struct ramdisk_dev *dev ;

	int i = 0;
	while ((req = blk_fetch_request(q)) != NULL) {
		dev = req->rq_disk->private_data;
		/*
		if (! blk_fs_request(req)) {
			printk (KERN_NOTICE "Skip non-fs request\n");
			__blk_end_request_all(req, -EIO);
			continue;
		}
		*/
		nsect = ramdisk_xfer_request(dev, req);
       	__blk_end_request(req, 0, (nsect<<9)); 
		printk ("i = %d\n", ++i);
	}
}

//The direct make request version
static void ramdisk_make_request(struct request_queue *q, struct bio *bio)
{
	struct ramdisk_dev *dev = q->queuedata;
	int status;

	status = ramdisk_xfer_bio(dev, bio);
	bio_endio(bio, status);  

	return;
}

/*
 * Open and close.
 */

static int ramdisk_open(struct block_device *bdev,fmode_t mode )
{
	struct ramdisk_dev *dev = bdev->bd_disk->private_data;
	
	spin_lock(&dev->lock);
	dev->users++;
	spin_unlock(&dev->lock);
	return 0;
}

static int ramdisk_release(struct gendisk *bd_disk, fmode_t mode)
{
	struct ramdisk_dev *dev = bd_disk->private_data;

	spin_lock(&dev->lock);
	dev->users--;
	spin_unlock(&dev->lock);

	return 0;
}

static int ramdisk_getgeo(struct block_device *bdev, struct hd_geometry *geo)
{
	unsigned long size;
	struct ramdisk_dev *pdev = bdev->bd_disk->private_data;

	size = pdev->size;
	geo->heads	= 4;
	geo->sectors = 16; 
	geo->start = 0;
	
	return 0;
}


/*
 * The device operations structure.
 */
static struct block_device_operations ramdisk_ops = {
	.owner           = THIS_MODULE,
	.open 	         = ramdisk_open,
	.release 	 = ramdisk_release,
	.getgeo			= ramdisk_getgeo,
};

/*
 * Set up our internal device.
 */
static void setup_device(struct ramdisk_dev *dev, int which)
{
	/*
	 * Get some memory.
	 */
	memset (dev, 0, sizeof (struct ramdisk_dev));
	dev->size = nsectors * hardsect_size;
	dev->data = vmalloc(dev->size);
	if (dev->data == NULL) {
		printk (KERN_NOTICE "vmalloc failure.\n");
		return;
	}
	spin_lock_init(&dev->lock);
	
		
	/*
	 * The I/O queue, depending on whether we are using our own
	 * make_request function or not.
	 */
	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, ramdisk_make_request);
		break;

	    case RM_FULL:
		dev->queue = blk_init_queue(ramdisk_full_request, &dev->lock);
		if (dev->queue == NULL)
			goto out_vfree;
		break;

	    case RM_SIMPLE:
		dev->queue = blk_init_queue(ramdisk_request, &dev->lock);
		if (dev->queue == NULL)
			goto out_vfree;
		break;
		
		default:
		printk(KERN_NOTICE "Bad request mode %d, using simple\n", request_mode);
        	/* fall into.. */
	}
	dev->queue->queuedata = dev;
	/*
	 * And the gendisk structure.
	 */
	dev->gd = alloc_disk(ramdisk_MINORS);
	if (! dev->gd) {
		printk (KERN_NOTICE "alloc_disk failure\n");
		goto out_vfree;
	}
	dev->gd->major = ramdisk_major;
	dev->gd->first_minor = which*ramdisk_MINORS;
	dev->gd->fops = &ramdisk_ops;
	dev->gd->queue = dev->queue;
	dev->gd->private_data = dev;
	snprintf (dev->gd->disk_name, 32, "ramdisk%c", which + 'a');
	set_capacity(dev->gd, nsectors*(hardsect_size/KERNEL_SECTOR_SIZE));
	add_disk(dev->gd);

	return;

  out_vfree:
	if (dev->data)
		vfree(dev->data);
}

static int __init ramdisk_init(void)
{
	int i;
	/*
	 * Get registered.
	 */
	ramdisk_major = register_blkdev(ramdisk_major, "ramdisk");
	if (ramdisk_major <= 0) {
		printk(KERN_WARNING "ramdisk: unable to get major number\n");
		return -EBUSY;
	}
	/*
	 * Allocate the device array, and initialize each one.
	 */
	Devices = (struct ramdisk_dev *)kmalloc(ndevices*sizeof (struct ramdisk_dev), GFP_KERNEL);
	if (Devices == NULL)
		goto out_unregister;
	for (i = 0; i < ndevices; i++) 
		setup_device(Devices + i, i);
    
	return 0;

  out_unregister:
	unregister_blkdev(ramdisk_major, "ramdisk");
	return -ENOMEM;
}

static void ramdisk_exit(void)
{
	int i;

	for (i = 0; i < ndevices; i++) {
		struct ramdisk_dev *dev = Devices + i;

		if (dev->gd) {
			del_gendisk(dev->gd);
		}
		if (dev->queue) {
			if (request_mode != RM_NOQUEUE)
			{
				blk_cleanup_queue(dev->queue);
			}
		}
		if (dev->data)
			vfree(dev->data);
	}
	unregister_blkdev(ramdisk_major, "ramdisk");
	kfree(Devices);
}
	
module_init(ramdisk_init);
module_exit(ramdisk_exit);

下面是Makefile:

ifeq ($(KERNELRELEASE),)

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

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

modules_install:
	$(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install

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

.PHONY: modules modules_install clean

else
    obj-m := ramdisk.o
endif

执行make命令编译之后,既可以生成ramdisk.ko模块驱动程序,然后使用insmod命令之后就能将驱动加载到内核中去这时在/proc/partition中可以看到未分区的设备

然后使用fdisk命令进行分区设置,再挂载使用


你可能感兴趣的:(嵌入式,文件系统,cramfs)