4. 關於系統調用分析
4.1 創建字符設備文件節點--mknode
在使用字符設備之前通常要創建字符設備文件節點--例如:mknod /dev/char_key c 255 0
-->在/dev/目錄下創建char_key字符設備文件,主設備號255,次設備號0
mknod-->sys_mknodat(AT_FDCWD, filename, mode, dev)
//namei.c
-->SYSCALL_DEFINE4(mknodat, int, dfd, const char __user *, filename, int, mode, unsigned, dev)
{
int error;
char *tmp;
struct dentry *dentry;
struct nameidata nd;
if (S_ISDIR(mode))
return -EPERM;
error = user_path_parent(dfd, filename, &nd, &tmp); //取得當前進程的文件系統,和節點
if (error)
return error;
switch (mode & S_IFMT) {
case 0: case S_IFREG:
error = vfs_create(nd.path.dentry->d_inode,dentry,mode,&nd);
/* 通過相應的文件系調用相應地mknod創建節點
比如ext2的文件系統ext2_mknod; 賦值操作i_op
例如在init_special_inode ---->字符設備節點i_fop = &def_chr_fops;--------->(重要的***)
----->塊設備節點i_fop = &def_blk_fops
----->fifo節點i_fop = &def_fifo_fops;
----->sock節點i_fop = &bad_sock_fops
case default:
init_special_inode(inode, mode, dev);
break;
case S_IFREG:
inode->i_fop = &default_file_ops;
break;
case S_IFDIR:
inode->i_op = &simple_dir_inode_operations;
inode->i_fop = &simple_dir_operations;
break;
*/
case S_IFCHR: case S_IFBLK:
error = vfs_mknod(nd.path.dentry->d_inode,dentry,mode,
new_decode_dev(dev));
break;
case S_IFIFO: case S_IFSOCK:
error = vfs_mknod(nd.path.dentry->d_inode,dentry,mode,0);
break;
}
總結:對於字符設備,當調用mknod後:--->字符設備節點i_fop = &def_chr_fops;
4.1 打開字符設備--open
--int fd = open("dev/char_key", O_RDWR);
--sys_open
-->SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, int, mode)
---->long do_sys_open(int dfd, const char __user *filename, int flags, int mode)
----->struct file *do_filp_open(int dfd, const char *pathname,int open_flag, int mode, int acc_mode)
------>static struct file *finish_open(struct nameidata *nd, int open_flag, int acc_mode)
------->struct file *nameidata_to_filp(struct nameidata *nd)
--------->__dentry_open
{
/*當打開文件時,從將節點中的ops(def_chr_fops)給新申請的file的f_op*/
f->f_op = fops_get(inode->i_fop);
open = f->f_op->open; /*字符設備會調用def_chr_fops->chrdev_open*/
}
/**************接下來分析chrdev_open***************/
static int chrdev_open(struct inode *inode, struct file *filp)
{
struct cdev *p;
struct cdev *new = NULL;
int ret = 0;
spin_lock(&cdev_lock);
p = inode->i_cdev;
if (!p) {
kobj = kobj_lookup(cdev_map, inode->i_rdev, &idx); //通過設備號查找kobj
new = container_of(kobj, struct cdev, kobj); //通過kobj查找到cdev
p = inode->i_cdev; //先看是否設備已經存在
if (!p) {
inode->i_cdev = p = new; //將cdev --> inode->i_cdev
list_add(&inode->i_devices, &p->list);
new = NULL;
}
}
filp->f_op = fops_get(p->ops); //將設備的fops賦值給file->f_op
if (filp->f_op->open) {
ret = filp->f_op->open(inode,filp); //調用設備的fops中的open函數
}
}
總結:最後調用到設備中fops中的open函數
4.2 往字符設備讀寫數據--read/write
--read(fd, rbuf, sizeof(rbuf));
--->sys_write-->SYSCALL_DEFINE3(read,...)-->vfs_read
---->file->f_op->read(file, buf, count, pos); /*調用字符設備中的read函數*/
--write(fd, buf, sizeof(buf));
-->sys_write-->SYSCALL_DEFINE3(write,...)-->vfs_write
---->file->f_op->write(file, buf, count, pos); /*調用字符設備中的write函數*/
其他:進程爲打開的文件維護一個文件表,通過文件描述符fd做索引
/* open file information
struct files_struct *files;*/