OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [fs/] [jbd2/] [revoke.c] - Blame information for rev 62

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
2
 * linux/fs/jbd2/revoke.c
3
 *
4
 * Written by Stephen C. Tweedie <sct@redhat.com>, 2000
5
 *
6
 * Copyright 2000 Red Hat corp --- All Rights Reserved
7
 *
8
 * This file is part of the Linux kernel and is made available under
9
 * the terms of the GNU General Public License, version 2, or at your
10
 * option, any later version, incorporated herein by reference.
11
 *
12
 * Journal revoke routines for the generic filesystem journaling code;
13
 * part of the ext2fs journaling system.
14
 *
15
 * Revoke is the mechanism used to prevent old log records for deleted
16
 * metadata from being replayed on top of newer data using the same
17
 * blocks.  The revoke mechanism is used in two separate places:
18
 *
19
 * + Commit: during commit we write the entire list of the current
20
 *   transaction's revoked blocks to the journal
21
 *
22
 * + Recovery: during recovery we record the transaction ID of all
23
 *   revoked blocks.  If there are multiple revoke records in the log
24
 *   for a single block, only the last one counts, and if there is a log
25
 *   entry for a block beyond the last revoke, then that log entry still
26
 *   gets replayed.
27
 *
28
 * We can get interactions between revokes and new log data within a
29
 * single transaction:
30
 *
31
 * Block is revoked and then journaled:
32
 *   The desired end result is the journaling of the new block, so we
33
 *   cancel the revoke before the transaction commits.
34
 *
35
 * Block is journaled and then revoked:
36
 *   The revoke must take precedence over the write of the block, so we
37
 *   need either to cancel the journal entry or to write the revoke
38
 *   later in the log than the log block.  In this case, we choose the
39
 *   latter: journaling a block cancels any revoke record for that block
40
 *   in the current transaction, so any revoke for that block in the
41
 *   transaction must have happened after the block was journaled and so
42
 *   the revoke must take precedence.
43
 *
44
 * Block is revoked and then written as data:
45
 *   The data write is allowed to succeed, but the revoke is _not_
46
 *   cancelled.  We still need to prevent old log records from
47
 *   overwriting the new data.  We don't even need to clear the revoke
48
 *   bit here.
49
 *
50
 * Revoke information on buffers is a tri-state value:
51
 *
52
 * RevokeValid clear:   no cached revoke status, need to look it up
53
 * RevokeValid set, Revoked clear:
54
 *                      buffer has not been revoked, and cancel_revoke
55
 *                      need do nothing.
56
 * RevokeValid set, Revoked set:
57
 *                      buffer has been revoked.
58
 */
59
 
60
#ifndef __KERNEL__
61
#include "jfs_user.h"
62
#else
63
#include <linux/time.h>
64
#include <linux/fs.h>
65
#include <linux/jbd2.h>
66
#include <linux/errno.h>
67
#include <linux/slab.h>
68
#include <linux/list.h>
69
#include <linux/init.h>
70
#endif
71
#include <linux/log2.h>
72
 
73
static struct kmem_cache *jbd2_revoke_record_cache;
74
static struct kmem_cache *jbd2_revoke_table_cache;
75
 
76
/* Each revoke record represents one single revoked block.  During
77
   journal replay, this involves recording the transaction ID of the
78
   last transaction to revoke this block. */
79
 
80
struct jbd2_revoke_record_s
81
{
82
        struct list_head  hash;
83
        tid_t             sequence;     /* Used for recovery only */
84
        unsigned long long        blocknr;
85
};
86
 
87
 
88
/* The revoke table is just a simple hash table of revoke records. */
89
struct jbd2_revoke_table_s
90
{
91
        /* It is conceivable that we might want a larger hash table
92
         * for recovery.  Must be a power of two. */
93
        int               hash_size;
94
        int               hash_shift;
95
        struct list_head *hash_table;
96
};
97
 
98
 
99
#ifdef __KERNEL__
100
static void write_one_revoke_record(journal_t *, transaction_t *,
101
                                    struct journal_head **, int *,
102
                                    struct jbd2_revoke_record_s *);
