blob: 22e7eaf3ef11f37b872db3f8d8aa9c0f500ab634 [file] [log] [blame]
Theodore Ts'o3839e651997-04-26 13:21:57 +00001/*
2 * initialize.c --- initialize a filesystem handle given superblock
3 * parameters. Used by mke2fs when initializing a filesystem.
4 */
5
6#include <stdio.h>
7#include <string.h>
8#include <unistd.h>
9#include <stdlib.h>
10#include <fcntl.h>
11#include <time.h>
12#include <sys/stat.h>
13#include <sys/types.h>
14
Theodore Ts'o3839e651997-04-26 13:21:57 +000015#include <linux/ext2_fs.h>
16
17#include "ext2fs.h"
18
19errcode_t ext2fs_initialize(const char *name, int flags,
20 struct ext2_super_block *param,
21 io_manager manager, ext2_filsys *ret_fs)
22{
23 ext2_filsys fs;
24 errcode_t retval;
25 struct ext2_super_block *super;
26 int frags_per_block;
27 int rem;
28 int overhead = 0;
29 blk_t group_block;
30 int i, j;
Theodore Ts'of3db3561997-04-26 13:34:30 +000031 int numblocks;
32 char *buf;
Theodore Ts'o3839e651997-04-26 13:21:57 +000033
34 if (!param || !param->s_blocks_count)
35 return EINVAL;
36
37 fs = (ext2_filsys) malloc(sizeof(struct struct_ext2_filsys));
38 if (!fs)
39 return ENOMEM;
40
41 memset(fs, 0, sizeof(struct struct_ext2_filsys));
Theodore Ts'of3db3561997-04-26 13:34:30 +000042 fs->magic = EXT2_ET_MAGIC_EXT2FS_FILSYS;
Theodore Ts'o3839e651997-04-26 13:21:57 +000043 fs->flags = flags | EXT2_FLAG_RW;
44 retval = manager->open(name, IO_FLAG_RW, &fs->io);
45 if (retval)
46 goto cleanup;
47 fs->device_name = malloc(strlen(name)+1);
48 if (!fs->device_name) {
49 retval = ENOMEM;
50 goto cleanup;
51 }
52 strcpy(fs->device_name, name);
53 fs->super = super = malloc(SUPERBLOCK_SIZE);
54 if (!super) {
55 retval = ENOMEM;
56 goto cleanup;
57 }
58 memset(super, 0, SUPERBLOCK_SIZE);
59
60#define set_field(field, default) (super->field = param->field ? \
61 param->field : (default))
62
63 super->s_magic = EXT2_SUPER_MAGIC;
64 super->s_state = EXT2_VALID_FS;
65
66 set_field(s_log_block_size, 0); /* default blocksize: 1024 bytes */
67 set_field(s_log_frag_size, 0); /* default fragsize: 1024 bytes */
68 set_field(s_first_data_block, super->s_log_block_size ? 0 : 1);
69 set_field(s_max_mnt_count, EXT2_DFL_MAX_MNT_COUNT);
70 set_field(s_errors, EXT2_ERRORS_DEFAULT);
71
72 set_field(s_checkinterval, EXT2_DFL_CHECKINTERVAL);
73 super->s_lastcheck = time(NULL);
74
Theodore Ts'of3db3561997-04-26 13:34:30 +000075#ifdef EXT2_OS_LINUX
76 super->s_creator_os = EXT2_OS_LINUX;
77#endif
78
Theodore Ts'o3839e651997-04-26 13:21:57 +000079 fs->blocksize = EXT2_BLOCK_SIZE(super);
80 fs->fragsize = EXT2_FRAG_SIZE(super);
81 frags_per_block = fs->blocksize / fs->fragsize;
82
83 set_field(s_blocks_per_group, 8192); /* default: 8192 blocks/group */
84 super->s_frags_per_group = super->s_blocks_per_group * frags_per_block;
85
86 super->s_blocks_count = param->s_blocks_count;
Theodore Ts'of3db3561997-04-26 13:34:30 +000087 super->s_r_blocks_count = param->s_r_blocks_count;
88 if (super->s_r_blocks_count >= param->s_blocks_count) {
89 retval = EINVAL;
90 goto cleanup;
91 }
Theodore Ts'o3839e651997-04-26 13:21:57 +000092
93retry:
Theodore Ts'o3839e651997-04-26 13:21:57 +000094 fs->group_desc_count = (super->s_blocks_count -
95 super->s_first_data_block +
96 EXT2_BLOCKS_PER_GROUP(super) - 1)
97 / EXT2_BLOCKS_PER_GROUP(super);
98 fs->desc_blocks = (fs->group_desc_count +
99 EXT2_DESC_PER_BLOCK(super) - 1)
100 / EXT2_DESC_PER_BLOCK(super);
101
102 set_field(s_inodes_count, (super->s_blocks_count*fs->blocksize)/4096);
103
104 /*
105 * There should be at least as many inodes as the user
106 * requested. Figure out how many inodes per group that
107 * should be.
108 */
109 super->s_inodes_per_group = (super->s_inodes_count +
110 fs->group_desc_count - 1) /
111 fs->group_desc_count;
112
113 /*
114 * Make sure the number of inodes per group completely fills
115 * the inode table blocks in the descriptor. If not, add some
116 * additional inodes/group. Waste not, want not...
117 */
118 fs->inode_blocks_per_group = (super->s_inodes_per_group +
119 EXT2_INODES_PER_BLOCK(super) - 1) /
120 EXT2_INODES_PER_BLOCK(super);
121 super->s_inodes_per_group = fs->inode_blocks_per_group *
122 EXT2_INODES_PER_BLOCK(super);
123
124 /*
125 * adjust inode count to reflect the adjusted inodes_per_group
126 */
127 super->s_inodes_count = super->s_inodes_per_group *
128 fs->group_desc_count;
129 super->s_free_inodes_count = super->s_inodes_count;
130
131 /*
132 * Overhead is the number of bookkeeping blocks per group. It
133 * includes the superblock backup, the group descriptor
134 * backups, the inode bitmap, the block bitmap, and the inode
135 * table.
136 */
137 overhead = 3 + fs->desc_blocks + fs->inode_blocks_per_group;
138 super->s_free_blocks_count = super->s_blocks_count -
139 super->s_first_data_block - (overhead*fs->group_desc_count);
140
141 /*
142 * See if the last group is big enough to support the
143 * necessary data structures. If not, we need to get rid of
144 * it.
145 */
146 rem = (super->s_blocks_count - super->s_first_data_block) %
147 super->s_blocks_per_group;
148 if ((fs->group_desc_count == 1) && rem && (rem < overhead))
149 return EXT2_ET_TOOSMALL;
150 if (rem && (rem < overhead+50)) {
151 super->s_blocks_count -= rem;
152 goto retry;
153 }
154
155 /*
156 * At this point we know how big the filesystem will be. So
157 * we can do any and all allocations that depend on the block
158 * count.
159 */
160
Theodore Ts'of3db3561997-04-26 13:34:30 +0000161 buf = malloc(strlen(fs->device_name) + 80);
162 if (!buf) {
163 retval = ENOMEM;
164 goto cleanup;
165 }
166
167 sprintf(buf, "block bitmap for %s", fs->device_name);
168 retval = ext2fs_allocate_block_bitmap(fs, buf, &fs->block_map);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000169 if (retval)
170 goto cleanup;
171
Theodore Ts'of3db3561997-04-26 13:34:30 +0000172 sprintf(buf, "inode bitmap for %s", fs->device_name);
173 retval = ext2fs_allocate_inode_bitmap(fs, 0, &fs->inode_map);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000174 if (retval)
175 goto cleanup;
176
Theodore Ts'of3db3561997-04-26 13:34:30 +0000177 free(buf);
178
Theodore Ts'o3839e651997-04-26 13:21:57 +0000179 fs->group_desc = malloc(fs->desc_blocks * fs->blocksize);
180 if (!fs->group_desc) {
181 retval = ENOMEM;
182 goto cleanup;
183 }
184 memset(fs->group_desc, 0, fs->desc_blocks * fs->blocksize);
185
Theodore Ts'of3db3561997-04-26 13:34:30 +0000186 /*
187 * Reserve the superblock and group descriptors for each
188 * group, and fill in the correct group statistics for group.
189 * Note that although the block bitmap, inode bitmap, and
190 * inode table have not been allocated (and in fact won't be
191 * by this routine), they are accounted for nevertheless.
192 */
Theodore Ts'o3839e651997-04-26 13:21:57 +0000193 group_block = super->s_first_data_block;
194 for (i = 0; i < fs->group_desc_count; i++) {
195 for (j=0; j < fs->desc_blocks+1; j++)
Theodore Ts'of3db3561997-04-26 13:34:30 +0000196 ext2fs_mark_block_bitmap(fs->block_map,
Theodore Ts'o3839e651997-04-26 13:21:57 +0000197 group_block + j);
Theodore Ts'of3db3561997-04-26 13:34:30 +0000198
199 if (i == fs->group_desc_count-1) {
200 numblocks = (fs->super->s_blocks_count -
201 fs->super->s_first_data_block) %
202 fs->super->s_blocks_per_group;
203 if (!numblocks)
204 numblocks = fs->super->s_blocks_per_group;
205 } else
206 numblocks = fs->super->s_blocks_per_group;
207 numblocks -= 3 + fs->desc_blocks + fs->inode_blocks_per_group;
208
209 fs->group_desc[i].bg_free_blocks_count = numblocks;
210 fs->group_desc[i].bg_free_inodes_count =
211 fs->super->s_inodes_per_group;
212 fs->group_desc[i].bg_used_dirs_count = 0;
213
Theodore Ts'o3839e651997-04-26 13:21:57 +0000214 group_block += super->s_blocks_per_group;
215 }
216
217 ext2fs_mark_super_dirty(fs);
218 ext2fs_mark_bb_dirty(fs);
219 ext2fs_mark_ib_dirty(fs);
220
221 io_channel_set_blksize(fs->io, fs->blocksize);
222
223 *ret_fs = fs;
224 return 0;
225cleanup:
226 ext2fs_free(fs);
227 return retval;
228}
229
230
231