Linux字符设备原理探究--2(应用层调用)



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;*/

猜你喜欢

转载自blog.csdn.net/jun_8018/article/details/77621636