在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命令进行分区设置,再挂载使用