系统调用open的大概执行路径

系统调用open的执行路径

  • 系统调用open的执行路径

    • level 1 sys_open
    • level 21 sysfile_openVFS层
      • help routine 1 copy_path
    • level 22 file_open
    • level 23 vfs_open
      • Routine 1 vfs_lookup_parent
      • Routine 11 get_device
      • Routine 111 vfs_get_root
      • Routine 12 vop_lookup_parent
      • Routine 2 vop_create
      • Routine 21 sfs_create_nolock具体文件系统层
      • Routine 211 sfs_load_inode具体文件系统层
    • level 24 sfs_get_root具体文件系统层
    • level 25 sfs_load_inode
      • Routine 11 lookup_sfs_nolock
    • 总结

代码来自Ucore教学操作系统

//用户通过open系统调用接口,执行int 0x80指令,进入内核,查找系统调用表,调用sys_open。

level 1: sys_open

//---level 1---

static uint32_t
sys_open(uint32_t arg[]) {
    const char *path = (const char *)arg[0];
    uint32_t open_flags = (uint32_t)arg[1];

  //调用level 2.1 【VFS】
    return sysfile_open(path, open_flags); //返回打开文件的文件描述符fd
}

level 2.1: sysfile_open【VFS层】

//---level 2.1【VFS】---

int
sysfile_open(const char *__path, uint32_t open_flags) {
    int ret;
    char *path;

    if ((ret = copy_path(&path, __path)) != 0) {//help routine 1
        return ret; //返回错误信息
    }

 //----------------------------------------
     //调用level 2.2
    ret = file_open(path, open_flags);
 //----------------------------------------

    kfree(path); //释放path指向的内核空间

    return ret;//返回打开文件的文件描述符fd
}

help routine 1: copy_path

static int copy_path(char **to, const char *from)
{
    struct mm_struct *mm = current->mm;

    char *buffer;
    //为内核申请容纳字符串的空间
    if ((buffer = kmalloc(FS_MAX_FPATH_LEN + 1)) == NULL) {
      //kmalloc申请的空间来自物理内存的前896M,对应内核虚拟空间的直接映射区,物理/虚拟地址
      //空间均连续
        return -E_NO_MEM;
    }

    lock_mm(mm);

  //将用户空间的路径字符串拷贝到内核空间
    if (!copy_string(mm, buffer, from, FS_MAX_FPATH_LEN + 1)) {
        unlock_mm(mm);
        goto failed_cleanup;
    }

    unlock_mm(mm);

    *to = buffer;//to指向buffer

    return 0;

failed_cleanup:
    kfree(buffer);
    return -E_INVAL;
}

level 2.2: file_open

//---level 2.2---
/*
 这个函数会建立一个file并加入到进程打开文件数组中,返回一个文件描述符fd作为索引
*/
int
file_open(char *path, uint32_t open_flags) {

  //根据用户标志参数判断文件打开标志,用于在file结构体中设置读写标志
    bool readable = 0, writable = 0;
    switch (open_flags & O_ACCMODE) {
    case O_RDONLY: readable = 1; break;
    case O_WRONLY: writable = 1; break;
    case O_RDWR:
        readable = writable = 1;
        break;
    default:
        return -E_INVAL;
    }

    int ret;

    struct file *file;
  //新建一个文件,加入到进程的打开文件数组中
    if ((ret = filemap_alloc(NO_FD, &file)) != 0) {
        return ret;
    }

 //--------------------------------------------------------
    struct inode *node;
    //调用level 2.3
    if ((ret = vfs_open(path, open_flags, &node)) != 0) { //新建一个inode
 //-------------------------------------------------------- 

        filemap_free(file);
        return ret;
    }

    file->pos = 0;
    if (open_flags & O_APPEND) {
        struct stat __stat, *stat = &__stat;

        if ((ret = vop_fstat(node, stat)) != 0) {
            vfs_close(node);
            filemap_free(file);
            return ret;
        }
        file->pos = stat->st_size;//设置文件指针初始偏移位置
    }

    file->node = node;//指向node
    //设置读写模式
    file->readable = readable;
    file->writable = writable;

    //增加文件的引用计数
    filemap_open(file);

    return file->fd; //返回打开文件的文件描述符
}

