xref: /reactos/sdk/lib/fslib/ext2lib/Super.c (revision c2c66aff)
1*c2c66affSColin Finck /*
2*c2c66affSColin Finck  * PROJECT:          Mke2fs
3*c2c66affSColin Finck  * FILE:             Super.c
4*c2c66affSColin Finck  * PROGRAMMER:       Matt Wu <mattwu@163.com>
5*c2c66affSColin Finck  * HOMEPAGE:         http://ext2.yeah.net
6*c2c66affSColin Finck  */
7*c2c66affSColin Finck 
8*c2c66affSColin Finck /* INCLUDES **************************************************************/
9*c2c66affSColin Finck 
10*c2c66affSColin Finck #include "Mke2fs.h"
11*c2c66affSColin Finck #include <debug.h>
12*c2c66affSColin Finck 
13*c2c66affSColin Finck /* DEFINITIONS ***********************************************************/
14*c2c66affSColin Finck 
15*c2c66affSColin Finck extern int inode_ratio;
16*c2c66affSColin Finck 
17*c2c66affSColin Finck 
18*c2c66affSColin Finck /* FUNCTIONS *************************************************************/
19*c2c66affSColin Finck 
ext2_print_super(PEXT2_SUPER_BLOCK pExt2Sb)20*c2c66affSColin Finck void ext2_print_super(PEXT2_SUPER_BLOCK pExt2Sb)
21*c2c66affSColin Finck {
22*c2c66affSColin Finck     int i;
23*c2c66affSColin Finck 
24*c2c66affSColin Finck     DPRINT("\nExt2 Super Block Details ...\n\n");
25*c2c66affSColin Finck     DPRINT("     Inode Count: %lu\n", pExt2Sb->s_inodes_count);
26*c2c66affSColin Finck     DPRINT("     Block Count: %lu\n", pExt2Sb->s_blocks_count);
27*c2c66affSColin Finck     DPRINT("     Reserved Block Count: %lu\n", pExt2Sb->s_r_blocks_count);
28*c2c66affSColin Finck     DPRINT("     Free Blocks: %lu\n", pExt2Sb->s_free_blocks_count);
29*c2c66affSColin Finck     DPRINT("     Free Inodes: %lu\n", pExt2Sb->s_free_inodes_count);
30*c2c66affSColin Finck     DPRINT("     First Data Block: %lu\n", pExt2Sb->s_first_data_block);
31*c2c66affSColin Finck     DPRINT("     Log Block Size: %lu\n", pExt2Sb->s_log_block_size);
32*c2c66affSColin Finck     DPRINT("     Log Frag Size: %ld\n", pExt2Sb->s_log_frag_size);
33*c2c66affSColin Finck     DPRINT("     Blocks per Group: %lu\n", pExt2Sb->s_blocks_per_group);
34*c2c66affSColin Finck     DPRINT("     Fragments per Group: %lu\n", pExt2Sb->s_frags_per_group);
35*c2c66affSColin Finck     DPRINT("     Inodes per Group: %lu\n", pExt2Sb->s_inodes_per_group);
36*c2c66affSColin Finck //    DPRINT("     Mount Time: %s", ctime((time_t *) & (pExt2Sb->s_mtime)));
37*c2c66affSColin Finck //    DPRINT("     Write Time: %s", ctime((time_t *) & (pExt2Sb->s_wtime)));
38*c2c66affSColin Finck     DPRINT("     Mount Count: %u\n", pExt2Sb->s_mnt_count);
39*c2c66affSColin Finck     DPRINT("     Max Mount Count: %d\n", pExt2Sb->s_max_mnt_count);
40*c2c66affSColin Finck     DPRINT("     Magic Number: %X  (%s)\n", pExt2Sb->s_magic,
41*c2c66affSColin Finck         pExt2Sb->s_magic == EXT2_SUPER_MAGIC ? "OK" : "BAD");
42*c2c66affSColin Finck     DPRINT("     File System State: %X\n", pExt2Sb->s_state);
43*c2c66affSColin Finck     DPRINT("     Error Behaviour: %X\n", pExt2Sb->s_errors);
44*c2c66affSColin Finck     DPRINT("     Minor rev: %u\n", pExt2Sb->s_minor_rev_level);
45*c2c66affSColin Finck //    DPRINT("     Last Check: %s", ctime((time_t *) & (pExt2Sb->s_lastcheck)));
46*c2c66affSColin Finck     DPRINT("     Check Interval: %lu\n", pExt2Sb->s_checkinterval);
47*c2c66affSColin Finck     DPRINT("     Creator OS: %lu\n", pExt2Sb->s_creator_os);
48*c2c66affSColin Finck     DPRINT("     Revision Level: %lu\n", pExt2Sb->s_rev_level);
49*c2c66affSColin Finck     DPRINT("     Reserved Block Default UID: %u\n", pExt2Sb->s_def_resuid);
50*c2c66affSColin Finck     DPRINT("     Reserved Block Default GID: %u\n", pExt2Sb->s_def_resgid);
51*c2c66affSColin Finck     DPRINT("     uuid = ");
52*c2c66affSColin Finck     for (i=0; i < 16; i++)
53*c2c66affSColin Finck         DbgPrint("%x ", pExt2Sb->s_uuid[i]);
54*c2c66affSColin Finck     DbgPrint("\n");
55*c2c66affSColin Finck 
56*c2c66affSColin Finck     DPRINT("     volume label name: ");
57*c2c66affSColin Finck     for (i=0; i < 16; i++)
58*c2c66affSColin Finck     {
59*c2c66affSColin Finck         if (pExt2Sb->s_volume_name[i] == 0)
60*c2c66affSColin Finck             break;
61*c2c66affSColin Finck         DbgPrint("%c", pExt2Sb->s_volume_name[i]);
62*c2c66affSColin Finck     }
63*c2c66affSColin Finck     DbgPrint("\n");
64*c2c66affSColin Finck 
65*c2c66affSColin Finck     DPRINT("\n\n");
66*c2c66affSColin Finck }
67*c2c66affSColin Finck 
68*c2c66affSColin Finck #define set_field(field, default) if (!pExt2Sb->field) pExt2Sb->field = (default);
69*c2c66affSColin Finck 
70*c2c66affSColin Finck /*
71*c2c66affSColin Finck  *  Initialize super block ...
72*c2c66affSColin Finck  */
73*c2c66affSColin Finck 
ext2_initialize_sb(PEXT2_FILESYS Ext2Sys)74*c2c66affSColin Finck bool ext2_initialize_sb(PEXT2_FILESYS Ext2Sys)
75*c2c66affSColin Finck {
76*c2c66affSColin Finck     int frags_per_block = 0;
77*c2c66affSColin Finck     ULONG overhead      = 0;
78*c2c66affSColin Finck     ULONG rem           = 0;
79*c2c66affSColin Finck     ULONG   i = 0;
80*c2c66affSColin Finck     ULONG   group_block = 0;
81*c2c66affSColin Finck     ULONG   numblocks = 0;
82*c2c66affSColin Finck     PEXT2_SUPER_BLOCK pExt2Sb = Ext2Sys->ext2_sb;
83*c2c66affSColin Finck     LARGE_INTEGER   SysTime;
84*c2c66affSColin Finck 
85*c2c66affSColin Finck     NtQuerySystemTime(&SysTime);
86*c2c66affSColin Finck 
87*c2c66affSColin Finck     Ext2Sys->blocksize = EXT2_BLOCK_SIZE(pExt2Sb);
88*c2c66affSColin Finck     Ext2Sys->fragsize = EXT2_FRAG_SIZE(pExt2Sb);
89*c2c66affSColin Finck     frags_per_block = Ext2Sys->blocksize / Ext2Sys->fragsize;
90*c2c66affSColin Finck 
91*c2c66affSColin Finck     pExt2Sb->s_magic = EXT2_SUPER_MAGIC;
92*c2c66affSColin Finck     pExt2Sb->s_state = EXT2_VALID_FS;
93*c2c66affSColin Finck 
94*c2c66affSColin Finck     pExt2Sb->s_first_data_block =  (pExt2Sb->s_log_block_size) ? 0 : 1;
95*c2c66affSColin Finck     pExt2Sb->s_max_mnt_count = EXT2_DFL_MAX_MNT_COUNT;
96*c2c66affSColin Finck 
97*c2c66affSColin Finck     pExt2Sb->s_errors = EXT2_ERRORS_DEFAULT;
98*c2c66affSColin Finck 
99*c2c66affSColin Finck     pExt2Sb->s_checkinterval = EXT2_DFL_CHECKINTERVAL;
100*c2c66affSColin Finck 
101*c2c66affSColin Finck     if (!pExt2Sb->s_rev_level)
102*c2c66affSColin Finck         pExt2Sb->s_rev_level = EXT2_GOOD_OLD_REV;
103*c2c66affSColin Finck 
104*c2c66affSColin Finck     if (pExt2Sb->s_rev_level >= EXT2_DYNAMIC_REV)
105*c2c66affSColin Finck     {
106*c2c66affSColin Finck         set_field(s_first_ino, EXT2_GOOD_OLD_FIRST_INO);
107*c2c66affSColin Finck         set_field(s_inode_size, EXT2_GOOD_OLD_INODE_SIZE);
108*c2c66affSColin Finck     }
109*c2c66affSColin Finck 
110*c2c66affSColin Finck     RtlTimeToSecondsSince1970(&SysTime, &pExt2Sb->s_wtime);
111*c2c66affSColin Finck     pExt2Sb->s_lastcheck = pExt2Sb->s_mtime = pExt2Sb->s_wtime;
112*c2c66affSColin Finck 
113*c2c66affSColin Finck     if (!pExt2Sb->s_blocks_per_group)
114*c2c66affSColin Finck         pExt2Sb->s_blocks_per_group = Ext2Sys->blocksize * 8;
115*c2c66affSColin Finck 
116*c2c66affSColin Finck     pExt2Sb->s_frags_per_group = pExt2Sb->s_blocks_per_group *  frags_per_block;
117*c2c66affSColin Finck     pExt2Sb->s_creator_os = EXT2_OS_WINNT;
118*c2c66affSColin Finck 
119*c2c66affSColin Finck     if (pExt2Sb->s_r_blocks_count >= pExt2Sb->s_blocks_count)
120*c2c66affSColin Finck     {
121*c2c66affSColin Finck         goto cleanup;
122*c2c66affSColin Finck     }
123*c2c66affSColin Finck 
124*c2c66affSColin Finck     /*
125*c2c66affSColin Finck      * If we're creating an external journal device, we don't need
126*c2c66affSColin Finck      * to bother with the rest.
127*c2c66affSColin Finck      */
128*c2c66affSColin Finck     if (pExt2Sb->s_feature_incompat &
129*c2c66affSColin Finck         EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)
130*c2c66affSColin Finck     {
131*c2c66affSColin Finck         Ext2Sys->group_desc_count = 0;
132*c2c66affSColin Finck         // ext2fs_mark_super_dirty(fs);
133*c2c66affSColin Finck         return true;
134*c2c66affSColin Finck     }
135*c2c66affSColin Finck 
136*c2c66affSColin Finck retry:
137*c2c66affSColin Finck 
138*c2c66affSColin Finck     Ext2Sys->group_desc_count = (pExt2Sb->s_blocks_count - pExt2Sb->s_first_data_block
139*c2c66affSColin Finck         + EXT2_BLOCKS_PER_GROUP(pExt2Sb) - 1) / EXT2_BLOCKS_PER_GROUP(pExt2Sb);
140*c2c66affSColin Finck 
141*c2c66affSColin Finck     if (Ext2Sys->group_desc_count == 0)
142*c2c66affSColin Finck         return false;
143*c2c66affSColin Finck 
144*c2c66affSColin Finck     Ext2Sys->desc_blocks = (Ext2Sys->group_desc_count +  EXT2_DESC_PER_BLOCK(pExt2Sb)
145*c2c66affSColin Finck         - 1) / EXT2_DESC_PER_BLOCK(pExt2Sb);
146*c2c66affSColin Finck 
147*c2c66affSColin Finck     if (!pExt2Sb->s_inodes_count)
148*c2c66affSColin Finck         pExt2Sb->s_inodes_count = pExt2Sb->s_blocks_count / ( inode_ratio /Ext2Sys->blocksize);
149*c2c66affSColin Finck 
150*c2c66affSColin Finck     /*
151*c2c66affSColin Finck      * Make sure we have at least EXT2_FIRST_INO + 1 inodes, so
152*c2c66affSColin Finck      * that we have enough inodes for the filesystem(!)
153*c2c66affSColin Finck      */
154*c2c66affSColin Finck     if (pExt2Sb->s_inodes_count < EXT2_FIRST_INODE(pExt2Sb)+1)
155*c2c66affSColin Finck         pExt2Sb->s_inodes_count = EXT2_FIRST_INODE(pExt2Sb)+1;
156*c2c66affSColin Finck 
157*c2c66affSColin Finck     /*
158*c2c66affSColin Finck      * There should be at least as many inodes as the user
159*c2c66affSColin Finck      * requested.  Figure out how many inodes per group that
160*c2c66affSColin Finck      * should be.  But make sure that we don't allocate more than
161*c2c66affSColin Finck      * one bitmap's worth of inodes
162*c2c66affSColin Finck      */
163*c2c66affSColin Finck     pExt2Sb->s_inodes_per_group = (pExt2Sb->s_inodes_count + Ext2Sys->group_desc_count - 1)
164*c2c66affSColin Finck         /Ext2Sys->group_desc_count;
165*c2c66affSColin Finck 
166*c2c66affSColin Finck     if (pExt2Sb->s_inodes_per_group > (ULONG)(Ext2Sys->blocksize*8))
167*c2c66affSColin Finck         pExt2Sb->s_inodes_per_group = Ext2Sys->blocksize*8;
168*c2c66affSColin Finck 
169*c2c66affSColin Finck     /*
170*c2c66affSColin Finck      * Make sure the number of inodes per group completely fills
171*c2c66affSColin Finck      * the inode table blocks in the descriptor.  If not, add some
172*c2c66affSColin Finck      * additional inodes/group.  Waste not, want not...
173*c2c66affSColin Finck      */
174*c2c66affSColin Finck     Ext2Sys->inode_blocks_per_group = (((pExt2Sb->s_inodes_per_group * EXT2_INODE_SIZE(pExt2Sb))
175*c2c66affSColin Finck         + EXT2_BLOCK_SIZE(pExt2Sb) - 1) / EXT2_BLOCK_SIZE(pExt2Sb));
176*c2c66affSColin Finck 
177*c2c66affSColin Finck     pExt2Sb->s_inodes_per_group = ((Ext2Sys->inode_blocks_per_group * EXT2_BLOCK_SIZE(pExt2Sb))
178*c2c66affSColin Finck         / EXT2_INODE_SIZE(pExt2Sb));
179*c2c66affSColin Finck 
180*c2c66affSColin Finck     /*
181*c2c66affSColin Finck      * Finally, make sure the number of inodes per group is a
182*c2c66affSColin Finck      * multiple of 8.  This is needed to simplify the bitmap
183*c2c66affSColin Finck      * splicing code.
184*c2c66affSColin Finck      */
185*c2c66affSColin Finck     pExt2Sb->s_inodes_per_group &= ~7;
186*c2c66affSColin Finck     Ext2Sys->inode_blocks_per_group = (((pExt2Sb->s_inodes_per_group * EXT2_INODE_SIZE(pExt2Sb))
187*c2c66affSColin Finck         + EXT2_BLOCK_SIZE(pExt2Sb) - 1) / EXT2_BLOCK_SIZE(pExt2Sb));
188*c2c66affSColin Finck 
189*c2c66affSColin Finck     /*
190*c2c66affSColin Finck      * adjust inode count to reflect the adjusted inodes_per_group
191*c2c66affSColin Finck      */
192*c2c66affSColin Finck     pExt2Sb->s_inodes_count = pExt2Sb->s_inodes_per_group * Ext2Sys->group_desc_count;
193*c2c66affSColin Finck     pExt2Sb->s_free_inodes_count = pExt2Sb->s_inodes_count;
194*c2c66affSColin Finck 
195*c2c66affSColin Finck     /*
196*c2c66affSColin Finck      * Overhead is the number of bookkeeping blocks per group.  It
197*c2c66affSColin Finck      * includes the superblock backup, the group descriptor
198*c2c66affSColin Finck      * backups, the inode bitmap, the block bitmap, and the inode
199*c2c66affSColin Finck      * table.
200*c2c66affSColin Finck      *
201*c2c66affSColin Finck      * XXX Not all block groups need the descriptor blocks, but
202*c2c66affSColin Finck      * being clever is tricky...
203*c2c66affSColin Finck      */
204*c2c66affSColin Finck     overhead = (3 + Ext2Sys->desc_blocks + Ext2Sys->inode_blocks_per_group);
205*c2c66affSColin Finck 
206*c2c66affSColin Finck     /*
207*c2c66affSColin Finck      * See if the last group is big enough to support the
208*c2c66affSColin Finck      * necessary data structures.  If not, we need to get rid of
209*c2c66affSColin Finck      * it.
210*c2c66affSColin Finck      */
211*c2c66affSColin Finck     rem = ((pExt2Sb->s_blocks_count - pExt2Sb->s_first_data_block) %
212*c2c66affSColin Finck              pExt2Sb->s_blocks_per_group);
213*c2c66affSColin Finck 
214*c2c66affSColin Finck     if ((Ext2Sys->group_desc_count == 1) && rem && (rem < overhead))
215*c2c66affSColin Finck         return false;
216*c2c66affSColin Finck 
217*c2c66affSColin Finck     if (rem && (rem < overhead+50))
218*c2c66affSColin Finck     {
219*c2c66affSColin Finck         pExt2Sb->s_blocks_count -= rem;
220*c2c66affSColin Finck         goto retry;
221*c2c66affSColin Finck     }
222*c2c66affSColin Finck 
223*c2c66affSColin Finck     /*
224*c2c66affSColin Finck      * At this point we know how big the filesystem will be.  So we can do
225*c2c66affSColin Finck      * any and all allocations that depend on the block count.
226*c2c66affSColin Finck      */
227*c2c66affSColin Finck 
228*c2c66affSColin Finck     // Allocate block bitmap
229*c2c66affSColin Finck     if(!ext2_allocate_block_bitmap(Ext2Sys))
230*c2c66affSColin Finck     {
231*c2c66affSColin Finck         goto cleanup;
232*c2c66affSColin Finck     }
233*c2c66affSColin Finck 
234*c2c66affSColin Finck     // Allocate inode bitmap
235*c2c66affSColin Finck     if(!ext2_allocate_inode_bitmap(Ext2Sys))
236*c2c66affSColin Finck     {
237*c2c66affSColin Finck         goto cleanup;
238*c2c66affSColin Finck     }
239*c2c66affSColin Finck 
240*c2c66affSColin Finck     // Allocate gourp desc
241*c2c66affSColin Finck     if(!ext2_allocate_group_desc(Ext2Sys))
242*c2c66affSColin Finck     {
243*c2c66affSColin Finck         goto cleanup;
244*c2c66affSColin Finck     }
245*c2c66affSColin Finck 
246*c2c66affSColin Finck     /*
247*c2c66affSColin Finck      * Reserve the superblock and group descriptors for each
248*c2c66affSColin Finck      * group, and fill in the correct group statistics for group.
249*c2c66affSColin Finck      * Note that although the block bitmap, inode bitmap, and
250*c2c66affSColin Finck      * inode table have not been allocated (and in fact won't be
251*c2c66affSColin Finck      * by this routine), they are accounted for nevertheless.
252*c2c66affSColin Finck      */
253*c2c66affSColin Finck     group_block = pExt2Sb->s_first_data_block;
254*c2c66affSColin Finck     numblocks = 0;
255*c2c66affSColin Finck 
256*c2c66affSColin Finck     pExt2Sb->s_free_blocks_count = 0;
257*c2c66affSColin Finck 
258*c2c66affSColin Finck     for (i = 0; i < Ext2Sys->group_desc_count; i++)
259*c2c66affSColin Finck     {
260*c2c66affSColin Finck         if (i == Ext2Sys->group_desc_count-1)
261*c2c66affSColin Finck         {
262*c2c66affSColin Finck             numblocks = (pExt2Sb->s_blocks_count - pExt2Sb->s_first_data_block)
263*c2c66affSColin Finck                 % pExt2Sb->s_blocks_per_group;
264*c2c66affSColin Finck 
265*c2c66affSColin Finck             if (!numblocks)
266*c2c66affSColin Finck                 numblocks = pExt2Sb->s_blocks_per_group;
267*c2c66affSColin Finck         }
268*c2c66affSColin Finck         else
269*c2c66affSColin Finck         {
270*c2c66affSColin Finck             numblocks = pExt2Sb->s_blocks_per_group;
271*c2c66affSColin Finck         }
272*c2c66affSColin Finck 
273*c2c66affSColin Finck         if (ext2_bg_has_super(pExt2Sb, i))
274*c2c66affSColin Finck         {
275*c2c66affSColin Finck             ULONG j;
276*c2c66affSColin Finck 
277*c2c66affSColin Finck             for (j=0; j < Ext2Sys->desc_blocks+1; j++)
278*c2c66affSColin Finck                 ext2_mark_bitmap(Ext2Sys->block_map, group_block + j);
279*c2c66affSColin Finck 
280*c2c66affSColin Finck             numblocks -= 1 + Ext2Sys->desc_blocks;
281*c2c66affSColin Finck         }
282*c2c66affSColin Finck 
283*c2c66affSColin Finck         numblocks -= 2 + Ext2Sys->inode_blocks_per_group;
284*c2c66affSColin Finck 
285*c2c66affSColin Finck         pExt2Sb->s_free_blocks_count += numblocks;
286*c2c66affSColin Finck         Ext2Sys->group_desc[i].bg_free_blocks_count = (__u16)numblocks;
287*c2c66affSColin Finck         Ext2Sys->group_desc[i].bg_free_inodes_count = (__u16)pExt2Sb->s_inodes_per_group;
288*c2c66affSColin Finck         Ext2Sys->group_desc[i].bg_used_dirs_count = 0;
289*c2c66affSColin Finck 
290*c2c66affSColin Finck         group_block += pExt2Sb->s_blocks_per_group;
291*c2c66affSColin Finck     }
292*c2c66affSColin Finck 
293*c2c66affSColin Finck     return true;
294*c2c66affSColin Finck 
295*c2c66affSColin Finck cleanup:
296*c2c66affSColin Finck 
297*c2c66affSColin Finck     ext2_free_group_desc(Ext2Sys);
298*c2c66affSColin Finck     ext2_free_block_bitmap(Ext2Sys);
299*c2c66affSColin Finck     ext2_free_inode_bitmap(Ext2Sys);
300*c2c66affSColin Finck 
301*c2c66affSColin Finck     return false;
302*c2c66affSColin Finck }
303