zoukankan      html  css  js  c++  java
  • open

    open

    SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, umode_t, mode)
    {
      ......
      return do_sys_open(AT_FDCWD, filename, flags, mode);
    }
    
    long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode)
    {
      ......
      fd = get_unused_fd_flags(flags); // 1. 获取一个没有使用的文件描述符
      if (fd >= 0) {
        struct file *f = do_filp_open(dfd, tmp, &op); // 2. 创建struct file结构
        if (IS_ERR(f)) {
          put_unused_fd(fd);
          fd = PTR_ERR(f);
        } else {
          fsnotify_open(f);
          fd_install(fd, f); // 3. 将文件描述符和struct file关联起来
        }
      }
      putname(tmp);
      return fd;
    }

    如何获取这个文件描述符呢?

    // 在每一个进程的 task_struct 中,有一个指针 files,类型是 files_struct
    struct files_struct {
      ......
      // 文件描述符列表,每打开一个文件,就会在这个列表中分配一项,下标就是文件描述符,都会有一个 struct file 对应
      struct file __rcu * fd_array[NR_OPEN_DEFAULT];
    };

    对于任何一个进程,默认情况下,fd=0 表示 stdin 标准输入,fd=1 表示 stdout 标准输出,fd=2 表示 stderr 标准错误输出。

    struct file *do_filp_open(int dfd, struct filename *pathname,
        const struct open_flags *op)
    {
      ......
      set_nameidata(&nd, dfd, pathname); 
      filp = path_openat(&nd, op, flags | LOOKUP_RCU);
      ......
      restore_nameidata();
      return filp;
    }
    
    static struct file *path_openat(struct nameidata *nd, const struct open_flags *op, unsigned flags) { ...... file = get_empty_filp(); // 1. 生成一个 struct file 结构 ...... s = path_init(nd, flags); // 2. 初始化 struct nameidata,准备开始节点路径查找 ...... // 3.1 对于路径名逐层进行节点路径查找,这里面有一个大的循环,用“/”分隔逐层处理 while (!(error = link_path_walk(s, nd)) && // 3.2 获取文件对应的 inode 对象,并且初始化 file 对象 (error = do_last(nd, file, op, &opened)) > 0) { ...... } terminate_walk(nd); ...... return file; }
    // 在 struct nameidata 里面有一个关键的成员变量 struct path struct path { struct vfsmount *mnt; // 和文件系统的挂载有关 struct dentry *dentry; // 除用于标识目录之外,还可以表示文件名,还会建立文件名及其 inode 之间的关联 } __randomize_layout;

    例如,文件“/root/hello/world/data”,link_path_walk 会解析前面的路径部分“/root/hello/world”。

    解析完毕的时候 nameidata 的 dentry = “/root/hello/world”,而 nameidata 的 filename = “data”。

    static int do_last(struct nameidata *nd,
           struct file *file, const struct open_flags *op,
           int *opened)
    {
      ......
      // 1. 先从缓存中查找dentry
      error = lookup_fast(nd, &path, &inode, &seq);
      ......
      // 2. 如果缓存中没有找到,就需要到文件系统里面去找
        error = lookup_open(nd, &path, file, op, got_write, opened);
      ......
      // 3. 调用 f_op->open,比如ext4_file_open打开文件;将打开文件的所有信息,填写到 struct file 里面
      error = vfs_open(&nd->path, file, current_cred());
      ......
    }
    
    static int lookup_open(struct nameidata *nd, struct path *path,
          struct file *file,
          const struct open_flags *op,
          bool got_write, int *opened)
    {
        ......
        dentry = d_alloc_parallel(dir, &nd->last, &wq); // 1. 创建一个新的 dentry
        ......
        // 2. 调用上一级目录inode的 lookup 函数,比如 ext4_lookup,到文件系统里面去找 inode 
        struct dentry *res = dir_inode->i_op->lookup(dir_inode, dentry,
                       nd->flags);
        ......
        path->dentry = dentry; // 3. 将新生成的 dentry 赋给 path 变量
        path->mnt = nd->path.mnt;
    }
    
    int vfs_open(const struct path *path, struct file *file,
           const struct cred *cred)
    {
      struct dentry *dentry = d_real(path->dentry, NULL, file->f_flags, 0);
      ......
      file->f_path = *path;
      return do_dentry_open(file, d_backing_inode(dentry), NULL, cred);
    }
    
    static int do_dentry_open(struct file *f,
            struct inode *inode,
            int (*open)(struct inode *, struct file *),
            const struct cred *cred)
    {
    ......
      f->f_mode = OPEN_FMODE(f->f_flags) | FMODE_LSEEK |
            FMODE_PREAD | FMODE_PWRITE;
      path_get(&f->f_path);
      f->f_inode = inode;
      f->f_mapping = inode->i_mapping;
    ......
      f->f_op = fops_get(inode->i_fop);
    ......
      open = f->f_op->open;
    ......
      error = open(inode, f);
    ......
      f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC);
      file_ra_state_init(&f->f_ra, f->f_mapping->host->i_mapping);
      return 0;
    ......
    }
    const struct inode_operations ext4_dir_inode_operations = {
      .create    = ext4_create,
      .lookup    = ext4_lookup,
      ......
    }
    
    const struct file_operations ext4_file_operations = {
      ......
      .open    = ext4_file_open,
      ......
    };
    
    struct file {
      union {
        struct llist_node  fu_llist;
        struct rcu_head   fu_rcuhead;
      } f_u;
      struct path    f_path;
      struct inode    *f_inode;  /* cached value */
      const struct file_operations  *f_op;
      spinlock_t    f_lock;
      enum rw_hint    f_write_hint;
      atomic_long_t    f_count;
      unsigned int     f_flags;
      fmode_t      f_mode;
      struct mutex    f_pos_lock;
      loff_t      f_pos;
      struct fown_struct  f_owner;
      const struct cred  *f_cred;
      ......
      struct address_space  *f_mapping;
      errseq_t    f_wb_err;
    }

     

  • 相关阅读:
    border-radius
    border-style
    border-width
    border
    max-width
    min-width
    clip 语法
    left
    z-index
    position
  • 原文地址:https://www.cnblogs.com/sunnycindy/p/14883290.html
Copyright © 2011-2022 走看看