天天看點

96 如何建立一個裝置檔案

文章目錄

    • 一、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 工作流程

96 如何建立一個裝置檔案

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

進行配對。