文件系统小册(Fuse&Posix&K8s csi)【2 Posix】
往期文章:文件系统小册(Fuse&Posix&K8s csi)【1 Fuse】
POSIX:可移植操作系统接口(标准)
1 概念
POSIX:Portable Operating System Interface of UNIX,POSIX标准定义了操作系统应该为应用程序提供的接口标准,是在各种UNIX操作系统上运行的软件的一系列API标准的总称。是由IEEE指定的一个标准。
为一个POSIX兼容的操作系统编写的程序,应该可以在任何其它的POSIX操作系统(即使是来自另一个厂商)上编译执行。
POSIX 并不局限于 UNIX。许多其它的操作系统也支持POSIX,例如Windows NT就提供了与POSIX兼容的库。
应用程序通过应用编程接口(API)而不是直接通过系统调用来编程。因此程序员不关心系统调用,他们只需要使用好API,而操作系统只需要处理好系统调用。不同的操作系统内核实现同样的功能的方法不同,为了实现可移植性,不同操作系统需要遵循同一套标准。
POSIX 涵盖了以下内容:系统接口、命令和实用程序、网络文件访问等
相关文档:https://www.gnu.org/software/libc/manual/html_node/POSIX.html
拓展:GNU、Linux、Unix关系
GNU 是一个软件运动和一系列工具,而Linux是操作系统内核,Unix 是一个商业起源的操作系统家族。(
GNU+Linux内核组成了我们常说的"Linux",因此很多人认为Linux发行版应该叫做GNU/Linux
)
- GNU:
GNU 是一个自由软件项目,始于1983年,由理查德·斯托曼(Richard Stallman)发起,目标是创建一套完全自由的类Unix操作系统。
GNU 提供了许多Unix系统中常见的工具、库和编译器,如GCC(GNU Compiler Collection)、Glibc(GNU C Library)和GDB(GNU Debugger)等。GNU 自己并未完成操作系统内核的开发,但其软件组件被广泛用于各种操作系统中,尤其是Linux。- Linux:
Linux 是一个由林纳斯·托瓦兹(Linus Torvalds)开发的开源操作系统内核,首次发布于1991年。
Linux 并非GNU项目的一部分,但它通常与GNU软件一起使用,形成了所谓的GNU/Linux操作系统。这种组合提供了与Unix类似的环境,但其内核是Linux,而不是GNU。
Linux 内核是免费和开源的,可以与各种用户空间工具和库(包括许多GNU组件)结合,形成各种不同的Linux发行版,如Ubuntu、Fedora和Debian等。- Unix:
Unix 是一种最初由AT&T贝尔实验室开发的操作系统,首次发布于1969年。
Unix 是商业产品,历史上大部分版本都是闭源的,但也有一些开源实现,如OpenBSD、FreeBSD和Solaris。
Unix 设计理念对Linux和GNU项目有很大影响,比如它的命令行界面、文件系统结构和多任务处理机制。
Linux 和GNU项目都遵循POSIX(可移植操作系统接口)标准,以确保与Unix兼容。
三者联系与区别:
- 联系:
GNU/Linux 和 Unix 都是多用户、多任务的操作系统,它们都支持网络功能和提供类似的工作环境。
许多Unix的工具和概念在Linux和GNU项目中得到了实现和扩展,形成了强大的命令行工具链和开发环境。
Linux 和 GNU 软件的组合使得开发者可以在不侵犯版权的情况下获得与Unix类似的功能和体验。- 区别:
GNU 是一个软件运动和一系列工具,而Linux是操作系统内核。
Unix 是一个商业起源的操作系统家族,而Linux和GNU项目是开源的。
Linux 不是GNU项目的一部分,但GNU工具和库经常与Linux内核一起使用。
Unix 有多个商业和开源版本,而Linux主要以开源社区驱动的发行版形式存在。
参考文章:https://www.gnu.org/gnu/linux-and-gnu.html
2 POSIX的标准文件接口(常用部分)
POSIX标准的文件接口有:close、create、open、read、sync、write、dup、dup2、flock、fcntl、fsync、lseek、mkstemp等。
open:打开文件
close:关闭文件
creat:创建文件
read:读文件内容
write:写内容到文件
lseek:改变文件指针的位置(文件定位)
fsync:将文件数据从系统缓存区写到磁盘
flock:文件锁,用于进程间同步
stat:获取文件的统计信息
truncate:截断文件
symlink:创建符号链接(如:软链,类比快捷方式)
readlink:读取符号链接的内容
opendir:打开目录
readdir:读取目录内容
mkdir:创建目录
rmdir: 删除目录
telldir:定位目录的当前位置
seekdir:定位目录
rename:重命名
chmod:动态修改文件访问权限
chown:动态修改文件所有者和组别
3 与FUSE的关系:FUSE实现了POSIX
- FUSE设计的目标之一就是支持POSIX标准,这样基于FUSE构建的文件系统可以提供与原生内核文件系统类似的接口,使得用户能够使用标准的系统调用(如open、read、write等)来与FUSE文件系统交互。
- 通过FUSE,我们可以实现一个符合POSIX标准的文件系统,允许应用程序(包括那些依赖于标准文件操作的程序)无缝地与FUSE文件系统一起工作。
- FUSE(Filesystem in Userspace)并不直接实现所有的POSIX文件相关操作规范,但它提供了足够的接口来实现一个符合POSIX标准的文件系统。FUSE的核心在于它为用户空间的文件系统实现提供了一个桥梁,允许开发者通过用户空间的程序来响应内核的文件系统调用。这些调用包括了大部分POSIX标准中的文件操作,但不是所有。
fuse_operations 结构体定义了一系列的回调函数,这些函数对应于POSIX文件操作,例如:
- getattr: 实现stat操作。
- read: 实现read操作。
- write: 实现write操作。
- open: 实现open操作。
- create: 实现creat操作。
- unlink: 实现unlink操作。
- rename: 实现rename操作。
- mkdir: 实现mkdir操作。
- symlink: 实现symlink操作。
- readlink: 实现readlink操作。
- chmod: 实现chmod操作。
- chown: 实现chown操作。
- truncate: 实现truncate操作。
flush: 实现文件关闭前的清理操作。
…
源码:
- https://github.com/libfuse/libfuse/中的fuse.h文件
/** Get file attributes.
*
* Similar to stat(). The 'st_dev' and 'st_blksize' fields are
* ignored. The 'st_ino' field is ignored except if the 'use_ino'
* mount option is given. In that case it is passed to userspace,
* but libfuse and the kernel will still assign a different
* inode for internal use (called the "nodeid").
*
* `fi` will always be NULL if the file is not currently open, but
* may also be NULL if the file is open.
*/
int (*getattr) (const char *, struct stat *, struct fuse_file_info *fi);
/** Read the target of a symbolic link
*
* The buffer should be filled with a null terminated string. The
* buffer size argument includes the space for the terminating
* null character. If the linkname is too long to fit in the
* buffer, it should be truncated. The return value should be 0
* for success.
*/
int (*readlink) (const char *, char *, size_t);
/** Create a file node
*
* This is called for creation of all non-directory, non-symlink
* nodes. If the filesystem defines a create() method, then for
* regular files that will be called instead.
*/
int (*mknod) (const char *, mode_t, dev_t);
/** Create a directory
*
* Note that the mode argument may not have the type specification
* bits set, i.e. S_ISDIR(mode) can be false. To obtain the
* correct directory type bits use mode|S_IFDIR
* */
int (*mkdir) (const char *, mode_t);
/** Remove a file */
int (*unlink) (const char *);
/** Remove a directory */
int (*rmdir) (const char *);
/** Create a symbolic link */
int (*symlink) (const char *, const char *);
/** Rename a file
*
* *flags* may be `RENAME_EXCHANGE` or `RENAME_NOREPLACE`. If
* RENAME_NOREPLACE is specified, the filesystem must not
* overwrite *newname* if it exists and return an error
* instead. If `RENAME_EXCHANGE` is specified, the filesystem
* must atomically exchange the two files, i.e. both must
* exist and neither may be deleted.
*/
int (*rename) (const char *, const char *, unsigned int flags);
/** Create a hard link to a file */
int (*link) (const char *, const char *);
/** Change the permission bits of a file
*
* `fi` will always be NULL if the file is not currently open, but
* may also be NULL if the file is open.
*/
int (*chmod) (const char *, mode_t, struct fuse_file_info *fi);
/** Change the owner and group of a file
*
* `fi` will always be NULL if the file is not currently open, but
* may also be NULL if the file is open.
*
* Unless FUSE_CAP_HANDLE_KILLPRIV is disabled, this method is
* expected to reset the setuid and setgid bits.
*/
int (*chown) (const char *, uid_t, gid_t, struct fuse_file_info *fi);
/** Change the size of a file
*
* `fi` will always be NULL if the file is not currently open, but
* may also be NULL if the file is open.
*
* Unless FUSE_CAP_HANDLE_KILLPRIV is disabled, this method is
* expected to reset the setuid and setgid bits.
*/
int (*truncate) (const char *, off_t, struct fuse_file_info *fi);
...
4 测试系统是否满足POSIX语义 (pjdfstest)
pjdfstest:用于测试posix语义
#git clone源码
git clone https://github.com/pjd/pjdfstest.git
cd pjdfstest
# 编译源码
autoreconf -ifs
./configure
make pjdfstest
# 查看版本
prove --version
## 进入目标目录,执行pjdfstest脚本
cd /root/test (文件系统的挂载目录)
# 测试所有用例(-v显示进度)
prove -rv /root/pjdfstest/tests(pjdfstest里的tests目录)
# 测试单个语义
prove -r /root/pjdfstest/tests/open
参考:https://www.gnu.org/software/libc/manual/html_node/POSIX.html