Changeset 785

Show
Ignore:
Timestamp:
07/13/08 20:43:18 (2 months ago)
Author:
mwhitworth
Message:

Add basic recovery code (that passes and replays the journal, but does not deal with revoke blocks.

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • Whitix/branches/fs/fs/journal/recovery.c

    r763 r785  
    1717 */ 
    1818 
     19#include <fs/bcache.h> 
    1920#include <fs/journal.h> 
     21#include <fs/vfs.h> 
    2022#include <byteswap.h> 
    2123#include <module.h> 
     
    2325#include <wait.h> 
    2426 
     27int JournalCountTags(struct Buffer* buffer, int size) 
     28{ 
     29        char* tagPointer; 
     30        struct JournalBlockTag* tag; 
     31        int num=0; 
     32         
     33        tagPointer=&buffer->data[sizeof(struct JournalHeader)]; 
     34         
     35        while (((DWORD)tagPointer-(DWORD)buffer->data+sizeof(struct JournalBlockTag)) <= size) 
     36        { 
     37                tag=(struct JournalBlockTag*)tagPointer; 
     38                num++; 
     39                tagPointer+=sizeof(struct JournalBlockTag); 
     40                 
     41                if (!(tag->flags & BeToCpu32(JOURN_FLAG_SAME_UUID))) 
     42                        tagPointer+=16; 
     43                         
     44                if (tag->flags & BeToCpu32(JOURN_FLAG_LAST_TAG)) 
     45                        break; 
     46        } 
     47         
     48        return num; 
     49} 
     50 
     51int JournalReplayBlocks(struct Journal* journal, struct Buffer* buffer, DWORD* logBlock) 
     52{ 
     53        char* tagPointer; 
     54        struct JournalBlockTag* tag; 
     55        struct Buffer* journEntry, *onDisk; 
     56        int num=0; 
     57        DWORD ioBlock, blockNo; 
     58         
     59        tagPointer=&buffer->data[sizeof(struct JournalHeader)]; 
     60         
     61        while (((DWORD)tagPointer-(DWORD)buffer->data+sizeof(struct JournalBlockTag)) <= journal->sectorSize) 
     62        { 
     63                DWORD flags; 
     64                 
     65                tag=(struct JournalBlockTag*)tagPointer; 
     66                flags=BeToCpu32(tag->flags); 
     67                 
     68                ioBlock=*logBlock++; 
     69                /* WRAP */ 
     70                 
     71                /* Read the block of data in the journal */ 
     72                JournalBlockMap(journal, ioBlock, &blockNo); 
     73                 
     74                journEntry=JournalBlockRead(journal, blockNo); 
     75                 
     76                /* Handle error. */ 
     77                blockNo=BeToCpu32(tag->blockNum); 
     78                 
     79                onDisk=BlockBufferAlloc(journEntry->device, blockNo); 
     80                memcpy(onDisk->data, journEntry->data, journal->sectorSize); 
     81                 
     82                BlockWrite(onDisk->device, onDisk); 
     83                 
     84                BufferUnlock(onDisk); 
     85                BufferRelease(onDisk); 
     86                BufferRelease(journEntry); 
     87                 
     88                tagPointer+=sizeof(struct JournalBlockTag); 
     89                 
     90                if (!(tag->flags & BeToCpu32(JOURN_FLAG_SAME_UUID))) 
     91                        tagPointer+=16; 
     92                         
     93                if (tag->flags & BeToCpu32(JOURN_FLAG_LAST_TAG)) 
     94                        break; 
     95                 
     96        } 
     97         
     98        return 0; 
     99} 
     100 
     101int JournalDoOnePass(struct Journal* journal, struct JournalSuperBlock* jSb,  
     102        struct JournalRecovery* info, int type) 
     103{ 
     104        DWORD firstCommitId, nextCommitId; 
     105        DWORD nextLogBlock, blockNo; 
     106        DWORD blockType, sequence; 
     107        struct Buffer* buffer; 
     108        struct JournalHeader* head; 
     109         
     110        nextCommitId=BeToCpu32(jSb->sequence); 
     111        nextLogBlock=BeToCpu32(jSb->start); 
     112         
     113        firstCommitId=nextCommitId; 
     114         
     115        if (type == JOURN_PASS_SCAN) 
     116                info->firstTransaction=firstCommitId; 
     117         
     118        while (1) 
     119        { 
     120                KePrint("Scanning for %u, %u/%u\n", nextCommitId, nextLogBlock, journal->maxLength); 
     121                 
     122                JournalBlockMap(journal, nextLogBlock, &blockNo); 
     123                 
     124                buffer=JournalBlockRead(journal, blockNo); 
     125                 
     126                nextLogBlock++; 
     127                /* WRAP */ 
     128                 
     129                head=(struct JournalHeader*)(buffer->data); 
     130                 
     131                if (head->magic != CpuToBe32(JFS_MAGIC)) 
     132                { 
     133                        BufferRelease(buffer); 
     134                        break; 
     135                } 
     136                 
     137                sequence=BeToCpu32(head->sequence); 
     138                blockType=BeToCpu32(head->blockType); 
     139                 
     140                if (sequence != nextCommitId) 
     141                { 
     142                        BufferRelease(buffer); 
     143                        break; 
     144                } 
     145                 
     146                switch (blockType) 
     147                { 
     148                        case JFS_DESC_BLOCK: 
     149                                if (type != JOURN_PASS_REPLAY) 
     150                                { 
     151                                        nextLogBlock+=JournalCountTags(buffer, journal->sectorSize); 
     152                                        /* WRAP */ 
     153                                        BufferRelease(buffer); 
     154                                        continue; 
     155                                } 
     156                                 
     157                                JournalReplayBlocks(journal, buffer, &nextLogBlock); 
     158                                 
     159                                BufferRelease(buffer); 
     160                                continue; 
     161                                 
     162                        case JFS_COMMIT_BLOCK: 
     163                                BufferRelease(buffer); 
     164                                nextCommitId++; 
     165                                continue; 
     166                                 
     167                        default: 
     168                                KePrint("blockType = %u\n", blockType); 
     169                } 
     170        } 
     171         
     172        info->endTransaction=nextCommitId; 
     173         
     174        return 0; 
     175} 
     176 
    25177int JournalRecover(struct Journal* journal, struct JournalSuperBlock* jSb) 
    26178{ 
    27179        DWORD start=BeToCpu32(jSb->start); 
     180        struct JournalRecovery recovery; 
    28181 
    29182        if (!start) 
     
    36189        } 
    37190 
    38         KePrint(KERN_ERROR "Recovery needed!\n"); 
     191        JournalDoOnePass(journal, jSb, &recovery, JOURN_PASS_SCAN); 
     192        JournalDoOnePass(journal, jSb, &recovery, JOURN_PASS_REPLAY); 
     193         
     194        journal->transSequence=recovery.endTransaction++; 
     195         
     196        /* Sync all buffers. */ 
     197         
     198        KePrint("Finished recovery\n"); 
     199         
    39200        return 0; 
    40201}