📄 037_fs_devices_c.html
字号:
<html lang="zh-CN" xmlns:gdoc=""> <head> <meta content="text/html; charset=utf-8" http-equiv="Content-Type"> <style type="text/css">/* default css */table { font-size: 1em; line-height: inherit;}div, address, ol, ul, li, option, select { margin-top: 0px; margin-bottom: 0px;}p { margin: 0px;}body { margin: 0px; padding: 0px; font-family: Verdana, sans-serif; font-size: 10pt; background-color: #ffffff;}h6 { font-size: 10pt }h5 { font-size: 11pt }h4 { font-size: 12pt }h3 { font-size: 13pt }h2 { font-size: 14pt }h1 { font-size: 16pt }blockquote {padding: 10px; border: 1px #DDD dashed }a img {border: 0}div.google_header, div.google_footer { position: relative; margin-top: 1em; margin-bottom: 1em;}/* end default css */ /* default print css */ @media print { body { padding: 0; margin: 0; } div.google_header, div.google_footer { display: block; min-height: 0; border: none; } div.google_header { flow: static(header); } /* used to insert page numbers */ div.google_header::before, div.google_footer::before { position: absolute; top: 0; } div.google_footer { flow: static(footer); } /* always consider this element at the start of the doc */ div#google_footer { flow: static(footer, start); } span.google_pagenumber { content: counter(page); } span.google_pagecount { content: counter(pages); } } @page { @top { content: flow(header); } @bottom { content: flow(footer); } } /* end default print css */ /* custom css *//* end custom css */ /* ui edited css */ body { font-family: Verdana; font-size: 10.0pt; line-height: normal; background-color: #ffffff; } .documentBG { background-color: #ffffff; } /* end ui edited css */</style> </head> <body revision="dcbsxfpf_21gsc4r6:67"> <table align=center cellpadding=0 cellspacing=0 height=5716 width=800>
<tbody>
<tr>
<td height=5716 valign=top width=800>
<pre><br>2007-11-28 <br> by heyl<br><br>/*<br> * linux/fs/devices.c<br> *<br> * (C) 1993 Matthias Urlichs -- <font color=#3333ff><b>collected common code and tables.</b></font><br> * <br> * Copyright (C) 1991, 1992 Linus Torvalds<br> *<br> * Added kerneld support: Jacques Gelinas and Bjorn Ekwall<br> * (changed to kmod)<br> */<br> 看到这儿注释,不难理解这里为啥不搭边...<br><br>这里是char dev的天下?想起了block_dev 的相关结构,倒是和这个有点类似.<br>struct <font color=#333399><b>device_struct</b></font> {<br> const char * name;<br> struct <font color=#3333ff>file_operations</font> * fops;<br>};<br>和blkdev是不同的,存储的是name和fops. <br>static struct {<br> const char *name;<br> struct block_device_operations *bdops;<br>} blkdevs[MAX_BLKDEV];<br><br>static rwlock_t chrdevs_lock = RW_LOCK_UNLOCKED;<br>static struct device_struct <font color=#000099><b>chrdevs</b></font>[MAX_CHRDEV];<br><br>int <font color=#000099><b>get_device_list</b></font>(char * page) : 获取char dev 和block dev的列表,极尽简单.<br><br><font color=#009900>static</font> struct file_operations * <font color=#000099><b>get_chrfops</b></font>(unsigned int major, unsigned int minor) : 从char获取file ops, char dev<br>直接面对file,真是素面朝天的做法,比起block dev的七拐八拐直接多了.这个函数无非就是如果是tty照顾到了kmod. 参考major.h,里边是<br>所有已知设备的major number.<br><br>chardev的注册函数,真是直白,我们需要这样子的代码.<br>int <font color=#000099>register_chrdev</font>(unsigned int major, const char * name, struct file_operations *fops)<br>int <font color=#000099>unregister_chrdev</font>(unsigned int major, const char * name)<br><br><br>/*<br> * Called every time a character special file is opened<br> */<br>int <font color=#000099><b>chrdev_open</b></font>(struct inode * inode, struct file * filp)<br>{<br> int ret = -ENODEV;<br><br> filp->f_op = <font color=#006600><b>get_chrfops</b></font>(MAJOR(inode->i_rdev), MINOR(inode->i_rdev));<br> if (filp->f_op) {<br> ret = 0;<br> if (filp->f_op->open != NULL) {<br> lock_kernel();<br> ret = filp-><font color=#006600><b>f_op->open</b></font>(inode,filp);<br> unlock_kernel();<br> }<br> }<br> return ret;<br>}<br><br>/*<br> * Dummy default file-operations: the only thing this does<br> * is contain the open that then fills in the correct operations<br> * depending on the special file...<br> */<br>static <font color=#cc0000>struct</font> file_operations <font color=#000099><b>def_chr_fops</b></font> = {<br> open: <font color=#006600>chrdev_open</font>,<br>};<br><br>def注册到inode的i_fops,<br>通denty_open这个file ops转移到filep->f_ops.<br>struct file *<font color=#000099><b>dentry_open</b></font>(struct dentry *dentry, struct vfsmount *mnt, int flags)<br>{<br> struct file * f;<br> .....<br> <font color=#006600>f->f_op = fops_get(inode->i_fop);</font><br>}<br><br>接下来就是一个很知名的函数了:<br>void <font color=#000099><b>init_special_inode</b></font>(struct inode *inode, umode_t mode, int rdev)<br>{<br> inode->i_mode = mode;<br> if (S_ISCHR(mode)) {<br> <font color=#006600><b>inode->i_fop</b></font> = &def_chr_fops;<br> <b>inode->i_rdev</b> = to_kdev_t(rdev);<br> } else if (S_ISBLK(mode)) { /*block dev 有两个dev和之对应*/<br> <font color=#006600><b>inode->i_fop</b></font> = &def_blk_fops;<br> <b>inode->i_rdev</b> = to_kdev_t(rdev); <font color=#3333ff>/*kdev,一个int, 系统中所有dev的统一handler*/</font><br> <b>inode->i_bdev</b> = bdget(rdev);<font color=#3333ff> /* block_device pointer */</font><br> } else if (S_ISFIFO(mode))<br> inode->i_fop = &def_fifo_fops;<br> else if (S_ISSOCK(mode))<br> <b>inode->i_fop</b> = &bad_sock_fops;<font color=#3333ff> /*sock使用另外的soket标准接口和文件系统相区别*/</font><br> else<br> printk(KERN_DEBUG "init_special_inode: bogus imode (%o)\n", mode);<br>}<br><br><font color=#3333ff>搜索init_special_inode的调用者,我们知道不是所有的文件系统都支持设备文件的, 比如vfat就免谈了.</font><br><br><br>剩下的函数看看名字好了.<br>const char * kdevname(kdev_t dev)<br>const char * cdevname(kdev_t dev)<br> static int sock_no_open(struct inode *irrelevant, struct file *dontcare)<br>static struct file_operations bad_sock_fops = {<br> open: sock_no_open<br>};<br><br>不想我们从这里得窥char device的一角, chardev 直接实现一个file ops给文件系统,倒是省心了不少. 比block dev干净许多啊.<br><br></pre>
</td>
</tr>
</tbody>
</table></body></html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -