| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761 |
- .. SPDX-License-Identifier: GPL-2.0
- Journal (jbd2)
- --------------
- Introduced in ext3, the ext4 filesystem employs a journal to protect the
- filesystem against metadata inconsistencies in the case of a system crash. Up
- to 10,240,000 file system blocks (see man mke2fs(8) for more details on journal
- size limits) can be reserved inside the filesystem as a place to land
- “important” data writes on-disk as quickly as possible. Once the important
- data transaction is fully written to the disk and flushed from the disk write
- cache, a record of the data being committed is also written to the journal. At
- some later point in time, the journal code writes the transactions to their
- final locations on disk (this could involve a lot of seeking or a lot of small
- read-write-erases) before erasing the commit record. Should the system
- crash during the second slow write, the journal can be replayed all the
- way to the latest commit record, guaranteeing the atomicity of whatever
- gets written through the journal to the disk. The effect of this is to
- guarantee that the filesystem does not become stuck midway through a
- metadata update.
- For performance reasons, ext4 by default only writes filesystem metadata
- through the journal. This means that file data blocks are /not/
- guaranteed to be in any consistent state after a crash. If this default
- guarantee level (``data=ordered``) is not satisfactory, there is a mount
- option to control journal behavior. If ``data=journal``, all data and
- metadata are written to disk through the journal. This is slower but
- safest. If ``data=writeback``, dirty data blocks are not flushed to the
- disk before the metadata are written to disk through the journal.
- In case of ``data=ordered`` mode, Ext4 also supports fast commits which
- help reduce commit latency significantly. The default ``data=ordered``
- mode works by logging metadata blocks to the journal. In fast commit
- mode, Ext4 only stores the minimal delta needed to recreate the
- affected metadata in fast commit space that is shared with JBD2.
- Once the fast commit area fills in or if fast commit is not possible
- or if JBD2 commit timer goes off, Ext4 performs a traditional full commit.
- A full commit invalidates all the fast commits that happened before
- it and thus it makes the fast commit area empty for further fast
- commits. This feature needs to be enabled at mkfs time.
- The journal inode is typically inode 8. The first 68 bytes of the
- journal inode are replicated in the ext4 superblock. The journal itself
- is normal (but hidden) file within the filesystem. The file usually
- consumes an entire block group, though mke2fs tries to put it in the
- middle of the disk.
- All fields in jbd2 are written to disk in big-endian order. This is the
- opposite of ext4.
- NOTE: Both ext4 and ocfs2 use jbd2.
- The maximum size of a journal embedded in an ext4 filesystem is 2^32
- blocks. jbd2 itself does not seem to care.
- Layout
- ~~~~~~
- Generally speaking, the journal has this format:
- .. list-table::
- :widths: 16 48 16
- :header-rows: 1
- * - Superblock
- - descriptor_block (data_blocks or revocation_block) [more data or
- revocations] commmit_block
- - [more transactions...]
- * -
- - One transaction
- -
- Notice that a transaction begins with either a descriptor and some data,
- or a block revocation list. A finished transaction always ends with a
- commit. If there is no commit record (or the checksums don't match), the
- transaction will be discarded during replay.
- External Journal
- ~~~~~~~~~~~~~~~~
- Optionally, an ext4 filesystem can be created with an external journal
- device (as opposed to an internal journal, which uses a reserved inode).
- In this case, on the filesystem device, ``s_journal_inum`` should be
- zero and ``s_journal_uuid`` should be set. On the journal device there
- will be an ext4 super block in the usual place, with a matching UUID.
- The journal superblock will be in the next full block after the
- superblock.
- .. list-table::
- :widths: 12 12 12 32 12
- :header-rows: 1
- * - 1024 bytes of padding
- - ext4 Superblock
- - Journal Superblock
- - descriptor_block (data_blocks or revocation_block) [more data or
- revocations] commmit_block
- - [more transactions...]
- * -
- -
- -
- - One transaction
- -
- Block Header
- ~~~~~~~~~~~~
- Every block in the journal starts with a common 12-byte header
- ``struct journal_header_s``:
- .. list-table::
- :widths: 8 8 24 40
- :header-rows: 1
- * - Offset
- - Type
- - Name
- - Description
- * - 0x0
- - __be32
- - h_magic
- - jbd2 magic number, 0xC03B3998.
- * - 0x4
- - __be32
- - h_blocktype
- - Description of what this block contains. See the jbd2_blocktype_ table
- below.
- * - 0x8
- - __be32
- - h_sequence
- - The transaction ID that goes with this block.
- .. _jbd2_blocktype:
- The journal block type can be any one of:
- .. list-table::
- :widths: 16 64
- :header-rows: 1
- * - Value
- - Description
- * - 1
- - Descriptor. This block precedes a series of data blocks that were
- written through the journal during a transaction.
- * - 2
- - Block commit record. This block signifies the completion of a
- transaction.
- * - 3
- - Journal superblock, v1.
- * - 4
- - Journal superblock, v2.
- * - 5
- - Block revocation records. This speeds up recovery by enabling the
- journal to skip writing blocks that were subsequently rewritten.
- Super Block
- ~~~~~~~~~~~
- The super block for the journal is much simpler as compared to ext4's.
- The key data kept within are size of the journal, and where to find the
- start of the log of transactions.
- The journal superblock is recorded as ``struct journal_superblock_s``,
- which is 1024 bytes long:
- .. list-table::
- :widths: 8 8 24 40
- :header-rows: 1
- * - Offset
- - Type
- - Name
- - Description
- * -
- -
- -
- - Static information describing the journal.
- * - 0x0
- - journal_header_t (12 bytes)
- - s_header
- - Common header identifying this as a superblock.
- * - 0xC
- - __be32
- - s_blocksize
- - Journal device block size.
- * - 0x10
- - __be32
- - s_maxlen
- - Total number of blocks in this journal.
- * - 0x14
- - __be32
- - s_first
- - First block of log information.
- * -
- -
- -
- - Dynamic information describing the current state of the log.
- * - 0x18
- - __be32
- - s_sequence
- - First commit ID expected in log.
- * - 0x1C
- - __be32
- - s_start
- - Block number of the start of log. Contrary to the comments, this field
- being zero does not imply that the journal is clean!
- * - 0x20
- - __be32
- - s_errno
- - Error value, as set by jbd2_journal_abort().
- * -
- -
- -
- - The remaining fields are only valid in a v2 superblock.
- * - 0x24
- - __be32
- - s_feature_compat;
- - Compatible feature set. See the table jbd2_compat_ below.
- * - 0x28
- - __be32
- - s_feature_incompat
- - Incompatible feature set. See the table jbd2_incompat_ below.
- * - 0x2C
- - __be32
- - s_feature_ro_compat
- - Read-only compatible feature set. There aren't any of these currently.
- * - 0x30
- - __u8
- - s_uuid[16]
- - 128-bit uuid for journal. This is compared against the copy in the ext4
- super block at mount time.
- * - 0x40
- - __be32
- - s_nr_users
- - Number of file systems sharing this journal.
- * - 0x44
- - __be32
- - s_dynsuper
- - Location of dynamic super block copy. (Not used?)
- * - 0x48
- - __be32
- - s_max_transaction
- - Limit of journal blocks per transaction. (Not used?)
- * - 0x4C
- - __be32
- - s_max_trans_data
- - Limit of data blocks per transaction. (Not used?)
- * - 0x50
- - __u8
- - s_checksum_type
- - Checksum algorithm used for the journal. See jbd2_checksum_type_ for
- more info.
- * - 0x51
- - __u8[3]
- - s_padding2
- -
- * - 0x54
- - __be32
- - s_num_fc_blocks
- - Number of fast commit blocks in the journal.
- * - 0x58
- - __be32
- - s_head
- - Block number of the head (first unused block) of the journal, only
- up-to-date when the journal is empty.
- * - 0x5C
- - __u32
- - s_padding[40]
- -
- * - 0xFC
- - __be32
- - s_checksum
- - Checksum of the entire superblock, with this field set to zero.
- * - 0x100
- - __u8
- - s_users[16*48]
- - ids of all file systems sharing the log. e2fsprogs/Linux don't allow
- shared external journals, but I imagine Lustre (or ocfs2?), which use
- the jbd2 code, might.
- .. _jbd2_compat:
- The journal compat features are any combination of the following:
- .. list-table::
- :widths: 16 64
- :header-rows: 1
- * - Value
- - Description
- * - 0x1
- - Journal maintains checksums on the data blocks.
- (JBD2_FEATURE_COMPAT_CHECKSUM)
- .. _jbd2_incompat:
- The journal incompat features are any combination of the following:
- .. list-table::
- :widths: 16 64
- :header-rows: 1
- * - Value
- - Description
- * - 0x1
- - Journal has block revocation records. (JBD2_FEATURE_INCOMPAT_REVOKE)
- * - 0x2
- - Journal can deal with 64-bit block numbers.
- (JBD2_FEATURE_INCOMPAT_64BIT)
- * - 0x4
- - Journal commits asynchronously. (JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT)
- * - 0x8
- - This journal uses v2 of the checksum on-disk format. Each journal
- metadata block gets its own checksum, and the block tags in the
- descriptor table contain checksums for each of the data blocks in the
- journal. (JBD2_FEATURE_INCOMPAT_CSUM_V2)
- * - 0x10
- - This journal uses v3 of the checksum on-disk format. This is the same as
- v2, but the journal block tag size is fixed regardless of the size of
- block numbers. (JBD2_FEATURE_INCOMPAT_CSUM_V3)
- * - 0x20
- - Journal has fast commit blocks. (JBD2_FEATURE_INCOMPAT_FAST_COMMIT)
- .. _jbd2_checksum_type:
- Journal checksum type codes are one of the following. crc32 or crc32c are the
- most likely choices.
- .. list-table::
- :widths: 16 64
- :header-rows: 1
- * - Value
- - Description
- * - 1
- - CRC32
- * - 2
- - MD5
- * - 3
- - SHA1
- * - 4
- - CRC32C
- Descriptor Block
- ~~~~~~~~~~~~~~~~
- The descriptor block contains an array of journal block tags that
- describe the final locations of the data blocks that follow in the
- journal. Descriptor blocks are open-coded instead of being completely
- described by a data structure, but here is the block structure anyway.
- Descriptor blocks consume at least 36 bytes, but use a full block:
- .. list-table::
- :widths: 8 8 24 40
- :header-rows: 1
- * - Offset
- - Type
- - Name
- - Descriptor
- * - 0x0
- - journal_header_t
- - (open coded)
- - Common block header.
- * - 0xC
- - struct journal_block_tag_s
- - open coded array[]
- - Enough tags either to fill up the block or to describe all the data
- blocks that follow this descriptor block.
- Journal block tags have any of the following formats, depending on which
- journal feature and block tag flags are set.
- If JBD2_FEATURE_INCOMPAT_CSUM_V3 is set, the journal block tag is
- defined as ``struct journal_block_tag3_s``, which looks like the
- following. The size is 16 or 32 bytes.
- .. list-table::
- :widths: 8 8 24 40
- :header-rows: 1
- * - Offset
- - Type
- - Name
- - Descriptor
- * - 0x0
- - __be32
- - t_blocknr
- - Lower 32-bits of the location of where the corresponding data block
- should end up on disk.
- * - 0x4
- - __be32
- - t_flags
- - Flags that go with the descriptor. See the table jbd2_tag_flags_ for
- more info.
- * - 0x8
- - __be32
- - t_blocknr_high
- - Upper 32-bits of the location of where the corresponding data block
- should end up on disk. This is zero if JBD2_FEATURE_INCOMPAT_64BIT is
- not enabled.
- * - 0xC
- - __be32
- - t_checksum
- - Checksum of the journal UUID, the sequence number, and the data block.
- * -
- -
- -
- - This field appears to be open coded. It always comes at the end of the
- tag, after t_checksum. This field is not present if the "same UUID" flag
- is set.
- * - 0x8 or 0xC
- - char
- - uuid[16]
- - A UUID to go with this tag. This field appears to be copied from the
- ``j_uuid`` field in ``struct journal_s``, but only tune2fs touches that
- field.
- .. _jbd2_tag_flags:
- The journal tag flags are any combination of the following:
- .. list-table::
- :widths: 16 64
- :header-rows: 1
- * - Value
- - Description
- * - 0x1
- - On-disk block is escaped. The first four bytes of the data block just
- happened to match the jbd2 magic number.
- * - 0x2
- - This block has the same UUID as previous, therefore the UUID field is
- omitted.
- * - 0x4
- - The data block was deleted by the transaction. (Not used?)
- * - 0x8
- - This is the last tag in this descriptor block.
- If JBD2_FEATURE_INCOMPAT_CSUM_V3 is NOT set, the journal block tag
- is defined as ``struct journal_block_tag_s``, which looks like the
- following. The size is 8, 12, 24, or 28 bytes:
- .. list-table::
- :widths: 8 8 24 40
- :header-rows: 1
- * - Offset
- - Type
- - Name
- - Descriptor
- * - 0x0
- - __be32
- - t_blocknr
- - Lower 32-bits of the location of where the corresponding data block
- should end up on disk.
- * - 0x4
- - __be16
- - t_checksum
- - Checksum of the journal UUID, the sequence number, and the data block.
- Note that only the lower 16 bits are stored.
- * - 0x6
- - __be16
- - t_flags
- - Flags that go with the descriptor. See the table jbd2_tag_flags_ for
- more info.
- * -
- -
- -
- - This next field is only present if the super block indicates support for
- 64-bit block numbers.
- * - 0x8
- - __be32
- - t_blocknr_high
- - Upper 32-bits of the location of where the corresponding data block
- should end up on disk.
- * -
- -
- -
- - This field appears to be open coded. It always comes at the end of the
- tag, after t_flags or t_blocknr_high. This field is not present if the
- "same UUID" flag is set.
- * - 0x8 or 0xC
- - char
- - uuid[16]
- - A UUID to go with this tag. This field appears to be copied from the
- ``j_uuid`` field in ``struct journal_s``, but only tune2fs touches that
- field.
- If JBD2_FEATURE_INCOMPAT_CSUM_V2 or
- JBD2_FEATURE_INCOMPAT_CSUM_V3 are set, the end of the block is a
- ``struct jbd2_journal_block_tail``, which looks like this:
- .. list-table::
- :widths: 8 8 24 40
- :header-rows: 1
- * - Offset
- - Type
- - Name
- - Descriptor
- * - 0x0
- - __be32
- - t_checksum
- - Checksum of the journal UUID + the descriptor block, with this field set
- to zero.
- Data Block
- ~~~~~~~~~~
- In general, the data blocks being written to disk through the journal
- are written verbatim into the journal file after the descriptor block.
- However, if the first four bytes of the block match the jbd2 magic
- number then those four bytes are replaced with zeroes and the “escaped”
- flag is set in the descriptor block tag.
- Revocation Block
- ~~~~~~~~~~~~~~~~
- A revocation block is used to prevent replay of a block in an earlier
- transaction. This is used to mark blocks that were journalled at one
- time but are no longer journalled. Typically this happens if a metadata
- block is freed and re-allocated as a file data block; in this case, a
- journal replay after the file block was written to disk will cause
- corruption.
- **NOTE**: This mechanism is NOT used to express “this journal block is
- superseded by this other journal block”, as the author (djwong)
- mistakenly thought. Any block being added to a transaction will cause
- the removal of all existing revocation records for that block.
- Revocation blocks are described in
- ``struct jbd2_journal_revoke_header_s``, are at least 16 bytes in
- length, but use a full block:
- .. list-table::
- :widths: 8 8 24 40
- :header-rows: 1
- * - Offset
- - Type
- - Name
- - Description
- * - 0x0
- - journal_header_t
- - r_header
- - Common block header.
- * - 0xC
- - __be32
- - r_count
- - Number of bytes used in this block.
- * - 0x10
- - __be32 or __be64
- - blocks[0]
- - Blocks to revoke.
- After r_count is a linear array of block numbers that are effectively
- revoked by this transaction. The size of each block number is 8 bytes if
- the superblock advertises 64-bit block number support, or 4 bytes
- otherwise.
- If JBD2_FEATURE_INCOMPAT_CSUM_V2 or
- JBD2_FEATURE_INCOMPAT_CSUM_V3 are set, the end of the revocation
- block is a ``struct jbd2_journal_revoke_tail``, which has this format:
- .. list-table::
- :widths: 8 8 24 40
- :header-rows: 1
- * - Offset
- - Type
- - Name
- - Description
- * - 0x0
- - __be32
- - r_checksum
- - Checksum of the journal UUID + revocation block
- Commit Block
- ~~~~~~~~~~~~
- The commit block is a sentry that indicates that a transaction has been
- completely written to the journal. Once this commit block reaches the
- journal, the data stored with this transaction can be written to their
- final locations on disk.
- The commit block is described by ``struct commit_header``, which is 32
- bytes long (but uses a full block):
- .. list-table::
- :widths: 8 8 24 40
- :header-rows: 1
- * - Offset
- - Type
- - Name
- - Descriptor
- * - 0x0
- - journal_header_s
- - (open coded)
- - Common block header.
- * - 0xC
- - unsigned char
- - h_chksum_type
- - The type of checksum to use to verify the integrity of the data blocks
- in the transaction. See jbd2_checksum_type_ for more info.
- * - 0xD
- - unsigned char
- - h_chksum_size
- - The number of bytes used by the checksum. Most likely 4.
- * - 0xE
- - unsigned char
- - h_padding[2]
- -
- * - 0x10
- - __be32
- - h_chksum[JBD2_CHECKSUM_BYTES]
- - 32 bytes of space to store checksums. If
- JBD2_FEATURE_INCOMPAT_CSUM_V2 or JBD2_FEATURE_INCOMPAT_CSUM_V3
- are set, the first ``__be32`` is the checksum of the journal UUID and
- the entire commit block, with this field zeroed. If
- JBD2_FEATURE_COMPAT_CHECKSUM is set, the first ``__be32`` is the
- crc32 of all the blocks already written to the transaction.
- * - 0x30
- - __be64
- - h_commit_sec
- - The time that the transaction was committed, in seconds since the epoch.
- * - 0x38
- - __be32
- - h_commit_nsec
- - Nanoseconds component of the above timestamp.
- Fast commits
- ~~~~~~~~~~~~
- Fast commit area is organized as a log of tag length values. Each TLV has
- a ``struct ext4_fc_tl`` in the beginning which stores the tag and the length
- of the entire field. It is followed by variable length tag specific value.
- Here is the list of supported tags and their meanings:
- .. list-table::
- :widths: 8 20 20 32
- :header-rows: 1
- * - Tag
- - Meaning
- - Value struct
- - Description
- * - EXT4_FC_TAG_HEAD
- - Fast commit area header
- - ``struct ext4_fc_head``
- - Stores the TID of the transaction after which these fast commits should
- be applied.
- * - EXT4_FC_TAG_ADD_RANGE
- - Add extent to inode
- - ``struct ext4_fc_add_range``
- - Stores the inode number and extent to be added in this inode
- * - EXT4_FC_TAG_DEL_RANGE
- - Remove logical offsets to inode
- - ``struct ext4_fc_del_range``
- - Stores the inode number and the logical offset range that needs to be
- removed
- * - EXT4_FC_TAG_CREAT
- - Create directory entry for a newly created file
- - ``struct ext4_fc_dentry_info``
- - Stores the parent inode number, inode number and directory entry of the
- newly created file
- * - EXT4_FC_TAG_LINK
- - Link a directory entry to an inode
- - ``struct ext4_fc_dentry_info``
- - Stores the parent inode number, inode number and directory entry
- * - EXT4_FC_TAG_UNLINK
- - Unlink a directory entry of an inode
- - ``struct ext4_fc_dentry_info``
- - Stores the parent inode number, inode number and directory entry
- * - EXT4_FC_TAG_PAD
- - Padding (unused area)
- - None
- - Unused bytes in the fast commit area.
- * - EXT4_FC_TAG_TAIL
- - Mark the end of a fast commit
- - ``struct ext4_fc_tail``
- - Stores the TID of the commit, CRC of the fast commit of which this tag
- represents the end of
- Fast Commit Replay Idempotence
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Fast commits tags are idempotent in nature provided the recovery code follows
- certain rules. The guiding principle that the commit path follows while
- committing is that it stores the result of a particular operation instead of
- storing the procedure.
- Let's consider this rename operation: 'mv /a /b'. Let's assume dirent '/a'
- was associated with inode 10. During fast commit, instead of storing this
- operation as a procedure "rename a to b", we store the resulting file system
- state as a "series" of outcomes:
- - Link dirent b to inode 10
- - Unlink dirent a
- - Inode 10 with valid refcount
- Now when recovery code runs, it needs "enforce" this state on the file
- system. This is what guarantees idempotence of fast commit replay.
- Let's take an example of a procedure that is not idempotent and see how fast
- commits make it idempotent. Consider following sequence of operations:
- 1) rm A
- 2) mv B A
- 3) read A
- If we store this sequence of operations as is then the replay is not idempotent.
- Let's say while in replay, we crash after (2). During the second replay,
- file A (which was actually created as a result of "mv B A" operation) would get
- deleted. Thus, file named A would be absent when we try to read A. So, this
- sequence of operations is not idempotent. However, as mentioned above, instead
- of storing the procedure fast commits store the outcome of each procedure. Thus
- the fast commit log for above procedure would be as follows:
- (Let's assume dirent A was linked to inode 10 and dirent B was linked to
- inode 11 before the replay)
- 1) Unlink A
- 2) Link A to inode 11
- 3) Unlink B
- 4) Inode 11
- If we crash after (3) we will have file A linked to inode 11. During the second
- replay, we will remove file A (inode 11). But we will create it back and make
- it point to inode 11. We won't find B, so we'll just skip that step. At this
- point, the refcount for inode 11 is not reliable, but that gets fixed by the
- replay of last inode 11 tag. Thus, by converting a non-idempotent procedure
- into a series of idempotent outcomes, fast commits ensured idempotence during
- the replay.
- Journal Checkpoint
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Checkpointing the journal ensures all transactions and their associated buffers
- are submitted to the disk. In-progress transactions are waited upon and included
- in the checkpoint. Checkpointing is used internally during critical updates to
- the filesystem including journal recovery, filesystem resizing, and freeing of
- the journal_t structure.
- A journal checkpoint can be triggered from userspace via the ioctl
- EXT4_IOC_CHECKPOINT. This ioctl takes a single, u64 argument for flags.
- Currently, three flags are supported. First, EXT4_IOC_CHECKPOINT_FLAG_DRY_RUN
- can be used to verify input to the ioctl. It returns error if there is any
- invalid input, otherwise it returns success without performing
- any checkpointing. This can be used to check whether the ioctl exists on a
- system and to verify there are no issues with arguments or flags. The
- other two flags are EXT4_IOC_CHECKPOINT_FLAG_DISCARD and
- EXT4_IOC_CHECKPOINT_FLAG_ZEROOUT. These flags cause the journal blocks to be
- discarded or zero-filled, respectively, after the journal checkpoint is
- complete. EXT4_IOC_CHECKPOINT_FLAG_DISCARD and EXT4_IOC_CHECKPOINT_FLAG_ZEROOUT
- cannot both be set. The ioctl may be useful when snapshotting a system or for
- complying with content deletion SLOs.
|