在f2fs读写文件的时候,每修改一个块,都会改动f2fs_node的地址映射和NAT、SIT信息。为了避免频繁刷盘,f2fs将这种小变化写到journal里,在CP的时候再写入磁盘。

journal相关的数据结构有

struct f2fs_journal {
	union {
		__le16 n_nats; /* 这个journal里面包含多少个nat_journal对象 */
		__le16 n_sits; /* 这个journal里面包含多少个sit_journal对象 */
	};
	/* spare area is used by NAT or SIT journals or extra info */
	union {
		struct nat_journal nat_j;
		struct sit_journal sit_j;
		struct f2fs_extra_info info;
	};
} __packed;

这表示一个f2fs_journal要么保存nat,要么保存sit。

nat journal:

struct nat_journal {
	struct nat_journal_entry entries[NAT_JOURNAL_ENTRIES];
	__u8 reserved[NAT_JOURNAL_RESERVED];
} __packed;

struct nat_journal_entry {
	__le32 nid;
	struct f2fs_nat_entry ne;
} __packed;

struct f2fs_nat_entry {
	__u8 version;		/* latest version of cached nat entry */
	__le32 ino;		/* inode number */
	__le32 block_addr;	/* block address */
} __packed;

sit journal

struct sit_journal {
	struct sit_journal_entry entries[SIT_JOURNAL_ENTRIES];
	__u8 reserved[SIT_JOURNAL_RESERVED];
} __packed;

struct sit_journal_entry {
	__le32 segno;
	struct f2fs_sit_entry se;
} __packed;

struct f2fs_sit_entry {
	__le16 vblocks;				/* reference above */
	__u8 valid_map[SIT_VBLOCK_MAP_SIZE];	/* SIT_VBLOCK_MAP_SIZE = 64,64 * 8 = 512 可以表示每一个块的valid状态 */
	__le64 mtime;				/* segment age for cleaning */
} __packed;

在f2fs_get_node_info中,首先在journal中找到地址。如果没找到,再去读盘上的f2fs_nat_block。

在cp的时候,将journal的信息写盘。

  1. f2fs_flush_nat_entries 和 f2fs_flush_sit_entries 函数将entry都写入到 curseg_info->f2fs_summary->journal 的变量中。
  2. do_checkpoint函数 读取 curseg_info->f2fs_summary,然后通过函数f2fs_write_node_summariesf2fs_write_data_summaries` 刷写到磁盘中。