CSE_lecture3:File System 2
File System API and Disk I/O
implement the file system API
API有以下几个:
CHDIR(即cd),MKDIRCREAT,LINK,UNLINK,RENAMESYMLINKMOUNT,UNMOUNT(读取super block)OPEN,READ,WRITE,APPEND,CLOSESYNC(将内存数据放到磁盘上)
这些API通过system call暴露给用户
区分一下open()和fopen():
- open是来自操作系统的system call,而fopen是c语言规范中libc的一个API
- open返回一个fd,而fopen返回一个指向文件的指针
- 只有fopen在windows和linux上都同名,而open不见得
- fopen具备更好的性能,因为fopen使用了一个buffer I/O,可能并没有直接写入磁盘
inode是file的metadata,里面除了上节课讲的几个之外,还有:
- owner id: 用于权限控制
- types of permission: 谁有权限,有哪些权限(mode: read, write, execute)
- time stamps: access time(管理read), modify time(管理write), change of time(管理link)
1 | |
open时的过程为:
- 通过id和mode检查是否有打开的权限
- 更新atime
- 返回fd
每个进程默认有三个fd,分别管理stdin(0), stdout(1), stderr(2),fd还可以通知一些device,这是因为这些device本质都是文件
为什么使用fd而不是inode pointer?
- 为了安全不让你了解kernel的数据结构,实现os和应用的隔离
- 同时让文件修改全权交给kernel,实现non-bypassability
- 对于同一个文件,不同的操作对应的fd不一样
fd要求返回当前可用fd中最小的那个,而这就导致了当open过多时要加锁,导致性能下降
文件被打开时,file cursor默认指向0的位置,而read和write时,cursor向前移动,同时read和write也是从当前cursor开始的,使用SEEK来任意移动file cursor
sharing file cursor: 父进程将fd传给子进程,在写log时有用;not sharing file cursor: 两个进程打开同一个文件
使用fd_table和file_table维护file cursor(这些都是in memory的),其中file_table全局,而file_table里面的refcnt与inode里面的区分,而是表明有多少进程共享同一个index,而当refcnt = 0时回收资源
1 | |
1 | |
每次OPEN, READ, CREATION时到底调用了多少次read和write?见以下两张图
每次READ时都要在inode里面write,很麻烦,因此添加参数-no-atime,并在close的时候再一并更新atime
注意在create到bar inode时要先read再write,这是因为write的粒度都是4KB,而inode只有1KB,因此只能先读上来4KB;而create最后foo inode因为先前已经read过了,所以就只用write了;像bar inode[0]就直接write了,因为直接write 4KB就行
以下三个写操作顺序,哪个最合理?检查什么时候断电,权衡后选择第一个,但也不完美
- update block bitmap, write new data, update inode(size and pointer): 1后断电,浪费一个block;2后断电,白写了data,还是浪费一个block
- update block bitmap, update inode(size and pointer), write new data: 2后断电,等价于访问旧的数据,非常危险
- update inode(size and pointer), update block bitmap, write new data: 1后断电,inode里面的pointer指向一个还没覆写的block,有可能读到旧的数据,非常危险
SYNC将cache写入磁盘,避免断电时数据丢失
delete after open but before close: inode在close前不会回收即可
rename有一个更好的方案:
LINK(from_name, to_name): 注意这里是to_name的inode num被修改成from_name的,然后refcnt变为2UNLINK(from_name): refcnt变回1
在1和2之间断电,至少保证了from_name和to_name指向同一个文件
other file systems(not inode)
- 方法1:使用连续的block存储文件
- 方法2:使用linked list,即FAT(file allcation table):
- FAT为一个linked list,和block一一对应,这导致FAT的容错性差
- file number为list起始位置得索引
- 将空的block视为一个大文件,对应一个free list
- 写入文件时,从free list中获取空闲的block,并将它们link起来
- FAT的目录包含了file name, file number, next,因此也不支持硬链接,根目录在sector 0
