应用层open->软中断指令->底层驱动xxx_open(下)

简介: 应用层open->软中断指令->底层驱动xxx_open(下)

do_filp_open

/*
 * for the internal routines (ie open_namei()/follow_link() etc). 00 is
 * used by symlinks.
 */
static struct file *do_filp_open(int dfd, const char *filename, int flags,
         int mode)
{
  int namei_flags, error;
  struct nameidata nd;
  /*内外标记不一样*/
  namei_flags = flags;
  if ((namei_flags+1) & O_ACCMODE)
    namei_flags++;
  /*顺着文件名打开操作*/
  error = open_namei(dfd, filename, namei_flags, mode, &nd);
  if (!error)/*根据得到的文件数据,填充file结构体*/
    return nameidata_to_filp(&nd, flags);
  return ERR_PTR(error);
}

open_namei

int open_namei(int dfd, const char *pathname, int flag,
    int mode, struct nameidata *nd)
{
  int acc_mode, error;
  struct path path;
  struct dentry *dir;
  int count = 0;
  /*从flags得到打开模式*/
  acc_mode = ACC_MODE(flag);
  /* O_TRUNC表示我们需要检查写的权限 */
  if (flag & O_TRUNC)
    acc_mode |= MAY_WRITE;
  /*O_APPEND需要MAY_APPEND权限  */
  if (flag & O_APPEND)
    acc_mode |= MAY_APPEND;
  /*如果是不是创建文件的话,就调用path_lookup_open函数获得文件的dentry和vfsmount填充nameidata结构体,找到后就直接返回*/
  if (!(flag & O_CREAT)) {
    error = path_lookup_open(dfd, pathname, lookup_flags(flag),
           nd, flag);
    /*获得后就直接返回函数*/
    if (error)
      return error;
    goto ok;
  }
  /*如果是要创建文件,我们需要知道父目录,所以加上LOOKUP_PARENT的flag*/
  error = path_lookup_create(dfd,pathname,LOOKUP_PARENT,nd,flag,mode);
  if (error)
    return error;
  /*已经拥有了父目录,我们检查下返回结果,如果最后找到的是目录就返回错误,我们只创建文件不创建目录 */
  error = -EISDIR;
  if (nd->last_type != LAST_NORM || nd->last.name[nd->last.len])
    goto exit;
  /**/
  dir = nd->dentry;
  nd->flags &= ~LOOKUP_PARENT;
  mutex_lock(&dir->d_inode->i_mutex);
  /*填充path结构体*/
  path.dentry = lookup_hash(nd);
  path.mnt = nd->mnt;
do_last:
  /*如果获得的参数有问题就返回错误*/
  error = PTR_ERR(path.dentry);
  if (IS_ERR(path.dentry)) {
    mutex_unlock(&dir->d_inode->i_mutex);
    goto exit;
  }
  if (IS_ERR(nd->intent.open.file)) {
    mutex_unlock(&dir->d_inode->i_mutex);
    error = PTR_ERR(nd->intent.open.file);
    goto exit_dput;
  }
  /* 错误的dentry,直接创建文件 */
  if (!path.dentry->d_inode) {
    error = open_namei_create(nd, &path, flag, mode);
    if (error)
      goto exit;
    return 0;
  }
  /*
   * 说明文件已经存在
   */
  mutex_unlock(&dir->d_inode->i_mutex);
  audit_inode(pathname, path.dentry->d_inode);
  /*O_EXCL标志代表如果文件存在就退出*/
  error = -EEXIST;
  if (flag & O_EXCL)
    goto exit_dput;
  /*找到真正的挂载点*/
  if (__follow_mount(&path)) {
    error = -ELOOP;
    if (flag & O_NOFOLLOW)
      goto exit_dput;
  }
  error = -ENOENT;
  /*说明创建失败*/
  if (!path.dentry->d_inode)
    goto exit_dput;
  /*处理连接*/
  if (path.dentry->d_inode->i_op && path.dentry->d_inode->i_op->follow_link)
    goto do_link;
  /*path结构体转成nameidata结构体*/
  path_to_nameidata(&path, nd);
  error = -EISDIR;
  /*再次检查*/
  if (path.dentry->d_inode && S_ISDIR(path.dentry->d_inode->i_mode))
    goto exit;
ok:
  /*写之前的一些检查和准备工作*/
  error = may_open(nd, acc_mode, flag);
  if (error)
    goto exit;
  return 0;
exit_dput:
  /*退出前释放path*/
  dput_path(&path, nd);
exit:
  if (!IS_ERR(nd->intent.open.file))
    release_open_intent(nd);
  path_release(nd);
  return error;
do_link:
  /*如果flag有O_NOFOLLOW,说明禁止链接,直接返回错误*/
  error = -ELOOP;
  if (flag & O_NOFOLLOW)
    goto exit_dput;
  /*首先找到父目录*/
  nd->flags |= LOOKUP_PARENT;
  /*安全操作,暂时不管*/
  error = security_inode_follow_link(path.dentry, nd);
  if (error)
    goto exit_dput;
  /*搜寻,并创建*/
  error = __do_follow_link(&path, nd);
  if (error) {
    release_open_intent(nd);
    return error;
  }
  nd->flags &= ~LOOKUP_PARENT;
  /*检验返回结果*/
  if (nd->last_type == LAST_BIND)
    goto ok;
  error = -EISDIR;
  if (nd->last_type != LAST_NORM)
    goto exit;
  if (nd->last.name[nd->last.len]) {
    __putname(nd->last.name);
    goto exit;
  }
  error = -ELOOP;
  /*超出循环最大次数*/
  if (count++==32) {
    __putname(nd->last.name);
    goto exit;
  }
  /*填充返回结果*/
  dir = nd->dentry;
  mutex_lock(&dir->d_inode->i_mutex);
  path.dentry = lookup_hash(nd);
  path.mnt = nd->mnt;
  __putname(nd->last.name);
  goto do_last;
}