103
static void flush_descriptor(journal_t *, struct journal_head *, int);
104
#endif
105
 
106
/* Utility functions to maintain the revoke table */
107
 
108
/* Borrowed from buffer.c: this is a tried and tested block hash function */
109
static inline int hash(journal_t *journal, unsigned long long block)
110
{
111
        struct jbd2_revoke_table_s *table = journal->j_revoke;
112
        int hash_shift = table->hash_shift;
113
        int hash = (int)block ^ (int)((block >> 31) >> 1);
114
 
115
        return ((hash << (hash_shift - 6)) ^
116
                (hash >> 13) ^
117
                (hash << (hash_shift - 12))) & (table->hash_size - 1);
118
}
119
 
120
static int insert_revoke_hash(journal_t *journal, unsigned long long blocknr,
121
                              tid_t seq)
122
{
123
        struct list_head *hash_list;
124
        struct jbd2_revoke_record_s *record;
125
 
126
repeat:
127
        record = kmem_cache_alloc(jbd2_revoke_record_cache, GFP_NOFS);
128
        if (!record)
129
                goto oom;
130
 
131
        record->sequence = seq;
132
        record->blocknr = blocknr;
133
        hash_list = &journal->j_revoke->hash_table[hash(journal, blocknr)];
134
        spin_lock(&journal->j_revoke_lock);
135
        list_add(&record->hash, hash_list);
136
        spin_unlock(&journal->j_revoke_lock);
137
        return 0;
138
 
139
oom:
140
        if (!journal_oom_retry)
141
                return -ENOMEM;
142
        jbd_debug(1, "ENOMEM in %s, retrying\n", __FUNCTION__);
143
        yield();
144
        goto repeat;
145
}
146
 
147
/* Find a revoke record in the journal's hash table. */
148
 
149
static struct jbd2_revoke_record_s *find_revoke_record(journal_t *journal,
150
                                                      unsigned long long blocknr)
151
{
152
        struct list_head *hash_list;
153
        struct jbd2_revoke_record_s *record;
154
 
155
        hash_list = &journal->j_revoke->hash_table[hash(journal, blocknr)];
156
 
157
        spin_lock(&journal->j_revoke_lock);
158
        record = (struct jbd2_revoke_record_s *) hash_list->next;
159
        while (&(record->hash) != hash_list) {
160
                if (record->blocknr == blocknr) {
161
                        spin_unlock(&journal->j_revoke_lock);
162
                        return record;
163
                }
164
                record = (struct jbd2_revoke_record_s *) record->hash.next;
165
        }
166
        spin_unlock(&journal->j_revoke_lock);
167
        return NULL;
168
}
169
 
170
int __init jbd2_journal_init_revoke_caches(void)
171
{
172
        jbd2_revoke_record_cache = kmem_cache_create("jbd2_revoke_record",
173
                                           sizeof(struct jbd2_revoke_record_s),
174
                                           0, SLAB_HWCACHE_ALIGN, NULL);
175
        if (jbd2_revoke_record_cache == 0)
176
                return -ENOMEM;
177
 
178
        jbd2_revoke_table_cache = kmem_cache_create("jbd2_revoke_table",
179
                                           sizeof(struct jbd2_revoke_table_s),
180
                                           0, 0, NULL);
181
        if (jbd2_revoke_table_cache == 0) {
182
                kmem_cache_destroy(jbd2_revoke_record_cache);
183
                jbd2_revoke_record_cache = NULL;
184
                return -ENOMEM;
185
        }
186
        return 0;
187
}
188
 
189
void jbd2_journal_destroy_revoke_caches(void)
190
{
191
        kmem_cache_destroy(jbd2_revoke_record_cache);
192
        jbd2_revoke_record_cache = NULL;
193
        kmem_cache_destroy(jbd2_revoke_table_cache);
194
        jbd2_revoke_table_cache = NULL;
195
}
196
 
197
/* Initialise the revoke table for a given journal to a given size. */
198
 
199
int jbd2_journal_init_revoke(journal_t *journal, int hash_size)
200
{
201
        int shift, tmp;
202
 
203
        J_ASSERT (journal->j_revoke_table[0] == NULL);
204
 
205
        shift = 0;
206
        tmp = hash_size;
207
        while((tmp >>= 1UL) != 0UL)
208
                shift++;
209
 
210
        journal->j_revoke_table[0] = kmem_cache_alloc(jbd2_revoke_table_cache, GFP_KERNEL);
211
        if (!journal->j_revoke_table[0])
212
                return -ENOMEM;
213
        journal->j_revoke = journal->j_revoke_table[0];
214
 
215
        /* Check that the hash_size is a power of two */
216
        J_ASSERT(is_power_of_2(hash_size));
217
 
218
        journal->j_revoke->hash_size = hash_size;
219
 
220
        journal->j_revoke->hash_shift = shift;
221
 
222
        journal->j_revoke->hash_table =
223
                kmalloc(hash_size * sizeof(struct list_head), GFP_KERNEL);
224
        if (!journal->j_revoke->hash_table) {
225
                kmem_cache_free(jbd2_revoke_table_cache, journal->j_revoke_table[0]);
226
                journal->j_revoke = NULL;
227
                return -ENOMEM;
228
        }
229
 
230
        for (tmp = 0; tmp < hash_size; tmp++)
231
                INIT_LIST_HEAD(&journal->j_revoke->hash_table[tmp]);
232
 
233
        journal->j_revoke_table[1] = kmem_cache_alloc(jbd2_revoke_table_cache, GFP_KERNEL);
234
        if (!journal->j_revoke_table[1]) {
235
                kfree(journal->j_revoke_table[0]->hash_table);
236
                kmem_cache_free(jbd2_revoke_table_cache, journal->j_revoke_table[0]);
237
                return -ENOMEM;
238
        }
239
 
240
        journal->j_revoke = journal->j_revoke_table[1];
241
 
242
        /* Check that the hash_size is a power of two */
243
        J_ASSERT(is_power_of_2(hash_size));
244
 
245
        journal->j_revoke->hash_size = hash_size;
246
 
247
        journal->j_revoke->hash_shift = shift;
248
 
249
        journal->j_revoke->hash_table =
250
                kmalloc(hash_size * sizeof(struct list_head), GFP_KERNEL);
251
        if (!journal->j_revoke->hash_table) {
252
                kfree(journal->j_revoke_table[0]->hash_table);
253
                kmem_cache_free(jbd2_revoke_table_cache, journal->j_revoke_table[0]);
254
                kmem_cache_free(jbd2_revoke_table_cache, journal->j_revoke_table[1]);
255
                journal->j_revoke = NULL;
256
                return -ENOMEM;
257
        }
258
 
259
        for (tmp = 0; tmp < hash_size; tmp++)
260
                INIT_LIST_HEAD(&journal->j_revoke->hash_table[tmp]);
261
 
262
        spin_lock_init(&journal->j_revoke_lock);
263
 
264
        return 0;
265
}
266
 
267
/* Destoy a journal's revoke table.  The table must already be empty! */
268
 
269
void jbd2_journal_destroy_revoke(journal_t *journal)
270
{
271
        struct jbd2_revoke_table_s *table;
272
        struct list_head *hash_list;
273
        int i;
274
 
275
        table = journal->j_revoke_table[0];
276
        if (!table)
277
                return;
278
 
279
        for (i=0; i<table->hash_size; i++) {
280
                hash_list = &table->hash_table[i];
281
                J_ASSERT (list_empty(hash_list));
282
        }
283
 
284
        kfree(table->hash_table);
285
        kmem_cache_free(jbd2_revoke_table_cache, table);
286
        journal->j_revoke = NULL;
287
 
288
        table = journal->j_revoke_table[1];
289
        if (!table)
290
                return;
291
 
292
        for (i=0; i<table->hash_size; i++) {
293
                hash_list = &table->hash_table[i];
294
                J_ASSERT (list_empty(hash_list));
295
        }
296
 
297
        kfree(table->hash_table);
298
        kmem_cache_free(jbd2_revoke_table_cache, table);
299
        journal->j_revoke = NULL;
300
}
301
 
302
 
303
#ifdef __KERNEL__
304
 
305
/*
306
 * jbd2_journal_revoke: revoke a given buffer_head from the journal.  This
307
 * prevents the block from being replayed during recovery if we take a
308
 * crash after this current transaction commits.  Any subsequent
309
 * metadata writes of the buffer in this transaction cancel the
310
 * revoke.
311
 *
312
 * Note that this call may block --- it is up to the caller to make
313
 * sure that there are no further calls to journal_write_metadata
314
 * before the revoke is complete.  In ext3, this implies calling the
315
 * revoke before clearing the block bitmap when we are deleting
316
 * metadata.
317
 *
318
 * Revoke performs a jbd2_journal_forget on any buffer_head passed in as a
319
 * parameter, but does _not_ forget the buffer_head if the bh was only
320
 * found implicitly.
321
 *
322
 * bh_in may not be a journalled buffer - it may have come off
323
 * the hash tables without an attached journal_head.
324
 *
325
 * If bh_in is non-zero, jbd2_journal_revoke() will decrement its b_count
326
 * by one.
327
 */
328
 
329
int jbd2_journal_revoke(handle_t *handle, unsigned long long blocknr,
330
                   struct buffer_head *bh_in)
331
{
332
        struct buffer_head *bh = NULL;
333
        journal_t *journal;
334
        struct block_device *bdev;
335
        int err;
336
 
337
        might_sleep();
338
        if (bh_in)
339
                BUFFER_TRACE(bh_in, "enter");
340
 
341
        journal = handle->h_transaction->t_journal;
342
        if (!jbd2_journal_set_features(journal, 0, 0, JBD2_FEATURE_INCOMPAT_REVOKE)){
343
                J_ASSERT (!"Cannot set revoke feature!");
344
                return -EINVAL;
345
        }
346
 
347
        bdev = journal->j_fs_dev;
348
        bh = bh_in;
349
 
350
        if (!bh) {
351
                bh = __find_get_block(bdev, blocknr, journal->j_blocksize);
352
                if (bh)
353
                        BUFFER_TRACE(bh, "found on hash");
354
        }
355
#ifdef JBD2_EXPENSIVE_CHECKING
356
        else {
357
                struct buffer_head *bh2;
358
 
359
                /* If there is a different buffer_head lying around in
360
                 * memory anywhere... */
361
                bh2 = __find_get_block(bdev, blocknr, journal->j_blocksize);
362
                if (bh2) {
363
                        /* ... and it has RevokeValid status... */
364
                        if (bh2 != bh && buffer_revokevalid(bh2))
365
                                /* ...then it better be revoked too,
366
                                 * since it's illegal to create a revoke
367
                                 * record against a buffer_head which is
368
                                 * not marked revoked --- that would
369
                                 * risk missing a subsequent revoke
370
                                 * cancel. */
371
                                J_ASSERT_BH(bh2, buffer_revoked(bh2));
372
                        put_bh(bh2);
373
                }
374
        }
375
#endif
376
 
377
        /* We really ought not ever to revoke twice in a row without
378
           first having the revoke cancelled: it's illegal to free a
379
           block twice without allocating it in between! */
380
        if (bh) {
381
                if (!J_EXPECT_BH(bh, !buffer_revoked(bh),
382
                                 "inconsistent data on disk")) {
383
                        if (!bh_in)
384
                                brelse(bh);
385
                        return -EIO;
386
                }
387
                set_buffer_revoked(bh);
388
                set_buffer_revokevalid(bh);
389
                if (bh_in) {
390
                        BUFFER_TRACE(bh_in, "call jbd2_journal_forget");
391
                        jbd2_journal_forget(handle, bh_in);
392
                } else {
393
                        BUFFER_TRACE(bh, "call brelse");
394
                        __brelse(bh);
395
                }
396
        }
397
 
398
        jbd_debug(2, "insert revoke for block %llu, bh_in=%p\n",blocknr, bh_in);
399
        err = insert_revoke_hash(journal, blocknr,
400
                                handle->h_transaction->t_tid);
401
        BUFFER_TRACE(bh_in, "exit");
402
        return err;
403
}
404
 
405
/*
406
 * Cancel an outstanding revoke.  For use only internally by the
407
 * journaling code (called from jbd2_journal_get_write_access).
408
 *
409
 * We trust buffer_revoked() on the buffer if the buffer is already
410
 * being journaled: if there is no revoke pending on the buffer, then we
411
 * don't do anything here.
412
 *
413
 * This would break if it were possible for a buffer to be revoked and
414
 * discarded, and then reallocated within the same transaction.  In such
415
 * a case we would have lost the revoked bit, but when we arrived here
416
 * the second time we would still have a pending revoke to cancel.  So,
417
 * do not trust the Revoked bit on buffers unless RevokeValid is also
418
 * set.
419
 *
420
 * The caller must have the journal locked.
421
 */
422
int jbd2_journal_cancel_revoke(handle_t *handle, struct journal_head *jh)
423
{
424
        struct jbd2_revoke_record_s *record;
425
        journal_t *journal = handle->h_transaction->t_journal;
426
        int need_cancel;
427
        int did_revoke = 0;      /* akpm: debug */
428
        struct buffer_head *bh = jh2bh(jh);
429
 
430
        jbd_debug(4, "journal_head %p, cancelling revoke\n", jh);
431
 
432
        /* Is the existing Revoke bit valid?  If so, we trust it, and
433
         * only perform the full cancel if the revoke bit is set.  If
434
         * not, we can't trust the revoke bit, and we need to do the
435
         * full search for a revoke record. */
436
        if (test_set_buffer_revokevalid(bh)) {
437
                need_cancel = test_clear_buffer_revoked(bh);
438
        } else {
439
                need_cancel = 1;
440
                clear_buffer_revoked(bh);
441
        }
442
 
443
        if (need_cancel) {
444
                record = find_revoke_record(journal, bh->b_blocknr);
445
                if (record) {
446
                        jbd_debug(4, "cancelled existing revoke on "
447
                                  "blocknr %llu\n", (unsigned long long)bh->b_blocknr);
448
                        spin_lock(&journal->j_revoke_lock);
449
                        list_del(&record->hash);
450
                        spin_unlock(&journal->j_revoke_lock);
451
                        kmem_cache_free(jbd2_revoke_record_cache, record);
452
                        did_revoke = 1;
453
                }
454
        }
455
 
456
#ifdef JBD2_EXPENSIVE_CHECKING
457
        /* There better not be one left behind by now! */
458
        record = find_revoke_record(journal, bh->b_blocknr);
459
        J_ASSERT_JH(jh, record == NULL);
460
#endif
461
 
462
        /* Finally, have we just cleared revoke on an unhashed
463
         * buffer_head?  If so, we'd better make sure we clear the
464
         * revoked status on any hashed alias too, otherwise the revoke
465
         * state machine will get very upset later on. */
466
        if (need_cancel) {
467
                struct buffer_head *bh2;
468
                bh2 = __find_get_block(bh->b_bdev, bh->b_blocknr, bh->b_size);
469
                if (bh2) {
470
                        if (bh2 != bh)
471
                                clear_buffer_revoked(bh2);
472
                        __brelse(bh2);
473
                }
474
        }
475
        return did_revoke;
476
}
477
 
478
/* journal_switch_revoke table select j_revoke for next transaction
479
 * we do not want to suspend any processing until all revokes are
480
 * written -bzzz
481
 */
482
void jbd2_journal_switch_revoke_table(journal_t *journal)
483
{
484
        int i;
485
 
486
        if (journal->j_revoke == journal->j_revoke_table[0])
487
                journal->j_revoke = journal->j_revoke_table[1];
488
        else
489
                journal->j_revoke = journal->j_revoke_table[0];
490
 
491
        for (i = 0; i < journal->j_revoke->hash_size; i++)
492
                INIT_LIST_HEAD(&journal->j_revoke->hash_table[i]);
493
}
494
 
495
/*
496
 * Write revoke records to the journal for all entries in the current
497
 * revoke hash, deleting the entries as we go.
498
 *
499
 * Called with the journal lock held.
500
 */
501
 
502
void jbd2_journal_write_revoke_records(journal_t *journal,
503
                                  transaction_t *transaction)
504
{
505
        struct journal_head *descriptor;
506
        struct jbd2_revoke_record_s *record;
507
        struct jbd2_revoke_table_s *revoke;
508
        struct list_head *hash_list;
509
        int i, offset, count;
510
 
511
        descriptor = NULL;
512
        offset = 0;
513
        count = 0;
514
 
515
        /* select revoke table for committing transaction */
516
        revoke = journal->j_revoke == journal->j_revoke_table[0] ?
517
                journal->j_revoke_table[1] : journal->j_revoke_table[0];
518
 
519
        for (i = 0; i < revoke->hash_size; i++) {
520
                hash_list = &revoke->hash_table[i];
521
 
522
                while (!list_empty(hash_list)) {
523
                        record = (struct jbd2_revoke_record_s *)
524
                                hash_list->next;
525
                        write_one_revoke_record(journal, transaction,
526
                                                &descriptor, &offset,
527
                                                record);
528
                        count++;
529
                        list_del(&record->hash);
530
                        kmem_cache_free(jbd2_revoke_record_cache, record);
531
                }
532
        }
533
        if (descriptor)
534
                flush_descriptor(journal, descriptor, offset);
535
        jbd_debug(1, "Wrote %d revoke records\n", count);
536
}
537
 
538
/*
539
 * Write out one revoke record.  We need to create a new descriptor
540
 * block if the old one is full or if we have not already created one.
541
 */
542
 
543
static void write_one_revoke_record(journal_t *journal,
544
                                    transaction_t *transaction,
545
                                    struct journal_head **descriptorp,
546
                                    int *offsetp,
547
                                    struct jbd2_revoke_record_s *record)
548
{
549
        struct journal_head *descriptor;
550
        int offset;
551
        journal_header_t *header;
552
 
553
        /* If we are already aborting, this all becomes a noop.  We
554
           still need to go round the loop in
555
           jbd2_journal_write_revoke_records in order to free all of the
556
           revoke records: only the IO to the journal is omitted. */
557
        if (is_journal_aborted(journal))
558
                return;
559
 
560
        descriptor = *descriptorp;
561
        offset = *offsetp;
562
 
563
        /* Make sure we have a descriptor with space left for the record */
564
        if (descriptor) {
565
                if (offset == journal->j_blocksize) {
566
                        flush_descriptor(journal, descriptor, offset);
567
                        descriptor = NULL;
568
                }
569
        }
570
 
571
        if (!descriptor) {
572
                descriptor = jbd2_journal_get_descriptor_buffer(journal);
573
                if (!descriptor)
574
                        return;
575
                header = (journal_header_t *) &jh2bh(descriptor)->b_data[0];
576
                header->h_magic     = cpu_to_be32(JBD2_MAGIC_NUMBER);
577
                header->h_blocktype = cpu_to_be32(JBD2_REVOKE_BLOCK);
578
                header->h_sequence  = cpu_to_be32(transaction->t_tid);
579
 
580
                /* Record it so that we can wait for IO completion later */
581
                JBUFFER_TRACE(descriptor, "file as BJ_LogCtl");
582
                jbd2_journal_file_buffer(descriptor, transaction, BJ_LogCtl);
583
 
584
                offset = sizeof(jbd2_journal_revoke_header_t);
585
                *descriptorp = descriptor;
586
        }
587
 
588
        if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_64BIT)) {
589
                * ((__be64 *)(&jh2bh(descriptor)->b_data[offset])) =
590
                        cpu_to_be64(record->blocknr);
591
                offset += 8;
592
 
593
        } else {
594
                * ((__be32 *)(&jh2bh(descriptor)->b_data[offset])) =
595
                        cpu_to_be32(record->blocknr);
596
                offset += 4;
597
        }
