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