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

系统调用open的执行路径

代码来自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的文件打开操作路径更容易抓住主线,理解在打开文件系统调用的执行过程中,文件系统大概干了什么事、都有那些主要的分层。


这里写图片描述

发布了53 篇原创文章 · 获赞 51 · 访问量 13万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 精致技术 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览