1 /*
2  * COPYRIGHT:        See COPYRIGHT.TXT
3  * PROJECT:          Ext2 File System Driver for WinNT/2K/XP
4  * FILE:             recover.c
5  * PROGRAMMER:       Matt Wu <mattwu@163.com>
6  * HOMEPAGE:         http://www.ext2fsd.com
7  * UPDATE HISTORY:
8  */
9 
10 /* INCLUDES *****************************************************************/
11 
12 #include <ext2fs.h>
13 #include <linux/jbd.h>
14 #include <linux/ext3_fs.h>
15 
16 /* GLOBALS ***************************************************************/
17 
18 extern PEXT2_GLOBAL Ext2Global;
19 
20 /* DEFINITIONS *************************************************************/
21 
22 #ifdef ALLOC_PRAGMA
23 #pragma alloc_text(PAGE, Ext2LoadInternalJournal)
24 #pragma alloc_text(PAGE, Ext2CheckJournal)
25 #pragma alloc_text(PAGE, Ext2RecoverJournal)
26 #endif
27 
28 PEXT2_MCB
29 Ext2LoadInternalJournal(
30     PEXT2_VCB         Vcb,
31     ULONG             jNo
32 )
33 {
34     PEXT2_MCB   Jcb = NULL;
35 
36     Jcb = Ext2AllocateMcb(Vcb, NULL, NULL, 0);
37     if (!Jcb) {
38         goto errorout;
39     }
40 
41     Jcb->Inode.i_ino = jNo;
42     Jcb->Inode.i_sb = &Vcb->sb;
43     if (!Ext2LoadInode(Vcb, &Jcb->Inode)) {
44         DbgBreak();
45         Ext2FreeMcb(Vcb, Jcb);
46         goto errorout;
47     }
48 
49 errorout:
50 
51     return Jcb;
52 }
53 
54 INT
55 Ext2CheckJournal(
56     PEXT2_VCB          Vcb,
57     PULONG             jNo
58 )
59 {
60     struct ext3_super_block* esb = NULL;
61 
62     /* check ext3 super block */
63     esb = (struct ext3_super_block *)Vcb->SuperBlock;
64     if (IsFlagOn(esb->s_feature_incompat,
65                  EXT3_FEATURE_INCOMPAT_RECOVER)) {
66         SetLongFlag(Vcb->Flags, VCB_JOURNAL_RECOVER);
67     }
68 
69     /* must stop here if volume is read-only */
70     if (IsVcbReadOnly(Vcb)) {
71         goto errorout;
72     }
73 
74     /* journal is external ? */
75     if (esb->s_journal_inum == 0) {
76         goto errorout;
77     }
78 
79     /* oops: volume is corrupted */
80     if (esb->s_journal_dev) {
81         goto errorout;
82     }
83 
84     /* return the journal inode number */
85     *jNo = esb->s_journal_inum;
86 
87     return TRUE;
88 
89 errorout:
90 
91     return FALSE;
92 }
93 
94 INT
95 Ext2RecoverJournal(
96     PEXT2_IRP_CONTEXT  IrpContext,
97     PEXT2_VCB          Vcb
98 )
99 {
100     INT rc = 0;
101     ULONG                   jNo = 0;
102     PEXT2_MCB               jcb = NULL;
103     struct block_device *   bd = &Vcb->bd;
104 #ifndef __REACTOS__
105     struct super_block *    sb = &Vcb->sb;
106 #endif
107     struct inode *          ji = NULL;
108     journal_t *             journal = NULL;
109     struct ext3_super_block *esb;
110 
111     ExAcquireResourceExclusiveLite(&Vcb->MainResource, TRUE);
112 
113     /* check journal inode number */
114     if (!Ext2CheckJournal(Vcb, &jNo)) {
115         rc = -1;
116         goto errorout;
117     }
118 
119     /* allocate journal Mcb */
120     jcb =  Ext2LoadInternalJournal(Vcb, jNo);
121     if (!jcb) {
122         rc = -6;
123         goto errorout;
124     }
125 
126     /* allocate journal inode */
127     ji = &jcb->Inode;
128 
129     /* initialize journal file from inode */
130     journal = journal_init_inode(ji);
131 
132     /* initialzation succeeds ? */
133     if (!journal) {
134         iput(ji);
135         rc = -8;
136         goto errorout;
137     }
138 
139     /* start journal recovery */
140     rc = journal_load(journal);
141     if (0 != rc) {
142         rc = -9;
143         DbgPrint("Ext2Fsd: recover_journal: failed "
144                  "to recover journal data.\n");
145     }
146 
147     /* reload super_block and group_description */
148     Ext2RefreshSuper(IrpContext, Vcb);
149     Ext2RefreshGroup(IrpContext, Vcb);
150 
151     /* wipe journal data and clear recover flag in sb */
152     if (rc == 0) {
153         journal_wipe_recovery(journal);
154         ClearLongFlag(
155             Vcb->SuperBlock->s_feature_incompat,
156             EXT3_FEATURE_INCOMPAT_RECOVER );
157         Ext2SaveSuper(IrpContext, Vcb);
158         sync_blockdev(bd);
159         ClearLongFlag(Vcb->Flags, VCB_JOURNAL_RECOVER);
160     }
161 
162 errorout:
163 
164     /* destroy journal structure */
165     if (journal) {
166         journal_destroy(journal);
167     }
168 
169     /* destory journal Mcb */
170     if (jcb) {
171         Ext2FreeMcb(Vcb, jcb);
172     }
173 
174     ExReleaseResourceLite(&Vcb->MainResource);
175 
176     return rc;
177 }
178