Commit 47def82672b3ba4e7c5e9a4fe48a556f8684d0d6
1 parent
4038968738
Exists in
master
and in
4 other branches
jbd2: Remove __GFP_NOFAIL from jbd2 layer
__GFP_NOFAIL is going away, so add our own retry loop. Also add jbd2__journal_start() and jbd2__journal_restart() which take a gfp mask, so that file systems can optionally (re)start transaction handles using GFP_KERNEL. If they do this, then they need to be prepared to handle receiving an PTR_ERR(-ENOMEM) error, and be ready to reflect that error up to userspace. Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Showing 3 changed files with 57 additions and 23 deletions Side-by-side Diff
fs/jbd2/journal.c
... | ... | @@ -41,6 +41,7 @@ |
41 | 41 | #include <linux/hash.h> |
42 | 42 | #include <linux/log2.h> |
43 | 43 | #include <linux/vmalloc.h> |
44 | +#include <linux/backing-dev.h> | |
44 | 45 | |
45 | 46 | #define CREATE_TRACE_POINTS |
46 | 47 | #include <trace/events/jbd2.h> |
... | ... | @@ -48,8 +49,6 @@ |
48 | 49 | #include <asm/uaccess.h> |
49 | 50 | #include <asm/page.h> |
50 | 51 | |
51 | -EXPORT_SYMBOL(jbd2_journal_start); | |
52 | -EXPORT_SYMBOL(jbd2_journal_restart); | |
53 | 52 | EXPORT_SYMBOL(jbd2_journal_extend); |
54 | 53 | EXPORT_SYMBOL(jbd2_journal_stop); |
55 | 54 | EXPORT_SYMBOL(jbd2_journal_lock_updates); |
... | ... | @@ -311,7 +310,17 @@ |
311 | 310 | */ |
312 | 311 | J_ASSERT_BH(bh_in, buffer_jbddirty(bh_in)); |
313 | 312 | |
314 | - new_bh = alloc_buffer_head(GFP_NOFS|__GFP_NOFAIL); | |
313 | +retry_alloc: | |
314 | + new_bh = alloc_buffer_head(GFP_NOFS); | |
315 | + if (!new_bh) { | |
316 | + /* | |
317 | + * Failure is not an option, but __GFP_NOFAIL is going | |
318 | + * away; so we retry ourselves here. | |
319 | + */ | |
320 | + congestion_wait(BLK_RW_ASYNC, HZ/50); | |
321 | + goto retry_alloc; | |
322 | + } | |
323 | + | |
315 | 324 | /* keep subsequent assertions sane */ |
316 | 325 | new_bh->b_state = 0; |
317 | 326 | init_buffer(new_bh, NULL, NULL); |
fs/jbd2/transaction.c
... | ... | @@ -26,6 +26,8 @@ |
26 | 26 | #include <linux/mm.h> |
27 | 27 | #include <linux/highmem.h> |
28 | 28 | #include <linux/hrtimer.h> |
29 | +#include <linux/backing-dev.h> | |
30 | +#include <linux/module.h> | |
29 | 31 | |
30 | 32 | static void __jbd2_journal_temp_unlink_buffer(struct journal_head *jh); |
31 | 33 | |
32 | 34 | |
33 | 35 | |
34 | 36 | |
35 | 37 | |
... | ... | @@ -83,30 +85,38 @@ |
83 | 85 | * transaction's buffer credits. |
84 | 86 | */ |
85 | 87 | |
86 | -static int start_this_handle(journal_t *journal, handle_t *handle) | |
88 | +static int start_this_handle(journal_t *journal, handle_t *handle, | |
89 | + int gfp_mask) | |
87 | 90 | { |
88 | 91 | transaction_t *transaction; |
89 | 92 | int needed; |
90 | 93 | int nblocks = handle->h_buffer_credits; |
91 | 94 | transaction_t *new_transaction = NULL; |
92 | - int ret = 0; | |
93 | 95 | unsigned long ts = jiffies; |
94 | 96 | |
95 | 97 | if (nblocks > journal->j_max_transaction_buffers) { |
96 | 98 | printk(KERN_ERR "JBD: %s wants too many credits (%d > %d)\n", |
97 | 99 | current->comm, nblocks, |
98 | 100 | journal->j_max_transaction_buffers); |
99 | - ret = -ENOSPC; | |
100 | - goto out; | |
101 | + return -ENOSPC; | |
101 | 102 | } |
102 | 103 | |
103 | 104 | alloc_transaction: |
104 | 105 | if (!journal->j_running_transaction) { |
105 | - new_transaction = kzalloc(sizeof(*new_transaction), | |
106 | - GFP_NOFS|__GFP_NOFAIL); | |
106 | + new_transaction = kzalloc(sizeof(*new_transaction), gfp_mask); | |
107 | 107 | if (!new_transaction) { |
108 | - ret = -ENOMEM; | |
109 | - goto out; | |
108 | + /* | |
109 | + * If __GFP_FS is not present, then we may be | |
110 | + * being called from inside the fs writeback | |
111 | + * layer, so we MUST NOT fail. Since | |
112 | + * __GFP_NOFAIL is going away, we will arrange | |
113 | + * to retry the allocation ourselves. | |
114 | + */ | |
115 | + if ((gfp_mask & __GFP_FS) == 0) { | |
116 | + congestion_wait(BLK_RW_ASYNC, HZ/50); | |
117 | + goto alloc_transaction; | |
118 | + } | |
119 | + return -ENOMEM; | |
110 | 120 | } |
111 | 121 | } |
112 | 122 | |
... | ... | @@ -123,8 +133,8 @@ |
123 | 133 | if (is_journal_aborted(journal) || |
124 | 134 | (journal->j_errno != 0 && !(journal->j_flags & JBD2_ACK_ERR))) { |
125 | 135 | spin_unlock(&journal->j_state_lock); |
126 | - ret = -EROFS; | |
127 | - goto out; | |
136 | + kfree(new_transaction); | |
137 | + return -EROFS; | |
128 | 138 | } |
129 | 139 | |
130 | 140 | /* Wait on the journal's transaction barrier if necessary */ |
... | ... | @@ -240,10 +250,8 @@ |
240 | 250 | spin_unlock(&journal->j_state_lock); |
241 | 251 | |
242 | 252 | lock_map_acquire(&handle->h_lockdep_map); |
243 | -out: | |
244 | - if (unlikely(new_transaction)) /* It's usually NULL */ | |
245 | - kfree(new_transaction); | |
246 | - return ret; | |
253 | + kfree(new_transaction); | |
254 | + return 0; | |
247 | 255 | } |
248 | 256 | |
249 | 257 | static struct lock_class_key jbd2_handle_key; |
... | ... | @@ -278,7 +286,7 @@ |
278 | 286 | * |
279 | 287 | * Return a pointer to a newly allocated handle, or NULL on failure |
280 | 288 | */ |
281 | -handle_t *jbd2_journal_start(journal_t *journal, int nblocks) | |
289 | +handle_t *jbd2__journal_start(journal_t *journal, int nblocks, int gfp_mask) | |
282 | 290 | { |
283 | 291 | handle_t *handle = journal_current_handle(); |
284 | 292 | int err; |
... | ... | @@ -298,7 +306,7 @@ |
298 | 306 | |
299 | 307 | current->journal_info = handle; |
300 | 308 | |
301 | - err = start_this_handle(journal, handle); | |
309 | + err = start_this_handle(journal, handle, gfp_mask); | |
302 | 310 | if (err < 0) { |
303 | 311 | jbd2_free_handle(handle); |
304 | 312 | current->journal_info = NULL; |
305 | 313 | |
... | ... | @@ -308,7 +316,16 @@ |
308 | 316 | out: |
309 | 317 | return handle; |
310 | 318 | } |
319 | +EXPORT_SYMBOL(jbd2__journal_start); | |
311 | 320 | |
321 | + | |
322 | +handle_t *jbd2_journal_start(journal_t *journal, int nblocks) | |
323 | +{ | |
324 | + return jbd2__journal_start(journal, nblocks, GFP_NOFS); | |
325 | +} | |
326 | +EXPORT_SYMBOL(jbd2_journal_start); | |
327 | + | |
328 | + | |
312 | 329 | /** |
313 | 330 | * int jbd2_journal_extend() - extend buffer credits. |
314 | 331 | * @handle: handle to 'extend' |
... | ... | @@ -394,8 +411,7 @@ |
394 | 411 | * transaction capabable of guaranteeing the requested number of |
395 | 412 | * credits. |
396 | 413 | */ |
397 | - | |
398 | -int jbd2_journal_restart(handle_t *handle, int nblocks) | |
414 | +int jbd2__journal_restart(handle_t *handle, int nblocks, int gfp_mask) | |
399 | 415 | { |
400 | 416 | transaction_t *transaction = handle->h_transaction; |
401 | 417 | journal_t *journal = transaction->t_journal; |
402 | 418 | |
403 | 419 | |
... | ... | @@ -428,10 +444,17 @@ |
428 | 444 | |
429 | 445 | lock_map_release(&handle->h_lockdep_map); |
430 | 446 | handle->h_buffer_credits = nblocks; |
431 | - ret = start_this_handle(journal, handle); | |
447 | + ret = start_this_handle(journal, handle, gfp_mask); | |
432 | 448 | return ret; |
433 | 449 | } |
450 | +EXPORT_SYMBOL(jbd2__journal_restart); | |
434 | 451 | |
452 | + | |
453 | +int jbd2_journal_restart(handle_t *handle, int nblocks) | |
454 | +{ | |
455 | + return jbd2__journal_restart(handle, nblocks, GFP_NOFS); | |
456 | +} | |
457 | +EXPORT_SYMBOL(jbd2_journal_restart); | |
435 | 458 | |
436 | 459 | /** |
437 | 460 | * void jbd2_journal_lock_updates () - establish a transaction barrier. |
include/linux/jbd2.h
... | ... | @@ -1081,7 +1081,9 @@ |
1081 | 1081 | */ |
1082 | 1082 | |
1083 | 1083 | extern handle_t *jbd2_journal_start(journal_t *, int nblocks); |
1084 | -extern int jbd2_journal_restart (handle_t *, int nblocks); | |
1084 | +extern handle_t *jbd2__journal_start(journal_t *, int nblocks, int gfp_mask); | |
1085 | +extern int jbd2_journal_restart(handle_t *, int nblocks); | |
1086 | +extern int jbd2__journal_restart(handle_t *, int nblocks, int gfp_mask); | |
1085 | 1087 | extern int jbd2_journal_extend (handle_t *, int nblocks); |
1086 | 1088 | extern int jbd2_journal_get_write_access(handle_t *, struct buffer_head *); |
1087 | 1089 | extern int jbd2_journal_get_create_access (handle_t *, struct buffer_head *); |