SO2 课程 08——文件系统管理

文件系统管理

文件系统抽象

文件系统抽象——在内存中

../_images/ditaa-29f54aaa1a85b819ff29cb7d101a4d646b3b0b06.png

文件系统抽象——在存储中

../_images/ditaa-bc662dab7bb3d9ba3a37efbf69b82c513dcaadd4.png

简易文件系统示例

 

../_images/ditaa-8b59fc3f5245ffb5d7089dc80cf2e306c39a62d8.png

概览

../_images/ditaa-6d39f541805ae8197b413ec9c79116382abc4dbc.png

文件系统操作

挂载文件系统

打开文件

查询文件属性

从文件读取数据

向文件写入数据

关闭文件

目录

目录是包含一个或多个 dentry 的特殊文件。

创建文件

删除文件

虚拟文件系统

../_images/ditaa-e3a27a84dde42de58bcc5c360e1c4b15062507c2.png

超级块操作

  • fill_super
  • put_super
  • write_super
  • read_inode
  • write_inode
  • evict_inode
  • statfs
  • remount_fs

Inode 操作

  • create
  • lookup
  • link
  • unlink
  • symlink
  • mkdir
  • rmdir
  • rename
  • readlink
  • follow_link
  • put_link
  • ...

Inode 缓存

目录项缓存

页面缓存

struct address_space

/**
 * struct address_space——可缓存、可映射对象的内容。
 * @host: 所有者,可以是 inode 或 block_device。
 * @i_pages: 缓存的页面。
 * @gfp_mask: 用于分配页面的内存分配标志。
 * @i_mmap_writable: VM_SHARED 映射的数量。
 * @nr_thps: 页面缓存中的 THP 数量(仅用于非 shmem)。
 * @i_mmap: 私有和共享映射的树。
 * @i_mmap_rwsem: 保护 @i_mmap 和 @i_mmap_writable。
 * @nrpages: 页面条目的数量,由 i_pages 锁保护。
 * @nrexceptional: 阴影或 DAX 条目,由 i_pages 锁保护。
 * @writeback_index: 写回的起始位置。
 * @a_ops: 方法。
 * @flags: 错误位和标志(AS_*)。
 * @wb_err: 最近发生的错误。
 * @private_lock: 由 address_space 所有者使用。
 * @private_list: 由 address_space 所有者使用。
 * @private_data: 由 address_space 所有者使用。
 */
struct address_space {
  struct inode            *host;
  struct xarray           i_pages;
  gfp_t                   gfp_mask;
  atomic_t                i_mmap_writable;
#ifdef CONFIG_READ_ONLY_THP_FOR_FS
  /* number of thp, only for non-shmem files */
  atomic_t                nr_thps;
#endif
  struct rb_root_cached   i_mmap;
  struct rw_semaphore     i_mmap_rwsem;
  unsigned long           nrpages;
  unsigned long           nrexceptional;
  pgoff_t                 writeback_index;
  const struct address_space_operations *a_ops;
  unsigned long           flags;
  errseq_t                wb_err;
  spinlock_t              private_lock;
  struct list_head        private_list;
  void                    *private_data;
} __attribute__((aligned(sizeof(long)))) __randomize_layout;

struct address_space_operations {
  int (*writepage)(struct page *page, struct writeback_control *wbc);
  int (*readpage)(struct file *, struct page *);

  /* Write back some dirty pages from this mapping. */
  int (*writepages)(struct address_space *, struct writeback_control *);

  /* Set a page dirty.  Return true if this dirtied it */
  int (*set_page_dirty)(struct page *page);

  /*
   * Reads in the requested pages. Unlike ->readpage(), this is
   * PURELY used for read-ahead!.
   */
  int (*readpages)(struct file *filp, struct address_space *mapping,
                  struct list_head *pages, unsigned nr_pages);
  void (*readahead)(struct readahead_control *);

  int (*write_begin)(struct file *, struct address_space *mapping,
                          loff_t pos, unsigned len, unsigned flags,
                          struct page **pagep, void **fsdata);
  int (*write_end)(struct file *, struct address_space *mapping,
                          loff_t pos, unsigned len, unsigned copied,
                          struct page *page, void *fsdata);

  /* Unfortunately this kludge is needed for FIBMAP. Don't use it */
  sector_t (*bmap)(struct address_space *, sector_t);
  void (*invalidatepage) (struct page *, unsigned int, unsigned int);
  int (*releasepage) (struct page *, gfp_t);
  void (*freepage)(struct page *);
  ssize_t (*direct_IO)(struct kiocb *, struct iov_iter *iter);
  /*
   * migrate the contents of a page to the specified target. If
   * migrate_mode is MIGRATE_ASYNC, it must not block.
   */
  int (*migratepage) (struct address_space *,
                  struct page *, struct page *, enum migrate_mode);
  bool (*isolate_page)(struct page *, isolate_mode_t);
  void (*putback_page)(struct page *);
  int (*launder_page) (struct page *);
  int (*is_partially_uptodate) (struct page *, unsigned long,
                                  unsigned long);
  void (*is_dirty_writeback) (struct page *, bool *, bool *);
  int (*error_remove_page)(struct address_space *, struct page *);

  /* swapfile support */
  int (*swap_activate)(struct swap_info_struct *sis, struct file *file,
                          sector_t *span);
  void (*swap_deactivate)(struct file *file);
};

读取数据

/**
 * generic_file_read_iter——通用的文件系统读取例程
 * @iocb: 内核 I/O 控制块
 * @iter: 用于存储读取数据的目标
 *
 * 这是所有可以直接使用页面缓存的文件系统的“read_iter()”例程。
 *
 * iocb->ki_flags 中的 IOCB_NOWAIT 标志表示,当没有数据可以在等待 I/O 请求完成的情况下读取时,应返回 -EAGAIN;它不会阻止预读。
 *
 * iocb->ki_flags 中的 IOCB_NOIO 标志表示,对于读取或预读,不应发起新的 I/O 请求。当无法读取数据时,应返回 -EAGAIN。当触发预读时,应返回部分(可能为空)读取。
 *
 * 返回:
 * * 拷贝的字节数,即使是部分读取
 * * 负错误代码(如果 IOCB_NOIO)表示没有读取任何内容
 */
ssize_t
generic_file_read_iter(struct kiocb *iocb, struct iov_iter *iter)

/*
 * 用于具有正常 get_block 功能的块设备的通用“读取页面”函数。这适用于大多数块设备文件系统。
 * 异步读取页面——unlock_buffer() 和 set/clear_buffer_uptodate() 函数在 IO 完成后将缓冲区状态传播到页面结构中。
 */
int block_read_full_page(struct page *page, get_block_t *get_block)