linux系统(vfs)支持的 特殊文件系统_第1页
已阅读5页,还剩6页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、linux系统(vfs)支持的 特殊文件系统rootplato lsmodmodule size used bysimple_lkm 1536 0autofs4 26244 0video 13956 0button 5264 0battery 7684 0ac 3716 0yenta_socket 18952 3rsrc_nonstatic 9472 1 yenta_socketuhci_hcd 32144 0i2c_piix4 7824 0dm_mod 56468 3rootplato rmmod simple-lkmrootplato注重,内核的输出进到了内核回环缓冲区中,而不是打印到 s

2、tdout 上,这是由于 stdout 是进程特有的环境。要查看内核回环缓冲区中的消息,可以用法 dmesg 工具(或者通过 /proc 本身用法 cat /proc/kmsg 指令)。清单 6 给出了 dmesg 显示的最后几条消息。清单 6. 查看来自 lkm 的内核输出rootplato dmesg | tail -5cs: io port probe 0xa00-0xaff: clean.eth0: link is downeth0: link is up, running at 100mbit half-duplexmy_module_init called. module is n

3、ow loaded.my_module_cleanup called. module is now unloaded.rootplato可以在内核输出中看到这个模块的消息。现在让我们临时离开这个容易的例子,来看几个可以用来开发实用 lkm 的内核 api。集成到 /proc 文件系统中内核程序员可以用法的标准 api,lkm 程序员也可以用法。lkm 甚至可以导出内核用法的新变量和函数。有关 api 的完整介绍已经超出了本文的范围,因此我们在这里只是容易地介绍后面在展示一个更实用的 lkm 时所用法的几个元素。创建并删除 /proc 项要在 /proc 文件系统中创建一个虚拟文件,请用法 cr

4、eate_proc_entry 函数。这个函数可以接收一个文件名、一组权限和这个文件在 /proc 文件系统中浮现的位置。create_proc_entry 的返回值是一个proc_dir_entry 指针(或者为 null,解释在 create 时发生了错误)。然后就可以用法这个返回的指针来配置这个虚拟文件的其他参数,例如在对该文件执行读操作时应当调用的函数。create_proc_entry的原型和 proc_dir_entry 结构中的一部分如清单 7 所示。清单 7. 用来管理 /proc 文件系统项的元素struct proc_dir_entry *create_proc_entry

5、( const char *name, mode_t mode,struct proc_dir_entry *parent );struct proc_dir_entry const char *name; / virtual file namemode_t mode; / mode permissionsuid_t uid; / file's user idgid_t gid; / file's group idstruct inode_operations *proc_iops; / inode operations functionsstruct file_operati

6、ons *proc_fops; / file operations functionsstruct proc_dir_entry *parent; / parent directory.read_proc_t *read_proc; / /proc read functionwrite_proc_t *write_proc; / /proc write functionvoid *data; / pointer to private dataatomic_t count; / use count.;void remove_proc_entry( const char *name, struct

7、 proc_dir_entry *parent );稍后我们就可以看到如何用法 read_proc 和 write_proc 指令来插入对这个虚拟文件举行读写的函数。要从 /proc 中删除一个文件,可以用法 remove_proc_entry 函数。要用法这个函数,我们需要提供文件名字符串,以及这个文件在 /proc 文件系统中的位置(parent)。这个函数原型如清单 7 所示。parent 参数可以为 null(表示 /proc 根名目),也可以是无数其他值,这取决于我们希翼将这个文件放到什么地方。表 1 列出了可以用法的其他一些父 proc_dir_entry,以及它们在这个文件系统中

8、的位置。表 1. proc_dir_entry 快捷变量proc_dir_entry 在文件系统中的位置proc_root_fs /procproc_net /proc/netproc_bus /proc/busproc_root_driver /proc/driver回调函数我们可以用法 write_proc 函数向 /proc 中写入一项。这个函数的原型如下:int mod_write( struct file *filp, const char _user *buff,unsigned long len, void *data );filp 参数事实上是一个打开文件结构(我们可以忽视这个

9、参数)。buff 参数是传递给您的字符串数据。缓冲区地址事实上是一个用户空间的缓冲区,因此我们不能挺直读取它。len 参数定义了在 buff 中有多少数据要被写入。data 参数是一个指向私有数据的指针(参见 清单 7)。在这个模块中,我们声明白一个这种类型的函数来处理到达的数据。linux 提供了一组 api 来在用户空间和内核空间之间移动数据。对于 write_proc 的状况来说,我们用法了 copy_from_user 函数来维护用户空间的数据。读回调函数我们可以用法 read_proc 函数从一个 /proc 项中读取数据(从内核空间到用户空间)。这个函数的原型如下:int mod_

10、read( char *page, char *start, off_t off,int count, int *eof, void *data );page 参数是这些数据写入到的位置,其中 count 定义了可以写入的最大字符数。在返回多页数据(通常一页是 4kb)时,我们需要用法 start 和 off 参数。当全部数据所有写入之后,就需要设置 eof(文件结束参数)。与 write 类似,data 表示的也是私有数据。此处提供的 page 缓冲区在内核空间中。因此,我们可以挺直写入,而不用调用 copy_to_user。其他实用的函数我们还可以用法 proc_mkdir、symlink

