`

关于操作系统例程

阅读更多

把自己认为有保留价值的几个代码片断给放在这里,以供参考!

1.进行proc文件系统编程,在内核中维护一张表格(表格记录了学生的姓名和学号),可以向表格添加记录,显示记录和删除记录,并编写一个用户程序进行测试

老师给的答案(好像有问题):

/*
* a mini module do nothing
* test passed on linux redhat 9 'kernel 2.4.20-8'
* Compile:
* gcc -c -I/usr/src/linux/include -Wall procf.c
*/


//#define __NO_VERSION__
#define LINUX
#define __KERNEL__
#define MODULE

#include <linux/kernel.h> /* program in kernel */
#include <linux/module.h> /* program as module */
#include <linux/proc_fs.h>
#include <asm/uaccess.h>

#define KBUILD_MODNAME procf

char content[100] = "this my file content";
int len = 20;

int my_read_proc(char *buf, char **start, off_t offset, int xlen, int *eof, void *data)
{
//copy_to_user(buf, content, len);
int i;
for(i=0; i<len+1; i++) buf[i] = content[i];
return len;
}

int my_write_proc(struct file *file, const char *buf,
unsigned long count, void *data)
{
int i;
if( count > 99 ) count = 99;
//copy_from_user(content, buf, count);
for(i=0; i<count; i++) content[i] = buf[i];
len = i;
content[i] = '\0';

return len;
}

struct proc_dir_entry my_entry = {
0,
6, /* unsigned short namelen */
"myname", /* const char *name */
S_IFREG | S_IRUGO, /* mode_t mode */
1, /* nlink_t nlink */
0, /* uid_t uid */
0, /* gid_t gid */
2, /* unsigned long size */
NULL, /* struct inode_operations *ops */
NULL,
NULL,
NULL, NULL, NULL,
NULL,
my_read_proc,
my_write_proc,
NULL,
0,
0
};


int init_module()
{
int i;
for(i=49, len =0; i<59; i++){
content[i-49] = i;
len ++;
}
content[i] = '\0';
proc_register(&proc_root, &my_entry);
printk("Hello world\n");
return 0;
}

void cleanup_module()
{
proc_unregister(&proc_root, my_entry.low_ino);
printk("bye\n");
}

MODULE_LICENSE("GPL");

自己改造过的答案:

#define LINUX
#define __KERNEL__
#define MODULE

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include <linux/sched.h>
#include <asm/uaccess.h>
//#include <string.h>
//#include <stdio.h>

#define NAMELEN 10
#define IDLEN 10
#define STRINGLEN 100
struct person_information{
char name[NAMELEN];
char id[IDLEN];
};

char global_buffer[1024];

struct person_information global_buffer_student[STRINGLEN];
//struct proc_dir_entry student_file = {
//0,
//strlen("student_file"), /*unsigned short namelen*/
//"student_file",/*const char* name*/
//S_IFREG|S_IRUGO,/*mode_t mode*/
//1,/*nlink_t nlink*/
//0,/*uid_t uid*/
//0,/*gid_t gid*/
//2,/*unsigned long size*/
//NULL,/*struct inode_operation *pos*/
//NULL,
//NULL,
//NULL,NULL,NULL,
//NULL,
//proc_read_student,
//proc_write_student,
//NULL,
//0,
//0
//};

struct proc_dir_entry *student_file;
struct proc_dir_entry *example_dir;
struct proc_dir_entry *current_file;
struct proc_dir_entry *hello_file;
struct proc_dir_entry *symlink;

int proc_read_student(char* page,char** start,off_t off,int count,int* eof,void* data);
int proc_write_student(struct file *file,const char *buffer,unsigned long count,void* data);

int proc_read_current(char* page,char** start,off_t off,int count,int *eof,void* data);

int proc_read_hello(char* page,char** start,off_t off,int count,int* eof,void* data);
int proc_write_hello(struct file *file,const char *buffer,unsigned long count,void* data);


void init_student(){
int i=0;
for(i;i<STRINGLEN;++i){
memset(global_buffer_student[i].name,'0'+i,NAMELEN);
memset(global_buffer_student[i].id,i,IDLEN);
}
}

int proc_read_student(char* page,char** start,off_t off,int count,int* eof,void* data){
int len;
MOD_INC_USE_COUNT;
len = sprintf(page,"golbal_buffer==%s\n",global_buffer);
int i;
//init_student();
i=0;
//for(i=0;i<STRINGLEN;++i){
printk("name==%s,id==%s\n",global_buffer_student[i].name,global_buffer_student[i].id);
//}
MOD_DEC_USE_COUNT;
return len;
}

int proc_write_student(struct file *file,const char *buffer,unsigned long count,void* data){
int len;
MOD_INC_USE_COUNT;
if(count>=STRINGLEN)
len = STRINGLEN-1;
else
len = count;
copy_from_user(global_buffer_student,buffer,len);
global_buffer[len]='\0';
MOD_DEC_USE_COUNT;
return 0;
}

int init_module(){
example_dir = proc_mkdir("proc_test",NULL);
example_dir->owner = THIS_MODULE;

current_file = create_proc_read_entry("current",666,example_dir,proc_read_current,NULL);
current_file->owner = THIS_MODULE;

hello_file = create_proc_entry("hello",666,example_dir);
strcpy(global_buffer,"this is a global_buffer\n");
hello_file->read_proc = proc_read_hello;
hello_file->write_proc = proc_write_hello;
hello_file->owner = THIS_MODULE;

student_file = create_proc_entry("student",666,example_dir);
student_file->read_proc = proc_read_student;
student_file->write_proc = proc_write_student;
student_file->owner = THIS_MODULE;

symlink = proc_symlink("current_symlink",example_dir,"current");
symlink->owner = THIS_MODULE;
init_student();
//proc_register(&proc_root,&proc_read_student);
//int i=0;
//for(i;i<STRINGLEN;++i){
//memset(global_buffer_student[i].name,0,NAMELEN);
//memset(global_buffer_student[i].id,0,IDLEN);
//}
printk("init_module msg form tested_proc.c\n");
return 0;
}

int proc_read_current(char* page,char** start,off_t off,int count,int *eof,void* data){
int len;
MOD_INC_USE_COUNT;
len = sprintf(page,"current process usages:\nname:%s\ngid:%d\npid:%d\n",current->comm,current->pgrp,current->pid);
MOD_DEC_USE_COUNT;
return len;
}

//void proc_write_information(){

//}

int proc_read_hello(char* page,char** start,off_t off,int count,int* eof,void* data){
int len;
MOD_INC_USE_COUNT;
len = sprintf(page,"hello message:\n %s write: %s \n",current->comm,global_buffer);
MOD_DEC_USE_COUNT;
return len;
}

int proc_write_hello(struct file *file,const char *buffer,unsigned long count,void* data){ int len;
MOD_INC_USE_COUNT;
if(count >= 1024)
len = 1024-1;
else
len = count;
copy_from_user(global_buffer,buffer,len);
global_buffer[len]='\0';
MOD_DEC_USE_COUNT;
return len;
}


void cleanup_module(){
remove_proc_entry("current_symlink",example_dir);
remove_proc_entry("hello",example_dir);
remove_proc_entry("student",example_dir);
remove_proc_entry("current",example_dir);
remove_proc_entry("proc_test",NULL);
//proc_unregister(&proc_root,proc_read_student.low_ino);
printk("cleanup_module msg form tested_proc.c\n");
}

MODULE_LICENSE("GPL");


2.示例如何使用模块

/* rwbuf: read/write a buffer
* a demo on how to build a device in a kernel module
* test pass with Mandrake 7(Kernel 2.2.14) in vmare, 2005/12
* test pass with RedHat 9(Kernel 2.4.20-8) in vmware, 2005/12
*
* how to test ?
* so :
*
* $ first you must be ROOT
compile in Kernel 2.4
* # gcc -I/usr/src/linux/include/ -D KERNEL2_4 -c rwbuf.c
compile in Kernel 2.2
* # gcc -I/usr/src/linux/include/ -c rwbuf.c
* # insmod rwbuf.o // you should see that 'rwbuf' in there
* # lsmod
* # mknod /dev/rwbuf c 60 0 // this can do only once
* # // now you can use /dev/rwbuf
*/


#define LINUX
#define __KERNEL__
#define MODULE

#define KBUILD_MODNAME rwbuf

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>

#ifdef KERNEL2_4
#define HAVE_MEMCPY /* no export 'memcpy' in kernel 2.2 */
#define HAVE_MOD_LIC /* no Module License in kernel 2.2 */
#endif


#ifndef HAVE_MEMCPY
#include <asm/uaccess.h> /* copy_to_user, copy_from_user */
#endif

#define RWBUF_prefix rwbuf// not used yet
#define RWBUF_NAME "rwbuf" // device's symbol name
#define RWBUF_ID 60// device's major no
#define RW_CLEAR 0x909090 // IO ctl command

#define rwbuf_size 1000// 1k enough
static unsigned char rwbuf[rwbuf_size+1]; //
static int rwlen=0;// how many bytes used in <rwbuf>
static int inuse=0;// only one process permited at the same time

static int rwbuf_open(struct inode *inode,struct file * filep)
{
if (inuse==1)// the buf is used by another process, so fail to open
return -1;
inuse=1;

MOD_INC_USE_COUNT;// don't ask what this means
return 0;
}

static int rwbuf_close(struct inode *inode,struct file * filep)
{
inuse=0;

MOD_DEC_USE_COUNT;
return 0;
}

static ssize_t rwbuf_write(struct file * filep,
const char *buf, size_t count, loff_t * ppos)
{
if (count>rwbuf_size)
count = rwbuf_size;
#ifndef HAVE_MEMCPY /* no export 'memcpy' in kernel 2.2 */
copy_from_user(rwbuf, buf, count);
#else
memcpy(rwbuf, buf, count); // as you see
#endif
rwlen = count;
printk("user-to-kernel: %s\n", rwbuf);
return count;
}

static ssize_t rwbuf_read(struct file* filep,
char * buf, size_t count, loff_t* ppos)
{
if (count>rwlen)
count = rwlen;
#ifndef HAVE_MEMCPY /* no export 'memcpy' in kernel 2.2 */
copy_to_user(buf, rwbuf, count);
#else
memcpy(buf, rwbuf, count);
#endif
printk("kernel-to-user: %s\n", buf);
return count;
}

static int rwbuf_ioctl(struct inode *inode,struct file * filep,
unsigned int cmd,unsigned long arg)
{
switch (cmd)
{
case RW_CLEAR:
rwlen = 0;// clear buf by set its len to zero
printk("rwbuf in kernel zero-ed\n");
break;

default:
break;
};

return 0;
}


static struct file_operations rwbuf_fops =
{
open: rwbuf_open,
release: rwbuf_close,
read: rwbuf_read,
write: rwbuf_write,
ioctl: rwbuf_ioctl,
};

int init_module()
{
printk("Hello world\n");
if (register_chrdev(RWBUF_ID, RWBUF_NAME, &rwbuf_fops))
printk("register error\n");
else
printk("register ok\n");
return 0;
}

void cleanup_module()
{
if (unregister_chrdev(RWBUF_ID, RWBUF_NAME)!=0)
printk("unreg err\n");
else
printk("unreg ok\n");
printk("bye\n");
}

#ifdef HAVE_MOD_LIC
MODULE_LICENSE("GPL");
#endif

3.了解和熟悉Linux中设备驱动程序的概念和设计,能独立编写一个简单的字符型或是块型设备驱动程序

------------------------radimo.h---------------------------------------
#define RADIMO_MAJOR42

#define RADIMO_TIMER_DELAY60*HZ

/* msg masks */
#define RADIMO_OPEN1
#define RADIMO_IOCTL2
#define RADIMO_INFO4
#define RADIMO_REQUEST8
#define RADIMO_TIMER16
#define RADIMO_ERROR32

#ifndef MSG_MASK
#define MSG_MASK ( RADIMO_IOCTL | RADIMO_INFO | RADIMO_ERROR | RADIMO_REQUEST | RADIMO_OPEN)
#endif

#define MSG(mask, string, args...) \
if (MSG_MASK & mask) printk(KERN_DEBUG "radimo: " string, ##args)

------------------------radimo.c---------------------------------------
/*
* Sample Ram DIsk Module, Radimo
*
*/

#include <linux/module.h>

#if defined(CONFIG_SMP)
#define __SMP__
#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_NRRADIMO_MAJOR// 定义了RADIMO的主设备号
#define DEVICE_NAME"radimo"// 定义了RADIMO的设备名
#define DEVICE_NR(device)(MINOR(device))
#define DEVICE_ON(device)
#define DEVICE_OFF(device)
#define DEVICE_NO_RANDOM

#include <linux/blk.h>

#define RADIMO_HARDS_BITS9/* 2**9 byte hardware sector */
#define RADIMO_BLOCK_SIZE1024/* block size */
//定义了一个块的大小,以字节为单位
#define RADIMO_TOTAL_SIZE2048/* 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;

struct timer_list radimo_timer;
//定义了一个定时器,这个程序中我们并没有用到。这里作为一个使用定时器的例子

/* 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 struct block_device_operations radimo_fops = {
open:radimo_open,
release:radimo_release,
ioctl:radimo_ioctl,
};
//用一个结构把三个接口函数组装起来,以便通知操作系统


static int radimo_request(request_queue_t *request_queue, int rw, struct buffer_head *sbh)
{//【重要】这是块设备驱动程序处理读写请求的函数,是本程序中最重要的部分
unsigned long offset, total;
//int *make_oops = NULL; // CR: access to this pointer will cause Oops, for debug only.

MSG(RADIMO_REQUEST, "%s sector rsector = %lu, blocknr = %lu\n",
rw == READ ? "read" : "write",
sbh->b_rsector,
sbh->b_blocknr);
//MSG宏的定义在radimo.h中,相当于printk,

//用于在log文件中打印一行,以便调试

offset = sbh->b_rsector * radimo_hard;
total = (unsigned long)sbh->b_size;
//计算需要访问的地址和大小

/* access beyond end of the device */
if (total+offset > radimo_size * (radimo_hard << 1)) {
MSG(RADIMO_REQUEST, "Error: access beyond end of the device");
/* error in request */
buffer_IO_error(sbh);
return 0;
}
//判断访问地址是否越界

MSG(RADIMO_REQUEST, "offset = %lu, total = %lu\n", offset, total);

if (rw == READ || rw==READA) {//如果是读操作,从虚拟盘的内存中复制数据到缓冲区中
memcpy(bh_kmap(sbh), radimo_storage+offset, total);
} else if (rw == WRITE) { //如果是写操作,从缓冲区中复制数据到虚拟盘的内存中
memcpy(radimo_storage+offset, bh_kmap(sbh), total);
} else {/* can't happen */
MSG(RADIMO_ERROR, "cmd == %d is invalid\n", rw);
}
/* successful */

sbh->b_end_io(sbh,1);//结束读写操作

return 0;
}

void radimo_timer_fn(unsigned long 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, "closed\n");
MOD_DEC_USE_COUNT;//减少引用计数
return 0;
}

static int radimo_open(struct inode *inode, struct file *file)
{//打开设备时调用
MSG(RADIMO_OPEN, "opened\n");
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: BLKFLSBUF\n");
/* 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: BLKGETSIZE\n");
if (!arg)
return -EINVAL;
return put_user(radimo_size*2, (long *) arg);
}

case BLKRASET: {//设置设备预读值的操作
/* set read ahead value */
int tmp;
MSG(RADIMO_IOCTL, "ioctl: BLKRASET\n");
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: BLKRAGET\n");
if (!arg)
return -EINVAL;
return put_user(read_ahead[RADIMO_MAJOR], (long *)arg);
}

case BLKSSZGET: {//得到设备块大小的操作
/* return block size */
MSG(RADIMO_IOCTL, "ioctl: BLKSSZGET\n");
if (!arg)
return -EINVAL;
return put_user(radimo_soft, (long *)arg);
}

default: {//其他操作
MSG(RADIMO_ERROR, "ioctl wanted %u\n", cmd);
return -ENOTTY;
}
}
return 0;
}

int init_module(void)
{//在模块被加载的时候调用
int res;

/* 块大小必须是扇区大小的整数倍 */
if (radimo_soft & ((1 << RADIMO_HARDS_BITS)-1)) {
MSG(RADIMO_ERROR, "Block size not a multiple of sector size\n");
return -EINVAL;
}

/* 分配存储空间 */
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);

/* 【重要】向系统注册块设备 */
res = register_blkdev(RADIMO_MAJOR, "radimo", &radimo_fops);
if (res) {
MSG(RADIMO_ERROR, "couldn't register block device\n");
return res;
}

init_timer(&radimo_timer);

/* 在系统中注册块的大小、存储容量等参数 */
hardsect_size[RADIMO_MAJOR] = &radimo_hard;
blksize_size[RADIMO_MAJOR] = &radimo_soft;
blk_size[RADIMO_MAJOR] = &radimo_size;

/* 在系统中注册响应读写请求的函数 */
blk_queue_make_request(BLK_DEFAULT_QUEUE(RADIMO_MAJOR), &radimo_request);
read_ahead[RADIMO_MAJOR] = radimo_readahead;

MSG(RADIMO_INFO, "loaded\n");
MSG(RADIMO_INFO, "sector size of %d, block size of %d, total size = %dKb\n",
radimo_hard, radimo_soft, radimo_size);

printk("init_module from radimo.c ");
return 0;
}

void cleanup_module(void)
{//在模块被卸载的时候调用
unregister_blkdev(RADIMO_MAJOR, "radimo");
del_timer(&radimo_timer);

invalidate_buffers(MKDEV(RADIMO_MAJOR,0));

/* remove our request function */
blk_dev[RADIMO_MAJOR].request_queue.request_fn = 0;

vfree(radimo_storage);

MSG(RADIMO_INFO, "unloaded\n");
printk("cleanup_module from radimo.c ");
}
MODULE_LICENSE("GPL");


------------------------Makefile---------------------------------------
# standards
INCLUDE= /usr/src/linux-2.4/include
CC = gcc
CFLAGS = -D__KERNEL__ -I$(INCLUDE) -DMODULE -Wall -O2

TARGET= radimo
SRC= radimo.c

all: $(TARGET).o

clean:
rm -f *.o *~ core

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics