0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080 #ifndef __KERNEL__
0081 #include "jfs_user.h"
0082 #else
0083 #include <linux/time.h>
0084 #include <linux/fs.h>
0085 #include <linux/jbd2.h>
0086 #include <linux/errno.h>
0087 #include <linux/slab.h>
0088 #include <linux/list.h>
0089 #include <linux/init.h>
0090 #include <linux/bio.h>
0091 #include <linux/log2.h>
0092 #include <linux/hash.h>
0093 #endif
0094
0095 static struct kmem_cache *jbd2_revoke_record_cache;
0096 static struct kmem_cache *jbd2_revoke_table_cache;
0097
0098
0099
0100
0101
0102 struct jbd2_revoke_record_s
0103 {
0104 struct list_head hash;
0105 tid_t sequence;
0106 unsigned long long blocknr;
0107 };
0108
0109
0110
0111 struct jbd2_revoke_table_s
0112 {
0113
0114
0115 int hash_size;
0116 int hash_shift;
0117 struct list_head *hash_table;
0118 };
0119
0120
0121 #ifdef __KERNEL__
0122 static void write_one_revoke_record(transaction_t *,
0123 struct list_head *,
0124 struct buffer_head **, int *,
0125 struct jbd2_revoke_record_s *);
0126 static void flush_descriptor(journal_t *, struct buffer_head *, int);
0127 #endif
0128
0129
0130
0131 static inline int hash(journal_t *journal, unsigned long long block)
0132 {
0133 return hash_64(block, journal->j_revoke->hash_shift);
0134 }
0135
0136 static int insert_revoke_hash(journal_t *journal, unsigned long long blocknr,
0137 tid_t seq)
0138 {
0139 struct list_head *hash_list;
0140 struct jbd2_revoke_record_s *record;
0141 gfp_t gfp_mask = GFP_NOFS;
0142
0143 if (journal_oom_retry)
0144 gfp_mask |= __GFP_NOFAIL;
0145 record = kmem_cache_alloc(jbd2_revoke_record_cache, gfp_mask);
0146 if (!record)
0147 return -ENOMEM;
0148
0149 record->sequence = seq;
0150 record->blocknr = blocknr;
0151 hash_list = &journal->j_revoke->hash_table[hash(journal, blocknr)];
0152 spin_lock(&journal->j_revoke_lock);
0153 list_add(&record->hash, hash_list);
0154 spin_unlock(&journal->j_revoke_lock);
0155 return 0;
0156 }
0157
0158
0159
0160 static struct jbd2_revoke_record_s *find_revoke_record(journal_t *journal,
0161 unsigned long long blocknr)
0162 {
0163 struct list_head *hash_list;
0164 struct jbd2_revoke_record_s *record;
0165
0166 hash_list = &journal->j_revoke->hash_table[hash(journal, blocknr)];
0167
0168 spin_lock(&journal->j_revoke_lock);
0169 record = (struct jbd2_revoke_record_s *) hash_list->next;
0170 while (&(record->hash) != hash_list) {
0171 if (record->blocknr == blocknr) {
0172 spin_unlock(&journal->j_revoke_lock);
0173 return record;
0174 }
0175 record = (struct jbd2_revoke_record_s *) record->hash.next;
0176 }
0177 spin_unlock(&journal->j_revoke_lock);
0178 return NULL;
0179 }
0180
0181 void jbd2_journal_destroy_revoke_record_cache(void)
0182 {
0183 kmem_cache_destroy(jbd2_revoke_record_cache);
0184 jbd2_revoke_record_cache = NULL;
0185 }
0186
0187 void jbd2_journal_destroy_revoke_table_cache(void)
0188 {
0189 kmem_cache_destroy(jbd2_revoke_table_cache);
0190 jbd2_revoke_table_cache = NULL;
0191 }
0192
0193 int __init jbd2_journal_init_revoke_record_cache(void)
0194 {
0195 J_ASSERT(!jbd2_revoke_record_cache);
0196 jbd2_revoke_record_cache = KMEM_CACHE(jbd2_revoke_record_s,
0197 SLAB_HWCACHE_ALIGN|SLAB_TEMPORARY);
0198
0199 if (!jbd2_revoke_record_cache) {
0200 pr_emerg("JBD2: failed to create revoke_record cache\n");
0201 return -ENOMEM;
0202 }
0203 return 0;
0204 }
0205
0206 int __init jbd2_journal_init_revoke_table_cache(void)
0207 {
0208 J_ASSERT(!jbd2_revoke_table_cache);
0209 jbd2_revoke_table_cache = KMEM_CACHE(jbd2_revoke_table_s,
0210 SLAB_TEMPORARY);
0211 if (!jbd2_revoke_table_cache) {
0212 pr_emerg("JBD2: failed to create revoke_table cache\n");
0213 return -ENOMEM;
0214 }
0215 return 0;
0216 }
0217
0218 static struct jbd2_revoke_table_s *jbd2_journal_init_revoke_table(int hash_size)
0219 {
0220 int shift = 0;
0221 int tmp = hash_size;
0222 struct jbd2_revoke_table_s *table;
0223
0224 table = kmem_cache_alloc(jbd2_revoke_table_cache, GFP_KERNEL);
0225 if (!table)
0226 goto out;
0227
0228 while((tmp >>= 1UL) != 0UL)
0229 shift++;
0230
0231 table->hash_size = hash_size;
0232 table->hash_shift = shift;
0233 table->hash_table =
0234 kmalloc_array(hash_size, sizeof(struct list_head), GFP_KERNEL);
0235 if (!table->hash_table) {
0236 kmem_cache_free(jbd2_revoke_table_cache, table);
0237 table = NULL;
0238 goto out;
0239 }
0240
0241 for (tmp = 0; tmp < hash_size; tmp++)
0242 INIT_LIST_HEAD(&table->hash_table[tmp]);
0243
0244 out:
0245 return table;
0246 }
0247
0248 static void jbd2_journal_destroy_revoke_table(struct jbd2_revoke_table_s *table)
0249 {
0250 int i;
0251 struct list_head *hash_list;
0252
0253 for (i = 0; i < table->hash_size; i++) {
0254 hash_list = &table->hash_table[i];
0255 J_ASSERT(list_empty(hash_list));
0256 }
0257
0258 kfree(table->hash_table);
0259 kmem_cache_free(jbd2_revoke_table_cache, table);
0260 }
0261
0262
0263 int jbd2_journal_init_revoke(journal_t *journal, int hash_size)
0264 {
0265 J_ASSERT(journal->j_revoke_table[0] == NULL);
0266 J_ASSERT(is_power_of_2(hash_size));
0267
0268 journal->j_revoke_table[0] = jbd2_journal_init_revoke_table(hash_size);
0269 if (!journal->j_revoke_table[0])
0270 goto fail0;
0271
0272 journal->j_revoke_table[1] = jbd2_journal_init_revoke_table(hash_size);
0273 if (!journal->j_revoke_table[1])
0274 goto fail1;
0275
0276 journal->j_revoke = journal->j_revoke_table[1];
0277
0278 spin_lock_init(&journal->j_revoke_lock);
0279
0280 return 0;
0281
0282 fail1:
0283 jbd2_journal_destroy_revoke_table(journal->j_revoke_table[0]);
0284 journal->j_revoke_table[0] = NULL;
0285 fail0:
0286 return -ENOMEM;
0287 }
0288
0289
0290 void jbd2_journal_destroy_revoke(journal_t *journal)
0291 {
0292 journal->j_revoke = NULL;
0293 if (journal->j_revoke_table[0])
0294 jbd2_journal_destroy_revoke_table(journal->j_revoke_table[0]);
0295 if (journal->j_revoke_table[1])
0296 jbd2_journal_destroy_revoke_table(journal->j_revoke_table[1]);
0297 }
0298
0299
0300 #ifdef __KERNEL__
0301
0302
0303
0304
0305
0306
0307
0308
0309
0310
0311
0312
0313
0314
0315
0316
0317
0318
0319
0320
0321
0322
0323
0324
0325
0326 int jbd2_journal_revoke(handle_t *handle, unsigned long long blocknr,
0327 struct buffer_head *bh_in)
0328 {
0329 struct buffer_head *bh = NULL;
0330 journal_t *journal;
0331 struct block_device *bdev;
0332 int err;
0333
0334 might_sleep();
0335 if (bh_in)
0336 BUFFER_TRACE(bh_in, "enter");
0337
0338 journal = handle->h_transaction->t_journal;
0339 if (!jbd2_journal_set_features(journal, 0, 0, JBD2_FEATURE_INCOMPAT_REVOKE)){
0340 J_ASSERT (!"Cannot set revoke feature!");
0341 return -EINVAL;
0342 }
0343
0344 bdev = journal->j_fs_dev;
0345 bh = bh_in;
0346
0347 if (!bh) {
0348 bh = __find_get_block(bdev, blocknr, journal->j_blocksize);
0349 if (bh)
0350 BUFFER_TRACE(bh, "found on hash");
0351 }
0352 #ifdef JBD2_EXPENSIVE_CHECKING
0353 else {
0354 struct buffer_head *bh2;
0355
0356
0357
0358 bh2 = __find_get_block(bdev, blocknr, journal->j_blocksize);
0359 if (bh2) {
0360
0361 if (bh2 != bh && buffer_revokevalid(bh2))
0362
0363
0364
0365
0366
0367
0368 J_ASSERT_BH(bh2, buffer_revoked(bh2));
0369 put_bh(bh2);
0370 }
0371 }
0372 #endif
0373
0374 if (WARN_ON_ONCE(handle->h_revoke_credits <= 0)) {
0375 if (!bh_in)
0376 brelse(bh);
0377 return -EIO;
0378 }
0379
0380
0381
0382 if (bh) {
0383 if (!J_EXPECT_BH(bh, !buffer_revoked(bh),
0384 "inconsistent data on disk")) {
0385 if (!bh_in)
0386 brelse(bh);
0387 return -EIO;
0388 }
0389 set_buffer_revoked(bh);
0390 set_buffer_revokevalid(bh);
0391 if (bh_in) {
0392 BUFFER_TRACE(bh_in, "call jbd2_journal_forget");
0393 jbd2_journal_forget(handle, bh_in);
0394 } else {
0395 BUFFER_TRACE(bh, "call brelse");
0396 __brelse(bh);
0397 }
0398 }
0399 handle->h_revoke_credits--;
0400
0401 jbd2_debug(2, "insert revoke for block %llu, bh_in=%p\n",blocknr, bh_in);
0402 err = insert_revoke_hash(journal, blocknr,
0403 handle->h_transaction->t_tid);
0404 BUFFER_TRACE(bh_in, "exit");
0405 return err;
0406 }
0407
0408
0409
0410
0411
0412
0413
0414
0415
0416
0417
0418
0419
0420
0421
0422
0423 int jbd2_journal_cancel_revoke(handle_t *handle, struct journal_head *jh)
0424 {
0425 struct jbd2_revoke_record_s *record;
0426 journal_t *journal = handle->h_transaction->t_journal;
0427 int need_cancel;
0428 int did_revoke = 0;
0429 struct buffer_head *bh = jh2bh(jh);
0430
0431 jbd2_debug(4, "journal_head %p, cancelling revoke\n", jh);
0432
0433
0434
0435
0436
0437 if (test_set_buffer_revokevalid(bh)) {
0438 need_cancel = test_clear_buffer_revoked(bh);
0439 } else {
0440 need_cancel = 1;
0441 clear_buffer_revoked(bh);
0442 }
0443
0444 if (need_cancel) {
0445 record = find_revoke_record(journal, bh->b_blocknr);
0446 if (record) {
0447 jbd2_debug(4, "cancelled existing revoke on "
0448 "blocknr %llu\n", (unsigned long long)bh->b_blocknr);
0449 spin_lock(&journal->j_revoke_lock);
0450 list_del(&record->hash);
0451 spin_unlock(&journal->j_revoke_lock);
0452 kmem_cache_free(jbd2_revoke_record_cache, record);
0453 did_revoke = 1;
0454 }
0455 }
0456
0457 #ifdef JBD2_EXPENSIVE_CHECKING
0458
0459 record = find_revoke_record(journal, bh->b_blocknr);
0460 J_ASSERT_JH(jh, record == NULL);
0461 #endif
0462
0463
0464
0465
0466
0467 if (need_cancel) {
0468 struct buffer_head *bh2;
0469 bh2 = __find_get_block(bh->b_bdev, bh->b_blocknr, bh->b_size);
0470 if (bh2) {
0471 if (bh2 != bh)
0472 clear_buffer_revoked(bh2);
0473 __brelse(bh2);
0474 }
0475 }
0476 return did_revoke;
0477 }
0478
0479
0480
0481
0482
0483
0484 void jbd2_clear_buffer_revoked_flags(journal_t *journal)
0485 {
0486 struct jbd2_revoke_table_s *revoke = journal->j_revoke;
0487 int i = 0;
0488
0489 for (i = 0; i < revoke->hash_size; i++) {
0490 struct list_head *hash_list;
0491 struct list_head *list_entry;
0492 hash_list = &revoke->hash_table[i];
0493
0494 list_for_each(list_entry, hash_list) {
0495 struct jbd2_revoke_record_s *record;
0496 struct buffer_head *bh;
0497 record = (struct jbd2_revoke_record_s *)list_entry;
0498 bh = __find_get_block(journal->j_fs_dev,
0499 record->blocknr,
0500 journal->j_blocksize);
0501 if (bh) {
0502 clear_buffer_revoked(bh);
0503 __brelse(bh);
0504 }
0505 }
0506 }
0507 }
0508
0509
0510
0511
0512
0513 void jbd2_journal_switch_revoke_table(journal_t *journal)
0514 {
0515 int i;
0516
0517 if (journal->j_revoke == journal->j_revoke_table[0])
0518 journal->j_revoke = journal->j_revoke_table[1];
0519 else
0520 journal->j_revoke = journal->j_revoke_table[0];
0521
0522 for (i = 0; i < journal->j_revoke->hash_size; i++)
0523 INIT_LIST_HEAD(&journal->j_revoke->hash_table[i]);
0524 }
0525
0526
0527
0528
0529
0530 void jbd2_journal_write_revoke_records(transaction_t *transaction,
0531 struct list_head *log_bufs)
0532 {
0533 journal_t *journal = transaction->t_journal;
0534 struct buffer_head *descriptor;
0535 struct jbd2_revoke_record_s *record;
0536 struct jbd2_revoke_table_s *revoke;
0537 struct list_head *hash_list;
0538 int i, offset, count;
0539
0540 descriptor = NULL;
0541 offset = 0;
0542 count = 0;
0543
0544
0545 revoke = journal->j_revoke == journal->j_revoke_table[0] ?
0546 journal->j_revoke_table[1] : journal->j_revoke_table[0];
0547
0548 for (i = 0; i < revoke->hash_size; i++) {
0549 hash_list = &revoke->hash_table[i];
0550
0551 while (!list_empty(hash_list)) {
0552 record = (struct jbd2_revoke_record_s *)
0553 hash_list->next;
0554 write_one_revoke_record(transaction, log_bufs,
0555 &descriptor, &offset, record);
0556 count++;
0557 list_del(&record->hash);
0558 kmem_cache_free(jbd2_revoke_record_cache, record);
0559 }
0560 }
0561 if (descriptor)
0562 flush_descriptor(journal, descriptor, offset);
0563 jbd2_debug(1, "Wrote %d revoke records\n", count);
0564 }
0565
0566
0567
0568
0569
0570
0571 static void write_one_revoke_record(transaction_t *transaction,
0572 struct list_head *log_bufs,
0573 struct buffer_head **descriptorp,
0574 int *offsetp,
0575 struct jbd2_revoke_record_s *record)
0576 {
0577 journal_t *journal = transaction->t_journal;
0578 int csum_size = 0;
0579 struct buffer_head *descriptor;
0580 int sz, offset;
0581
0582
0583
0584
0585
0586 if (is_journal_aborted(journal))
0587 return;
0588
0589 descriptor = *descriptorp;
0590 offset = *offsetp;
0591
0592
0593 if (jbd2_journal_has_csum_v2or3(journal))
0594 csum_size = sizeof(struct jbd2_journal_block_tail);
0595
0596 if (jbd2_has_feature_64bit(journal))
0597 sz = 8;
0598 else
0599 sz = 4;
0600
0601
0602 if (descriptor) {
0603 if (offset + sz > journal->j_blocksize - csum_size) {
0604 flush_descriptor(journal, descriptor, offset);
0605 descriptor = NULL;
0606 }
0607 }
0608
0609 if (!descriptor) {
0610 descriptor = jbd2_journal_get_descriptor_buffer(transaction,
0611 JBD2_REVOKE_BLOCK);
0612 if (!descriptor)
0613 return;
0614
0615
0616 BUFFER_TRACE(descriptor, "file in log_bufs");
0617 jbd2_file_log_bh(log_bufs, descriptor);
0618
0619 offset = sizeof(jbd2_journal_revoke_header_t);
0620 *descriptorp = descriptor;
0621 }
0622
0623 if (jbd2_has_feature_64bit(journal))
0624 * ((__be64 *)(&descriptor->b_data[offset])) =
0625 cpu_to_be64(record->blocknr);
0626 else
0627 * ((__be32 *)(&descriptor->b_data[offset])) =
0628 cpu_to_be32(record->blocknr);
0629 offset += sz;
0630
0631 *offsetp = offset;
0632 }
0633
0634
0635
0636
0637
0638
0639
0640
0641 static void flush_descriptor(journal_t *journal,
0642 struct buffer_head *descriptor,
0643 int offset)
0644 {
0645 jbd2_journal_revoke_header_t *header;
0646
0647 if (is_journal_aborted(journal))
0648 return;
0649
0650 header = (jbd2_journal_revoke_header_t *)descriptor->b_data;
0651 header->r_count = cpu_to_be32(offset);
0652 jbd2_descriptor_block_csum_set(journal, descriptor);
0653
0654 set_buffer_jwrite(descriptor);
0655 BUFFER_TRACE(descriptor, "write");
0656 set_buffer_dirty(descriptor);
0657 write_dirty_buffer(descriptor, REQ_SYNC);
0658 }
0659 #endif
0660
0661
0662
0663
0664
0665
0666
0667
0668
0669
0670
0671
0672
0673
0674
0675
0676
0677
0678
0679
0680
0681
0682
0683 int jbd2_journal_set_revoke(journal_t *journal,
0684 unsigned long long blocknr,
0685 tid_t sequence)
0686 {
0687 struct jbd2_revoke_record_s *record;
0688
0689 record = find_revoke_record(journal, blocknr);
0690 if (record) {
0691
0692
0693 if (tid_gt(sequence, record->sequence))
0694 record->sequence = sequence;
0695 return 0;
0696 }
0697 return insert_revoke_hash(journal, blocknr, sequence);
0698 }
0699
0700
0701
0702
0703
0704
0705
0706
0707 int jbd2_journal_test_revoke(journal_t *journal,
0708 unsigned long long blocknr,
0709 tid_t sequence)
0710 {
0711 struct jbd2_revoke_record_s *record;
0712
0713 record = find_revoke_record(journal, blocknr);
0714 if (!record)
0715 return 0;
0716 if (tid_gt(sequence, record->sequence))
0717 return 0;
0718 return 1;
0719 }
0720
0721
0722
0723
0724
0725
0726 void jbd2_journal_clear_revoke(journal_t *journal)
0727 {
0728 int i;
0729 struct list_head *hash_list;
0730 struct jbd2_revoke_record_s *record;
0731 struct jbd2_revoke_table_s *revoke;
0732
0733 revoke = journal->j_revoke;
0734
0735 for (i = 0; i < revoke->hash_size; i++) {
0736 hash_list = &revoke->hash_table[i];
0737 while (!list_empty(hash_list)) {
0738 record = (struct jbd2_revoke_record_s*) hash_list->next;
0739 list_del(&record->hash);
0740 kmem_cache_free(jbd2_revoke_record_cache, record);
0741 }
0742 }
0743 }