요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.
1. 요약·해설
원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.
2. 영어 원문 전체
번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.
원문 전체 펼치기
The Linux Journalling API
=========================
Overview
--------
Details
~~~~~~~
The journalling layer is easy to use. You need to first of all create a
journal_t data structure. There are two calls to do this dependent on
how you decide to allocate the physical media on which the journal
resides. The jbd2_journal_init_inode() call is for journals stored in
filesystem inodes, or the jbd2_journal_init_dev() call can be used
for journal stored on a raw device (in a continuous range of blocks). A
journal_t is a typedef for a struct pointer, so when you are finally
finished make sure you call jbd2_journal_destroy() on it to free up
any used kernel memory.
Once you have got your journal_t object you need to 'mount' or load the
journal file. The journalling layer expects the space for the journal
was already allocated and initialized properly by the userspace tools.
When loading the journal you must call jbd2_journal_load() to process
journal contents. If the client file system detects the journal contents
does not need to be processed (or even need not have valid contents), it
may call jbd2_journal_wipe() to clear the journal contents before
calling jbd2_journal_load().
Note that jbd2_journal_wipe(..,0) calls
jbd2_journal_skip_recovery() for you if it detects any outstanding
transactions in the journal and similarly jbd2_journal_load() will
call jbd2_journal_recover() if necessary. I would advise reading
ext4_load_journal() in fs/ext4/super.c for examples on this stage.
Now you can go ahead and start modifying the underlying filesystem.
Almost.
You still need to actually journal your filesystem changes, this is done
by wrapping them into transactions. Additionally you also need to wrap
the modification of each of the buffers with calls to the journal layer,
so it knows what the modifications you are actually making are. To do
this use jbd2_journal_start() which returns a transaction handle.
jbd2_journal_start() and its counterpart jbd2_journal_stop(),
which indicates the end of a transaction are nestable calls, so you can
reenter a transaction if necessary, but remember you must call
jbd2_journal_stop() the same number of times as
jbd2_journal_start() before the transaction is completed (or more
accurately leaves the update phase). Ext4/VFS makes use of this feature to
simplify handling of inode dirtying, quota support, etc.
Inside each transaction you need to wrap the modifications to the
individual buffers (blocks). Before you start to modify a buffer you
need to call jbd2_journal_get_create_access() /
jbd2_journal_get_write_access() /
jbd2_journal_get_undo_access() as appropriate, this allows the
journalling layer to copy the unmodified
data if it needs to. After all the buffer may be part of a previously
uncommitted transaction. At this point you are at last ready to modify a
buffer, and once you are have done so you need to call
jbd2_journal_dirty_metadata(). Or if you've asked for access to a
buffer you now know is now longer required to be pushed back on the
device you can call jbd2_journal_forget() in much the same way as you
might have used bforget() in the past.
A jbd2_journal_flush() may be called at any time to commit and
checkpoint all your transactions.
Then at umount time , in your put_super() you can then call
jbd2_journal_destroy() to clean up your in-core journal object.
Unfortunately there a couple of ways the journal layer can cause a
deadlock. The first thing to note is that each task can only have a
single outstanding transaction at any one time, remember nothing commits
until the outermost jbd2_journal_stop(). This means you must complete
the transaction at the end of each file/inode/address etc. operation you
perform, so that the journalling system isn't re-entered on another
journal. Since transactions can't be nested/batched across differing
journals, and another filesystem other than yours (say ext4) may be
modified in a later syscall.
The second case to bear in mind is that jbd2_journal_start() can block
if there isn't enough space in the journal for your transaction (based
on the passed nblocks param) - when it blocks it merely(!) needs to wait
for transactions to complete and be committed from other tasks, so
essentially we are waiting for jbd2_journal_stop(). So to avoid
deadlocks you must treat jbd2_journal_start() /
jbd2_journal_stop() as if they were semaphores and include them in
your semaphore ordering rules to prevent
deadlocks. Note that jbd2_journal_extend() has similar blocking
behaviour to jbd2_journal_start() so you can deadlock here just as
easily as on jbd2_journal_start().
Try to reserve the right number of blocks the first time. ;-). This will
be the maximum number of blocks you are going to touch in this
transaction. I advise having a look at at least ext4_jbd.h to see the
basis on which ext4 uses to make these decisions.
Another wriggle to watch out for is your on-disk block allocation
strategy. Why? Because, if you do a delete, you need to ensure you
haven't reused any of the freed blocks until the transaction freeing
these blocks commits. If you reused these blocks and crash happens,
there is no way to restore the contents of the reallocated blocks at the
end of the last fully committed transaction. One simple way of doing
this is to mark blocks as free in internal in-memory block allocation
structures only after the transaction freeing them commits. Ext4 uses
journal commit callback for this purpose.
With journal commit callbacks you can ask the journalling layer to call
a callback function when the transaction is finally committed to disk,
so that you can do some of your own management. You ask the journalling
layer for calling the callback by simply setting
``journal->j_commit_callback`` function pointer and that function is
called after each transaction commit.
JBD2 also provides a way to block all transaction updates via
jbd2_journal_lock_updates() /
jbd2_journal_unlock_updates(). Ext4 uses this when it wants a
window with a clean and stable fs for a moment. E.g.
::
jbd2_journal_lock_updates() //stop new stuff happening..
jbd2_journal_flush() // checkpoint everything.
..do stuff on stable fs
jbd2_journal_unlock_updates() // carry on with filesystem use.
The opportunities for abuse and DOS attacks with this should be obvious,
if you allow unprivileged userspace to trigger codepaths containing
these calls.
Fast commits
~~~~~~~~~~~~
JBD2 to also allows you to perform file-system specific delta commits known as
fast commits. In order to use fast commits, you will need to set following
callbacks that perform corresponding work:
`journal->j_fc_cleanup_cb`: Cleanup function called after every full commit and
fast commit.
`journal->j_fc_replay_cb`: Replay function called for replay of fast commit
blocks.
File system is free to perform fast commits as and when it wants as long as it
gets permission from JBD2 to do so by calling the function
:c:func:`jbd2_fc_begin_commit()`. Once a fast commit is done, the client
file system should tell JBD2 about it by calling
:c:func:`jbd2_fc_end_commit()`. If the file system wants JBD2 to perform a full
commit immediately after stopping the fast commit it can do so by calling
:c:func:`jbd2_fc_end_commit_fallback()`. This is useful if fast commit operation
fails for some reason and the only way to guarantee consistency is for JBD2 to
perform the full traditional commit.
JBD2 helper functions to manage fast commit buffers. File system can use
:c:func:`jbd2_fc_get_buf()` and :c:func:`jbd2_fc_wait_bufs()` to allocate
and wait on IO completion of fast commit buffers.
Currently, only Ext4 implements fast commits. For details of its implementation
of fast commits, please refer to the top level comments in
fs/ext4/fast_commit.c.
Summary
~~~~~~~
Using the journal is a matter of wrapping the different context changes,
being each mount, each modification (transaction) and each changed
buffer to tell the journalling layer about them.
Data Types
----------
The journalling layer uses typedefs to 'hide' the concrete definitions
of the structures used. As a client of the JBD2 layer you can just rely
on the using the pointer as a magic cookie of some sort. Obviously the
hiding is not enforced as this is 'C'.
Structures
~~~~~~~~~~
.. kernel-doc:: include/linux/jbd2.h
:internal:
Functions
---------
The functions here are split into two groups those that affect a journal
as a whole, and those which are used to manage transactions
Journal Level
~~~~~~~~~~~~~
.. kernel-doc:: fs/jbd2/journal.c
:export:
.. kernel-doc:: fs/jbd2/recovery.c
:internal:
Transaction Level
~~~~~~~~~~~~~~~~~~
.. kernel-doc:: fs/jbd2/transaction.c
See also
--------
`Journaling the Linux ext2fs Filesystem, LinuxExpo 98, Stephen
Tweedie <http://kernel.org/pub/linux/kernel/people/sct/ext3/journal-design.ps.gz>`__
`Ext3 Journalling FileSystem, OLS 2000, Dr. Stephen
Tweedie <http://olstrans.sourceforge.net/release/OLS2000-ext3/OLS2000-ext3.html>`__
3. 한국어 전문 번역
영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.
journal 객체 생성과 복구 로드
1-43Linux journalling API를 사용하려면 먼저 `journal_t` 자료구조를 만듭니다. Journal이 파일시스템 inode에 저장되면 `jbd2_journal_init_inode()`, raw device의 연속 블록 범위에 저장되면 `jbd2_journal_init_dev()`를 사용합니다. `journal_t`는 구조체 포인터 typedef이므로 작업을 끝낼 때 `jbd2_journal_destroy()`를 호출해 사용한 커널 메모리를 해제해야 합니다.
객체를 만든 다음 journal 파일을 mount, 즉 load합니다. Journal 공간은 userspace 도구가 미리 할당하고 올바르게 초기화했다고 전제합니다. `jbd2_journal_load()`가 journal 내용을 처리하며, client 파일시스템이 내용을 처리할 필요가 없거나 유효할 필요조차 없다고 판단하면 load 전에 `jbd2_journal_wipe()`로 지울 수 있습니다.
`jbd2_journal_wipe(..., 0)`은 미완료 transaction을 발견하면 `jbd2_journal_skip_recovery()`를 대신 호출합니다. `jbd2_journal_load()`도 필요할 경우 `jbd2_journal_recover()`를 호출합니다. 이 단계의 실제 예는 `fs/ext4/super.c`의 `ext4_load_journal()`에서 볼 수 있습니다.
이제 하위 파일시스템을 수정할 수 있지만, 변경을 transaction으로 감싸고 각 buffer 변경도 journal layer 호출로 감싸야 합니다. `jbd2_journal_start()`가 transaction handle을 반환하면서 이 과정을 시작합니다.
저장 위치에 맞는 생성 함수에서 복구 가능한 journal 로드까지 이어집니다.
The Linux Journalling API
=========================
Overview
--------
Details
~~~~~~~
The journalling layer is easy to use. You need to first of all create a
journal_t data structure. There are two calls to do this dependent on
how you decide to allocate the physical media on which the journal
resides. The jbd2_journal_init_inode() call is for journals stored in
filesystem inodes, or the jbd2_journal_init_dev() call can be used
for journal stored on a raw device (in a continuous range of blocks). A
journal_t is a typedef for a struct pointer, so when you are finally
finished make sure you call jbd2_journal_destroy() on it to free up
any used kernel memory.
Once you have got your journal_t object you need to 'mount' or load the
journal file. The journalling layer expects the space for the journal
was already allocated and initialized properly by the userspace tools.
When loading the journal you must call jbd2_journal_load() to process
journal contents. If the client file system detects the journal contents
does not need to be processed (or even need not have valid contents), it
may call jbd2_journal_wipe() to clear the journal contents before
calling jbd2_journal_load().
Note that jbd2_journal_wipe(..,0) calls
jbd2_journal_skip_recovery() for you if it detects any outstanding
transactions in the journal and similarly jbd2_journal_load() will
call jbd2_journal_recover() if necessary. I would advise reading
ext4_load_journal() in fs/ext4/super.c for examples on this stage.
Now you can go ahead and start modifying the underlying filesystem.
Almost.
You still need to actually journal your filesystem changes, this is done
by wrapping them into transactions. Additionally you also need to wrap
the modification of each of the buffers with calls to the journal layer,
so it knows what the modifications you are actually making are. To do
this use jbd2_journal_start() which returns a transaction handle.
중첩 transaction과 buffer 접근 계약
44-71Transaction 종료를 알리는 `jbd2_journal_stop()`과 `jbd2_journal_start()`는 중첩할 수 있습니다. 필요하면 transaction에 다시 들어갈 수 있지만 update phase를 떠나 transaction이 완료되려면 start를 호출한 횟수만큼 stop도 호출해야 합니다. Ext4/VFS는 inode dirty 처리와 quota 지원 등을 단순화하는 데 이 성질을 사용합니다.
각 buffer를 수정하기 전에 목적에 맞게 `jbd2_journal_get_create_access()`, `jbd2_journal_get_write_access()`, `jbd2_journal_get_undo_access()`를 호출해야 합니다. 해당 buffer가 아직 commit되지 않은 이전 transaction에 속할 수 있으므로 journal layer가 필요하면 변경 전 데이터를 복사할 수 있게 하는 절차입니다.
수정을 마쳤으면 `jbd2_journal_dirty_metadata()`를 호출합니다. 접근 권한을 얻었지만 장치로 다시 내보낼 필요가 없어진 buffer라면 과거의 `bforget()`과 비슷하게 `jbd2_journal_forget()`을 사용할 수 있습니다.
`jbd2_journal_flush()`는 언제든 모든 transaction을 commit하고 checkpoint할 수 있습니다. Unmount 때는 `put_super()`에서 `jbd2_journal_destroy()`를 호출해 메모리 안 journal 객체를 정리합니다.
접근 선언과 실제 변경, dirty 등록의 순서를 지켜야 합니다.
jbd2_journal_start() and its counterpart jbd2_journal_stop(),
which indicates the end of a transaction are nestable calls, so you can
reenter a transaction if necessary, but remember you must call
jbd2_journal_stop() the same number of times as
jbd2_journal_start() before the transaction is completed (or more
accurately leaves the update phase). Ext4/VFS makes use of this feature to
simplify handling of inode dirtying, quota support, etc.
Inside each transaction you need to wrap the modifications to the
individual buffers (blocks). Before you start to modify a buffer you
need to call jbd2_journal_get_create_access() /
jbd2_journal_get_write_access() /
jbd2_journal_get_undo_access() as appropriate, this allows the
journalling layer to copy the unmodified
data if it needs to. After all the buffer may be part of a previously
uncommitted transaction. At this point you are at last ready to modify a
buffer, and once you are have done so you need to call
jbd2_journal_dirty_metadata(). Or if you've asked for access to a
buffer you now know is now longer required to be pushed back on the
device you can call jbd2_journal_forget() in much the same way as you
might have used bforget() in the past.
A jbd2_journal_flush() may be called at any time to commit and
checkpoint all your transactions.
Then at umount time , in your put_super() you can then call
jbd2_journal_destroy() to clean up your in-core journal object.
Transaction 중첩과 공간 부족 deadlock
72-98Journal layer가 deadlock을 일으킬 수 있는 첫 번째 경우는 task마다 미완료 transaction을 하나만 가질 수 있다는 제약에서 나옵니다. 가장 바깥쪽 `jbd2_journal_stop()` 전에는 아무것도 commit되지 않으므로 각 file·inode·address 연산이 끝날 때 transaction을 끝내야 다른 journal로 journalling system에 재진입하지 않습니다. 서로 다른 journal 사이에는 transaction을 중첩하거나 batch로 묶을 수 없고, 이후 syscall에서 ext4 같은 다른 파일시스템이 변경될 수도 있습니다.
두 번째 경우는 요청한 `nblocks`만큼 journal 공간이 부족할 때 `jbd2_journal_start()`가 block할 수 있다는 점입니다. 다른 task의 transaction이 끝나 commit되기를, 실질적으로 `jbd2_journal_stop()`을 기다립니다. 따라서 start와 stop을 semaphore처럼 취급하여 semaphore ordering 규칙에 포함해야 합니다.
`jbd2_journal_extend()`도 `jbd2_journal_start()`와 비슷하게 block하므로 같은 방식으로 deadlock을 일으킬 수 있습니다. 처음부터 transaction에서 건드릴 최대 블록 수를 정확히 예약하도록 노력해야 하며, ext4의 산정 근거는 적어도 `ext4_jbd.h`를 참고하십시오.
보유 중인 transaction과 공간 대기를 lock ordering 관점에서 봅니다.
Unfortunately there a couple of ways the journal layer can cause a
deadlock. The first thing to note is that each task can only have a
single outstanding transaction at any one time, remember nothing commits
until the outermost jbd2_journal_stop(). This means you must complete
the transaction at the end of each file/inode/address etc. operation you
perform, so that the journalling system isn't re-entered on another
journal. Since transactions can't be nested/batched across differing
journals, and another filesystem other than yours (say ext4) may be
modified in a later syscall.
The second case to bear in mind is that jbd2_journal_start() can block
if there isn't enough space in the journal for your transaction (based
on the passed nblocks param) - when it blocks it merely(!) needs to wait
for transactions to complete and be committed from other tasks, so
essentially we are waiting for jbd2_journal_stop(). So to avoid
deadlocks you must treat jbd2_journal_start() /
jbd2_journal_stop() as if they were semaphores and include them in
your semaphore ordering rules to prevent
deadlocks. Note that jbd2_journal_extend() has similar blocking
behaviour to jbd2_journal_start() so you can deadlock here just as
easily as on jbd2_journal_start().
Try to reserve the right number of blocks the first time. ;-). This will
be the maximum number of blocks you are going to touch in this
transaction. I advise having a look at at least ext4_jbd.h to see the
basis on which ext4 uses to make these decisions.
블록 재사용, commit callback, update 잠금
99-132On-disk block 할당에서는 삭제로 해제한 블록을 그 해제를 기록한 transaction이 commit되기 전에 재사용하면 안 됩니다. 재사용 뒤 crash가 나면 마지막으로 완전히 commit된 transaction 시점의 재할당 블록 내용을 복원할 방법이 없습니다.
간단한 해결책은 블록을 해제한 transaction이 commit된 뒤에만 메모리 내부 block allocation 구조에서 free로 표시하는 것입니다. Ext4는 이를 위해 journal commit callback을 사용합니다.
`journal->j_commit_callback` 함수 포인터를 설정하면 각 transaction이 디스크에 최종 commit된 뒤 journalling layer가 callback을 호출하므로 파일시스템 자체 관리 작업을 수행할 수 있습니다.
JBD2는 `jbd2_journal_lock_updates()`와 `jbd2_journal_unlock_updates()`로 모든 transaction update를 막을 수도 있습니다. Ext4는 잠시 깨끗하고 안정된 파일시스템 상태가 필요할 때 update를 잠그고, `jbd2_journal_flush()`로 모두 checkpoint하고, 필요한 작업을 한 뒤 잠금을 풉니다. 권한 없는 userspace가 이 경로를 실행할 수 있게 하면 남용과 DoS 공격 기회가 명백하므로 노출해서는 안 됩니다.
jbd2_journal_lock_updates() // 새 update 차단
jbd2_journal_flush() // 모든 transaction checkpoint
... 안정된 파일시스템에서 작업
jbd2_journal_unlock_updates() // 파일시스템 사용 재개
Another wriggle to watch out for is your on-disk block allocation
strategy. Why? Because, if you do a delete, you need to ensure you
haven't reused any of the freed blocks until the transaction freeing
these blocks commits. If you reused these blocks and crash happens,
there is no way to restore the contents of the reallocated blocks at the
end of the last fully committed transaction. One simple way of doing
this is to mark blocks as free in internal in-memory block allocation
structures only after the transaction freeing them commits. Ext4 uses
journal commit callback for this purpose.
With journal commit callbacks you can ask the journalling layer to call
a callback function when the transaction is finally committed to disk,
so that you can do some of your own management. You ask the journalling
layer for calling the callback by simply setting
``journal->j_commit_callback`` function pointer and that function is
called after each transaction commit.
JBD2 also provides a way to block all transaction updates via
jbd2_journal_lock_updates() /
jbd2_journal_unlock_updates(). Ext4 uses this when it wants a
window with a clean and stable fs for a moment. E.g.
::
jbd2_journal_lock_updates() //stop new stuff happening..
jbd2_journal_flush() // checkpoint everything.
..do stuff on stable fs
jbd2_journal_unlock_updates() // carry on with filesystem use.
The opportunities for abuse and DOS attacks with this should be obvious,
if you allow unprivileged userspace to trigger codepaths containing
these calls.
JBD2 fast commit 계약
133-163JBD2는 파일시스템별 delta commit인 fast commit도 지원합니다. 사용하려면 full commit과 fast commit 뒤 정리하는 `journal->j_fc_cleanup_cb`, fast commit 블록을 replay하는 `journal->j_fc_replay_cb`를 설정해야 합니다.
파일시스템은 `jbd2_fc_begin_commit()`으로 JBD2의 허가를 받은 경우 원하는 시점에 fast commit을 수행할 수 있습니다. 완료 뒤 client 파일시스템은 `jbd2_fc_end_commit()`으로 JBD2에 알려야 합니다.
Fast commit을 중단한 직후 full commit이 필요하면 `jbd2_fc_end_commit_fallback()`을 호출합니다. Fast commit이 실패해 일관성을 보장하는 유일한 방법이 전통적인 full commit일 때 유용합니다.
Fast commit buffer 관리에는 `jbd2_fc_get_buf()`와 `jbd2_fc_wait_bufs()`를 사용하여 buffer를 할당하고 I/O 완료를 기다릴 수 있습니다. 현재 fast commit을 구현한 파일시스템은 Ext4뿐이며 구현 세부는 `fs/ext4/fast_commit.c`의 최상위 주석을 참고합니다.
허가, delta 기록, 완료 통지 또는 full commit fallback의 흐름입니다.
Fast commits
~~~~~~~~~~~~
JBD2 to also allows you to perform file-system specific delta commits known as
fast commits. In order to use fast commits, you will need to set following
callbacks that perform corresponding work:
`journal->j_fc_cleanup_cb`: Cleanup function called after every full commit and
fast commit.
`journal->j_fc_replay_cb`: Replay function called for replay of fast commit
blocks.
File system is free to perform fast commits as and when it wants as long as it
gets permission from JBD2 to do so by calling the function
:c:func:`jbd2_fc_begin_commit()`. Once a fast commit is done, the client
file system should tell JBD2 about it by calling
:c:func:`jbd2_fc_end_commit()`. If the file system wants JBD2 to perform a full
commit immediately after stopping the fast commit it can do so by calling
:c:func:`jbd2_fc_end_commit_fallback()`. This is useful if fast commit operation
fails for some reason and the only way to guarantee consistency is for JBD2 to
perform the full traditional commit.
JBD2 helper functions to manage fast commit buffers. File system can use
:c:func:`jbd2_fc_get_buf()` and :c:func:`jbd2_fc_wait_bufs()` to allocate
and wait on IO completion of fast commit buffers.
Currently, only Ext4 implements fast commits. For details of its implementation
of fast commits, please refer to the top level comments in
fs/ext4/fast_commit.c.
요약, 자료형, kernel-doc 참조
164-213Journal 사용의 핵심은 mount, 각 변경 transaction, 변경되는 각 buffer라는 서로 다른 context 변화를 journalling layer에 알리도록 감싸는 것입니다.
Journalling layer는 구조체의 구체적인 정의를 감추려고 typedef를 사용합니다. JBD2 client는 포인터를 일종의 opaque cookie로 다룰 수 있지만 C 언어이므로 이러한 은닉이 강제되지는 않습니다.
구조체 내부 문서는 `include/linux/jbd2.h`의 kernel-doc에서 가져옵니다. 함수는 journal 전체에 영향을 주는 journal level과 transaction 관리에 쓰는 transaction level 두 그룹으로 나뉩니다. Journal level export는 `fs/jbd2/journal.c`, recovery 내부 함수는 `fs/jbd2/recovery.c`, transaction 함수는 `fs/jbd2/transaction.c`에 있습니다.
추가 자료로 Stephen Tweedie의 LinuxExpo 98 논문 `Journaling the Linux ext2fs Filesystem`과 OLS 2000 자료 `Ext3 Journalling FileSystem`을 제시합니다. 원문의 URL과 RST link 표기는 아래 영어 원문 블록에 그대로 보존됩니다.
구조체와 함수 그룹별 source path입니다.
Summary
~~~~~~~
Using the journal is a matter of wrapping the different context changes,
being each mount, each modification (transaction) and each changed
buffer to tell the journalling layer about them.
Data Types
----------
The journalling layer uses typedefs to 'hide' the concrete definitions
of the structures used. As a client of the JBD2 layer you can just rely
on the using the pointer as a magic cookie of some sort. Obviously the
hiding is not enforced as this is 'C'.
Structures
~~~~~~~~~~
.. kernel-doc:: include/linux/jbd2.h
:internal:
Functions
---------
The functions here are split into two groups those that affect a journal
as a whole, and those which are used to manage transactions
Journal Level
~~~~~~~~~~~~~
.. kernel-doc:: fs/jbd2/journal.c
:export:
.. kernel-doc:: fs/jbd2/recovery.c
:internal:
Transaction Level
~~~~~~~~~~~~~~~~~~
.. kernel-doc:: fs/jbd2/transaction.c
See also
--------
`Journaling the Linux ext2fs Filesystem, LinuxExpo 98, Stephen
Tweedie <http://kernel.org/pub/linux/kernel/people/sct/ext3/journal-design.ps.gz>`__
`Ext3 Journalling FileSystem, OLS 2000, Dr. Stephen
Tweedie <http://olstrans.sourceforge.net/release/OLS2000-ext3/OLS2000-ext3.html>`__
요약·해설
journalling.rst:1-213JBD2 client는 journal을 만들고 복구 가능한 상태로 load한 뒤, 모든 metadata 변경을 transaction과 buffer access 계약으로 감쌉니다. Transaction 중첩 수, journal 공간 대기, 해제 블록 재사용 시점은 deadlock과 crash consistency에 직접 영향을 줍니다.
Fast commit은 JBD2 허가와 완료 통지, 실패 시 full commit fallback을 명시적으로 연결해야 합니다. 안정된 파일시스템 창을 만드는 update 잠금은 강력하지만 권한 없는 호출 경로에 노출하면 DoS 위험이 있습니다.
초기화부터 종료까지의 핵심 경계입니다.