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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章