diff options
author | Ingo Molnar <mingo@elte.hu> | 2008-08-14 06:19:59 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-08-14 06:19:59 -0400 |
commit | 8d7ccaa545490cdffdfaff0842436a8dd85cf47b (patch) | |
tree | 8129b5907161bc6ae26deb3645ce1e280c5e1f51 /fs/jbd | |
parent | b2139aa0eec330c711c5a279db361e5ef1178e78 (diff) | |
parent | 30a2f3c60a84092c8084dfe788b710f8d0768cd4 (diff) |
Merge commit 'v2.6.27-rc3' into x86/prototypes
Conflicts:
include/asm-x86/dma-mapping.h
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'fs/jbd')
-rw-r--r-- | fs/jbd/commit.c | 68 | ||||
-rw-r--r-- | fs/jbd/journal.c | 8 | ||||
-rw-r--r-- | fs/jbd/revoke.c | 163 | ||||
-rw-r--r-- | fs/jbd/transaction.c | 61 |
4 files changed, 185 insertions, 115 deletions
diff --git a/fs/jbd/commit.c b/fs/jbd/commit.c index 5a8ca61498ca..ae08c057e751 100644 --- a/fs/jbd/commit.c +++ b/fs/jbd/commit.c | |||
@@ -36,7 +36,7 @@ static void journal_end_buffer_io_sync(struct buffer_head *bh, int uptodate) | |||
36 | 36 | ||
37 | /* | 37 | /* |
38 | * When an ext3-ordered file is truncated, it is possible that many pages are | 38 | * When an ext3-ordered file is truncated, it is possible that many pages are |
39 | * not sucessfully freed, because they are attached to a committing transaction. | 39 | * not successfully freed, because they are attached to a committing transaction. |
40 | * After the transaction commits, these pages are left on the LRU, with no | 40 | * After the transaction commits, these pages are left on the LRU, with no |
41 | * ->mapping, and with attached buffers. These pages are trivially reclaimable | 41 | * ->mapping, and with attached buffers. These pages are trivially reclaimable |
42 | * by the VM, but their apparent absence upsets the VM accounting, and it makes | 42 | * by the VM, but their apparent absence upsets the VM accounting, and it makes |
@@ -45,8 +45,8 @@ static void journal_end_buffer_io_sync(struct buffer_head *bh, int uptodate) | |||
45 | * So here, we have a buffer which has just come off the forget list. Look to | 45 | * So here, we have a buffer which has just come off the forget list. Look to |
46 | * see if we can strip all buffers from the backing page. | 46 | * see if we can strip all buffers from the backing page. |
47 | * | 47 | * |
48 | * Called under lock_journal(), and possibly under journal_datalist_lock. The | 48 | * Called under journal->j_list_lock. The caller provided us with a ref |
49 | * caller provided us with a ref against the buffer, and we drop that here. | 49 | * against the buffer, and we drop that here. |
50 | */ | 50 | */ |
51 | static void release_buffer_page(struct buffer_head *bh) | 51 | static void release_buffer_page(struct buffer_head *bh) |
52 | { | 52 | { |
@@ -63,7 +63,7 @@ static void release_buffer_page(struct buffer_head *bh) | |||
63 | goto nope; | 63 | goto nope; |
64 | 64 | ||
65 | /* OK, it's a truncated page */ | 65 | /* OK, it's a truncated page */ |
66 | if (TestSetPageLocked(page)) | 66 | if (!trylock_page(page)) |
67 | goto nope; | 67 | goto nope; |
68 | 68 | ||
69 | page_cache_get(page); | 69 | page_cache_get(page); |
@@ -78,6 +78,19 @@ nope: | |||
78 | } | 78 | } |
79 | 79 | ||
80 | /* | 80 | /* |
81 | * Decrement reference counter for data buffer. If it has been marked | ||
82 | * 'BH_Freed', release it and the page to which it belongs if possible. | ||
83 | */ | ||
84 | static void release_data_buffer(struct buffer_head *bh) | ||
85 | { | ||
86 | if (buffer_freed(bh)) { | ||
87 | clear_buffer_freed(bh); | ||
88 | release_buffer_page(bh); | ||
89 | } else | ||
90 | put_bh(bh); | ||
91 | } | ||
92 | |||
93 | /* | ||
81 | * Try to acquire jbd_lock_bh_state() against the buffer, when j_list_lock is | 94 | * Try to acquire jbd_lock_bh_state() against the buffer, when j_list_lock is |
82 | * held. For ranking reasons we must trylock. If we lose, schedule away and | 95 | * held. For ranking reasons we must trylock. If we lose, schedule away and |
83 | * return 0. j_list_lock is dropped in this case. | 96 | * return 0. j_list_lock is dropped in this case. |
@@ -172,7 +185,7 @@ static void journal_do_submit_data(struct buffer_head **wbuf, int bufs) | |||
172 | /* | 185 | /* |
173 | * Submit all the data buffers to disk | 186 | * Submit all the data buffers to disk |
174 | */ | 187 | */ |
175 | static void journal_submit_data_buffers(journal_t *journal, | 188 | static int journal_submit_data_buffers(journal_t *journal, |
176 | transaction_t *commit_transaction) | 189 | transaction_t *commit_transaction) |
177 | { | 190 | { |
178 | struct journal_head *jh; | 191 | struct journal_head *jh; |
@@ -180,6 +193,7 @@ static void journal_submit_data_buffers(journal_t *journal, | |||
180 | int locked; | 193 | int locked; |
181 | int bufs = 0; | 194 | int bufs = 0; |
182 | struct buffer_head **wbuf = journal->j_wbuf; | 195 | struct buffer_head **wbuf = journal->j_wbuf; |
196 | int err = 0; | ||
183 | 197 | ||
184 | /* | 198 | /* |
185 | * Whenever we unlock the journal and sleep, things can get added | 199 | * Whenever we unlock the journal and sleep, things can get added |
@@ -207,7 +221,7 @@ write_out_data: | |||
207 | * blocking lock_buffer(). | 221 | * blocking lock_buffer(). |
208 | */ | 222 | */ |
209 | if (buffer_dirty(bh)) { | 223 | if (buffer_dirty(bh)) { |
210 | if (test_set_buffer_locked(bh)) { | 224 | if (!trylock_buffer(bh)) { |
211 | BUFFER_TRACE(bh, "needs blocking lock"); | 225 | BUFFER_TRACE(bh, "needs blocking lock"); |
212 | spin_unlock(&journal->j_list_lock); | 226 | spin_unlock(&journal->j_list_lock); |
213 | /* Write out all data to prevent deadlocks */ | 227 | /* Write out all data to prevent deadlocks */ |
@@ -231,7 +245,7 @@ write_out_data: | |||
231 | if (locked) | 245 | if (locked) |
232 | unlock_buffer(bh); | 246 | unlock_buffer(bh); |
233 | BUFFER_TRACE(bh, "already cleaned up"); | 247 | BUFFER_TRACE(bh, "already cleaned up"); |
234 | put_bh(bh); | 248 | release_data_buffer(bh); |
235 | continue; | 249 | continue; |
236 | } | 250 | } |
237 | if (locked && test_clear_buffer_dirty(bh)) { | 251 | if (locked && test_clear_buffer_dirty(bh)) { |
@@ -253,15 +267,17 @@ write_out_data: | |||
253 | put_bh(bh); | 267 | put_bh(bh); |
254 | } else { | 268 | } else { |
255 | BUFFER_TRACE(bh, "writeout complete: unfile"); | 269 | BUFFER_TRACE(bh, "writeout complete: unfile"); |
270 | if (unlikely(!buffer_uptodate(bh))) | ||
271 | err = -EIO; | ||
256 | __journal_unfile_buffer(jh); | 272 | __journal_unfile_buffer(jh); |
257 | jbd_unlock_bh_state(bh); | 273 | jbd_unlock_bh_state(bh); |
258 | if (locked) | 274 | if (locked) |
259 | unlock_buffer(bh); | 275 | unlock_buffer(bh); |
260 | journal_remove_journal_head(bh); | 276 | journal_remove_journal_head(bh); |
261 | /* Once for our safety reference, once for | 277 | /* One for our safety reference, other for |
262 | * journal_remove_journal_head() */ | 278 | * journal_remove_journal_head() */ |
263 | put_bh(bh); | 279 | put_bh(bh); |
264 | put_bh(bh); | 280 | release_data_buffer(bh); |
265 | } | 281 | } |
266 | 282 | ||
267 | if (need_resched() || spin_needbreak(&journal->j_list_lock)) { | 283 | if (need_resched() || spin_needbreak(&journal->j_list_lock)) { |
@@ -271,6 +287,8 @@ write_out_data: | |||
271 | } | 287 | } |
272 | spin_unlock(&journal->j_list_lock); | 288 | spin_unlock(&journal->j_list_lock); |
273 | journal_do_submit_data(wbuf, bufs); | 289 | journal_do_submit_data(wbuf, bufs); |
290 | |||
291 | return err; | ||
274 | } | 292 | } |
275 | 293 | ||
276 | /* | 294 | /* |
@@ -410,8 +428,7 @@ void journal_commit_transaction(journal_t *journal) | |||
410 | * Now start flushing things to disk, in the order they appear | 428 | * Now start flushing things to disk, in the order they appear |
411 | * on the transaction lists. Data blocks go first. | 429 | * on the transaction lists. Data blocks go first. |
412 | */ | 430 | */ |
413 | err = 0; | 431 | err = journal_submit_data_buffers(journal, commit_transaction); |
414 | journal_submit_data_buffers(journal, commit_transaction); | ||
415 | 432 | ||
416 | /* | 433 | /* |
417 | * Wait for all previously submitted IO to complete. | 434 | * Wait for all previously submitted IO to complete. |
@@ -426,10 +443,21 @@ void journal_commit_transaction(journal_t *journal) | |||
426 | if (buffer_locked(bh)) { | 443 | if (buffer_locked(bh)) { |
427 | spin_unlock(&journal->j_list_lock); | 444 | spin_unlock(&journal->j_list_lock); |
428 | wait_on_buffer(bh); | 445 | wait_on_buffer(bh); |
429 | if (unlikely(!buffer_uptodate(bh))) | ||
430 | err = -EIO; | ||
431 | spin_lock(&journal->j_list_lock); | 446 | spin_lock(&journal->j_list_lock); |
432 | } | 447 | } |
448 | if (unlikely(!buffer_uptodate(bh))) { | ||
449 | if (!trylock_page(bh->b_page)) { | ||
450 | spin_unlock(&journal->j_list_lock); | ||
451 | lock_page(bh->b_page); | ||
452 | spin_lock(&journal->j_list_lock); | ||
453 | } | ||
454 | if (bh->b_page->mapping) | ||
455 | set_bit(AS_EIO, &bh->b_page->mapping->flags); | ||
456 | |||
457 | unlock_page(bh->b_page); | ||
458 | SetPageError(bh->b_page); | ||
459 | err = -EIO; | ||
460 | } | ||
433 | if (!inverted_lock(journal, bh)) { | 461 | if (!inverted_lock(journal, bh)) { |
434 | put_bh(bh); | 462 | put_bh(bh); |
435 | spin_lock(&journal->j_list_lock); | 463 | spin_lock(&journal->j_list_lock); |
@@ -443,17 +471,21 @@ void journal_commit_transaction(journal_t *journal) | |||
443 | } else { | 471 | } else { |
444 | jbd_unlock_bh_state(bh); | 472 | jbd_unlock_bh_state(bh); |
445 | } | 473 | } |
446 | put_bh(bh); | 474 | release_data_buffer(bh); |
447 | cond_resched_lock(&journal->j_list_lock); | 475 | cond_resched_lock(&journal->j_list_lock); |
448 | } | 476 | } |
449 | spin_unlock(&journal->j_list_lock); | 477 | spin_unlock(&journal->j_list_lock); |
450 | 478 | ||
451 | if (err) | 479 | if (err) { |
452 | journal_abort(journal, err); | 480 | char b[BDEVNAME_SIZE]; |
453 | 481 | ||
454 | journal_write_revoke_records(journal, commit_transaction); | 482 | printk(KERN_WARNING |
483 | "JBD: Detected IO errors while flushing file data " | ||
484 | "on %s\n", bdevname(journal->j_fs_dev, b)); | ||
485 | err = 0; | ||
486 | } | ||
455 | 487 | ||
456 | jbd_debug(3, "JBD: commit phase 2\n"); | 488 | journal_write_revoke_records(journal, commit_transaction); |
457 | 489 | ||
458 | /* | 490 | /* |
459 | * If we found any dirty or locked buffers, then we should have | 491 | * If we found any dirty or locked buffers, then we should have |
diff --git a/fs/jbd/journal.c b/fs/jbd/journal.c index b99c3b3654c4..aa7143a8349b 100644 --- a/fs/jbd/journal.c +++ b/fs/jbd/journal.c | |||
@@ -68,7 +68,6 @@ EXPORT_SYMBOL(journal_set_features); | |||
68 | EXPORT_SYMBOL(journal_create); | 68 | EXPORT_SYMBOL(journal_create); |
69 | EXPORT_SYMBOL(journal_load); | 69 | EXPORT_SYMBOL(journal_load); |
70 | EXPORT_SYMBOL(journal_destroy); | 70 | EXPORT_SYMBOL(journal_destroy); |
71 | EXPORT_SYMBOL(journal_update_superblock); | ||
72 | EXPORT_SYMBOL(journal_abort); | 71 | EXPORT_SYMBOL(journal_abort); |
73 | EXPORT_SYMBOL(journal_errno); | 72 | EXPORT_SYMBOL(journal_errno); |
74 | EXPORT_SYMBOL(journal_ack_err); | 73 | EXPORT_SYMBOL(journal_ack_err); |
@@ -1636,9 +1635,10 @@ static int journal_init_journal_head_cache(void) | |||
1636 | 1635 | ||
1637 | static void journal_destroy_journal_head_cache(void) | 1636 | static void journal_destroy_journal_head_cache(void) |
1638 | { | 1637 | { |
1639 | J_ASSERT(journal_head_cache != NULL); | 1638 | if (journal_head_cache) { |
1640 | kmem_cache_destroy(journal_head_cache); | 1639 | kmem_cache_destroy(journal_head_cache); |
1641 | journal_head_cache = NULL; | 1640 | journal_head_cache = NULL; |
1641 | } | ||
1642 | } | 1642 | } |
1643 | 1643 | ||
1644 | /* | 1644 | /* |
diff --git a/fs/jbd/revoke.c b/fs/jbd/revoke.c index 1bb43e987f4b..c7bd649bbbdc 100644 --- a/fs/jbd/revoke.c +++ b/fs/jbd/revoke.c | |||
@@ -166,138 +166,123 @@ static struct jbd_revoke_record_s *find_revoke_record(journal_t *journal, | |||
166 | return NULL; | 166 | return NULL; |
167 | } | 167 | } |
168 | 168 | ||
169 | void journal_destroy_revoke_caches(void) | ||
170 | { | ||
171 | if (revoke_record_cache) { | ||
172 | kmem_cache_destroy(revoke_record_cache); | ||
173 | revoke_record_cache = NULL; | ||
174 | } | ||
175 | if (revoke_table_cache) { | ||
176 | kmem_cache_destroy(revoke_table_cache); | ||
177 | revoke_table_cache = NULL; | ||
178 | } | ||
179 | } | ||
180 | |||
169 | int __init journal_init_revoke_caches(void) | 181 | int __init journal_init_revoke_caches(void) |
170 | { | 182 | { |
183 | J_ASSERT(!revoke_record_cache); | ||
184 | J_ASSERT(!revoke_table_cache); | ||
185 | |||
171 | revoke_record_cache = kmem_cache_create("revoke_record", | 186 | revoke_record_cache = kmem_cache_create("revoke_record", |
172 | sizeof(struct jbd_revoke_record_s), | 187 | sizeof(struct jbd_revoke_record_s), |
173 | 0, | 188 | 0, |
174 | SLAB_HWCACHE_ALIGN|SLAB_TEMPORARY, | 189 | SLAB_HWCACHE_ALIGN|SLAB_TEMPORARY, |
175 | NULL); | 190 | NULL); |
176 | if (!revoke_record_cache) | 191 | if (!revoke_record_cache) |
177 | return -ENOMEM; | 192 | goto record_cache_failure; |
178 | 193 | ||
179 | revoke_table_cache = kmem_cache_create("revoke_table", | 194 | revoke_table_cache = kmem_cache_create("revoke_table", |
180 | sizeof(struct jbd_revoke_table_s), | 195 | sizeof(struct jbd_revoke_table_s), |
181 | 0, SLAB_TEMPORARY, NULL); | 196 | 0, SLAB_TEMPORARY, NULL); |
182 | if (!revoke_table_cache) { | 197 | if (!revoke_table_cache) |
183 | kmem_cache_destroy(revoke_record_cache); | 198 | goto table_cache_failure; |
184 | revoke_record_cache = NULL; | 199 | |
185 | return -ENOMEM; | ||
186 | } | ||
187 | return 0; | 200 | return 0; |
188 | } | ||
189 | 201 | ||
190 | void journal_destroy_revoke_caches(void) | 202 | table_cache_failure: |
191 | { | 203 | journal_destroy_revoke_caches(); |
192 | kmem_cache_destroy(revoke_record_cache); | 204 | record_cache_failure: |
193 | revoke_record_cache = NULL; | 205 | return -ENOMEM; |
194 | kmem_cache_destroy(revoke_table_cache); | ||
195 | revoke_table_cache = NULL; | ||
196 | } | 206 | } |
197 | 207 | ||
198 | /* Initialise the revoke table for a given journal to a given size. */ | 208 | static struct jbd_revoke_table_s *journal_init_revoke_table(int hash_size) |
199 | |||
200 | int journal_init_revoke(journal_t *journal, int hash_size) | ||
201 | { | 209 | { |
202 | int shift, tmp; | 210 | int shift = 0; |
211 | int tmp = hash_size; | ||
212 | struct jbd_revoke_table_s *table; | ||
203 | 213 | ||
204 | J_ASSERT (journal->j_revoke_table[0] == NULL); | 214 | table = kmem_cache_alloc(revoke_table_cache, GFP_KERNEL); |
215 | if (!table) | ||
216 | goto out; | ||
205 | 217 | ||
206 | shift = 0; | ||
207 | tmp = hash_size; | ||
208 | while((tmp >>= 1UL) != 0UL) | 218 | while((tmp >>= 1UL) != 0UL) |
209 | shift++; | 219 | shift++; |
210 | 220 | ||
211 | journal->j_revoke_table[0] = kmem_cache_alloc(revoke_table_cache, GFP_KERNEL); | 221 | table->hash_size = hash_size; |
212 | if (!journal->j_revoke_table[0]) | 222 | table->hash_shift = shift; |
213 | return -ENOMEM; | 223 | table->hash_table = |
214 | journal->j_revoke = journal->j_revoke_table[0]; | ||
215 | |||
216 | /* Check that the hash_size is a power of two */ | ||
217 | J_ASSERT(is_power_of_2(hash_size)); | ||
218 | |||
219 | journal->j_revoke->hash_size = hash_size; | ||
220 | |||
221 | journal->j_revoke->hash_shift = shift; | ||
222 | |||
223 | journal->j_revoke->hash_table = | ||
224 | kmalloc(hash_size * sizeof(struct list_head), GFP_KERNEL); | 224 | kmalloc(hash_size * sizeof(struct list_head), GFP_KERNEL); |
225 | if (!journal->j_revoke->hash_table) { | 225 | if (!table->hash_table) { |
226 | kmem_cache_free(revoke_table_cache, journal->j_revoke_table[0]); | 226 | kmem_cache_free(revoke_table_cache, table); |
227 | journal->j_revoke = NULL; | 227 | table = NULL; |
228 | return -ENOMEM; | 228 | goto out; |
229 | } | 229 | } |
230 | 230 | ||
231 | for (tmp = 0; tmp < hash_size; tmp++) | 231 | for (tmp = 0; tmp < hash_size; tmp++) |
232 | INIT_LIST_HEAD(&journal->j_revoke->hash_table[tmp]); | 232 | INIT_LIST_HEAD(&table->hash_table[tmp]); |
233 | 233 | ||
234 | journal->j_revoke_table[1] = kmem_cache_alloc(revoke_table_cache, GFP_KERNEL); | 234 | out: |
235 | if (!journal->j_revoke_table[1]) { | 235 | return table; |
236 | kfree(journal->j_revoke_table[0]->hash_table); | 236 | } |
237 | kmem_cache_free(revoke_table_cache, journal->j_revoke_table[0]); | 237 | |
238 | return -ENOMEM; | 238 | static void journal_destroy_revoke_table(struct jbd_revoke_table_s *table) |
239 | { | ||
240 | int i; | ||
241 | struct list_head *hash_list; | ||
242 | |||
243 | for (i = 0; i < table->hash_size; i++) { | ||
244 | hash_list = &table->hash_table[i]; | ||
245 | J_ASSERT(list_empty(hash_list)); | ||
239 | } | 246 | } |
240 | 247 | ||
241 | journal->j_revoke = journal->j_revoke_table[1]; | 248 | kfree(table->hash_table); |
249 | kmem_cache_free(revoke_table_cache, table); | ||
250 | } | ||
242 | 251 | ||
243 | /* Check that the hash_size is a power of two */ | 252 | /* Initialise the revoke table for a given journal to a given size. */ |
253 | int journal_init_revoke(journal_t *journal, int hash_size) | ||
254 | { | ||
255 | J_ASSERT(journal->j_revoke_table[0] == NULL); | ||
244 | J_ASSERT(is_power_of_2(hash_size)); | 256 | J_ASSERT(is_power_of_2(hash_size)); |
245 | 257 | ||
246 | journal->j_revoke->hash_size = hash_size; | 258 | journal->j_revoke_table[0] = journal_init_revoke_table(hash_size); |
259 | if (!journal->j_revoke_table[0]) | ||
260 | goto fail0; | ||
247 | 261 | ||
248 | journal->j_revoke->hash_shift = shift; | 262 | journal->j_revoke_table[1] = journal_init_revoke_table(hash_size); |
263 | if (!journal->j_revoke_table[1]) | ||
264 | goto fail1; | ||
249 | 265 | ||
250 | journal->j_revoke->hash_table = | 266 | journal->j_revoke = journal->j_revoke_table[1]; |
251 | kmalloc(hash_size * sizeof(struct list_head), GFP_KERNEL); | ||
252 | if (!journal->j_revoke->hash_table) { | ||
253 | kfree(journal->j_revoke_table[0]->hash_table); | ||
254 | kmem_cache_free(revoke_table_cache, journal->j_revoke_table[0]); | ||
255 | kmem_cache_free(revoke_table_cache, journal->j_revoke_table[1]); | ||
256 | journal->j_revoke = NULL; | ||
257 | return -ENOMEM; | ||
258 | } | ||
259 | |||
260 | for (tmp = 0; tmp < hash_size; tmp++) | ||
261 | INIT_LIST_HEAD(&journal->j_revoke->hash_table[tmp]); | ||
262 | 267 | ||
263 | spin_lock_init(&journal->j_revoke_lock); | 268 | spin_lock_init(&journal->j_revoke_lock); |
264 | 269 | ||
265 | return 0; | 270 | return 0; |
266 | } | ||
267 | 271 | ||
268 | /* Destoy a journal's revoke table. The table must already be empty! */ | 272 | fail1: |
273 | journal_destroy_revoke_table(journal->j_revoke_table[0]); | ||
274 | fail0: | ||
275 | return -ENOMEM; | ||
276 | } | ||
269 | 277 | ||
278 | /* Destroy a journal's revoke table. The table must already be empty! */ | ||
270 | void journal_destroy_revoke(journal_t *journal) | 279 | void journal_destroy_revoke(journal_t *journal) |
271 | { | 280 | { |
272 | struct jbd_revoke_table_s *table; | ||
273 | struct list_head *hash_list; | ||
274 | int i; | ||
275 | |||
276 | table = journal->j_revoke_table[0]; | ||
277 | if (!table) | ||
278 | return; | ||
279 | |||
280 | for (i=0; i<table->hash_size; i++) { | ||
281 | hash_list = &table->hash_table[i]; | ||
282 | J_ASSERT (list_empty(hash_list)); | ||
283 | } | ||
284 | |||
285 | kfree(table->hash_table); | ||
286 | kmem_cache_free(revoke_table_cache, table); | ||
287 | journal->j_revoke = NULL; | ||
288 | |||
289 | table = journal->j_revoke_table[1]; | ||
290 | if (!table) | ||
291 | return; | ||
292 | |||
293 | for (i=0; i<table->hash_size; i++) { | ||
294 | hash_list = &table->hash_table[i]; | ||
295 | J_ASSERT (list_empty(hash_list)); | ||
296 | } | ||
297 | |||
298 | kfree(table->hash_table); | ||
299 | kmem_cache_free(revoke_table_cache, table); | ||
300 | journal->j_revoke = NULL; | 281 | journal->j_revoke = NULL; |
282 | if (journal->j_revoke_table[0]) | ||
283 | journal_destroy_revoke_table(journal->j_revoke_table[0]); | ||
284 | if (journal->j_revoke_table[1]) | ||
285 | journal_destroy_revoke_table(journal->j_revoke_table[1]); | ||
301 | } | 286 | } |
302 | 287 | ||
303 | 288 | ||
diff --git a/fs/jbd/transaction.c b/fs/jbd/transaction.c index 67ff2024c23c..0540ca27a446 100644 --- a/fs/jbd/transaction.c +++ b/fs/jbd/transaction.c | |||
@@ -291,7 +291,7 @@ handle_t *journal_start(journal_t *journal, int nblocks) | |||
291 | goto out; | 291 | goto out; |
292 | } | 292 | } |
293 | 293 | ||
294 | lock_acquire(&handle->h_lockdep_map, 0, 0, 0, 2, _THIS_IP_); | 294 | lock_map_acquire(&handle->h_lockdep_map); |
295 | 295 | ||
296 | out: | 296 | out: |
297 | return handle; | 297 | return handle; |
@@ -1448,7 +1448,7 @@ int journal_stop(handle_t *handle) | |||
1448 | spin_unlock(&journal->j_state_lock); | 1448 | spin_unlock(&journal->j_state_lock); |
1449 | } | 1449 | } |
1450 | 1450 | ||
1451 | lock_release(&handle->h_lockdep_map, 1, _THIS_IP_); | 1451 | lock_map_release(&handle->h_lockdep_map); |
1452 | 1452 | ||
1453 | jbd_free_handle(handle); | 1453 | jbd_free_handle(handle); |
1454 | return err; | 1454 | return err; |
@@ -1648,12 +1648,42 @@ out: | |||
1648 | return; | 1648 | return; |
1649 | } | 1649 | } |
1650 | 1650 | ||
1651 | /* | ||
1652 | * journal_try_to_free_buffers() could race with journal_commit_transaction() | ||
1653 | * The latter might still hold the a count on buffers when inspecting | ||
1654 | * them on t_syncdata_list or t_locked_list. | ||
1655 | * | ||
1656 | * journal_try_to_free_buffers() will call this function to | ||
1657 | * wait for the current transaction to finish syncing data buffers, before | ||
1658 | * tryinf to free that buffer. | ||
1659 | * | ||
1660 | * Called with journal->j_state_lock held. | ||
1661 | */ | ||
1662 | static void journal_wait_for_transaction_sync_data(journal_t *journal) | ||
1663 | { | ||
1664 | transaction_t *transaction = NULL; | ||
1665 | tid_t tid; | ||
1666 | |||
1667 | spin_lock(&journal->j_state_lock); | ||
1668 | transaction = journal->j_committing_transaction; | ||
1669 | |||
1670 | if (!transaction) { | ||
1671 | spin_unlock(&journal->j_state_lock); | ||
1672 | return; | ||
1673 | } | ||
1674 | |||
1675 | tid = transaction->t_tid; | ||
1676 | spin_unlock(&journal->j_state_lock); | ||
1677 | log_wait_commit(journal, tid); | ||
1678 | } | ||
1651 | 1679 | ||
1652 | /** | 1680 | /** |
1653 | * int journal_try_to_free_buffers() - try to free page buffers. | 1681 | * int journal_try_to_free_buffers() - try to free page buffers. |
1654 | * @journal: journal for operation | 1682 | * @journal: journal for operation |
1655 | * @page: to try and free | 1683 | * @page: to try and free |
1656 | * @unused_gfp_mask: unused | 1684 | * @gfp_mask: we use the mask to detect how hard should we try to release |
1685 | * buffers. If __GFP_WAIT and __GFP_FS is set, we wait for commit code to | ||
1686 | * release the buffers. | ||
1657 | * | 1687 | * |
1658 | * | 1688 | * |
1659 | * For all the buffers on this page, | 1689 | * For all the buffers on this page, |
@@ -1682,9 +1712,11 @@ out: | |||
1682 | * journal_try_to_free_buffer() is changing its state. But that | 1712 | * journal_try_to_free_buffer() is changing its state. But that |
1683 | * cannot happen because we never reallocate freed data as metadata | 1713 | * cannot happen because we never reallocate freed data as metadata |
1684 | * while the data is part of a transaction. Yes? | 1714 | * while the data is part of a transaction. Yes? |
1715 | * | ||
1716 | * Return 0 on failure, 1 on success | ||
1685 | */ | 1717 | */ |
1686 | int journal_try_to_free_buffers(journal_t *journal, | 1718 | int journal_try_to_free_buffers(journal_t *journal, |
1687 | struct page *page, gfp_t unused_gfp_mask) | 1719 | struct page *page, gfp_t gfp_mask) |
1688 | { | 1720 | { |
1689 | struct buffer_head *head; | 1721 | struct buffer_head *head; |
1690 | struct buffer_head *bh; | 1722 | struct buffer_head *bh; |
@@ -1713,7 +1745,28 @@ int journal_try_to_free_buffers(journal_t *journal, | |||
1713 | if (buffer_jbd(bh)) | 1745 | if (buffer_jbd(bh)) |
1714 | goto busy; | 1746 | goto busy; |
1715 | } while ((bh = bh->b_this_page) != head); | 1747 | } while ((bh = bh->b_this_page) != head); |
1748 | |||
1716 | ret = try_to_free_buffers(page); | 1749 | ret = try_to_free_buffers(page); |
1750 | |||
1751 | /* | ||
1752 | * There are a number of places where journal_try_to_free_buffers() | ||
1753 | * could race with journal_commit_transaction(), the later still | ||
1754 | * holds the reference to the buffers to free while processing them. | ||
1755 | * try_to_free_buffers() failed to free those buffers. Some of the | ||
1756 | * caller of releasepage() request page buffers to be dropped, otherwise | ||
1757 | * treat the fail-to-free as errors (such as generic_file_direct_IO()) | ||
1758 | * | ||
1759 | * So, if the caller of try_to_release_page() wants the synchronous | ||
1760 | * behaviour(i.e make sure buffers are dropped upon return), | ||
1761 | * let's wait for the current transaction to finish flush of | ||
1762 | * dirty data buffers, then try to free those buffers again, | ||
1763 | * with the journal locked. | ||
1764 | */ | ||
1765 | if (ret == 0 && (gfp_mask & __GFP_WAIT) && (gfp_mask & __GFP_FS)) { | ||
1766 | journal_wait_for_transaction_sync_data(journal); | ||
1767 | ret = try_to_free_buffers(page); | ||
1768 | } | ||
1769 | |||
1717 | busy: | 1770 | busy: |
1718 | return ret; | 1771 | return ret; |
1719 | } | 1772 | } |