【问题标题】:How Linux system calls interact with filesystemLinux 系统调用如何与文件系统交互
【发布时间】:2017-12-12 22:34:04
【问题描述】:

最近我遇到了这个练习:

鉴于 Linux C 语言程序中的系统调用序列:

fd = open("f123", O_RDWRT | O_CREAT, 0777);
lseek(fd, 0x1000000L, 0);
write(fd, &fd, sizeof(int));

绘制被这些操作修改的文件系统数据结构和磁盘块,考虑 4 KB 的块大小和 4 字节的索引块指针。

对于第一个系统调用 (open),我意识到它是如何工作的,并以这种方式对其进行了模式化:

现在,跳过 draw 部分(我意识到这很难回答),我想了解 lseekwrite 在 inode 和索引块方面的工作原理(不管它们是什么)。

我试图确定lseek 计算了正确的 inode(因为块大小是已知的),但仍然不知道它是如何工作的。

【问题讨论】:

  • open() 确定 inode — 其他函数使用该信息。您需要一个打开的文件描述符表和一个打开的文件描述表(这可能是您所说的“文件表”,但我不确定)。描述(与描述符相反)保存查找偏移量(文件中的当前位置)。一般来说,多个描述符可以引用一个描述——这些描述符不必都在同一个进程中,尽管在您的示例代码中,只涉及一个进程。
  • 有道理。所以 lseek 只是改变了描述表中的当前偏移量,然后搜索正确的块(如果有的话)?
  • lseek() 不搜索正确的块;它不需要。这是下一个 I/O 操作——与移动操作相反——需要跟踪块。例如,您可以寻找超出当前文件结尾的方法。接下来会发生什么取决于您是读取(EOF)还是写入(写入新材料,并且任何跳过的块都被视为所有字节为零;包含当前EOF的最后一个块的尾部和当前块的开头可能需要被强制归零)。您不能从一开始就使用负偏移量,否则,lseek() 会成功(受类型限制)。

标签: c linux filesystems system-calls


【解决方案1】:

在 Linux 中,这些系统调用与虚拟文件系统 (VFS) 交互。 VFS 在真实文件系统之上构建了一个抽象,它定义了一些有用的数据结构来组织文件系统。

  • inode 代表磁盘上的真实文件。通过 inodes 结构不仅可以访问 inode 块,还可以访问磁盘上的数据块。
  • 目录条目 代表路径的一部分。 d_entry 并不总是引用磁盘上的真实文件。如果它引用磁盘上的一个目录,就会有一个指向该目录文件的inode结构的指针。
  • file 代表进程打开的文件。结构中还有一个指向其 d_entry 的指针。

这里是来自file结构的sn-ps:

struct file {
    // ... other attributes
    struct path     f_path;
    #define f_dentry    f_path.dentry
    #define f_vfsmnt    f_path.mnt
    const struct file_operations    *f_op;
};
struct file_operations {
    // ... other operations
    struct module *owner;
    loff_t (*llseek) (struct file *, loff_t, int);
    ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
    ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
}

这些对象都有一个操作列表字段。 VFS 定义了这些操作,底层文件系统实现这些操作或使用 VFS 提供的通用实现。

系统调用open()创建文件对象,其他系统调用如lseek()只需获取file对象(通过fd)并调用操作列表中的相应函数,如write()会调用f->f_op->write(f, ...),然后是文件系统可以按照file -> d_entry -> inode 路径访问磁盘上的文件。

【讨论】:

    最近更新 更多