open_namei_create

static int open_namei_create(struct nameidata *nd, struct path *path,
        int flag, int mode)
{
  int error;
  struct dentry *dir = nd->dentry;
  /*POSIX权限标准检查*/
  if (!IS_POSIXACL(dir->d_inode))
    mode &= ~current->fs->umask;
  /*vfs层调用文件创造*/
  error = vfs_create(dir->d_inode, path->dentry, mode, nd);
  mutex_unlock(&dir->d_inode->i_mutex);
  dput(nd->dentry);
  /*创建后放到nameidata里*/
  nd->dentry = path->dentry;
  if (error)
    return error;
  /*权限检查,不检查写权限和truncate权限*/
  return may_open(nd, 0, flag & ~O_TRUNC);
}

vfs_create

int vfs_create(struct inode *dir, struct dentry *dentry, int mode,
    struct nameidata *nd)
{
  /*打开前的权限检查*/
  int error = may_create(dir, dentry, nd);
  if (error)
    return error;
  /*inode的inode_operation函数表的create函数*/
  if (!dir->i_op || !dir->i_op->create)
    return -EACCES; /* shouldn't it be ENOSYS? */
  mode &= S_IALLUGO;
  mode |= S_IFREG;
  /*安全检查操作*/
  error = security_inode_create(dir, dentry, mode);
  if (error)
    return error;
  DQUOT_INIT(dir);
  /*创建*/
  error = dir->i_op->create(dir, dentry, mode, nd);
  if (!error)
    fsnotify_create(dir, dentry);
  return error;
}
目录
相关文章
|
存储 Linux 调度
【看表情包学Linux】系统下的文件操作 | 文件系统接口 | 系统调用与封装 | open,write,close 接口 | 系统传递标记位 O_RDWR,O_RDONLY,O_WRONLY...
【看表情包学Linux】系统下的文件操作 | 文件系统接口 | 系统调用与封装 | open,write,close 接口 | 系统传递标记位 O_RDWR,O_RDONLY,O_WRONLY...
113 1
|
2月前
|
网络协议 API Windows
MASM32v11编程调用Process32First失败: 程序发出命令,但命令长度不正确
MASM32v11编程调用Process32First失败: 程序发出命令,但命令长度不正确
|
2月前
|
监控 Linux C++
perf_event_open学习 —— mmap方式读取
perf_event_open学习 —— mmap方式读取
|
4月前
|
存储 编解码 容器
FFmpeg avformat_open_input() 函数返回错误protocol not found解决方法(实测有效!附简单FFMPEG的编解码流程)
我个人出现这个错误的时候是在打开文件时报的错误,开始以为我需要加上资源文件,那样QT确实能检测到文件的存在,但是在Debug中他是检测不到这个文件的。
420 1
|
API 开发工具
【Pintos】实现自定义 UserProg 系统调用 | 添加 syscall-nr 系统调用号 | 编写新的参数调用宏
【Pintos】实现自定义 UserProg 系统调用 | 添加 syscall-nr 系统调用号 | 编写新的参数调用宏
115 0
|
6月前
|
Linux 开发者
Linux文件编程(open read write close函数)
通过这些函数,开发者可以在Linux环境下进行文件的读取、写入和管理。 买CN2云服务器,免备案服务器,高防服务器,就选蓝易云。百度搜索:蓝易云
167 4
应用层open->软中断指令->底层驱动xxx_open(上)
应用层open->软中断指令->底层驱动xxx_open
95 0
|
Linux
内核是如何运行ko文件的--系统调用
内核是如何运行ko文件的--系统调用
356 0
|
存储 Java Linux
【Linux】基础IO --- 系统级文件接口、文件描述符表、文件控制块、fd分配规则、重定向…
【Linux】基础IO --- 系统级文件接口、文件描述符表、文件控制块、fd分配规则、重定向…
|
Python
x64dbg 实现插件Socket反向通信
编写一个带有socket通信功能的插件,x64dbg运行后,用户点击链接按钮可直接连接到外部的python中,python作为服务端,当x64dbg内部出现某个事件后,自动将消息推送到外部python脚本上,实现反向传参的目的。
179 0
x64dbg 实现插件Socket反向通信