文件系统和文件 文件系统简述:
文件系统是操作系统用于明确 “存储设备或分区上的文件” 的 “一组方法和数据结构”,是操作系统中负责管理和存储文件信息的软件机构(被称为文件管理系统,简称文件系统)
注意:文件系统是对应硬盘的分区的,而不是整个硬盘,不管是硬盘只有一个分区,还是几个分区,不同的分区可以有着不同的文件系统
文件系统由三部分组成:
文件系统的接口层(用于对文件系统进行操作的一系列函数)
文件系统抽象层(“对象操纵和管理” 软件的集合)
对象及属性
从系统角度来看,文件系统是对文件存储设备的空间进行组织和分配,负责文件存储并对存入的文件进行保护和检索的系统,具体地说,它负责为用户建立文件,存入、读出、修改、转储文件,控制文件的存取,当用户不再使用时撤销文件等,文件系统是软件系统的一部分,它的存在使得应用可以方便的使用抽象命名的数据对象和大小可变的空间
比如桌面上的各种文件:操作系统提供了一种抽象来控制管理这些文件,可以是图形界面,也可以是命令行,这些抽象可以让我们忽略一些底层的原理,免去了大量复杂的操作
文件系统的功能:
管理和调度文件的存储空间,提供文件的逻辑结构、物理结构和存储方法
实现文件从标识到实际地址的映射,实现文件的控制操作和存取操作,实现文件信息的共享并提供可靠的文件保密和保护措施,提供文件的安全措施
文件系统-访问接口层 下面就是在内核中通用的文件相关函数(上层的文件系统需要的系统调用),同时也是我们在uCore中最常使用的函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 int sysfile_open (const char *path, uint32_t open_flags) ; int sysfile_close (int fd) ; int sysfile_read (int fd, void *base, size_t len) ; int sysfile_write (int fd, void *base, size_t len) ; int sysfile_seek (int fd, off_t pos, int whence) ; int sysfile_fstat (int fd, struct stat *stat) ; int sysfile_fsync (int fd) ; int sysfile_chdir (const char *path) ; int sysfile_mkdir (const char *path) ; int sysfile_link (const char *path1, const char *path2) ; int sysfile_rename (const char *path1, const char *path2) ; int sysfile_unlink (const char *path) ; int sysfile_getcwd (char *buf, size_t len) ; int sysfile_getdirentry (int fd, struct dirent *direntp) ; int sysfile_dup (int fd1, int fd2) ; int sysfile_pipe (int *fd_store) ; int sysfile_mkfifo (const char *name, uint32_t open_flags) ;
1 2 3 4 5 6 7 8 9 10 11 int sysfile_open (const char *__path, uint32_t open_flags) { int ret; char *path; if ((ret = copy_path(&path, __path)) != 0 ) { return ret; } ret = file_open(path, open_flags); kfree(path); return ret; }
sysfile_close:关闭一个打开的vnode
1 2 3 4 int sysfile_close (int fd) { return file_close(fd); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 int sysfile_read (int fd, void *base, size_t len) { struct mm_struct *mm = current->mm; if (len == 0 ) { return 0 ; } if (!file_testfd(fd, 1 , 0 )) { return -E_INVAL; } void *buffer; if ((buffer = kmalloc(IOBUF_SIZE)) == NULL ) { return -E_NO_MEM; } int ret = 0 ; size_t copied = 0 , alen; while (len != 0 ) { if ((alen = IOBUF_SIZE) > len) { alen = len; } ret = file_read(fd, buffer, alen, &alen); if (alen != 0 ) { lock_mm(mm); { if (copy_to_user(mm, base, buffer, alen)) { assert(len >= alen); base += alen, len -= alen, copied += alen; } else if (ret == 0 ) { ret = -E_INVAL; } } unlock_mm(mm); } if (ret != 0 || alen == 0 ) { goto out; } } out: kfree(buffer); if (copied != 0 ) { return copied; } return ret; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 int sysfile_write (int fd, void *base, size_t len) { struct mm_struct *mm = current->mm; if (len == 0 ) { return 0 ; } if (!file_testfd(fd, 0 , 1 )) { return -E_INVAL; } void *buffer; if ((buffer = kmalloc(IOBUF_SIZE)) == NULL ) { return -E_NO_MEM; } int ret = 0 ; size_t copied = 0 , alen; while (len != 0 ) { if ((alen = IOBUF_SIZE) > len) { alen = len; } lock_mm(mm); { if (!copy_from_user(mm, buffer, base, alen, 0 )) { ret = -E_INVAL; } } unlock_mm(mm); if (ret == 0 ) { ret = file_write(fd, buffer, alen, &alen); if (alen != 0 ) { assert(len >= alen); base += alen, len -= alen, copied += alen; } } if (ret != 0 || alen == 0 ) { goto out; } } out: kfree(buffer); if (copied != 0 ) { return copied; } return ret; }
1 2 3 4 int sysfile_seek (int fd, off_t pos, int whence) { return file_seek(fd, pos, whence); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 int sysfile_fstat (int fd, struct stat *__stat) { struct mm_struct *mm = current->mm; int ret; struct stat __local_stat , *stat = &__local_stat; if ((ret = file_fstat(fd, stat)) != 0 ) { return ret; } lock_mm(mm); { if (!copy_to_user(mm, __stat, stat, sizeof (struct stat))) { ret = -E_INVAL; } } unlock_mm(mm); return ret; }
1 2 3 4 int sysfile_fsync (int fd) { return file_fsync(fd); }
sysfile_chdir:改变DIR(页目录表)
1 2 3 4 5 6 7 8 9 10 11 int sysfile_chdir (const char *__path) { int ret; char *path; if ((ret = copy_path(&path, __path)) != 0 ) { return ret; } ret = vfs_chdir(path); kfree(path); return ret; }
sysfile_mkdir:创建DIR(页目录表),ucore没有该接口,它采用另一种方式实现
sysfile_link:设置path1的链接设置为path2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 int sysfile_link (const char *__path1, const char *__path2) { int ret; char *old_path, *new_path; if ((ret = copy_path(&old_path, __path1)) != 0 ) { return ret; } if ((ret = copy_path(&new_path, __path2)) != 0 ) { kfree(old_path); return ret; } ret = vfs_link(old_path, new_path); kfree(old_path), kfree(new_path); return ret; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 int sysfile_rename (const char *__path1, const char *__path2) { int ret; char *old_path, *new_path; if ((ret = copy_path(&old_path, __path1)) != 0 ) { return ret; } if ((ret = copy_path(&new_path, __path2)) != 0 ) { kfree(old_path); return ret; } ret = vfs_rename(old_path, new_path); kfree(old_path), kfree(new_path); return ret; }
1 2 3 4 5 6 7 8 9 10 11 int sysfile_unlink (const char *__path) { int ret; char *path; if ((ret = copy_path(&path, __path)) != 0 ) { return ret; } ret = vfs_unlink(path); kfree(path); return ret; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 int sysfile_getcwd (char *buf, size_t len) { struct mm_struct *mm = current->mm; if (len == 0 ) { return -E_INVAL; } int ret = -E_INVAL; lock_mm(mm); { if (user_mem_check(mm, (uintptr_t )buf, len, 1 )) { struct iobuf __iob , *iob = iobuf_init(&__iob, buf, len, 0 ); ret = vfs_getcwd(iob); } } unlock_mm(mm); return ret; }
sysfile_getdirentry:在DIR中获取文件条目
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 int sysfile_getdirentry (int fd, struct dirent *__direntp) { struct mm_struct *mm = current->mm; struct dirent *direntp ; if ((direntp = kmalloc(sizeof (struct dirent))) == NULL ) { return -E_NO_MEM; } int ret = 0 ; lock_mm(mm); { if (!copy_from_user(mm, &(direntp->offset), &(__direntp->offset), sizeof (direntp->offset), 1 )) { ret = -E_INVAL; } } unlock_mm(mm); if (ret != 0 || (ret = file_getdirentry(fd, direntp)) != 0 ) { goto out; } lock_mm(mm); { if (!copy_to_user(mm, __direntp, direntp, sizeof (struct dirent))) { ret = -E_INVAL; } } unlock_mm(mm); out: kfree(direntp); return ret; }
1 2 3 4 int sysfile_dup (int fd1, int fd2) { return file_dup(fd1, fd2); }
1 2 3 4 int sysfile_pipe (int *fd_store) { return -E_UNIMP; }
sysfile_mkfifo:生成命名管道(未完成)
1 2 3 4 int sysfile_mkfifo (const char *__name, uint32_t open_flags) { return -E_UNIMP; }
这些 sysfile_xx
函数本质上就是更底层的 file_xx
函数(直接控制文件的函数)的外包装,可以说 file_xx
函数再外加一些对文件系统的操作就是 sysfile_xx
了:
1 2 3 4 5 6 7 8 9 10 11 int file_open (char *path, uint32_t open_flags) ;int file_close (int fd) ;int file_read (int fd, void *base, size_t len, size_t *copied_store) ;int file_write (int fd, void *base, size_t len, size_t *copied_store) ;int file_seek (int fd, off_t pos, int whence) ;int file_fstat (int fd, struct stat *stat) ;int file_fsync (int fd) ;int file_getdirentry (int fd, struct dirent *dirent) ;int file_dup (int fd1, int fd2) ;int file_pipe (int fd[]) ;int file_mkfifo (const char *name, uint32_t open_flags) ;
通常来讲,这些函数都会操作当前进程访问文件的数据接口,即 current->filesp
(这也是进程描述结构体 proc_struct 新增的条目-filesp)
文件系统-抽象层 文件系统抽象层是把 不同文件系统 的 对外共性接口 提取出来,形成一个函数指针数组,这样,通用文件系统访问接口层只需访问文件系统抽象层,而不需关心具体文件系统的实现细节和接口(有点面向对象的味道)
VFS虚拟文件系统-实现抽象层的技术
系统接口(通用文件系统访问接口层)再下一层就到了 VFS 虚拟文件系统
虚拟文件系统(VFS)是 物理文件系统与服务之间的一个接口层 (用于在文件系统与服务之间进行最初的解析),它对 Linux 的每个文件系统的所有细节进行抽象,使得不同的文件系统在 Linux 核心以及系统中运行的其他进程看来都是相同的
虚拟文件系统中,所使用的相关函数接口分别是 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 void vfs_init (void ) ; void vfs_cleanup (void ) ; void vfs_devlist_init (void ) ;int vfs_set_curdir (struct inode *dir) ; int vfs_get_curdir (struct inode **dir_store) ; int vfs_get_root (const char *devname, struct inode **root_store) ; const char *vfs_get_devname (struct fs *fs) ; int vfs_open (char *path, uint32_t open_flags, struct inode **inode_store) ; int vfs_close (struct inode *node) ; int vfs_link (char *old_path, char *new_path) ; int vfs_symlink (char *old_path, char *new_path) ; int vfs_readlink (char *path, struct iobuf *iob) ; int vfs_mkdir (char *path) ; int vfs_unlink (char *path) ; int vfs_rename (char *old_path, char *new_path) ; int vfs_chdir (char *path) ; int vfs_getcwd (struct iobuf *iob) ; int vfs_lookup (char *path, struct inode **node_store) ; int vfs_lookup_parent (char *path, struct inode **node_store, char **endp) ; int vfs_set_bootfs (char *fsname) ;int vfs_get_bootfs (struct inode **node_store) ;int vfs_add_fs (const char *devname, struct fs *fs) ;int vfs_add_dev (const char *devname, struct inode *devnode, bool mountable) ;int vfs_mount (const char *devname, int (*mountfunc)(struct device *dev, struct fs **fs_store)) ;int vfs_unmount (const char *devname) ;int vfs_unmount_all (void ) ;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_fsync)(struct inode *node); int (*vop_namefile)(struct inode *node, struct iobuf *iob); int (*vop_getdirentry)(struct inode *node, struct iobuf *iob); int (*vop_reclaim)(struct inode *node); int (*vop_gettype)(struct inode *node, uint32_t *type_store); int (*vop_tryseek)(struct inode *node, off_t pos); int (*vop_truncate)(struct inode *node, off_t len); int (*vop_create)(struct inode *node, const char *name, bool excl, struct inode **node_store); int (*vop_lookup)(struct inode *node, char *path, struct inode **node_store); int (*vop_ioctl)(struct inode *node, int op, void *data); };
ucore 虚拟文件系统中有四大对象:SuperBlock、inode、dentry、file
超级块主要从文件系统的全局角度描述特定文件系统的全局信息,它的作用范围是整个OS空间
ucore 中有如下结构体来描述超级块:
1 2 3 4 5 6 struct sfs_super { uint32_t magic; uint32_t blocks; uint32_t unused_blocks; char info[SFS_MAX_INFO_LEN + 1 ]; };
PS:内核通过 magic 来检查磁盘镜像是否是合法的 SFS 镜像
UNIX 将文件的相关元数据信息(如访问控制权限、大小、拥有者、创建时间、数据内容等等信息)存储在一个单独的数据结构中,该结构被称为索引节点(每个文件都有一个 inode)
Linux 系统为每一个文件都分配了一个 inode 编号,这个编号中记录了文件相关的一些元信息,通过这些元信息可以用来唯一标识一个文件(操作系统上的 inode 并非无穷无尽,通常在你安装操作系统后,系统上的 inode 数量就已经确定了下来)
ucore 中的 inode 由如下结构体确定:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 struct inode { union { struct device __device_info ; struct sfs_inode __sfs_inode_info ; } in_info; enum { inode_type_device_info = 0x1234 , inode_type_sfs_inode_info, } in_type; int ref_count; int open_count; struct fs *in_fs ; const struct inode_ops *in_ops ; };
接下来看看几种类型的索引结点:
一,磁盘索引结点——保存在硬盘中的索引结点
sfs_disk_inode 结构记录了文件或目录的内容存储的索引信息,该数据结构在硬盘里储存,需要时读入内存:
1 2 3 4 5 6 7 8 struct sfs_disk_inode { uint32_t size; uint16_t type; uint16_t nlinks; uint32_t blocks; uint32_t direct[SFS_NDIRECT]; uint32_t indirect; };
对于普通文件:索引值 direct 指向的 block 中保存的是文件中的数据
对于目录:索引值 direct 指向的数据保存的是目录下所有的文件名,以及对应的索引节点所在的索引块(磁盘块)所形成的数组,数据结构如下:(其实就是它就是目录项)
1 2 3 4 struct sfs_disk_entry { uint32_t ino; char name[SFS_MAX_FNAME_LEN + 1 ]; };
不管是文件还是目录,磁盘索引结点都需要与内存索引结点进行“绑定”,这样才可以操控磁盘上的数据
当 uCore 创建一个“用于存储文件/目录”的 inode 结构时(即该 inode -> in_info 成员变量为 sfs_inode 类型),程序会执行函数 sfs_create_inode,该函数会将 inode -> sfs_inode 成员与磁盘对应结点 sfs_disk_inode 相关联,从而使得只凭 inode 即可操作该结点
PS:用于描述设备 device 的 inode 会在其他函数中被初始化,不会执行函数 sfs_create_inode
二,内存索引结点——保存在内存中的索引结点(inode 结构体的条目之一)
1 2 3 4 5 6 7 8 9 struct sfs_inode { struct sfs_disk_inode *din ; uint32_t ino; bool dirty; int reclaim_count; semaphore_t sem; list_entry_t inode_link; list_entry_t hash_link; };
SFS 中的内存 sfs_inode 包含SFS的硬盘 sfs_disk_inode 信息,而且还增加了其他一些信息,这些信息用于:判断相关硬盘位置是否改写、互斥操作、回收和快速地定位
PS:一个内存 sfs_inode 是在打开一个文件后才创建的,如果关机则相关信息都会消失,而硬盘 sfs_disk_inode 的内容是保存在硬盘中的,只是在进程需要时才被读入到内存中,用于访问文件或目录的具体内容数据
三,文件结点——用于指向磁盘索引结点的结点(有助于硬链接的实现)
1 2 3 4 struct sfs_disk_entry { uint32_t ino; char name[SFS_MAX_FNAME_LEN + 1 ]; };
inode->in_ops 指向 inode 接口,是对常规文件、目录、设备文件所有操作的一个抽象函数表示
对于某一具体的文件系统中的文件或目录,只需实现相关的函数,就可以被用户进程访问具体的文件了(用户进程无需了解具体文件系统的实现细节)
inode_ops 采用如下结构体进行组织:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 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_fsync)(struct inode *node); int (*vop_namefile)(struct inode *node, struct iobuf *iob); int (*vop_getdirentry)(struct inode *node, struct iobuf *iob); int (*vop_reclaim)(struct inode *node); int (*vop_gettype)(struct inode *node, uint32_t *type_store); int (*vop_tryseek)(struct inode *node, off_t pos); int (*vop_truncate)(struct inode *node, off_t len); int (*vop_create)(struct inode *node, const char *name, bool excl, struct inode **node_store); int (*vop_lookup)(struct inode *node, char *path, struct inode **node_store); int (*vop_ioctl)(struct inode *node, int op, void *data); };
inode 结构是与文件系统相关的,不同文件系统所实现的 inode 结构是不同的 (主要体现在 inode_ops 条目),它的存在可以让 VFS 忽略更下一级的文件系统差异,使之注重于提供一个统一的文件系统接口
inode_ops 根据其 in_info 的不同而实现其不同的功能:(目录,文件,外设)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 static const struct inode_ops sfs_node_dirops = { .vop_magic = VOP_MAGIC, .vop_open = sfs_opendir, .vop_close = sfs_close, .vop_fstat = sfs_fstat, .vop_fsync = sfs_fsync, .vop_namefile = sfs_namefile, .vop_getdirentry = sfs_getdirentry, .vop_reclaim = sfs_reclaim, .vop_gettype = sfs_gettype, .vop_lookup = sfs_lookup, }; static const struct inode_ops sfs_node_fileops = { .vop_magic = VOP_MAGIC, .vop_open = sfs_openfile, .vop_close = sfs_close, .vop_read = sfs_read, .vop_write = sfs_write, .vop_fstat = sfs_fstat, .vop_fsync = sfs_fsync, .vop_reclaim = sfs_reclaim, .vop_gettype = sfs_gettype, .vop_tryseek = sfs_tryseek, .vop_truncate = sfs_truncfile, }; static const struct inode_ops dev_node_ops = { .vop_magic = VOP_MAGIC, .vop_open = dev_open, .vop_close = dev_close, .vop_read = dev_read, .vop_write = dev_write, .vop_fstat = dev_fstat, .vop_ioctl = dev_ioctl, .vop_gettype = dev_gettype, .vop_tryseek = dev_tryseek, .vop_lookup = dev_lookup, };
目录项不是目录,而是目录的组成部分
目录项是描述文件的逻辑属性,只存在于内存中,并没有实际对应的磁盘上的描述,更确切的说是存在于内存的目录项缓存,为了提高查找性能而设计
UNIX 中目录被看作一种特定的文件,而目录项是文件路径中的一部分
如一个文件路径名是 “/test/testfile” ,则包含的目录项为:
根目录 “/” ,目录 “test” 和文件 “testfile” ,这三个都是目录项
一般而言,目录项包含目录项的名字(文件名或目录名)和目录项的索引节点位置
注意:目录也是一种文件,所以也存在对应的 inode,打开目录,实际上就是打开对应的目录文件
1 2 3 4 struct sfs_disk_entry { uint32_t ino; char name[SFS_MAX_FNAME_LEN + 1 ]; };
dentry(具体为struct sfs_disk_entry)就是一个内存实体:其中的 ino 成员指向对应的 inode number,另外一个成员是 file name
它主要从进程的角度描述了一个进程在访问文件时需要了解的文件标识,文件读写的位置,文件引用情况等信息,它的作用范围是某一具体进程
下面是用于描述文件的结构体:file(又称打开的文件描述)
1 2 3 4 5 6 7 8 9 10 11 struct file { enum { FD_NONE, FD_INIT, FD_OPENED, FD_CLOSED, } status; bool readable; bool writable; int fd; off_t pos; struct inode *node ; int open_count; };
上面的 file 只是对一个文件而言,对于一个进程(用户)来说,可以同时处理多个文件,所以需要另一个结构来管理所有的 files:
1 2 3 4 5 6 struct files_struct { struct inode *pwd ; struct file *fd_array ; int files_count; semaphore_t files_sem; };
文件系统-文件系统层 从 VFS 向下一层,就是 SFS(Simple FS,文件系统层,简称 SFS)
ucore 内核把所有文件都看作是字节流,任何内部逻辑结构都是专用的,由应用程序负责解释,但是 ucore 区分文件的物理结构,ucore 目前支持如下几种类型的文件:
常规文件:文件中包括的内容信息是由应用程序输入,SFS 文件系统在普通文件上不强加任何内部结构,把其文件内容信息看作为字节
目录:包含一系列的 entry,每个 entry 包含文件名和指向与之相关联的索引节点(index node)的指针,目录是按层次结构组织的
链接文件:实际上一个链接文件是一个已经存在的文件的另一个可选择的文件名
设备文件:不包含数据,但是提供了一个映射物理设备(如串口、键盘等)到一个文件名的机制,可通过设备文件访问外围设备
管道:管道是进程间通讯的一个基础设施,管道缓存了其输入端所接受的数据,以便在管道输出端读的进程能一个先进先出的方式来接受数据
SFS 文件系统中目录和常规文件具有共同的属性,而这些属性保存在索引节点中,SFS 通过索引节点来管理目录和常规文件,索引节点包含操作系统所需要的关于某个文件的关键信息,比如文件的属性、访问许可权以及其它控制信息都保存在索引节点中
函数接口与数据结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 void sfs_init (void ) ;int sfs_mount (const char *devname) ;void lock_sfs_fs (struct sfs_fs *sfs) ;void lock_sfs_io (struct sfs_fs *sfs) ;void unlock_sfs_fs (struct sfs_fs *sfs) ;void unlock_sfs_io (struct sfs_fs *sfs) ;int sfs_rblock (struct sfs_fs *sfs, void *buf, uint32_t blkno, uint32_t nblks) ;int sfs_wblock (struct sfs_fs *sfs, void *buf, uint32_t blkno, uint32_t nblks) ;int sfs_rbuf (struct sfs_fs *sfs, void *buf, size_t len, uint32_t blkno, off_t offset) ;int sfs_wbuf (struct sfs_fs *sfs, void *buf, size_t len, uint32_t blkno, off_t offset) ;int sfs_sync_super (struct sfs_fs *sfs) ;int sfs_sync_freemap (struct sfs_fs *sfs) ;int sfs_clear_block (struct sfs_fs *sfs, uint32_t blkno, uint32_t nblks) ;int sfs_load_inode (struct sfs_fs *sfs, struct inode **node_store, uint32_t ino) ;static int sfs_sync (struct fs *fs) ;static struct inode* sfs_get_root (struct fs *fs) ;static int sfs_unmount (struct fs *fs) ;static void sfs_cleanup (struct fs *fs) ;static int fs_init_read (struct device *dev, uint32_t blkno, void *blk_buffer) ;static int fs_do_mount (struct device *dev, struct fs **fs_store) ;
在 SFS
中涉及到了两种文件系统结构,分别是 fs
和 sfs_fs
fs
结构是我们 在上层函数调用中所直接操作 的抽象文件系统结构
sfs_fs
结构则是 在下层函数中所使用的
在原先 sfs_fs
上抽象出一层 fs
结构有助于忽略不同文件系统的差异,其实现如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 struct fs { union { struct sfs_fs __sfs_info ; } fs_info; enum { fs_type_sfs_info, } fs_type; int (*fs_sync)(struct fs *fs); struct inode *(*fs_get_root )(struct fs *fs ); int (*fs_unmount)(struct fs *fs); void (*fs_cleanup)(struct fs *fs); };
1 2 3 4 5 6 7 8 9 10 11 12 struct sfs_fs { struct sfs_super super ; struct device *dev ; struct bitmap *freemap ; bool super_dirty; void *sfs_buffer; semaphore_t fs_sem; semaphore_t io_sem; semaphore_t mutex_sem; list_entry_t inode_list; list_entry_t *hash_list; };
sfs_fs
结构中包含了底层设备的超级块 superblock
、所挂载的设备 dev
、以及底层设备中用于表示空间分配情况的 freemap
等
文件系统布局
文件系统通常保存在磁盘上
在本实验中,第三个磁盘(即 disk0,前两个磁盘分别是 ucore.img 和 swap.img)用于存放一个SFS文件系统(Simple Filesystem),通常文件系统中,磁盘的使用是以扇区(Sector)为单位的,但是为了实现简便,SFS 中以 block (4K,与内存 page 大小相等)为基本单位
SFS文件系统的布局如下:
1 2 3 +------------+----------+---------+-------------------------------------+ | superblock | root-dir | freemap | Inode / File Data / Dir Data blocks | +------------+----------+---------+-------------------------------------+
第0个块是超级块(superblock)
它包含了关于文件系统的所有关键参数,当计算机被启动或文件系统被首次接触时,超级块的内容就会被装入内存
第1个块放了一个 root-dir 的 inode,用来记录根目录的相关信息
root-dir 是 SFS 文件系统的根结点
通过这个 root-dir 的 inode 信息就可以定位并查找到根目录下的所有文件信息
从第2个块开始,根据 SFS 中所有块的数量,用1个bit来表示一个块的占用和未被占用的情况
这个区域称为 SFS 的 freemap 区域,这将占用若干个块空间(为了更好地记录和管理 freemap 区域)
最后在剩余的磁盘空间中,存放了所有其他目录和文件的inode信息和内容数据信息
需要注意的是:虽然 inode 的大小小于一个块的大小(4096B),但为了实现简单,每个 inode 都占用一个完整的 block
文件系统-外设接口层 再底层一点就是 I/O 设备的相关实现,例如结构体 device
:
1 2 3 4 5 6 7 8 struct device { size_t d_blocks; size_t d_blocksize; int (*d_open)(struct device *dev, uint32_t open_flags); int (*d_close)(struct device *dev); int (*d_io)(struct device *dev, struct iobuf *iob, bool write); int (*d_ioctl)(struct device *dev, int op, void *data); };
该结构体支持对块设备、字符设备的表示,完成对设备的基本操作
结构体 device 只表示了一个设备所能使用的功能,我们需要一个数据结构用于将 device 和 fs 关联 ,同时,为了将连接的所有设备连接在一起,uCore定义了一个链表,通过该链表即可访问到所有设备,而这就是定义 vfs_dev_t
结构体的目的:
1 2 3 4 5 6 7 typedef struct { const char *devname; struct inode *devnode ; struct fs *fs ; bool mountable; list_entry_t vdev_link; } vfs_dev_t ;
文件系统挂载流程 一个文件系统在使用前,需要将其挂载至内核中(使一个存储设备上的计算机文件和目录,可供用户通过计算机的文件系统访问的一个过程),在 uCore 里,硬盘 disk0
的挂载流程如下:
程序会先执行 fs_init 函数:
1 2 3 4 5 6 void fs_init (void ) { vfs_init(); dev_init(); sfs_init(); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 static semaphore_t bootfs_sem; static semaphore_t vdev_list_sem; static list_entry_t vdev_list; void vfs_init (void ) { sem_init(&bootfs_sem, 1 ); vfs_devlist_init(); } void vfs_devlist_init (void ) { list_init(&vdev_list); sem_init(&vdev_list_sem, 1 ); } void sem_init (semaphore_t *sem, int value) { sem->value = value; wait_queue_init(&(sem->wait_queue)); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 void dev_init (void ) { init_device(stdin ); init_device(stdout ); init_device(disk0); } #define init_device(x) \ do { \ extern void dev_init_##x(void); \ dev_init_##x(); \ } while (0) void dev_init_disk0 (void ) { struct inode *node ; if ((node = dev_create_inode()) == NULL ) { panic("disk0: dev_create_node.\n" ); } disk0_device_init(vop_info(node, device)); int ret; if ((ret = vfs_add_dev("disk0" , node, 1 )) != 0 ) { panic("disk0: vfs_add_dev: %e.\n" , ret); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 void sfs_init (void ) { int ret; if ((ret = sfs_mount("disk0" )) != 0 ) { panic("failed: sfs: sfs_mount: %e.\n" , ret); } } int sfs_mount (const char *devname) { return vfs_mount(devname, sfs_do_mount); } int vfs_mount (const char *devname, int (*mountfunc)(struct device *dev, struct fs **fs_store)) { int ret; lock_vdev_list(); vfs_dev_t *vdev; if ((ret = find_mount(devname, &vdev)) != 0 ) { goto out; } if (vdev->fs != NULL ) { ret = -E_BUSY; goto out; } assert(vdev->devname != NULL && vdev->mountable); struct device *dev = vop_info(vdev->devnode, device); if ((ret = mountfunc(dev, &(vdev->fs))) == 0 ) { assert(vdev->fs != NULL ); cprintf("vfs: mount %s.\n" , vdev->devname); } out: unlock_vdev_list(); return ret; }
调用流程为:
1 sfs_init -> sfs_mount -> vfs_mount -> sfs_do_mount
sfs_do_mount 挂载函数会执行以下几个操作:
从待挂载设备中读取超级块,并验证超级块中,魔数与总块数是否存在错误
初始化哈希链表
从待挂载设备中读入 freemap
并测试其正确性
设置 fs
结构的相关信息,并在函数最后将该信息设置为传入的 device
结构体中的 fs
成员变量
文件打开流程 用户进程调用 open 函数时,调用链如下:
1 open -> sysfile_open -> file_open(包含vfs_open)
file_open 的实现如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 int file_open (char *path, uint32_t open_flags) { 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 = fd_array_alloc(NO_FD, &file)) != 0 ) { return ret; } struct inode *node ; if ((ret = vfs_open(path, open_flags, &node)) != 0 ) { fd_array_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); fd_array_free(file); return ret; } file->pos = stat->st_size; } file->node = node; file->readable = readable; file->writable = writable; fd_array_open(file); return file->fd; }
vfs_open 的实现如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 int vfs_open (char *path, uint32_t open_flags, struct inode **node_store) { bool can_write = 0 ; switch (open_flags & O_ACCMODE) { case O_RDONLY: break ; case O_WRONLY: case O_RDWR: can_write = 1 ; break ; default : return -E_INVAL; } if (open_flags & O_TRUNC) { if (!can_write) { return -E_INVAL; } } int ret; struct inode *node ; bool excl = (open_flags & O_EXCL) != 0 ; bool create = (open_flags & O_CREAT) != 0 ; ret = vfs_lookup(path, &node); if (ret != 0 ) { if (ret == -16 && (create)) { char *name; struct inode *dir ; if ((ret = vfs_lookup_parent(path, &dir, &name)) != 0 ) { return ret; } ret = vop_create(dir, name, excl, &node); } else return ret; } else if (excl && create) { return -E_EXISTS; } assert(node != NULL ); if ((ret = vop_open(node, open_flags)) != 0 ) { vop_ref_dec(node); return ret; } vop_open_inc(node); if (open_flags & O_TRUNC || create) { if ((ret = vop_truncate(node, 0 )) != 0 ) { vop_open_dec(node); vop_ref_dec(node); return ret; } } *node_store = node; return 0 ; }
文件读取流程 用户进程调用 read 函数时,调用链如下:
1 read -> sysfile_read -> file_read -> sfs_read -> sfs_io -> sfs_io_nolock
file_read 的实现如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 int file_read (int fd, void *base, size_t len, size_t *copied_store) { int ret; struct file *file ; *copied_store = 0 ; if ((ret = fd2file(fd, &file)) != 0 ) { return ret; } if (!file->readable) { return -E_INVAL; } fd_array_acquire(file); struct iobuf __iob , *iob = iobuf_init(&__iob, base, len, file->pos); ret = vop_read(file->node, iob); size_t copied = iobuf_used(iob); if (file->status == FD_OPENED) { file->pos += copied; } *copied_store = copied; fd_array_release(file); return ret; }
file_read 中涉及到 IO 缓冲区,在 ucore 中,IO 缓冲区由如下结构体进行管理:
1 2 3 4 5 6 struct iobuf { void *io_base; off_t io_offset; size_t io_len; size_t io_resid; };
file_read 会进一步调用 vop_read,将数据读取至缓冲区 iob,最终调用 sfs_io_nolock:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 static int sfs_read (struct inode *node, struct iobuf *iob) { return sfs_io(node, iob, 0 ); } static inline int sfs_io (struct inode *node, struct iobuf *iob, bool write) { struct sfs_fs *sfs = fsop_info(vop_fs(node), sfs); struct sfs_inode *sin = vop_info(node, sfs_inode); int ret; lock_sin(sin ); { size_t alen = iob->io_resid; ret = sfs_io_nolock(sfs, sin , iob->io_base, iob->io_offset, &alen, write); if (alen != 0 ) { iobuf_skip(iob, alen); } } unlock_sin(sin ); return ret; }
sfs_io_nolock 函数将在练习1中详细讲解
练习0-把 lab7 的内容复制粘贴到 lab8 练习1-完成读文件操作的实现 用户进程调用 read 函数时,调用链如下:
1 read -> sysfile_read -> file_read -> sfs_read -> sfs_io -> sfs_io_nolock
前面几个函数都可以跳过了,我们的任务就是补全最后一个函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 static int sfs_io_nolock (struct sfs_fs *sfs, struct sfs_inode *sin , void *buf, off_t offset, size_t *alenp, bool write) { struct sfs_disk_inode *din = sin ->din; assert(din->type != SFS_TYPE_DIR); off_t endpos = offset + *alenp, blkoff; *alenp = 0 ; if (offset < 0 || offset >= SFS_MAX_FILE_SIZE || offset > endpos) { return -E_INVAL; } if (offset == endpos) { return 0 ; } if (endpos > SFS_MAX_FILE_SIZE) { endpos = SFS_MAX_FILE_SIZE; } if (!write) { if (offset >= din->size) { return 0 ; } if (endpos > din->size) { endpos = din->size; } } int (*sfs_buf_op)(struct sfs_fs *sfs, void *buf, size_t len, uint32_t blkno, off_t offset); int (*sfs_block_op)(struct sfs_fs *sfs, void *buf, uint32_t blkno, uint32_t nblks); if (write) { sfs_buf_op = sfs_wbuf, sfs_block_op = sfs_wblock; } else { sfs_buf_op = sfs_rbuf, sfs_block_op = sfs_rblock; } int ret = 0 ; size_t size, alen = 0 ; uint32_t ino; uint32_t blkno = offset / SFS_BLKSIZE; uint32_t nblks = endpos / SFS_BLKSIZE - blkno; out: *alenp = alen; if (offset + alen > sin ->din->size) { sin ->din->size = offset + alen; sin ->dirty = 1 ; } return ret; }
实现过程:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 static int sfs_io_nolock (struct sfs_fs *sfs, struct sfs_inode *sin , void *buf, off_t offset, size_t *alenp, bool write) { struct sfs_disk_inode *din = sin ->din; assert(din->type != SFS_TYPE_DIR); off_t endpos = offset + *alenp, blkoff; *alenp = 0 ; if (offset < 0 || offset >= SFS_MAX_FILE_SIZE || offset > endpos) { return -E_INVAL; } if (offset == endpos) { return 0 ; } if (endpos > SFS_MAX_FILE_SIZE) { endpos = SFS_MAX_FILE_SIZE; } if (!write) { if (offset >= din->size) { return 0 ; } if (endpos > din->size) { endpos = din->size; } } int (*sfs_buf_op)(struct sfs_fs *sfs, void *buf, size_t len, uint32_t blkno, off_t offset); int (*sfs_block_op)(struct sfs_fs *sfs, void *buf, uint32_t blkno, uint32_t nblks); if (write) { sfs_buf_op = sfs_wbuf, sfs_block_op = sfs_wblock; } else { sfs_buf_op = sfs_rbuf, sfs_block_op = sfs_rblock; } int ret = 0 ; size_t size, alen = 0 ; uint32_t ino; uint32_t blkno = offset / SFS_BLKSIZE; uint32_t nblks = endpos / SFS_BLKSIZE - blkno; if ((blkoff = offset % SFS_BLKSIZE) != 0 ) { size = (nblks != 0 ) ? (SFS_BLKSIZE - blkoff) : (endpos - offset); if ((ret = sfs_bmap_load_nolock(sfs, sin , blkno, &ino)) != 0 ) { goto out; } if ((ret = sfs_buf_op(sfs, buf, size, ino, blkoff)) != 0 ) { goto out; } alen += size; if (nblks == 0 ) { goto out; } buf += size, blkno ++, nblks --; } size = SFS_BLKSIZE; while (nblks != 0 ) { if ((ret = sfs_bmap_load_nolock(sfs, sin , blkno, &ino)) != 0 ) { goto out; } if ((ret = sfs_block_op(sfs, buf, ino, 1 )) != 0 ) { goto out; } alen += size, buf += size, blkno ++, nblks --; } if ((size = endpos % SFS_BLKSIZE) != 0 ) { if ((ret = sfs_bmap_load_nolock(sfs, sin , blkno, &ino)) != 0 ) { goto out; } if ((ret = sfs_buf_op(sfs, buf, size, ino, 0 )) != 0 ) { goto out; } alen += size; } out: *alenp = alen; if (offset + alen > sin ->din->size) { sin ->din->size = offset + alen; sin ->dirty = 1 ; } return ret; }
练习2-完成基于文件系统的执行程序机制的实现 基于文件系统的执行程序机制,有几部分地方需要添加代码,分别是 alloc_proc
、 do_fork
、 load_icode
三个函数
alloc_proc:分配一个 proc_struct,用于描述进程的信息(在之前实验已经实现过了)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 static struct proc_struct *alloc_proc (void ) { struct proc_struct *proc = kmalloc(sizeof (struct proc_struct)); if (proc != NULL ) { proc->state = PROC_UNINIT; proc->pid = -1 ; proc->runs = 0 ; proc->kstack = 0 ; proc->need_resched = 0 ; proc->parent = NULL ; proc->mm = NULL ; memset (&(proc->context), 0 , sizeof (struct context)); proc->tf = NULL ; proc->cr3 = boot_cr3; proc->flags = 0 ; memset (proc->name, 0 , PROC_NAME_LEN); proc->wait_state = 0 ; proc->cptr = proc->optr = proc->yptr = NULL ; proc->rq = NULL ; list_init(&(proc->run_link)); proc->time_slice = 0 ; proc->lab6_run_pool.left = proc->lab6_run_pool.right = proc->lab6_run_pool.parent = NULL ; proc->lab6_stride = 0 ; proc->lab6_priority = 0 ; proc->filesp = NULL ; } return proc; }
新增的条目为 files_struct
结构体:(用于在进程中管理多个 file
结构体)
1 2 3 4 5 6 struct files_struct { struct inode *pwd ; struct file *fd_array ; int files_count; semaphore_t files_sem; };
do_fork:创建当前内核线程的一个副本,它们的执行上下文、代码、数据都一样,但是存储位置不同,在这个过程中,需要给新内核线程分配资源,并且复制原进程的状态(在之前实验已经实现过了)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 int do_fork (uint32_t clone_flags, uintptr_t stack , struct trapframe *tf) { int ret = -E_NO_FREE_PROC; struct proc_struct *proc ; if (nr_process >= MAX_PROCESS) { goto fork_out; } ret = -E_NO_MEM; if ((proc = alloc_proc()) == NULL ) { goto fork_out; } proc->parent = current; assert(current->wait_state == 0 ); if (setup_kstack(proc) != 0 ) { goto bad_fork_cleanup_proc; } if (copy_fs(clone_flags, proc) != 0 ) { goto bad_fork_cleanup_kstack; } if (copy_mm(clone_flags, proc) != 0 ) { goto bad_fork_cleanup_fs; } copy_thread(proc, stack , tf); bool intr_flag; local_intr_save(intr_flag); { proc->pid = get_pid(); hash_proc(proc); set_links(proc); } local_intr_restore(intr_flag); wakeup_proc(proc); ret = proc->pid; fork_out: return ret; bad_fork_cleanup_fs: put_fs(proc); bad_fork_cleanup_kstack: put_kstack(proc); bad_fork_cleanup_proc: kfree(proc); goto fork_out; }
load_icode:加载并解析一个处于内存中的ELF执行文件格式的应用程序(函数改动较大)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 static int load_icode (int fd, int argc, char **kargv) { assert(argc >= 0 && argc <= EXEC_MAX_ARG_NUM); if (current->mm != NULL ) { panic("load_icode: current->mm must be empty.\n" ); } int ret = -E_NO_MEM; struct mm_struct *mm ; if ((mm = mm_create()) == NULL ) { goto bad_mm; } if (setup_pgdir(mm) != 0 ) { goto bad_pgdir_cleanup_mm; } struct Page *page ; struct elfhdr __elf , *elf = &__elf; if ((ret = load_icode_read(fd, elf, sizeof (struct elfhdr), 0 )) != 0 ) { goto bad_elf_cleanup_pgdir; } if (elf->e_magic != ELF_MAGIC) { ret = -E_INVAL_ELF; goto bad_elf_cleanup_pgdir; } struct proghdr __ph , *ph = &__ph; uint32_t vm_flags, perm, phnum; for (phnum = 0 ; phnum < elf->e_phnum; phnum ++) { off_t phoff = elf->e_phoff + sizeof (struct proghdr) * phnum; if ((ret = load_icode_read(fd, ph, sizeof (struct proghdr), phoff)) != 0 ) { goto bad_cleanup_mmap; } if (ph->p_type != ELF_PT_LOAD) { continue ; } if (ph->p_filesz > ph->p_memsz) { ret = -E_INVAL_ELF; goto bad_cleanup_mmap; } if (ph->p_filesz == 0 ) { continue ; } vm_flags = 0 , perm = PTE_U; if (ph->p_flags & ELF_PF_X) vm_flags |= VM_EXEC; if (ph->p_flags & ELF_PF_W) vm_flags |= VM_WRITE; if (ph->p_flags & ELF_PF_R) vm_flags |= VM_READ; if (vm_flags & VM_WRITE) perm |= PTE_W; if ((ret = mm_map(mm, ph->p_va, ph->p_memsz, vm_flags, NULL )) != 0 ) { goto bad_cleanup_mmap; } off_t offset = ph->p_offset; size_t off, size; uintptr_t start = ph->p_va, end, la = ROUNDDOWN(start, PGSIZE); ret = -E_NO_MEM; end = ph->p_va + ph->p_filesz; while (start < end) { if ((page = pgdir_alloc_page(mm->pgdir, la, perm)) == NULL ) { ret = -E_NO_MEM; goto bad_cleanup_mmap; } off = start - la; size = PGSIZE - off; la += PGSIZE; if (end < la) { size -= la - end; } if ((ret = load_icode_read(fd, page2kva(page) + off, size, offset)) != 0 ) { goto bad_cleanup_mmap; } start += size, offset += size; } end = ph->p_va + ph->p_memsz; if (start < la) { if (start == end) { continue ; } off = start + PGSIZE - la, size = PGSIZE - off; if (end < la) { size -= la - end; } memset (page2kva(page) + off, 0 , size); start += size; assert((end < la && start == end) || (end >= la && start == la)); } while (start < end) { if ((page = pgdir_alloc_page(mm->pgdir, la, perm)) == NULL ) { ret = -E_NO_MEM; goto bad_cleanup_mmap; } off = start - la, size = PGSIZE - off, la += PGSIZE; if (end < la) { size -= la - end; } memset (page2kva(page) + off, 0 , size); start += size; } } sysfile_close(fd); vm_flags = VM_READ | VM_WRITE | VM_STACK; if ((ret = mm_map(mm, USTACKTOP - USTACKSIZE, USTACKSIZE, vm_flags, NULL )) != 0 ) { goto bad_cleanup_mmap; } assert(pgdir_alloc_page(mm->pgdir, USTACKTOP-PGSIZE , PTE_USER) != NULL ); assert(pgdir_alloc_page(mm->pgdir, USTACKTOP-2 *PGSIZE , PTE_USER) != NULL ); assert(pgdir_alloc_page(mm->pgdir, USTACKTOP-3 *PGSIZE , PTE_USER) != NULL ); assert(pgdir_alloc_page(mm->pgdir, USTACKTOP-4 *PGSIZE , PTE_USER) != NULL ); mm_count_inc(mm); current->mm = mm; current->cr3 = PADDR(mm->pgdir); lcr3(PADDR(mm->pgdir)); uint32_t argv_size=0 , i; for (i = 0 ; i < argc; i ++) { argv_size += strnlen(kargv[i],EXEC_MAX_ARG_LEN + 1 )+1 ; } uintptr_t stacktop = USTACKTOP - (argv_size/sizeof (long )+1 )*sizeof (long ); char ** uargv=(char **)(stacktop - argc * sizeof (char *)); argv_size = 0 ; for (i = 0 ; i < argc; i ++) { uargv[i] = strcpy ((char *)(stacktop + argv_size ), kargv[i]); argv_size += strnlen(kargv[i],EXEC_MAX_ARG_LEN + 1 )+1 ; } stacktop = (uintptr_t )uargv - sizeof (int ); *(int *)stacktop = argc; struct trapframe *tf = current->tf; memset (tf, 0 , sizeof (struct trapframe)); tf->tf_cs = USER_CS; tf->tf_ds = tf->tf_es = tf->tf_ss = USER_DS; tf->tf_esp = stacktop; tf->tf_eip = elf->e_entry; tf->tf_eflags = FL_IF; ret = 0 ; out: return ret; bad_cleanup_mmap: exit_mmap(mm); bad_elf_cleanup_pgdir: put_pgdir(mm); bad_pgdir_cleanup_mm: mm_destroy(mm); bad_mm: goto out; }