區塊類型驅動程式
V1.1
email: mesmerli@hotmail.com
RAMDISK 驅動程式實驗步驟
Host 端
- root file system 組態設定。
- 建構新的 root file system (RAMDISK)
- dd if=/dev/zero of=ext2new bs=1k count=8192
- mke2fs -F -m0 -I 2000 ext2new
- mount -w -o loop ext2new /mnt/loop
- mount -w -o loop ext2org /mnt/looporg
- cp -dpR /mnt/looporg/. /mnt/loop/.
- cd /mnt/loop/dev (/dev 檔案夾下,建立 裝置節點)
- mknod -m 777 ramblock0 b 42 0
- cd /
- umount -l /mnt/loop
- gzip -9 ext2new
- 建構新的 root file system (RAMDISK)
- 重新燒錄 root file system。
- 編譯 RAMDISK 驅動程式
- init_timer(&radimo_timer); // (Line 307) 第一次實驗時,註解掉此一列程式,避免模擬磁碟片抽換
- make -f Makefile_Cross
Taget 端
-
使用 NFS 的方式,mount host 端的目錄,以存取剛剛建立的 RAMDISK 驅動程式。
- mount 192.168.0.200:/usr/src/creator/nfs /mnt
- 安裝驅動程式
- cd /dev
- mknod -m 777 ramblock0 b 42 0
- cd /mnt/Day3/blk-driver/radimo
- insmod radiomo_Cross.o
-
格式化檔案系統為 Ext2
- ./mke2fs_Cross.exe /dev/ramblock0
-
mount Ext2 檔案系統
- mkdir /mnt2
- mount /dev/ramblock0 /mnt2
- 讀寫 /mnt2 目錄,此時 /mnt2 目錄的內容即為透過 RAMDISK 驅動程式操作的 Ext2 檔案系統。
- cat /proc/kmsg 觀察執行流程
radimo.c
/*
* Sample RAm DIsk MOdule, Radimo
*
*/
#include <linux/init.h>
#include <linux/module.h>
#if defined(CONFIG_SMP)
#define __SMP__
#endif
#if defined(CONFIG_MODVERSIONS)
#define MODVERSIONS
#include <linux/modversions.h>
#endif
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/fs.h>
#include <linux/vmalloc.h>
#include <asm/uaccess.h>
#include "radimo.h"
#define MAJOR_NR RADIMO_MAJOR
#define DEVICE_NAME "radimo"
#define DEVICE_REQUEST radimo_request
#define DEVICE_NR(device) (MINOR(device))
#define DEVICE_ON(device)
#define DEVICE_OFF(device)
#define DEVICE_NO_RANDOM
#include <linux/blk.h> // 在引入 blk 之前,必須定義以上常數用於定義巨集
#define RADIMO_HARDS_BITS 9 /* 2**9 byte hardware sector */
#define RADIMO_BLOCK_SIZE 1024 /* block size */
#define RADIMO_TOTAL_SIZE 2048 /* size in blocks */
/* the storage pool */
static char *radimo_storage;
static int radimo_hard = 1 << RADIMO_HARDS_BITS;
static int radimo_soft = RADIMO_BLOCK_SIZE;
static int radimo_size = RADIMO_TOTAL_SIZE;
static int radimo_readahead = 4;
/* for media changes */
static int radimo_changed;
struct timer_list radimo_timer;
/* module parameters and descriptions */
MODULE_PARM(radimo_soft, "1i");
MODULE_PARM_DESC(radimo_soft, "Software block size");
MODULE_PARM(radimo_size, "1i");
MODULE_PARM_DESC(radimo_size, "Total size in KB");
MODULE_PARM(radimo_readahead, "1i");
MODULE_PARM_DESC(radimo_readahead, "Max number of sectors to read ahead");
MODULE_LICENSE("GPL");
/* forward declarations for _fops */
static int radimo_open(struct inode *inode, struct file *file);
static int radimo_release(struct inode *inode, struct file *file);
static int radimo_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg);
static int radimo_media_change(kdev_t dev);
static int radimo_revalidate(kdev_t dev);
/* Because the kernel interface to device drivers changes a bit
from version to version, we have to test kernel versions here.
If you need your module to compile on older kernels, you can usei
this as an example for your device drivers. It should
work on kernels from 2.3 to 2.6.0
*/
#if LINUX_VERSION_CODE < 0x20326
static struct file_operations radimo_fops = {
read: block_read,
write: block_write,
ioctl: radimo_ioctl,
open: radimo_open,
release: radimo_release,
check_media_change: radimo_media_change,
revalidate: radimo_revalidate,
};
#else
static struct block_device_operations radimo_fops = {
open: radimo_open,
release: radimo_release,
ioctl: radimo_ioctl,
check_media_change: radimo_media_change,
revalidate: radimo_revalidate,
#if LINUX_VERSION_CODE >= 0x20414
owner: THIS_MODULE,
#endif
};
#endif
static void radimo_request(request_queue_t *q)
{
unsigned long offset, total;
radimo_begin:
INIT_REQUEST;
MSG(RADIMO_REQUEST, "%s sector %lu of %lun",
CURRENT->cmd == READ ? "read" : "write",
CURRENT->sector,
CURRENT->current_nr_sectors);
offset = CURRENT->sector * radimo_hard;
total = CURRENT->current_nr_sectors * radimo_hard;
/* access beyond end of the device */
if (total+offset > radimo_size * (radimo_hard << 1)) {
/* error in request */
end_request(0);
goto radimo_begin;
}
MSG(RADIMO_REQUEST, "offset = %lu, total = %lun", offset, total);
if (CURRENT->cmd == READ) {
memcpy(CURRENT->buffer, radimo_storage+offset, total);
} else if (CURRENT->cmd == WRITE) {
memcpy(radimo_storage+offset, CURRENT->buffer, total);
} else {
/* can't happen */
MSG(RADIMO_ERROR, "cmd == %d is invalidn", CURRENT->cmd);
end_request(0);
}
/* successful */
end_request(1);
/* let INIT_REQUEST return when we are done */
goto radimo_begin;
}
static int radimo_media_change(kdev_t dev)
{
if (radimo_changed)
MSG(RADIMO_INFO, "media has changedn");
/* 0 means medium has not changed, while 1 indicates a change */
return radimo_changed;
}
static int radimo_revalidate(kdev_t dev)
{
MSG(RADIMO_INFO, "revalidaten");
/* just return 0, check_disk_change ignores it anyway */
return 0;
}
void radimo_timer_fn(unsigned long data)
{
MSG(RADIMO_TIMER, "timer expiredn");
/* only "change media" if device is unused */
if (1 || MOD_IN_USE) {
radimo_changed = 0;
} else {
/* medium changed, clear storage and */
MSG(RADIMO_TIMER, "simulating media changen");
/* By erasing the first four blocks! */
memset(radimo_storage, 0, RADIMO_BLOCK_SIZE * 4 );
radimo_changed = 1;
/* data contains i_rdev */
fsync_dev(data);
invalidate_buffers(data);
}
/* set it up again */
radimo_timer.expires = RADIMO_TIMER_DELAY + jiffies;
add_timer(&radimo_timer);
}
static int radimo_release(struct inode *inode, struct file *file)
{
MSG(RADIMO_OPEN, "closedn");
MOD_DEC_USE_COUNT;
return 0;
}
static int radimo_open(struct inode *inode, struct file *file)
{
MSG(RADIMO_OPEN, "openedn");
MOD_INC_USE_COUNT;
/* timer function needs device to invalidate buffers. pass it as
data. */
radimo_timer.data = inode->i_rdev;
radimo_timer.expires = RADIMO_TIMER_DELAY + jiffies;
radimo_timer.function = &radimo_timer_fn;
if (!timer_pending(&radimo_timer))
add_timer(&radimo_timer);
return 0;
}
static int radimo_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
unsigned int minor;
if (!inode || !inode->i_rdev)
return -EINVAL;
minor = MINOR(inode->i_rdev);
switch (cmd) {
case BLKFLSBUF: {
/* flush buffers */
MSG(RADIMO_IOCTL, "ioctl: BLKFLSBUFn");
/* deny all but root */
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
fsync_dev(inode->i_rdev);
invalidate_buffers(inode->i_rdev);
break;
}
case BLKGETSIZE: {
/* return device size */
MSG(RADIMO_IOCTL, "ioctl: BLKGETSIZEn");
if (!arg)
return -EINVAL;
return put_user(radimo_size*2, (long *) arg);
}
case BLKRASET: {
/* set read ahead value */
int tmp;
MSG(RADIMO_IOCTL, "ioctl: BLKRASETn");
if (get_user(tmp, (long *)arg))
return -EINVAL;
if (tmp > 0xff)
return -EINVAL;
read_ahead[RADIMO_MAJOR] = tmp;
return 0;
}
case BLKRAGET: {
/* return read ahead value */
MSG(RADIMO_IOCTL, "ioctl: BLKRAGETn");
if (!arg)
return -EINVAL;
return put_user(read_ahead[RADIMO_MAJOR], (long *)arg);
}
case BLKSSZGET: {
/* return block size */
MSG(RADIMO_IOCTL, "ioctl: BLKSSZGETn");
if (!arg)
return -EINVAL;
return put_user(radimo_soft, (long *)arg);
}
default: {
MSG(RADIMO_ERROR, "ioctl wanted %un", cmd);
return -ENOTTY;
}
}
return 0;
}
static int __init radimo_init(void)
{
int res;
/* block size must be a multiple of sector size */
if (radimo_soft & ((1 << RADIMO_HARDS_BITS)-1)) {
MSG(RADIMO_ERROR, "Block size not a multiple of sector sizen");
return -EINVAL;
}
/* allocate room for data */
radimo_storage = (char *) vmalloc(1024*radimo_size);
if (radimo_storage == NULL) {
MSG(RADIMO_ERROR, "Not enough memory. Try a smaller size.n");
return -ENOMEM;
}
memset(radimo_storage, 0, 1024*radimo_size);
/* register block device */
res = register_blkdev(RADIMO_MAJOR, "radimo", &radimo_fops);
if (res) {
MSG(RADIMO_ERROR, "couldn't register block devicen");
return res;
}
/* for media change */
radimo_changed = 0;
init_timer(&radimo_timer); // 第一次實驗時,註解掉此一列程式,避免模擬磁碟片抽換
/* set hard- and soft blocksize */
hardsect_size[RADIMO_MAJOR] = &radimo_hard;
blksize_size[RADIMO_MAJOR] = &radimo_soft;
blk_size[RADIMO_MAJOR] = &radimo_size;
/* define our request function */
/* Here's another instance where kernel versions really matter.
The request queue interface changed in the 2.4 series kernels
*/
#if LINUX_VERSION_CODE < 0x20320
blk_dev[RADIMO_MAJOR].request_fn = &radimo_request;
#else
blk_init_queue(BLK_DEFAULT_QUEUE(RADIMO_MAJOR), radimo_request);
#endif
read_ahead[RADIMO_MAJOR] = radimo_readahead;
MSG(RADIMO_INFO, "loadedn");
MSG(RADIMO_INFO, "sector size of %d, block size of %d, total size = %dKbn",
radimo_hard, radimo_soft, radimo_size);
return 0;
}
static void __exit radimo_cleanup(void)
{
unregister_blkdev(RADIMO_MAJOR, "radimo");
del_timer(&radimo_timer);
invalidate_buffers(MKDEV(RADIMO_MAJOR,0));
/* remove our request function */
#if LINUX_VERSION_CODE < 0x20320
blk_dev[RADIMO_MAJOR].request_fn = 0;
#else
blk_cleanup_queue(BLK_DEFAULT_QUEUE(RADIMO_MAJOR));
#endif
vfree(radimo_storage);
MSG(RADIMO_INFO, "unloadedn");
}
module_init(radimo_init);
module_exit(radimo_cleanup);
radimo.h
#define RADIMO_MAJOR 42
#define RADIMO_TIMER_DELAY 60*HZ
/* msg masks */
#define RADIMO_OPEN 1
#define RADIMO_IOCTL 2
#define RADIMO_INFO 4
#define RADIMO_REQUEST 8
#define RADIMO_TIMER 16
#define RADIMO_ERROR 32
#ifndef MSG_MASK
#define MSG_MASK ( RADIMO_REQUEST | RADIMO_OPEN | RADIMO_IOCTL | RADIMO_INFO | RADIMO_ERROR | RADIMO_TIMER)
#endif
#define MSG(mask, string, args...)
if (MSG_MASK & mask) printk(KERN_DEBUG "radimo: " string, ##args)
0 意見:
張貼留言