598
 
599
        *offsetp = offset;
600
}
601
 
602
/*
603
 * Flush a revoke descriptor out to the journal.  If we are aborting,
604
 * this is a noop; otherwise we are generating a buffer which needs to
605
 * be waited for during commit, so it has to go onto the appropriate
606
 * journal buffer list.
607
 */
608
 
609
static void flush_descriptor(journal_t *journal,
610
                             struct journal_head *descriptor,
611
                             int offset)
612
{
613
        jbd2_journal_revoke_header_t *header;
614
        struct buffer_head *bh = jh2bh(descriptor);
615
 
616
        if (is_journal_aborted(journal)) {
617
                put_bh(bh);
618
                return;
619
        }
620
 
621
        header = (jbd2_journal_revoke_header_t *) jh2bh(descriptor)->b_data;
622
        header->r_count = cpu_to_be32(offset);
623
        set_buffer_jwrite(bh);
624
        BUFFER_TRACE(bh, "write");
625
        set_buffer_dirty(bh);
626
        ll_rw_block(SWRITE, 1, &bh);
627
}
628
#endif
629
 
630
/*
631
 * Revoke support for recovery.
632
 *
633
 * Recovery needs to be able to:
634
 *
635
 *  record all revoke records, including the tid of the latest instance
636
 *  of each revoke in the journal
637
 *
638
 *  check whether a given block in a given transaction should be replayed
639
 *  (ie. has not been revoked by a revoke record in that or a subsequent
640
 *  transaction)
641
 *
642
 *  empty the revoke table after recovery.
643
 */
644
 
645
/*
646
 * First, setting revoke records.  We create a new revoke record for
647
 * every block ever revoked in the log as we scan it for recovery, and
648
 * we update the existing records if we find multiple revokes for a
649
 * single block.
650
 */
651
 
652
int jbd2_journal_set_revoke(journal_t *journal,
653
                       unsigned long long blocknr,
654
                       tid_t sequence)
655
{
656
        struct jbd2_revoke_record_s *record;
657
 
658
        record = find_revoke_record(journal, blocknr);
659
        if (record) {
660
                /* If we have multiple occurrences, only record the
661
                 * latest sequence number in the hashed record */
662
                if (tid_gt(sequence, record->sequence))
663
                        record->sequence = sequence;
664
                return 0;
665
        }
666
        return insert_revoke_hash(journal, blocknr, sequence);
667
}
668
 
669
/*
670
 * Test revoke records.  For a given block referenced in the log, has
671
 * that block been revoked?  A revoke record with a given transaction
672
 * sequence number revokes all blocks in that transaction and earlier
673
 * ones, but later transactions still need replayed.
674
 */
675
 
676
int jbd2_journal_test_revoke(journal_t *journal,
677
                        unsigned long long blocknr,
678
                        tid_t sequence)
679
{
680
        struct jbd2_revoke_record_s *record;
681
 
682
        record = find_revoke_record(journal, blocknr);
683
        if (!record)
684
                return 0;
685
        if (tid_gt(sequence, record->sequence))
686
                return 0;
687
        return 1;
688
}
689
 
690
/*
691
 * Finally, once recovery is over, we need to clear the revoke table so
692
 * that it can be reused by the running filesystem.
693
 */
694
 
695
void jbd2_journal_clear_revoke(journal_t *journal)
696
{
697
        int i;
698
        struct list_head *hash_list;
699
        struct jbd2_revoke_record_s *record;
700
        struct jbd2_revoke_table_s *revoke;
701
 
702
        revoke = journal->j_revoke;
703
 
704
        for (i = 0; i < revoke->hash_size; i++) {
705
                hash_list = &revoke->hash_table[i];
706
                while (!list_empty(hash_list)) {
707
                        record = (struct jbd2_revoke_record_s*) hash_list->next;
708
                        list_del(&record->hash);
709
                        kmem_cache_free(jbd2_revoke_record_cache, record);
710
                }
711
        }
712
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.