文章目錄
-
- 一、mknod引入
- 二、mknod 工作流程
- 三、要點
一、mknod引入
用于建立指定類型的特殊檔案。
一般流程是建立一個裝置檔案,然後根據 mknod 指令中的裝置号,将
struct inode
和
cdev_map->probes->cdev->file_operations
綁定起來。
檢視 mknod 指令使用幫助:
mknod --help
用法:mknod [選項]... 檔案名稱 類型 [主裝置号 次裝置号]
Create the special file NAME of the given TYPE.
...
當類型為"p"時可不指定主裝置号和次裝置号,否則它們是必須指定的。
如果主裝置号和次裝置号以"0x"或"0X"開頭,它們會被視作十六進制數來解析;
如果以"0"開頭,則被視作八進制數;其餘情況下被視作十進制數。
可用的類型包括:
b 建立(有緩沖的)區塊特殊檔案
c, u 建立(沒有緩沖的)字元特殊檔案
p 建立先進先出(FIFO)特殊檔案
如:
mkmod /dev/test c 2 0
可以自己編寫一個裝置驅動子產品,加載後使用
cat /proc/devices
檢視主裝置号。
再使用 mknod 建立一個檔案,要求主裝置号相同,次裝置号相同或者在範圍内。 file_operation 複制成功。
二、mknod 工作流程
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiAzNfRHLGZkRGZkRfJ3bs92YsYTMfVmepNHL90TQNlnVXpVdsJjW1ZlMMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnL3cjMxQDO1kTMwEjNwEjMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
ext4_mknod:新建立一個 inode 節點。
init_special_inode函數分析
定義在:
/fs/inode.c
函數主要操作:判斷檔案類型,如果是
字元裝置類型
,則把
def_chr_fops
作為該檔案的操作接口,并把裝置号記錄在
inode->i_rdev
。
/* inode:新建立的 inode 節點。
* mode:檔案的讀寫權限。
* rdev:裝置檔案關聯的主次裝置号,是在shell調用mknod指令傳參進來的。
*/
void init_special_inode(struct inode *inode, umode_t mode, dev_t rdev)
{
inode->i_mode = mode;
if (S_ISCHR(mode)) { /* 判斷檔案是否屬于字元裝置,可由 mknod 指定 */
/* 設定檔案的操作接口。
* def_chr_fops 是字元裝置通用的檔案操作接口,詳見下一個代碼塊。
*/
inode->i_fop = &def_chr_fops;
/* 設定裝置号,由參數傳進來 */
inode->i_rdev = rdev;
} else if (S_ISBLK(mode)) { /* 判斷是否是塊裝置 */
inode->i_fop = &def_blk_fops;
inode->i_rdev = rdev;
} else if (S_ISFIFO(mode)) /* 判斷是否是管道類型 */
inode->i_fop = &pipefifo_fops;
else if (S_ISSOCK(mode))
; /* leave it no_open_fops */
else
printk(KERN_DEBUG "init_special_inode: bogus i_mode (%o) for"
" inode %s:%lu\n", mode, inode->i_sb->s_id,
inode->i_ino);
}
EXPORT_SYMBOL(init_special_inode);
結構體
def_chr_fops
定義在
fs/chr_dev.c
*
* Dummy default file-operations: the only thing this does
* is contain the open that then fills in the correct operations
* depending on the special file...
*/
const struct file_operations def_chr_fops = {
/* 在此函數綁定自定義的file_operations到檔案中 */
.open = chrdev_open,
.llseek = noop_llseek,
};
函數
chrdev_open
定義在
fs/chr_dev.c
/*
* Called every time a character special file is opened
*/
static int chrdev_open(struct inode *inode, struct file *filp)
{
const struct file_operations *fops;
struct cdev *p;
struct cdev *new = NULL;
int ret = 0;
spin_lock(&cdev_lock);
p = inode->i_cdev;
if (!p) {
struct kobject *kobj;
int idx;
spin_unlock(&cdev_lock);
kobj = kobj_lookup(cdev_map, inode->i_rdev, &idx);
if (!kobj)
return -ENXIO;
new = container_of(kobj, struct cdev, kobj);
spin_lock(&cdev_lock);
/* Check i_cdev again in case somebody beat us to it while
we dropped the lock. */
p = inode->i_cdev;
if (!p) {
inode->i_cdev = p = new;
list_add(&inode->i_devices, &p->list);
new = NULL;
} else if (!cdev_get(p))
ret = -ENXIO;
} else if (!cdev_get(p))
ret = -ENXIO;
spin_unlock(&cdev_lock);
cdev_put(new);
if (ret)
return ret;
ret = -ENXIO;
fops = fops_get(p->ops);
if (!fops)
goto out_cdev_put;
/* 在此處完成自定義fops的綁定 */
replace_fops(filp, fops);
if (filp->f_op->open) {
ret = filp->f_op->open(inode, filp);
if (ret)
goto out_cdev_put;
}
return 0;
out_cdev_put:
cdev_put(p);
return ret;
}
三、要點
struct inode
中的 成員變量
file_operation
一開始并不是自己構造的
file_operation
,而是字元裝置通用的
def_chr_fops
。
在應用程式對此檔案進行 open 操作後,會執行
def_chr_fops->open
,在此函數中完成對
struct inode
和
裝置号對應cdev_map->probes 哈希表中的 cdev->file_operation
進行配對。