level 2.3: vfs_open

//---level 2.3---   

/* Does most of the work for open(). */

//建立好对应打开文件的inode【VFS层】
int
vfs_open(char *path, uint32_t open_flags, struct inode **node_store) {

...
    int ret;
    struct inode *dir, *node;
    if (open_flags & O_CREAT) {
        char *name;
        bool excl = (open_flags & O_EXCL) != 0;

      //根据用户传过来的路径,查找文件父目录
      /*
      例如:path="/home/work/tesf_file",则该函数会将对应work的inode找到。有了这个
      父目录的inode,内核就能载入父目录文件,从而得到【修改、更新、添加】其中目录项:
      file_name-->inode_num
      */
      //文件的上级目录-->dir
        if ((ret = vfs_lookup_parent(path, &dir, &name)) != 0) {//Routine 1
            return ret;
        }

      //用文件的父目录inode中注册的vop_create方法创建一个inode
        ret = vop_create(dir, name, excl, &node); //Routine 2

    }
  ...

    //增加打开计数
    vop_open_inc(node);

    *node_store = node; //传递给上层

    return 0;
}

Routine 1: vfs_lookup_parent

/*
作用:文件的上级目录-->node_store
*/
int
vfs_lookup_parent(char *path, struct inode **node_store, char **endp) {
    int ret;
    struct inode *node;

   //返回路径对应的文件系统的root inode/current work inode --> node
    if ((ret = get_device(path, &path, &node)) != 0) { //Routine 1.1
        return ret;
    }

    ret = (*path != ‘\0‘) ?
      //接口的包装,作用:文件的上级目录-->node_store
      vop_lookup_parent(node, path, node_store, endp) : -E_INVAL; //Routine 1.2

    vop_ref_dec(node);

    return ret;
}

Routine 1.1: get_device

/*
 * Common code to pull the device name, if any, off the front of a
 * path and choose the inode to begin the name lookup relative to.
 */

//作用:返回路径对应的文件系统的root inode/current work inode --> node_store
static int get_device(char *path, char **subpath, struct inode **node_store)
{
    int i, slash = -1, colon = -1;
    /*
     * Locate the first colon or slash.
     */
    for (i = 0; path[i] != ‘\0‘; i++) {
        if (path[i] == ‘:‘) {
            colon = i;
            break;
        }
        if (path[i] == ‘/‘) {
            slash = i;
            break;
        }
    }
    if (colon < 0 && slash != 0) {//相对路径
        /* *
         * No colon before a slash, so no device name specified, and the slash isn‘t
         * leading or is also absent, so this is a relative path or just a bare
         * filename. Start from the current directory, and use the whole thing as the
         * subpath.
         * */
        *subpath = path;

       //Get current directory as a inode.
        return vfs_get_curdir(node_store);//node_store=current->fs_struct->pwd

    }

    if (colon > 0) {//绝对路径 device:/... 

        path[colon] = ‘\0‘;

        while (path[++colon] == ‘/‘) ;

        *subpath = path + colon;

        //获取根结点:root inode --> node_store
        return vfs_get_root(path, node_store); //Routine 1.1.1
    }

  ...

    return 0;
}

Routine 1.1.1: vfs_get_root

/*
 * Given a device name (lhd0, emu0, somevolname, null, etc.), hand
 * back an appropriate inode.
 */
