标签:
代码来自Ucore教学操作系统
//用户通过open系统调用接口,执行int 0x80指令,进入内核,查找系统调用表,调用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【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
}
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并加入到进程打开文件数组中,返回一个文件描述符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---
/* 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;
}
/*
作用:文件的上级目录-->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;
}
/*
* 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;
}
/*
* 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;
#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)
{
...
}
//接口的包装,最终会调用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;
}
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;
}
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;
}
//在设备上的文件系统安装时,对应整个文件系统的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---
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;
}
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的文件打开操作路径更容易抓住主线,理解在打开文件系统调用的执行过程中,文件系统大概干了什么事、都有那些主要的分层。
标签:
原文地址:http://blog.csdn.net/unclerunning/article/details/51812531