11、s 以及 proc_symlink 在 /proc 文件系统中创建名目。对于只需要一个 read 函数的容易 /proc 项来说,可以用法 create_proc_read_entry,这会创建一个 /proc 项,并在一个调用中对 read_proc 函数举行初始化。这些函数的原型如清单 8 所示。清单 8. 其他实用的 /proc 函数/* create a directory in the proc filesystem */struct proc_dir_entry *proc_mkdir( const char *name,struct proc_dir_entry *parent

12、);/* create a symlink in the proc filesystem */struct proc_dir_entry *proc_symlink( const char *name,struct proc_dir_entry *parent,const char *dest );/* create a proc_dir_entry with a read_proc_t in one call */struct proc_dir_entry *create_proc_read_entry( const char *name,mode_t mode,struct proc_di

13、r_entry *base,read_proc_t *read_proc,void *data );/* copy buffer to user-space from kernel-space */unsigned long copy_to_user( void _user *to,const void *from,unsigned long n );/* copy buffer to kernel-space from user-space */unsigned long copy_from_user( void *to,const void _user *from,unsigned lon

14、g n );/* allocate a 'virtually' contiguous block of memory */void *vmalloc( unsigned long size );/* free a vmalloc'd block of memory */void vfree( void *addr );/* export a symbol to the kernel (make it visible to the kernel) */export_symbol( symbol );/* export all symbols in a file to th

15、e kernel (declare before module.h) */export_symtab回页首通过 /proc 文件系统实现财宝分发下面是一个可以支持读写的 lkm。这个容易的程序提供了一个财宝甜点分发。在加载这个模块之后,用户就可以用法 echo 指令向其中导入文本财宝,然后再用法 cat 指令逐一读出。清单 9 给出了基本的模块函数和变量。init 函数(init_fortune_module)负责用法 vmalloc 来为这个点心罐分配空间,然后用法 memset 将其所有清零。用法所分配并已经清空的 cookie_pot 内存,我们在 /proc 中创建了一个 proc_d

16、ir_entry 项,并将其称为 fortune。当 proc_entry 胜利创建之后,对自己的本地变量和 proc_entry 结构举行了初始化。我们加载了 /proc read 和 write 函数(如清单 9 和清单 10 所示),并确定这个模块的全部者。cleanup 函数容易地从 /proc 文件系统中删除这一项,然后释放 cookie_pot 所占领的内存。cookie_pot 是一个固定大小(4kb)的页,它用法两个索引举行管理。第一个是 cookie_index,标识了要将下一个 cookie 写到哪里去。变量 next_fortune 标识了下一个 cookie 应当从哪里

17、读取以便举行输出。在全部的 fortune 项都读取之后,我们容易地回到了 next_fortune。清单 9. 模块的 init/cleanup 和变量includeincludeincludeincludeincludeincludemodule_license("gpl");module_description("fortune cookie kernel module");module_author("m. tim jones");define max_cookie_length page_sizestatic struct

18、proc_dir_entry *proc_entry;static char *cookie_pot; / space for fortune stringsstatic int cookie_index; / index to write next fortunestatic int next_fortune; / index to read next fortuneint init_fortune_module( void ) int ret = 0; cookie_pot = (char *)vmalloc( max_cookie_length ); if (!cookie_pot) r

19、et = -enomem; else memset( cookie_pot, 0, max_cookie_length ); proc_entry = create_proc_entry( "fortune", 0644, null ); if (proc_entry = null) ret = -enomem; vfree(cookie_pot); printk(kern_info "fortune: couldn't create proc entryn"); else cookie_index = 0; next_fortune = 0;

20、proc_entry->read_proc = fortune_read; proc_entry->write_proc = fortune_write; proc_entry->owner = this_module; printk(kern_info "fortune: module loaded.n"); return ret; void cleanup_fortune_module( void ) remove_proc_entry("fortune", &proc_root); vfree(cookie_pot); p

21、rintk(kern_info "fortune: module unloaded.n"); module_init( init_fortune_module );module_exit( cleanup_fortune_module );向这个罐中新写入一个 cookie 十分容易(如清单 10 所示)。用法这个写入 cookie 的长度,我们可以检查是否有这么多空间可用。假如没有,就返回 -enospc,它会返回给用户空间。否则,就解释空间存在,我们用法 copy_from_user 将用户缓冲区中的数据挺直拷贝到 cookie_pot 中。然后增大 cookie_in

22、dex(基于用户缓冲区的长度)并用法 null 来结束这个字符串。最后,返回实际写入 cookie_pot的字符的个数,它会返回到用户进程。清单 10. 对 fortune 举行写入操作所用法的函数 ssize_t fortune_write( struct file *filp, const char _user *buff, unsigned long len, void *data ) int space_available = (max_cookie_length-cookie_index)+1; if (len > space_available) printk(kern_in

23、fo "fortune: cookie pot is full!n"); return -enospc; if (copy_from_user( &cookie_potcookie_index, buff, len ) return -efault; cookie_index += len; cookie_potcookie_index-1 = 0; return len; 对 fortune 举行读取也十分容易,如清单 11 所示。因为我们刚才写入数据的缓冲区(page)已经在内核空间中了,因此可以挺直对其举行操作,并用法 sprintf 来写入下一个 fortu

24、ne。假如next_fortune 索引大于 cookie_index(要写入的下一个位置),那么我们就将 next_fortune 返回为 0,这是第一个 fortune 的索引。在将这个 fortune 写入用户缓冲区之后,在 next_fortune 索引上增强刚才写入的 fortune 的长度。这样就变成了下一个可用 fortune 的索引。这个 fortune 的长度会被返回并传递给用户。清单 11. 对 fortune 举行读取操作所用法的函数 int fortune_read( char *page, char *start, off_t off, int count, int *eof, void *data ) int len; if (off > 0) *eof = 1; return 0; /* wrap-around */ if (next_fortune >= cookie_index) next_fortune = 0

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论