//作用:返回设备上被加载的文件系统的root inode
int vfs_get_root(const char *devname, struct inode **node_store)
{
    assert(devname != NULL);
    int ret = -E_NO_DEV;

    if (!list_empty(&vdev_list)) {//全局设备描述符链表:vdev_list

        lock_vdev_list();

        {
            list_entry_t *list = &vdev_list, *le = list;
            while ((le = list_next(le)) != list) {
                vfs_dev_t *vdev = le2vdev(le, vdev_link);

                if (strcmp(devname, vdev->devname) == 0) {//设备名配备

                    struct inode *found = NULL;

                    if (vdev->fs != NULL) {//如果设备上的文件已安装。

         //--------------------------------------------------------
                      //【通往具体文件系统层的接口】
                      //fsop_get_root是VFS层到具体文件系统层的接口
                      //作用:获得该文件系统的根inode
                      //调用level 2.4
                        found = fsop_get_root(vdev->fs);
         //--------------------------------------------------------                      

                    } 

                  ...

                    if (found != NULL) {
                        /*
                         * If DEVNAME names the device, and we get here, it
                         * must have no fs and not be mountable. In this case,
                         * we return the inode of device itself--node_store.
                         */
                        ret = 0, *node_store = found;//devnode or root_inode
                    } else {
                        /*
                         * If we got here, the device specified by devname doesn‘t
                         * exist.
                         */
                        ret = -E_NA_DEV;
                    }
                    break;
                }
                /*
                 * If none of the above tests matched, we didn‘t name
                 * any of the names of this device, so go on to the
                 * next one.
                 */
            }
        }

        unlock_vdev_list();
    }
    return ret;

Routine 1.2: vop_lookup_parent

#define __vop_op(node, sym)  \
    ({        struct inode *__node = (node);        assert(__node != NULL && __node->in_ops != NULL        && __node->in_ops->vop_##sym != NULL);      \
        inode_check(__node, #sym);                \
        __node->in_ops->vop_##sym;                 \
     })

//接口的包装,最终转化为调用某个inode的成员in_ops中的相应函数,不同类型的inode有不同的
//in_ops的实现
#define vop_lookup_parent(node, path, node_store, endp)            \
(__vop_op(node, lookup_parent)(node, path, node_store, endp))

//---inode_ops函数表【接口】---
/*
struct inode_ops {
    unsigned long vop_magic;
    int (*vop_open) (struct inode * node, uint32_t open_flags);
    int (*vop_close) (struct inode * node);
    int (*vop_read) (struct inode * node, struct iobuf * iob);
    int (*vop_write) (struct inode * node, struct iobuf * iob);
    int (*vop_fstat) (struct inode * node, struct stat * stat);
    ...
    int (*vop_lookup_parent) (struct inode * node, char *path,
               struct inode ** node_store, char **endp);
};
*/

//---inode_ops函数表【实现】---
/*
//---Function table for device inodes.---
static const struct inode_ops dev_node_ops = {
    .vop_magic = VOP_MAGIC,
    .vop_open = dev_open,
    .vop_close = dev_close,
...
    .vop_lookup_parent = NULL_VOP_NOTDIR,
};

static const struct inode_ops ffs_node_dirops = {
    .vop_magic = VOP_MAGIC,
    .vop_open = ffs_opendir,
    .vop_close = ffs_closedir,
..
    .vop_lookup_parent = ffs_lookup_parent,
};

//---Function table for yaffs【文件系统】 inodes.---
static const struct inode_ops yaffs_node_dirops = {
  .vop_magic                      = VOP_MAGIC,
  .vop_open                       = yaffs_vop_opendir,
  .vop_close                      = yaffs_vop_close,
  .vop_read                       = NULL_VOP_ISDIR,
...
  .vop_lookup_parent              = yaffs_vop_lookup_parent,
};

static const struct inode_ops yaffs_node_fileops = {
  .vop_magic                      = VOP_MAGIC,
  .vop_open                       = yaffs_vop_openfile,
  .vop_close                      = yaffs_vop_close,
..
  .vop_lookup_parent              = NULL_VOP_NOTDIR,
};

//---Function table for sfs【文件系统】 inodes.---
static const struct inode_ops sfs_node_dirops = {
    .vop_magic = VOP_MAGIC,
    .vop_open = sfs_opendir,
    .vop_close = sfs_close,
...
    .vop_lookup = sfs_lookup,
    .vop_lookup_parent = sfs_lookup_parent,
};

static const struct inode_ops sfs_node_fileops = {
    .vop_magic = VOP_MAGIC,
    .vop_open = sfs_openfile,
    .vop_close = sfs_close,
...
    .vop_lookup_parent = NULL_VOP_NOTDIR,
};
*/

sfs【简单文件系统】对inode->inode_ops->vop_lookup_parent的实现

//具体文件系统层

static int
sfs_lookup_parent(struct inode *node, char *path, struct inode **node_store,
          char **endp)
{
...
}

Routine 2: vop_create

//接口的包装,最终会调用node->in_ops->vop_create
//例如:调用简单文件系统的 sfs_create
//作用:为文件创建一个inode
#define vop_create(node, name, excl, node_store)  \
    (__vop_op(node, create)(node, name, excl, node_store))

sfs【简单文件系统】对inode->inode_ops->vop_create的实现

//作用:为sfs文件系统的文件创建一个inode 【具体文件系统层】
static int
sfs_create(struct inode *node, const char *name, bool excl,
       struct inode **node_store)
{
...
    struct sfs_fs *sfs = fsop_info(vop_fs(node), sfs);
    struct sfs_inode *sin = vop_info(node, sfs_inode);

    int ret;
    if ((ret = trylock_sin(sin)) == 0) {

        ret = sfs_create_nolock(sfs, sin, name, excl, node_store);//Routine 2.1

        unlock_sin(sin);
    }
    return ret;
}

Routine 2.1: sfs_create_nolock【具体文件系统层】

static int
sfs_create_nolock(struct sfs_fs *sfs, struct sfs_inode *sin, const char *name,
          bool excl, struct inode **node_store)
{
    int ret, slot;
    uint32_t ino;

    struct inode *link_node;

    if ((ret =
          //目录项:name <--> inode_num
         //根据名字name找到文件在【目录】sin中的【结点号】:inode_num-->ino
         sfs_dirent_search_nolock(sfs, sin, name, &ino, NULL,
                      &slot)) != -E_NOENT) {
        if (ret != 0) {
            return ret;
        }
        if (!excl) {
          //由文件的结点号ino、sfs创建对应文件的inode[link_node]
            if ((ret = sfs_load_inode(sfs, &link_node, ino)) != 0) {//Routine 2.1.1
                return ret;
            }
            if (vop_info(link_node, sfs_inode)->din->type ==
                SFS_TYPE_FILE) {
                goto out;
            }

          ...

out:
    *node_store = link_node; //将新建的对应文件的inode传给上层
    return 0;
}

Routine 2.1.1: sfs_load_inode【具体文件系统层】

int sfs_load_inode(struct sfs_fs *sfs, struct inode **node_store, uint32_t ino)
{
    lock_sfs_fs(sfs);

    struct inode *node;

    if ((node = lookup_sfs_nolock(sfs, ino)) != NULL) {
        goto out_unlock;
    }

    int ret = -E_NO_MEM;

    //分配一个sfs_disk_inode
  struct sfs_disk_inode *din;
    if ((din = kmalloc(sizeof(struct sfs_disk_inode))) == NULL) {
        goto failed_unlock;
    }

    assert(sfs_block_inuse(sfs, ino));
    if ((ret =
         //将磁盘中的sfs_disk_inode加载到din中,sfs_rbuf会转到io层,然后将加载任务交给
         //文件系统驱动
         sfs_rbuf(sfs, din, sizeof(struct sfs_disk_inode), ino, 0)) != 0) {
        goto failed_cleanup_din;
    }

    assert(din->nlinks != 0);

  //为打开文件新建一个inode
    if ((ret = sfs_create_inode(sfs, din, ino, &node)) != 0) {
        goto failed_cleanup_din;
    }
    sfs_set_links(sfs, vop_info(node, sfs_inode));

out_unlock:
    unlock_sfs_fs(sfs);
    *node_store = node;
    return 0;

failed_cleanup_din:
    kfree(din);
failed_unlock:
    unlock_sfs_fs(sfs);
    return ret;
}

level 2.4: sfs_get_root【具体文件系统层】

//在设备上的文件系统安装时,对应整个文件系统的fs结构体被创建,其中的fs_get_root函数指针被注册
#define fsop_get_root(fs)                   ((fs)->fs_get_root(fs)) 

追踪mount的执行路径发现fs_get_root函数指针被注册为【简单文件系统的】sfs_get_root函数:

//---level 2.4【具体文件系统层】---

/*
 * Get inode for the root of the filesystem.
 * The root inode is always found in block 1 (SFS_ROOT_LOCATION).
 */
//返回root inode
static struct inode *sfs_get_root(struct fs *fs)
{
    struct inode *node;
    int ret;
    if ((ret =

         //--------------------------------------------------------
         //调用level 2.5
         //root inode --> node
         sfs_load_inode(fsop_info(fs, sfs), &node, SFS_BLKN_ROOT)) != 0) {
        //#define SFS_BLKN_ROOT           1 /* location of the root dir inode */
        //--------------------------------------------------------

        panic("load sfs root failed: %e", ret);

    }
    return node;
}

level 2.5: sfs_load_inode

//---level 2.5---

int sfs_load_inode(struct sfs_fs *sfs, struct inode **node_store, uint32_t ino)
{
    lock_sfs_fs(sfs);

    //依据ino,在sys_fs中的inode链表里找到root inode
    struct inode *node;
    if ((node = lookup_sfs_nolock(sfs, ino)) != NULL) { //Routine 1.1
        goto out_unlock;
    }

    //如果没有找到root inode,新建一个root inode
    int ret = -E_NO_MEM;

    struct sfs_disk_inode *din;
    if ((din = kmalloc(sizeof(struct sfs_disk_inode))) == NULL) {//分配空间
        goto failed_unlock;
    }

    assert(sfs_block_inuse(sfs, ino));
    if ((ret =
         //从设备中读取sfs_disk_inode【存储在磁盘上的inode】
         sfs_rbuf(sfs, din, sizeof(struct sfs_disk_inode), ino, 0)) != 0) {
        goto failed_cleanup_din;
    }

    assert(din->nlinks != 0);
    //为新建root inode创建一个inode
    if ((ret = sfs_create_inode(sfs, din, ino, &node)) != 0) {
        goto failed_cleanup_din;
    }

    //将root inode添加到sfs_fs的inode链表中
    sfs_set_links(sfs, vop_info(node, sfs_inode));

out_unlock:
    unlock_sfs_fs(sfs);
    *node_store = node;
    return 0;

failed_cleanup_din:
    kfree(din);
failed_unlock:
    unlock_sfs_fs(sfs);
    return ret;
}

Routine 1.1: lookup_sfs_nolock

static struct inode *lookup_sfs_nolock(struct sfs_fs *sfs, uint32_t ino)
{
    struct inode *node;
    list_entry_t *list = sfs_hash_list(sfs, ino), *le = list;

    while ((le = list_next(le)) != list) {

        struct sfs_inode *sin = le2sin(le, hash_link);

        if (sin->ino == ino) {

          //从sfs_inode成员得到inode
            node = info2node(sin, sfs_inode);

            if (vop_ref_inc(node) == 1) {
                sin->reclaim_count++;
            }
            return node;
        }
    }
    return NULL;
}

总结

Ucore是一个教学用的操作系统,虽然不完善,但是其设计的指导思想来自Linux/Unix,所以在文件系统设计这块Ucore在尝试模仿它们,所以捋一捋Ucore的文件打开操作路径更容易抓住主线,理解在打开文件系统调用的执行过程中,文件系统大概干了什么事、都有那些主要的分层。

时间: 2024-08-13 06:31:10

系统调用open的大概执行路径的相关文章

[转]Windows中的命令行提示符里的Start命令执行路径包含空格时的问题

转自:http://www.x2009.net/articles/windows-command-line-prompt-start-path-space.html 当使用Windows 中的命令行提示符执行这段指令时(测试Start命令执行带空格的路径的程序或文件问题),第一行Start会成功执行,跳出记事本程序,而第二行,会 Start跳出一个新的命令提示符,标题上写着路径,但是不会执行任何命令,第三行Start命令行提示符会提示C:\Program文件不存在,提示无 法执行. start

dex2oat将dex转换为oat的执行路径概览

dex2oat是一个可执行文件,在源码中通过编译文件art\dex2oat\Dex2oat.cc生成. dex2oat的执行入口是: int main(int argc, char** argv) { return art::dex2oat(argc, argv); } 在函数dex2oat中调用了dex2oat->CreateOatFile函数,在CreateOatFile函数中执行了driver->CompileAll(class_loader, dex_files, timings);语

优化SQL执行路径提高报表性能

报表出现性能问题需要对数据源计算进行优化时,执行路径难以确定从而被干预是阻碍报表优化的难题之一.由于数据库执行路径对开发人员不透明,报表优化需要指定执行路径时,程序员会很难甚至无法干预.而一般报表工具不具备强计算能力,大部分计算仍然要依靠数据库进行,这就导致很多报表优化效果不理想. 不同于一般报表工具,润乾集算报表内置了专门用于数据计算的集算引擎,开发人员可以通过编写集算脚本完成报表数据源准备.与数据库执行SQL路径不可控相比,集算脚本的执行过程是可控的,开发人员可根据实际情况编写或更改计算执行

nodejs取得当前执行路径

processor.cwd()  函数可以返回当前正在执行的项目路径 processor.execPath :属性返回的是  nodejs 的安装路径 API 文档: http://www.nodejs.org/api/process.html#process_process_cwd

获取node 安装当前执行路径

process.cwd() 当前执行程序的路径(执行命令行时候的路径,不是代码路径 例如 在根目录下执行 node ./xxx/xxx/a.js 则 cwd 返回的是 根目录地址 ) __dirname: 代码存放的位置 process.execPath: 当前执行的node路径(如:/bin/node) DEMO: console.log(process.execPath) console.log(__dirname) console.log(process.cwd())

python3找到当前文件执行路径,并加入临时环境变量

执行文件:__file__获取当前的文件执行的路径 主要解决不同操作环境下的获取当前路径 import os,sys base_dir=os.path.dirname(__file__) sys.path.append(base_dir) #临时修改环境变量 原文地址:https://www.cnblogs.com/hourglass-/p/9245515.html

我的脚本-修改dylib的执行路径

#!/bin/bash # 对变量赋值: a="hello world"  #等号两边均不能有空格存在 # 打印变量a的值: echo "A is:" $a # 步骤1:遍历路径下的所有文件 步骤2:获取所有文件的全路径和文件名 dir=${1:-.}  #取得参数值或当前路径 (cd $dir;pwd) #进入dir的路径,打印当前路径 list=$(find $dir)    # -print    遍历dir文件夹,保存到list数组 for item in

MySQL查询执行路径

1.客户端发送一条查询给服务器2.服务器先检查查询缓存,如果命中缓存,则立刻返回存储在缓存中的结果.3.服务器端进行SQL解析.预处理,再由优化器生成对应的执行计划.4.MySQL根据优化器生成的执行计划,调用存储引擎的API执行查询.5.返回结果给客户端.

linux 下查看一个进程执行路径

在linux下查看进程大家都会想到用 ps -ef|grep XXX 但是看到的不是全路径.怎么看全路径呢? 每一个进程启动之后在 /proc以下有一个于pid相应的路径 比如:ps -ef|grep python 显示:oracle ? ?4431 ?4366 ?0 18:56 pts/2 ? ?00:00:00 python Server.py 4431就是进程号 到/proc/4431下.ls -l 会看到(须要root权限): 总用量 0 -r--r--r-- ? ?1 oracle ?