diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-12-27 20:09:41 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-12-27 20:09:41 -0500 |
commit | f6b1495fba0b66cfa05efa0ca2370513b79b45b6 (patch) | |
tree | 0718aab1784d4a65474404029e72ab288531462a /fs/jbd2 | |
parent | bc77789a491cdc6f47e5bbd1d04ddd283d64658b (diff) | |
parent | 18f2c4fcebf2582f96cbd5f2238f4f354a0e4847 (diff) |
Merge tag 'ext4_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4
Pull ext4 updates from Ted Ts'o:
"All cleanups and bug fixes; most notably, fix some problems discovered
in ext4's NFS support, and fix an ioctl (EXT4_IOC_GROUP_ADD) used by
old versions of e2fsprogs which we accidentally broke a while back.
Also fixed some error paths in ext4's quota and inline data support.
Finally, improve tail latency in jbd2's commit code"
* tag 'ext4_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4:
ext4: check for shutdown and r/o file system in ext4_write_inode()
ext4: force inode writes when nfsd calls commit_metadata()
ext4: avoid declaring fs inconsistent due to invalid file handles
ext4: include terminating u32 in size of xattr entries when expanding inodes
ext4: compare old and new mode before setting update_mode flag
ext4: fix EXT4_IOC_GROUP_ADD ioctl
ext4: hard fail dax mount on unsupported devices
jbd2: update locking documentation for transaction_t
ext4: remove redundant condition check
jbd2: clean up indentation issue, replace spaces with tab
ext4: clean up indentation issues, remove extraneous tabs
ext4: missing unlock/put_page() in ext4_try_to_write_inline_data()
ext4: fix possible use after free in ext4_quota_enable
jbd2: avoid long hold times of j_state_lock while committing a transaction
ext4: add ext4_sb_bread() to disambiguate ENOMEM cases
Diffstat (limited to 'fs/jbd2')
-rw-r--r-- | fs/jbd2/commit.c | 3 | ||||
-rw-r--r-- | fs/jbd2/transaction.c | 45 |
2 files changed, 42 insertions, 6 deletions
diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c index 150cc030b4d7..2eb55c3361a8 100644 --- a/fs/jbd2/commit.c +++ b/fs/jbd2/commit.c | |||
@@ -439,6 +439,8 @@ void jbd2_journal_commit_transaction(journal_t *journal) | |||
439 | finish_wait(&journal->j_wait_updates, &wait); | 439 | finish_wait(&journal->j_wait_updates, &wait); |
440 | } | 440 | } |
441 | spin_unlock(&commit_transaction->t_handle_lock); | 441 | spin_unlock(&commit_transaction->t_handle_lock); |
442 | commit_transaction->t_state = T_SWITCH; | ||
443 | write_unlock(&journal->j_state_lock); | ||
442 | 444 | ||
443 | J_ASSERT (atomic_read(&commit_transaction->t_outstanding_credits) <= | 445 | J_ASSERT (atomic_read(&commit_transaction->t_outstanding_credits) <= |
444 | journal->j_max_transaction_buffers); | 446 | journal->j_max_transaction_buffers); |
@@ -505,6 +507,7 @@ void jbd2_journal_commit_transaction(journal_t *journal) | |||
505 | atomic_sub(atomic_read(&journal->j_reserved_credits), | 507 | atomic_sub(atomic_read(&journal->j_reserved_credits), |
506 | &commit_transaction->t_outstanding_credits); | 508 | &commit_transaction->t_outstanding_credits); |
507 | 509 | ||
510 | write_lock(&journal->j_state_lock); | ||
508 | trace_jbd2_commit_flushing(journal, commit_transaction); | 511 | trace_jbd2_commit_flushing(journal, commit_transaction); |
509 | stats.run.rs_flushing = jiffies; | 512 | stats.run.rs_flushing = jiffies; |
510 | stats.run.rs_locked = jbd2_time_diff(stats.run.rs_locked, | 513 | stats.run.rs_locked = jbd2_time_diff(stats.run.rs_locked, |
diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c index c0b66a7a795b..cc35537232f2 100644 --- a/fs/jbd2/transaction.c +++ b/fs/jbd2/transaction.c | |||
@@ -138,9 +138,9 @@ static inline void update_t_max_wait(transaction_t *transaction, | |||
138 | } | 138 | } |
139 | 139 | ||
140 | /* | 140 | /* |
141 | * Wait until running transaction passes T_LOCKED state. Also starts the commit | 141 | * Wait until running transaction passes to T_FLUSH state and new transaction |
142 | * if needed. The function expects running transaction to exist and releases | 142 | * can thus be started. Also starts the commit if needed. The function expects |
143 | * j_state_lock. | 143 | * running transaction to exist and releases j_state_lock. |
144 | */ | 144 | */ |
145 | static void wait_transaction_locked(journal_t *journal) | 145 | static void wait_transaction_locked(journal_t *journal) |
146 | __releases(journal->j_state_lock) | 146 | __releases(journal->j_state_lock) |
@@ -160,6 +160,32 @@ static void wait_transaction_locked(journal_t *journal) | |||
160 | finish_wait(&journal->j_wait_transaction_locked, &wait); | 160 | finish_wait(&journal->j_wait_transaction_locked, &wait); |
161 | } | 161 | } |
162 | 162 | ||
163 | /* | ||
164 | * Wait until running transaction transitions from T_SWITCH to T_FLUSH | ||
165 | * state and new transaction can thus be started. The function releases | ||
166 | * j_state_lock. | ||
167 | */ | ||
168 | static void wait_transaction_switching(journal_t *journal) | ||
169 | __releases(journal->j_state_lock) | ||
170 | { | ||
171 | DEFINE_WAIT(wait); | ||
172 | |||
173 | if (WARN_ON(!journal->j_running_transaction || | ||
174 | journal->j_running_transaction->t_state != T_SWITCH)) | ||
175 | return; | ||
176 | prepare_to_wait(&journal->j_wait_transaction_locked, &wait, | ||
177 | TASK_UNINTERRUPTIBLE); | ||
178 | read_unlock(&journal->j_state_lock); | ||
179 | /* | ||
180 | * We don't call jbd2_might_wait_for_commit() here as there's no | ||
181 | * waiting for outstanding handles happening anymore in T_SWITCH state | ||
182 | * and handling of reserved handles actually relies on that for | ||
183 | * correctness. | ||
184 | */ | ||
185 | schedule(); | ||
186 | finish_wait(&journal->j_wait_transaction_locked, &wait); | ||
187 | } | ||
188 | |||
163 | static void sub_reserved_credits(journal_t *journal, int blocks) | 189 | static void sub_reserved_credits(journal_t *journal, int blocks) |
164 | { | 190 | { |
165 | atomic_sub(blocks, &journal->j_reserved_credits); | 191 | atomic_sub(blocks, &journal->j_reserved_credits); |
@@ -183,7 +209,8 @@ static int add_transaction_credits(journal_t *journal, int blocks, | |||
183 | * If the current transaction is locked down for commit, wait | 209 | * If the current transaction is locked down for commit, wait |
184 | * for the lock to be released. | 210 | * for the lock to be released. |
185 | */ | 211 | */ |
186 | if (t->t_state == T_LOCKED) { | 212 | if (t->t_state != T_RUNNING) { |
213 | WARN_ON_ONCE(t->t_state >= T_FLUSH); | ||
187 | wait_transaction_locked(journal); | 214 | wait_transaction_locked(journal); |
188 | return 1; | 215 | return 1; |
189 | } | 216 | } |
@@ -360,8 +387,14 @@ repeat: | |||
360 | /* | 387 | /* |
361 | * We have handle reserved so we are allowed to join T_LOCKED | 388 | * We have handle reserved so we are allowed to join T_LOCKED |
362 | * transaction and we don't have to check for transaction size | 389 | * transaction and we don't have to check for transaction size |
363 | * and journal space. | 390 | * and journal space. But we still have to wait while running |
391 | * transaction is being switched to a committing one as it | ||
392 | * won't wait for any handles anymore. | ||
364 | */ | 393 | */ |
394 | if (transaction->t_state == T_SWITCH) { | ||
395 | wait_transaction_switching(journal); | ||
396 | goto repeat; | ||
397 | } | ||
365 | sub_reserved_credits(journal, blocks); | 398 | sub_reserved_credits(journal, blocks); |
366 | handle->h_reserved = 0; | 399 | handle->h_reserved = 0; |
367 | } | 400 | } |
@@ -910,7 +943,7 @@ repeat: | |||
910 | * this is the first time this transaction is touching this buffer, | 943 | * this is the first time this transaction is touching this buffer, |
911 | * reset the modified flag | 944 | * reset the modified flag |
912 | */ | 945 | */ |
913 | jh->b_modified = 0; | 946 | jh->b_modified = 0; |
914 | 947 | ||
915 | /* | 948 | /* |
916 | * If the buffer is not journaled right now, we need to make sure it | 949 | * If the buffer is not journaled right now, we need to make sure it |