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 | } |
