2 * mk_hugefiles.c -- create huge files
5 #define _XOPEN_SOURCE 600 /* for inclusion of PATH_MAX in Solaris */
15 #include <sys/utsname.h>
32 #include <sys/ioctl.h>
33 #include <sys/types.h>
37 #include <blkid/blkid.h>
39 #include "ext2fs/ext2_fs.h"
40 #include "ext2fs/ext2fsP.h"
41 #include "et/com_err.h"
42 #include "uuid/uuid.h"
44 #include "ext2fs/ext2fs.h"
48 #include "nls-enable.h"
53 static blk64_t num_blocks;
54 static blk64_t num_slack;
55 static unsigned long num_files;
57 static char *fn_prefix;
58 static int idx_digits;
60 static char *fn_numbuf;
61 int zero_hugefile = 1;
63 static errcode_t create_directory(ext2_filsys fs, char *dir,
67 struct ext2_inode inode;
68 ext2_ino_t ino = EXT2_ROOT_INO;
73 fn = malloc(strlen(dir) + 1);
80 next = strchr(cp, '/');
84 retval = ext2fs_new_inode(fs, ino, LINUX_S_IFDIR,
89 retval = ext2fs_mkdir(fs, ino, newdir, cp);
94 retval = ext2fs_read_inode(fs, ino, &inode);
98 inode.i_uid = uid & 0xFFFF;
99 ext2fs_set_i_uid_high(inode, (uid >> 16) & 0xffff);
100 inode.i_gid = gid & 0xFFFF;
101 ext2fs_set_i_gid_high(inode, (gid >> 16) & 0xffff);
102 retval = ext2fs_write_inode(fs, ino, &inode);
106 if (next == NULL || *next == '\0')
117 static errcode_t mk_hugefile(ext2_filsys fs, blk64_t num,
118 ext2_ino_t dir, unsigned long idx, ext2_ino_t *ino)
122 blk64_t lblk, bend = 0;
126 struct ext2_inode inode;
127 ext2_extent_handle_t handle;
129 retval = ext2fs_new_inode(fs, 0, LINUX_S_IFREG, NULL, ino);
133 memset(&inode, 0, sizeof(struct ext2_inode));
134 inode.i_mode = LINUX_S_IFREG | (0666 & ~fs->umask);
135 inode.i_links_count = 1;
136 inode.i_uid = uid & 0xFFFF;
137 ext2fs_set_i_uid_high(inode, (uid >> 16) & 0xffff);
138 inode.i_gid = gid & 0xFFFF;
139 ext2fs_set_i_gid_high(inode, (gid >> 16) & 0xffff);
141 retval = ext2fs_write_new_inode(fs, *ino, &inode);
145 ext2fs_inode_alloc_stats2(fs, *ino, +1, 0);
147 retval = ext2fs_extent_open2(fs, *ino, &inode, &handle);
152 left = num ? num : 1;
157 retval = ext2fs_find_first_zero_block_bitmap2(fs->block_map,
158 goal, ext2fs_blocks_count(fs->super) - 1, &end);
163 retval = ext2fs_find_first_set_block_bitmap2(fs->block_map, goal,
164 ext2fs_blocks_count(fs->super) - 1, &bend);
165 if (retval == ENOENT) {
166 bend = ext2fs_blocks_count(fs->super);
170 if (!num || bend - goal < left)
177 ext2fs_block_alloc_stats_range(fs, pblk, n, +1);
181 retval = ext2fs_zero_blocks2(fs, pblk, n,
185 com_err(program_name, retval,
186 _("while zeroing block %llu "
187 "for hugefile"), ret_blk);
192 struct ext2fs_extent newextent;
194 if (l > EXT_INIT_MAX_LEN)
195 l = EXT_INIT_MAX_LEN;
198 newextent.e_pblk = pblk;
199 newextent.e_lblk = lblk;
200 newextent.e_flags = 0;
202 retval = ext2fs_extent_insert(handle,
203 EXT2_EXTENT_INSERT_AFTER, &newextent);
212 retval = ext2fs_read_inode(fs, *ino, &inode);
216 retval = ext2fs_iblk_add_blocks(fs, &inode,
217 count / EXT2FS_CLUSTER_RATIO(fs));
220 size = (__u64) count * fs->blocksize;
221 inode.i_size = size & 0xffffffff;
222 inode.i_size_high = (size >> 32);
224 retval = ext2fs_write_new_inode(fs, *ino, &inode);
229 sprintf(fn_numbuf, "%0*lu", idx_digits, idx);
230 else if (num_files > 1)
231 sprintf(fn_numbuf, "%lu", idx);
234 retval = ext2fs_link(fs, dir, fn_buf, *ino, EXT2_FT_REG_FILE);
235 if (retval == EXT2_ET_DIR_NO_SPACE) {
236 retval = ext2fs_expand_dir(fs, dir);
247 ext2fs_extent_free(handle);
252 static blk64_t calc_overhead(ext2_filsys fs, blk64_t num)
254 blk64_t e_blocks, e_blocks2, e_blocks3, e_blocks4;
255 int extents_per_block;
256 int extents = (num + EXT_INIT_MAX_LEN - 1) / EXT_INIT_MAX_LEN;
262 * This calculation is due to the fact that we are inefficient
263 * in how handle extent splits when appending to the end of
264 * the extent tree. Sigh. We should fix this so that we can
265 * actually store 340 extents per 4k block, instead of only 170.
267 extents_per_block = ((fs->blocksize -
268 sizeof(struct ext3_extent_header)) /
269 sizeof(struct ext3_extent));
270 extents_per_block = (extents_per_block/ 2) - 1;
272 e_blocks = (extents + extents_per_block - 1) / extents_per_block;
273 e_blocks2 = (e_blocks + extents_per_block - 1) / extents_per_block;
274 e_blocks3 = (e_blocks2 + extents_per_block - 1) / extents_per_block;
275 e_blocks4 = (e_blocks3 + extents_per_block - 1) / extents_per_block;
276 return e_blocks + e_blocks2 + e_blocks3 + e_blocks4;
280 * Find the place where we should start allocating blocks for the huge
281 * files. Leave <slack> free blocks at the beginning of the file
282 * system for things like metadata blocks.
284 static blk64_t get_start_block(ext2_filsys fs, blk64_t slack)
287 blk64_t blk = fs->super->s_first_data_block, next;
288 blk64_t last_blk = ext2fs_blocks_count(fs->super) - 1;
291 retval = ext2fs_find_first_zero_block_bitmap2(fs->block_map,
292 blk, last_blk, &blk);
296 retval = ext2fs_find_first_set_block_bitmap2(fs->block_map,
297 blk, last_blk, &next);
302 if (next - blk > slack) {
307 slack -= (next - blk);
313 static blk64_t round_up_align(blk64_t b, unsigned long align)
325 errcode_t mk_hugefiles(ext2_filsys fs)
335 if (!get_bool_from_profile(fs_types, "make_hugefiles", 0))
338 uid = get_int_from_profile(fs_types, "hugefiles_uid", 0);
339 gid = get_int_from_profile(fs_types, "hugefiles_gid", 0);
340 fs->umask = get_int_from_profile(fs_types, "hugefiles_umask", 077);
341 num_files = get_int_from_profile(fs_types, "num_hugefiles", 0);
342 t = get_string_from_profile(fs_types, "hugefiles_slack", "1M");
343 num_slack = parse_num_blocks2(t, fs->super->s_log_block_size);
345 t = get_string_from_profile(fs_types, "hugefiles_size", "0");
346 num_blocks = parse_num_blocks2(t, fs->super->s_log_block_size);
348 t = get_string_from_profile(fs_types, "hugefiles_align", "0");
349 align = parse_num_blocks2(t, fs->super->s_log_block_size);
351 num_blocks = round_up_align(num_blocks, align);
352 zero_hugefile = get_bool_from_profile(fs_types, "zero_hugefiles",
355 t = get_string_from_profile(fs_types, "hugefiles_dir", "/");
356 retval = create_directory(fs, t, &dir);
361 fn_prefix = get_string_from_profile(fs_types, "hugefiles_name",
363 idx_digits = get_int_from_profile(fs_types, "hugefiles_digits", 5);
364 d = int_log10(num_files) + 1;
367 dsize = strlen(fn_prefix) + d + 16;
368 fn_buf = malloc(dsize);
373 strcpy(fn_buf, fn_prefix);
374 fn_numbuf = fn_buf + strlen(fn_prefix);
377 fs_blocks = ext2fs_free_blocks_count(fs->super);
378 if (fs_blocks < num_slack + align)
380 fs_blocks -= num_slack + align;
381 if (num_blocks && num_blocks > fs_blocks)
383 if (num_blocks == 0 && num_files == 0)
386 if (num_files == 0 && num_blocks) {
387 num_files = fs_blocks / num_blocks;
388 fs_blocks -= (num_files / 16) + 1;
389 fs_blocks -= calc_overhead(fs, num_blocks) * num_files;
390 num_files = fs_blocks / num_blocks;
393 if (num_blocks == 0 && num_files > 1) {
394 num_blocks = fs_blocks / num_files;
395 fs_blocks -= (num_files / 16) + 1;
396 fs_blocks -= calc_overhead(fs, num_blocks) * num_files;
397 num_blocks = fs_blocks / num_files;
400 num_slack += calc_overhead(fs, num_blocks) * num_files;
401 num_slack += (num_files / 16) + 1; /* space for dir entries */
402 goal = get_start_block(fs, num_slack);
403 goal = round_up_align(goal, align);
405 if ((num_blocks ? num_blocks : fs_blocks) >
406 (0x80000000UL / fs->blocksize))
407 fs->super->s_feature_ro_compat |=
408 EXT2_FEATURE_RO_COMPAT_LARGE_FILE;
411 if (zero_hugefile && verbose)
412 printf("%s", _("Huge files will be zero'ed\n"));
413 printf(_("Creating %lu huge file(s) "), num_files);
415 printf(_("with %llu blocks each"), num_blocks);
418 for (i=0; i < num_files; i++) {
421 retval = mk_hugefile(fs, num_blocks, dir, i, &ino);
423 com_err(program_name, retval,
424 _("while creating huge file %lu"), i);
429 fputs(_("done\n"), stdout);