xref: /aosp_15_r20/external/e2fsprogs/misc/mk_hugefiles.c (revision 6a54128f25917bfc36a8a6e9d722c04a0b4641b6)
1*6a54128fSAndroid Build Coastguard Worker /*
2*6a54128fSAndroid Build Coastguard Worker  * mk_hugefiles.c -- create huge files
3*6a54128fSAndroid Build Coastguard Worker  */
4*6a54128fSAndroid Build Coastguard Worker 
5*6a54128fSAndroid Build Coastguard Worker #include "config.h"
6*6a54128fSAndroid Build Coastguard Worker #include <stdio.h>
7*6a54128fSAndroid Build Coastguard Worker #include <string.h>
8*6a54128fSAndroid Build Coastguard Worker #include <strings.h>
9*6a54128fSAndroid Build Coastguard Worker #include <fcntl.h>
10*6a54128fSAndroid Build Coastguard Worker #include <ctype.h>
11*6a54128fSAndroid Build Coastguard Worker #include <time.h>
12*6a54128fSAndroid Build Coastguard Worker #ifdef __linux__
13*6a54128fSAndroid Build Coastguard Worker #include <sys/utsname.h>
14*6a54128fSAndroid Build Coastguard Worker #endif
15*6a54128fSAndroid Build Coastguard Worker #ifdef HAVE_GETOPT_H
16*6a54128fSAndroid Build Coastguard Worker #include <getopt.h>
17*6a54128fSAndroid Build Coastguard Worker #else
18*6a54128fSAndroid Build Coastguard Worker extern char *optarg;
19*6a54128fSAndroid Build Coastguard Worker extern int optind;
20*6a54128fSAndroid Build Coastguard Worker #endif
21*6a54128fSAndroid Build Coastguard Worker #ifdef HAVE_UNISTD_H
22*6a54128fSAndroid Build Coastguard Worker #include <unistd.h>
23*6a54128fSAndroid Build Coastguard Worker #endif
24*6a54128fSAndroid Build Coastguard Worker #ifdef HAVE_STDLIB_H
25*6a54128fSAndroid Build Coastguard Worker #include <stdlib.h>
26*6a54128fSAndroid Build Coastguard Worker #endif
27*6a54128fSAndroid Build Coastguard Worker #ifdef HAVE_ERRNO_H
28*6a54128fSAndroid Build Coastguard Worker #include <errno.h>
29*6a54128fSAndroid Build Coastguard Worker #endif
30*6a54128fSAndroid Build Coastguard Worker #ifdef HAVE_SYS_IOCTL_H
31*6a54128fSAndroid Build Coastguard Worker #include <sys/ioctl.h>
32*6a54128fSAndroid Build Coastguard Worker #endif
33*6a54128fSAndroid Build Coastguard Worker #include <sys/types.h>
34*6a54128fSAndroid Build Coastguard Worker #include <sys/stat.h>
35*6a54128fSAndroid Build Coastguard Worker #ifdef HAVE_SYS_SYSMACROS_H
36*6a54128fSAndroid Build Coastguard Worker #include <sys/sysmacros.h>
37*6a54128fSAndroid Build Coastguard Worker #endif
38*6a54128fSAndroid Build Coastguard Worker #include <libgen.h>
39*6a54128fSAndroid Build Coastguard Worker #include <limits.h>
40*6a54128fSAndroid Build Coastguard Worker #include <blkid/blkid.h>
41*6a54128fSAndroid Build Coastguard Worker 
42*6a54128fSAndroid Build Coastguard Worker #include "ext2fs/ext2_fs.h"
43*6a54128fSAndroid Build Coastguard Worker #include "ext2fs/ext2fsP.h"
44*6a54128fSAndroid Build Coastguard Worker #include "et/com_err.h"
45*6a54128fSAndroid Build Coastguard Worker #include "uuid/uuid.h"
46*6a54128fSAndroid Build Coastguard Worker #include "e2p/e2p.h"
47*6a54128fSAndroid Build Coastguard Worker #include "ext2fs/ext2fs.h"
48*6a54128fSAndroid Build Coastguard Worker #include "util.h"
49*6a54128fSAndroid Build Coastguard Worker #include "support/profile.h"
50*6a54128fSAndroid Build Coastguard Worker #include "support/prof_err.h"
51*6a54128fSAndroid Build Coastguard Worker #include "support/nls-enable.h"
52*6a54128fSAndroid Build Coastguard Worker #include "mke2fs.h"
53*6a54128fSAndroid Build Coastguard Worker 
54*6a54128fSAndroid Build Coastguard Worker static int uid;
55*6a54128fSAndroid Build Coastguard Worker static int gid;
56*6a54128fSAndroid Build Coastguard Worker static blk64_t num_blocks;
57*6a54128fSAndroid Build Coastguard Worker static blk64_t num_slack;
58*6a54128fSAndroid Build Coastguard Worker static unsigned long num_files;
59*6a54128fSAndroid Build Coastguard Worker static blk64_t goal;
60*6a54128fSAndroid Build Coastguard Worker static char *fn_prefix;
61*6a54128fSAndroid Build Coastguard Worker static int idx_digits;
62*6a54128fSAndroid Build Coastguard Worker static char *fn_buf;
63*6a54128fSAndroid Build Coastguard Worker static char *fn_numbuf;
64*6a54128fSAndroid Build Coastguard Worker int zero_hugefile = 1;
65*6a54128fSAndroid Build Coastguard Worker 
66*6a54128fSAndroid Build Coastguard Worker static blk64_t
get_partition_start(const char * device_name EXT2FS_ATTR ((unused)))67*6a54128fSAndroid Build Coastguard Worker get_partition_start(const char *device_name EXT2FS_ATTR((unused)))
68*6a54128fSAndroid Build Coastguard Worker {
69*6a54128fSAndroid Build Coastguard Worker #ifdef __linux__
70*6a54128fSAndroid Build Coastguard Worker 	unsigned long long start;
71*6a54128fSAndroid Build Coastguard Worker 	char		path[128];
72*6a54128fSAndroid Build Coastguard Worker 	struct stat	st;
73*6a54128fSAndroid Build Coastguard Worker 	FILE		*f;
74*6a54128fSAndroid Build Coastguard Worker 	int		n;
75*6a54128fSAndroid Build Coastguard Worker 
76*6a54128fSAndroid Build Coastguard Worker 	if ((stat(device_name, &st) < 0) || !S_ISBLK(st.st_mode))
77*6a54128fSAndroid Build Coastguard Worker 		return 0;
78*6a54128fSAndroid Build Coastguard Worker 
79*6a54128fSAndroid Build Coastguard Worker 	sprintf(path, "/sys/dev/block/%d:%d/start",
80*6a54128fSAndroid Build Coastguard Worker 		major(st.st_rdev), minor(st.st_rdev));
81*6a54128fSAndroid Build Coastguard Worker 	f = fopen(path, "r");
82*6a54128fSAndroid Build Coastguard Worker 	if (!f)
83*6a54128fSAndroid Build Coastguard Worker 		return 0;
84*6a54128fSAndroid Build Coastguard Worker 	n = fscanf(f, "%llu", &start);
85*6a54128fSAndroid Build Coastguard Worker 	fclose(f);
86*6a54128fSAndroid Build Coastguard Worker 	return (n == 1) ? start : 0;
87*6a54128fSAndroid Build Coastguard Worker #else
88*6a54128fSAndroid Build Coastguard Worker 	return 0;
89*6a54128fSAndroid Build Coastguard Worker #endif
90*6a54128fSAndroid Build Coastguard Worker }
91*6a54128fSAndroid Build Coastguard Worker 
create_directory(ext2_filsys fs,char * dir,ext2_ino_t * ret_ino)92*6a54128fSAndroid Build Coastguard Worker static errcode_t create_directory(ext2_filsys fs, char *dir,
93*6a54128fSAndroid Build Coastguard Worker 				  ext2_ino_t *ret_ino)
94*6a54128fSAndroid Build Coastguard Worker 
95*6a54128fSAndroid Build Coastguard Worker {
96*6a54128fSAndroid Build Coastguard Worker 	struct ext2_inode	inode;
97*6a54128fSAndroid Build Coastguard Worker 	ext2_ino_t		ino = EXT2_ROOT_INO;
98*6a54128fSAndroid Build Coastguard Worker 	ext2_ino_t		newdir;
99*6a54128fSAndroid Build Coastguard Worker 	errcode_t		retval = 0;
100*6a54128fSAndroid Build Coastguard Worker 	char			*fn, *cp, *next;
101*6a54128fSAndroid Build Coastguard Worker 
102*6a54128fSAndroid Build Coastguard Worker 	fn = malloc(strlen(dir) + 1);
103*6a54128fSAndroid Build Coastguard Worker 	if (fn == NULL)
104*6a54128fSAndroid Build Coastguard Worker 		return ENOMEM;
105*6a54128fSAndroid Build Coastguard Worker 
106*6a54128fSAndroid Build Coastguard Worker 	strcpy(fn, dir);
107*6a54128fSAndroid Build Coastguard Worker 	cp = fn;
108*6a54128fSAndroid Build Coastguard Worker 	while(1) {
109*6a54128fSAndroid Build Coastguard Worker 		next = strchr(cp, '/');
110*6a54128fSAndroid Build Coastguard Worker 		if (next)
111*6a54128fSAndroid Build Coastguard Worker 			*next++ = 0;
112*6a54128fSAndroid Build Coastguard Worker 		if (*cp) {
113*6a54128fSAndroid Build Coastguard Worker 			retval = ext2fs_new_inode(fs, ino, LINUX_S_IFDIR,
114*6a54128fSAndroid Build Coastguard Worker 						  NULL, &newdir);
115*6a54128fSAndroid Build Coastguard Worker 			if (retval)
116*6a54128fSAndroid Build Coastguard Worker 				goto errout;
117*6a54128fSAndroid Build Coastguard Worker 
118*6a54128fSAndroid Build Coastguard Worker 			retval = ext2fs_mkdir(fs, ino, newdir, cp);
119*6a54128fSAndroid Build Coastguard Worker 			if (retval)
120*6a54128fSAndroid Build Coastguard Worker 				goto errout;
121*6a54128fSAndroid Build Coastguard Worker 
122*6a54128fSAndroid Build Coastguard Worker 			ino = newdir;
123*6a54128fSAndroid Build Coastguard Worker 			retval = ext2fs_read_inode(fs, ino, &inode);
124*6a54128fSAndroid Build Coastguard Worker 			if (retval)
125*6a54128fSAndroid Build Coastguard Worker 				goto errout;
126*6a54128fSAndroid Build Coastguard Worker 
127*6a54128fSAndroid Build Coastguard Worker 			inode.i_uid = uid & 0xFFFF;
128*6a54128fSAndroid Build Coastguard Worker 			ext2fs_set_i_uid_high(inode, (uid >> 16) & 0xffff);
129*6a54128fSAndroid Build Coastguard Worker 			inode.i_gid = gid & 0xFFFF;
130*6a54128fSAndroid Build Coastguard Worker 			ext2fs_set_i_gid_high(inode, (gid >> 16) & 0xffff);
131*6a54128fSAndroid Build Coastguard Worker 			retval = ext2fs_write_inode(fs, ino, &inode);
132*6a54128fSAndroid Build Coastguard Worker 			if (retval)
133*6a54128fSAndroid Build Coastguard Worker 				goto errout;
134*6a54128fSAndroid Build Coastguard Worker 		}
135*6a54128fSAndroid Build Coastguard Worker 		if (next == NULL || *next == '\0')
136*6a54128fSAndroid Build Coastguard Worker 			break;
137*6a54128fSAndroid Build Coastguard Worker 		cp = next;
138*6a54128fSAndroid Build Coastguard Worker 	}
139*6a54128fSAndroid Build Coastguard Worker errout:
140*6a54128fSAndroid Build Coastguard Worker 	free(fn);
141*6a54128fSAndroid Build Coastguard Worker 	if (retval == 0)
142*6a54128fSAndroid Build Coastguard Worker 		*ret_ino = ino;
143*6a54128fSAndroid Build Coastguard Worker 	return retval;
144*6a54128fSAndroid Build Coastguard Worker }
145*6a54128fSAndroid Build Coastguard Worker 
mk_hugefile(ext2_filsys fs,blk64_t num,ext2_ino_t dir,unsigned long idx,ext2_ino_t * ino)146*6a54128fSAndroid Build Coastguard Worker static errcode_t mk_hugefile(ext2_filsys fs, blk64_t num,
147*6a54128fSAndroid Build Coastguard Worker 			     ext2_ino_t dir, unsigned long idx, ext2_ino_t *ino)
148*6a54128fSAndroid Build Coastguard Worker 
149*6a54128fSAndroid Build Coastguard Worker {
150*6a54128fSAndroid Build Coastguard Worker 	errcode_t		retval;
151*6a54128fSAndroid Build Coastguard Worker 	blk64_t			lblk, bend = 0;
152*6a54128fSAndroid Build Coastguard Worker 	__u64			size;
153*6a54128fSAndroid Build Coastguard Worker 	blk64_t			left;
154*6a54128fSAndroid Build Coastguard Worker 	blk64_t			count = 0;
155*6a54128fSAndroid Build Coastguard Worker 	struct ext2_inode	inode;
156*6a54128fSAndroid Build Coastguard Worker 	ext2_extent_handle_t	handle;
157*6a54128fSAndroid Build Coastguard Worker 
158*6a54128fSAndroid Build Coastguard Worker 	retval = ext2fs_new_inode(fs, 0, LINUX_S_IFREG, NULL, ino);
159*6a54128fSAndroid Build Coastguard Worker 	if (retval)
160*6a54128fSAndroid Build Coastguard Worker 		return retval;
161*6a54128fSAndroid Build Coastguard Worker 
162*6a54128fSAndroid Build Coastguard Worker 	memset(&inode, 0, sizeof(struct ext2_inode));
163*6a54128fSAndroid Build Coastguard Worker 	inode.i_mode = LINUX_S_IFREG | (0666 & ~fs->umask);
164*6a54128fSAndroid Build Coastguard Worker 	inode.i_links_count = 1;
165*6a54128fSAndroid Build Coastguard Worker 	inode.i_uid = uid & 0xFFFF;
166*6a54128fSAndroid Build Coastguard Worker 	ext2fs_set_i_uid_high(inode, (uid >> 16) & 0xffff);
167*6a54128fSAndroid Build Coastguard Worker 	inode.i_gid = gid & 0xFFFF;
168*6a54128fSAndroid Build Coastguard Worker 	ext2fs_set_i_gid_high(inode, (gid >> 16) & 0xffff);
169*6a54128fSAndroid Build Coastguard Worker 
170*6a54128fSAndroid Build Coastguard Worker 	retval = ext2fs_write_new_inode(fs, *ino, &inode);
171*6a54128fSAndroid Build Coastguard Worker 	if (retval)
172*6a54128fSAndroid Build Coastguard Worker 		return retval;
173*6a54128fSAndroid Build Coastguard Worker 
174*6a54128fSAndroid Build Coastguard Worker 	ext2fs_inode_alloc_stats2(fs, *ino, +1, 0);
175*6a54128fSAndroid Build Coastguard Worker 
176*6a54128fSAndroid Build Coastguard Worker 	retval = ext2fs_extent_open2(fs, *ino, &inode, &handle);
177*6a54128fSAndroid Build Coastguard Worker 	if (retval)
178*6a54128fSAndroid Build Coastguard Worker 		return retval;
179*6a54128fSAndroid Build Coastguard Worker 
180*6a54128fSAndroid Build Coastguard Worker 	/*
181*6a54128fSAndroid Build Coastguard Worker 	 * We don't use ext2fs_fallocate() here because hugefiles are
182*6a54128fSAndroid Build Coastguard Worker 	 * designed to be physically contiguous (if the block group
183*6a54128fSAndroid Build Coastguard Worker 	 * descriptors are configured to be in a single block at the
184*6a54128fSAndroid Build Coastguard Worker 	 * beginning of the file system, by using the
185*6a54128fSAndroid Build Coastguard Worker 	 * packed_meta_blocks layout), with the extent tree blocks
186*6a54128fSAndroid Build Coastguard Worker 	 * allocated near the beginning of the file system.
187*6a54128fSAndroid Build Coastguard Worker 	 */
188*6a54128fSAndroid Build Coastguard Worker 	lblk = 0;
189*6a54128fSAndroid Build Coastguard Worker 	left = num ? num : 1;
190*6a54128fSAndroid Build Coastguard Worker 	while (left) {
191*6a54128fSAndroid Build Coastguard Worker 		blk64_t pblk, end;
192*6a54128fSAndroid Build Coastguard Worker 		blk64_t n = left;
193*6a54128fSAndroid Build Coastguard Worker 
194*6a54128fSAndroid Build Coastguard Worker 		retval =  ext2fs_find_first_zero_block_bitmap2(fs->block_map,
195*6a54128fSAndroid Build Coastguard Worker 			goal, ext2fs_blocks_count(fs->super) - 1, &end);
196*6a54128fSAndroid Build Coastguard Worker 		if (retval)
197*6a54128fSAndroid Build Coastguard Worker 			goto errout;
198*6a54128fSAndroid Build Coastguard Worker 		goal = end;
199*6a54128fSAndroid Build Coastguard Worker 
200*6a54128fSAndroid Build Coastguard Worker 		retval =  ext2fs_find_first_set_block_bitmap2(fs->block_map, goal,
201*6a54128fSAndroid Build Coastguard Worker 			       ext2fs_blocks_count(fs->super) - 1, &bend);
202*6a54128fSAndroid Build Coastguard Worker 		if (retval == ENOENT) {
203*6a54128fSAndroid Build Coastguard Worker 			bend = ext2fs_blocks_count(fs->super);
204*6a54128fSAndroid Build Coastguard Worker 			if (num == 0)
205*6a54128fSAndroid Build Coastguard Worker 				left = 0;
206*6a54128fSAndroid Build Coastguard Worker 		}
207*6a54128fSAndroid Build Coastguard Worker 		if (!num || bend - goal < left)
208*6a54128fSAndroid Build Coastguard Worker 			n = bend - goal;
209*6a54128fSAndroid Build Coastguard Worker 		pblk = goal;
210*6a54128fSAndroid Build Coastguard Worker 		if (num)
211*6a54128fSAndroid Build Coastguard Worker 			left -= n;
212*6a54128fSAndroid Build Coastguard Worker 		goal += n;
213*6a54128fSAndroid Build Coastguard Worker 		count += n;
214*6a54128fSAndroid Build Coastguard Worker 		ext2fs_block_alloc_stats_range(fs, pblk, n, +1);
215*6a54128fSAndroid Build Coastguard Worker 
216*6a54128fSAndroid Build Coastguard Worker 		if (zero_hugefile) {
217*6a54128fSAndroid Build Coastguard Worker 			blk64_t ret_blk;
218*6a54128fSAndroid Build Coastguard Worker 			retval = ext2fs_zero_blocks2(fs, pblk, n,
219*6a54128fSAndroid Build Coastguard Worker 						     &ret_blk, NULL);
220*6a54128fSAndroid Build Coastguard Worker 
221*6a54128fSAndroid Build Coastguard Worker 			if (retval)
222*6a54128fSAndroid Build Coastguard Worker 				com_err(program_name, retval,
223*6a54128fSAndroid Build Coastguard Worker 					_("while zeroing block %llu "
224*6a54128fSAndroid Build Coastguard Worker 					  "for hugefile"),
225*6a54128fSAndroid Build Coastguard Worker 					(unsigned long long) ret_blk);
226*6a54128fSAndroid Build Coastguard Worker 		}
227*6a54128fSAndroid Build Coastguard Worker 
228*6a54128fSAndroid Build Coastguard Worker 		while (n) {
229*6a54128fSAndroid Build Coastguard Worker 			blk64_t l = n;
230*6a54128fSAndroid Build Coastguard Worker 			struct ext2fs_extent newextent;
231*6a54128fSAndroid Build Coastguard Worker 
232*6a54128fSAndroid Build Coastguard Worker 			if (l > EXT_INIT_MAX_LEN)
233*6a54128fSAndroid Build Coastguard Worker 				l = EXT_INIT_MAX_LEN;
234*6a54128fSAndroid Build Coastguard Worker 
235*6a54128fSAndroid Build Coastguard Worker 			newextent.e_len = l;
236*6a54128fSAndroid Build Coastguard Worker 			newextent.e_pblk = pblk;
237*6a54128fSAndroid Build Coastguard Worker 			newextent.e_lblk = lblk;
238*6a54128fSAndroid Build Coastguard Worker 			newextent.e_flags = 0;
239*6a54128fSAndroid Build Coastguard Worker 
240*6a54128fSAndroid Build Coastguard Worker 			retval = ext2fs_extent_insert(handle,
241*6a54128fSAndroid Build Coastguard Worker 					EXT2_EXTENT_INSERT_AFTER, &newextent);
242*6a54128fSAndroid Build Coastguard Worker 			if (retval)
243*6a54128fSAndroid Build Coastguard Worker 				return retval;
244*6a54128fSAndroid Build Coastguard Worker 			pblk += l;
245*6a54128fSAndroid Build Coastguard Worker 			lblk += l;
246*6a54128fSAndroid Build Coastguard Worker 			n -= l;
247*6a54128fSAndroid Build Coastguard Worker 		}
248*6a54128fSAndroid Build Coastguard Worker 	}
249*6a54128fSAndroid Build Coastguard Worker 
250*6a54128fSAndroid Build Coastguard Worker 	retval = ext2fs_read_inode(fs, *ino, &inode);
251*6a54128fSAndroid Build Coastguard Worker 	if (retval)
252*6a54128fSAndroid Build Coastguard Worker 		goto errout;
253*6a54128fSAndroid Build Coastguard Worker 
254*6a54128fSAndroid Build Coastguard Worker 	retval = ext2fs_iblk_add_blocks(fs, &inode,
255*6a54128fSAndroid Build Coastguard Worker 					count / EXT2FS_CLUSTER_RATIO(fs));
256*6a54128fSAndroid Build Coastguard Worker 	if (retval)
257*6a54128fSAndroid Build Coastguard Worker 		goto errout;
258*6a54128fSAndroid Build Coastguard Worker 	size = (__u64) count * fs->blocksize;
259*6a54128fSAndroid Build Coastguard Worker 	retval = ext2fs_inode_size_set(fs, &inode, size);
260*6a54128fSAndroid Build Coastguard Worker 	if (retval)
261*6a54128fSAndroid Build Coastguard Worker 		goto errout;
262*6a54128fSAndroid Build Coastguard Worker 
263*6a54128fSAndroid Build Coastguard Worker 	retval = ext2fs_write_new_inode(fs, *ino, &inode);
264*6a54128fSAndroid Build Coastguard Worker 	if (retval)
265*6a54128fSAndroid Build Coastguard Worker 		goto errout;
266*6a54128fSAndroid Build Coastguard Worker 
267*6a54128fSAndroid Build Coastguard Worker 	if (idx_digits)
268*6a54128fSAndroid Build Coastguard Worker 		sprintf(fn_numbuf, "%0*lu", idx_digits, idx);
269*6a54128fSAndroid Build Coastguard Worker 	else if (num_files > 1)
270*6a54128fSAndroid Build Coastguard Worker 		sprintf(fn_numbuf, "%lu", idx);
271*6a54128fSAndroid Build Coastguard Worker 
272*6a54128fSAndroid Build Coastguard Worker retry:
273*6a54128fSAndroid Build Coastguard Worker 	retval = ext2fs_link(fs, dir, fn_buf, *ino, EXT2_FT_REG_FILE);
274*6a54128fSAndroid Build Coastguard Worker 	if (retval == EXT2_ET_DIR_NO_SPACE) {
275*6a54128fSAndroid Build Coastguard Worker 		retval = ext2fs_expand_dir(fs, dir);
276*6a54128fSAndroid Build Coastguard Worker 		if (retval)
277*6a54128fSAndroid Build Coastguard Worker 			goto errout;
278*6a54128fSAndroid Build Coastguard Worker 		goto retry;
279*6a54128fSAndroid Build Coastguard Worker 	}
280*6a54128fSAndroid Build Coastguard Worker 
281*6a54128fSAndroid Build Coastguard Worker 	if (retval)
282*6a54128fSAndroid Build Coastguard Worker 		goto errout;
283*6a54128fSAndroid Build Coastguard Worker 
284*6a54128fSAndroid Build Coastguard Worker errout:
285*6a54128fSAndroid Build Coastguard Worker 	if (handle)
286*6a54128fSAndroid Build Coastguard Worker 		ext2fs_extent_free(handle);
287*6a54128fSAndroid Build Coastguard Worker 
288*6a54128fSAndroid Build Coastguard Worker 	return retval;
289*6a54128fSAndroid Build Coastguard Worker }
290*6a54128fSAndroid Build Coastguard Worker 
calc_overhead(ext2_filsys fs,blk64_t num)291*6a54128fSAndroid Build Coastguard Worker static blk64_t calc_overhead(ext2_filsys fs, blk64_t num)
292*6a54128fSAndroid Build Coastguard Worker {
293*6a54128fSAndroid Build Coastguard Worker 	blk64_t e_blocks, e_blocks2, e_blocks3, e_blocks4;
294*6a54128fSAndroid Build Coastguard Worker 	int extents_per_block;
295*6a54128fSAndroid Build Coastguard Worker 	int extents = (num + EXT_INIT_MAX_LEN - 1) / EXT_INIT_MAX_LEN;
296*6a54128fSAndroid Build Coastguard Worker 
297*6a54128fSAndroid Build Coastguard Worker 	if (extents <= 4)
298*6a54128fSAndroid Build Coastguard Worker 		return 0;
299*6a54128fSAndroid Build Coastguard Worker 
300*6a54128fSAndroid Build Coastguard Worker 	/*
301*6a54128fSAndroid Build Coastguard Worker 	 * This calculation is due to the fact that we are inefficient
302*6a54128fSAndroid Build Coastguard Worker 	 * in how handle extent splits when appending to the end of
303*6a54128fSAndroid Build Coastguard Worker 	 * the extent tree.  Sigh.  We should fix this so that we can
304*6a54128fSAndroid Build Coastguard Worker 	 * actually store 340 extents per 4k block, instead of only 170.
305*6a54128fSAndroid Build Coastguard Worker 	 */
306*6a54128fSAndroid Build Coastguard Worker 	extents_per_block = ((fs->blocksize -
307*6a54128fSAndroid Build Coastguard Worker 			      sizeof(struct ext3_extent_header)) /
308*6a54128fSAndroid Build Coastguard Worker 			     sizeof(struct ext3_extent));
309*6a54128fSAndroid Build Coastguard Worker 	extents_per_block = (extents_per_block/ 2) - 1;
310*6a54128fSAndroid Build Coastguard Worker 
311*6a54128fSAndroid Build Coastguard Worker 	e_blocks = (extents + extents_per_block - 1) / extents_per_block;
312*6a54128fSAndroid Build Coastguard Worker 	e_blocks2 = (e_blocks + extents_per_block - 1) / extents_per_block;
313*6a54128fSAndroid Build Coastguard Worker 	e_blocks3 = (e_blocks2 + extents_per_block - 1) / extents_per_block;
314*6a54128fSAndroid Build Coastguard Worker 	e_blocks4 = (e_blocks3 + extents_per_block - 1) / extents_per_block;
315*6a54128fSAndroid Build Coastguard Worker 	return (e_blocks + e_blocks2 + e_blocks3 + e_blocks4) *
316*6a54128fSAndroid Build Coastguard Worker 		EXT2FS_CLUSTER_RATIO(fs);
317*6a54128fSAndroid Build Coastguard Worker }
318*6a54128fSAndroid Build Coastguard Worker 
319*6a54128fSAndroid Build Coastguard Worker /*
320*6a54128fSAndroid Build Coastguard Worker  * Find the place where we should start allocating blocks for the huge
321*6a54128fSAndroid Build Coastguard Worker  * files.  Leave <slack> free blocks at the beginning of the file
322*6a54128fSAndroid Build Coastguard Worker  * system for things like metadata blocks.
323*6a54128fSAndroid Build Coastguard Worker  */
get_start_block(ext2_filsys fs,blk64_t slack)324*6a54128fSAndroid Build Coastguard Worker static blk64_t get_start_block(ext2_filsys fs, blk64_t slack)
325*6a54128fSAndroid Build Coastguard Worker {
326*6a54128fSAndroid Build Coastguard Worker 	errcode_t retval;
327*6a54128fSAndroid Build Coastguard Worker 	blk64_t blk = fs->super->s_first_data_block, next;
328*6a54128fSAndroid Build Coastguard Worker 	blk64_t last_blk = ext2fs_blocks_count(fs->super) - 1;
329*6a54128fSAndroid Build Coastguard Worker 
330*6a54128fSAndroid Build Coastguard Worker 	while (slack) {
331*6a54128fSAndroid Build Coastguard Worker 		retval = ext2fs_find_first_zero_block_bitmap2(fs->block_map,
332*6a54128fSAndroid Build Coastguard Worker 						blk, last_blk, &blk);
333*6a54128fSAndroid Build Coastguard Worker 		if (retval)
334*6a54128fSAndroid Build Coastguard Worker 			break;
335*6a54128fSAndroid Build Coastguard Worker 
336*6a54128fSAndroid Build Coastguard Worker 		retval = ext2fs_find_first_set_block_bitmap2(fs->block_map,
337*6a54128fSAndroid Build Coastguard Worker 						blk, last_blk, &next);
338*6a54128fSAndroid Build Coastguard Worker 		if (retval)
339*6a54128fSAndroid Build Coastguard Worker 			next = last_blk;
340*6a54128fSAndroid Build Coastguard Worker 
341*6a54128fSAndroid Build Coastguard Worker 		if (next - blk > slack) {
342*6a54128fSAndroid Build Coastguard Worker 			blk += slack;
343*6a54128fSAndroid Build Coastguard Worker 			break;
344*6a54128fSAndroid Build Coastguard Worker 		}
345*6a54128fSAndroid Build Coastguard Worker 
346*6a54128fSAndroid Build Coastguard Worker 		slack -= (next - blk);
347*6a54128fSAndroid Build Coastguard Worker 		blk = next;
348*6a54128fSAndroid Build Coastguard Worker 	}
349*6a54128fSAndroid Build Coastguard Worker 	return blk;
350*6a54128fSAndroid Build Coastguard Worker }
351*6a54128fSAndroid Build Coastguard Worker 
round_up_align(blk64_t b,unsigned long align,blk64_t part_offset)352*6a54128fSAndroid Build Coastguard Worker static blk64_t round_up_align(blk64_t b, unsigned long align,
353*6a54128fSAndroid Build Coastguard Worker 			      blk64_t part_offset)
354*6a54128fSAndroid Build Coastguard Worker {
355*6a54128fSAndroid Build Coastguard Worker 	unsigned long m;
356*6a54128fSAndroid Build Coastguard Worker 
357*6a54128fSAndroid Build Coastguard Worker 	if (align == 0)
358*6a54128fSAndroid Build Coastguard Worker 		return b;
359*6a54128fSAndroid Build Coastguard Worker 	part_offset = part_offset % align;
360*6a54128fSAndroid Build Coastguard Worker 	m = (b + part_offset) % align;
361*6a54128fSAndroid Build Coastguard Worker 	if (m)
362*6a54128fSAndroid Build Coastguard Worker 		b += align - m;
363*6a54128fSAndroid Build Coastguard Worker 	return b;
364*6a54128fSAndroid Build Coastguard Worker }
365*6a54128fSAndroid Build Coastguard Worker 
mk_hugefiles(ext2_filsys fs,const char * device_name)366*6a54128fSAndroid Build Coastguard Worker errcode_t mk_hugefiles(ext2_filsys fs, const char *device_name)
367*6a54128fSAndroid Build Coastguard Worker {
368*6a54128fSAndroid Build Coastguard Worker 	unsigned long	i;
369*6a54128fSAndroid Build Coastguard Worker 	ext2_ino_t	dir;
370*6a54128fSAndroid Build Coastguard Worker 	errcode_t	retval;
371*6a54128fSAndroid Build Coastguard Worker 	blk64_t		fs_blocks, part_offset = 0;
372*6a54128fSAndroid Build Coastguard Worker 	unsigned long	align;
373*6a54128fSAndroid Build Coastguard Worker 	int		d, dsize;
374*6a54128fSAndroid Build Coastguard Worker 	char		*t;
375*6a54128fSAndroid Build Coastguard Worker 
376*6a54128fSAndroid Build Coastguard Worker 	if (!get_bool_from_profile(fs_types, "make_hugefiles", 0))
377*6a54128fSAndroid Build Coastguard Worker 		return 0;
378*6a54128fSAndroid Build Coastguard Worker 
379*6a54128fSAndroid Build Coastguard Worker 	if (!ext2fs_has_feature_extents(fs->super))
380*6a54128fSAndroid Build Coastguard Worker 		return EXT2_ET_EXTENT_NOT_SUPPORTED;
381*6a54128fSAndroid Build Coastguard Worker 
382*6a54128fSAndroid Build Coastguard Worker 	uid = get_int_from_profile(fs_types, "hugefiles_uid", 0);
383*6a54128fSAndroid Build Coastguard Worker 	gid = get_int_from_profile(fs_types, "hugefiles_gid", 0);
384*6a54128fSAndroid Build Coastguard Worker 	fs->umask = get_int_from_profile(fs_types, "hugefiles_umask", 077);
385*6a54128fSAndroid Build Coastguard Worker 	num_files = get_int_from_profile(fs_types, "num_hugefiles", 0);
386*6a54128fSAndroid Build Coastguard Worker 	t = get_string_from_profile(fs_types, "hugefiles_slack", "1M");
387*6a54128fSAndroid Build Coastguard Worker 	num_slack = parse_num_blocks2(t, fs->super->s_log_block_size);
388*6a54128fSAndroid Build Coastguard Worker 	free(t);
389*6a54128fSAndroid Build Coastguard Worker 	t = get_string_from_profile(fs_types, "hugefiles_size", "0");
390*6a54128fSAndroid Build Coastguard Worker 	num_blocks = parse_num_blocks2(t, fs->super->s_log_block_size);
391*6a54128fSAndroid Build Coastguard Worker 	free(t);
392*6a54128fSAndroid Build Coastguard Worker 	t = get_string_from_profile(fs_types, "hugefiles_align", "0");
393*6a54128fSAndroid Build Coastguard Worker 	align = parse_num_blocks2(t, fs->super->s_log_block_size);
394*6a54128fSAndroid Build Coastguard Worker 	free(t);
395*6a54128fSAndroid Build Coastguard Worker 	if (get_bool_from_profile(fs_types, "hugefiles_align_disk", 0)) {
396*6a54128fSAndroid Build Coastguard Worker 		part_offset = get_partition_start(device_name) /
397*6a54128fSAndroid Build Coastguard Worker 			(fs->blocksize / 512);
398*6a54128fSAndroid Build Coastguard Worker 		if (part_offset % EXT2FS_CLUSTER_RATIO(fs)) {
399*6a54128fSAndroid Build Coastguard Worker 			fprintf(stderr,
400*6a54128fSAndroid Build Coastguard Worker 				_("Partition offset of %llu (%uk) blocks "
401*6a54128fSAndroid Build Coastguard Worker 				  "not compatible with cluster size %u.\n"),
402*6a54128fSAndroid Build Coastguard Worker 				(unsigned long long) part_offset, fs->blocksize,
403*6a54128fSAndroid Build Coastguard Worker 				EXT2_CLUSTER_SIZE(fs->super));
404*6a54128fSAndroid Build Coastguard Worker 			exit(1);
405*6a54128fSAndroid Build Coastguard Worker 		}
406*6a54128fSAndroid Build Coastguard Worker 	}
407*6a54128fSAndroid Build Coastguard Worker 	num_blocks = round_up_align(num_blocks, align, 0);
408*6a54128fSAndroid Build Coastguard Worker 	zero_hugefile = get_bool_from_profile(fs_types, "zero_hugefiles",
409*6a54128fSAndroid Build Coastguard Worker 					      zero_hugefile);
410*6a54128fSAndroid Build Coastguard Worker 
411*6a54128fSAndroid Build Coastguard Worker 	t = get_string_from_profile(fs_types, "hugefiles_dir", "/");
412*6a54128fSAndroid Build Coastguard Worker 	retval = create_directory(fs, t, &dir);
413*6a54128fSAndroid Build Coastguard Worker 	free(t);
414*6a54128fSAndroid Build Coastguard Worker 	if (retval)
415*6a54128fSAndroid Build Coastguard Worker 		return retval;
416*6a54128fSAndroid Build Coastguard Worker 
417*6a54128fSAndroid Build Coastguard Worker 	fn_prefix = get_string_from_profile(fs_types, "hugefiles_name",
418*6a54128fSAndroid Build Coastguard Worker 					    "hugefile");
419*6a54128fSAndroid Build Coastguard Worker 	idx_digits = get_int_from_profile(fs_types, "hugefiles_digits", 5);
420*6a54128fSAndroid Build Coastguard Worker 	d = int_log10(num_files) + 1;
421*6a54128fSAndroid Build Coastguard Worker 	if (idx_digits > d)
422*6a54128fSAndroid Build Coastguard Worker 		d = idx_digits;
423*6a54128fSAndroid Build Coastguard Worker 	dsize = strlen(fn_prefix) + d + 16;
424*6a54128fSAndroid Build Coastguard Worker 	fn_buf = malloc(dsize);
425*6a54128fSAndroid Build Coastguard Worker 	if (!fn_buf) {
426*6a54128fSAndroid Build Coastguard Worker 		free(fn_prefix);
427*6a54128fSAndroid Build Coastguard Worker 		return ENOMEM;
428*6a54128fSAndroid Build Coastguard Worker 	}
429*6a54128fSAndroid Build Coastguard Worker 	strcpy(fn_buf, fn_prefix);
430*6a54128fSAndroid Build Coastguard Worker 	fn_numbuf = fn_buf + strlen(fn_prefix);
431*6a54128fSAndroid Build Coastguard Worker 	free(fn_prefix);
432*6a54128fSAndroid Build Coastguard Worker 
433*6a54128fSAndroid Build Coastguard Worker 	fs_blocks = ext2fs_free_blocks_count(fs->super);
434*6a54128fSAndroid Build Coastguard Worker 	if (fs_blocks < num_slack + align)
435*6a54128fSAndroid Build Coastguard Worker 		return ENOSPC;
436*6a54128fSAndroid Build Coastguard Worker 	fs_blocks -= num_slack + align;
437*6a54128fSAndroid Build Coastguard Worker 	if (num_blocks && num_blocks > fs_blocks)
438*6a54128fSAndroid Build Coastguard Worker 		return ENOSPC;
439*6a54128fSAndroid Build Coastguard Worker 	if (num_blocks == 0 && num_files == 0)
440*6a54128fSAndroid Build Coastguard Worker 		num_files = 1;
441*6a54128fSAndroid Build Coastguard Worker 
442*6a54128fSAndroid Build Coastguard Worker 	if (num_files == 0 && num_blocks) {
443*6a54128fSAndroid Build Coastguard Worker 		num_files = fs_blocks / num_blocks;
444*6a54128fSAndroid Build Coastguard Worker 		fs_blocks -= (num_files / 16) + 1;
445*6a54128fSAndroid Build Coastguard Worker 		fs_blocks -= calc_overhead(fs, num_blocks) * num_files;
446*6a54128fSAndroid Build Coastguard Worker 		num_files = fs_blocks / num_blocks;
447*6a54128fSAndroid Build Coastguard Worker 	}
448*6a54128fSAndroid Build Coastguard Worker 
449*6a54128fSAndroid Build Coastguard Worker 	if (num_blocks == 0 && num_files > 1) {
450*6a54128fSAndroid Build Coastguard Worker 		num_blocks = fs_blocks / num_files;
451*6a54128fSAndroid Build Coastguard Worker 		fs_blocks -= (num_files / 16) + 1;
452*6a54128fSAndroid Build Coastguard Worker 		fs_blocks -= calc_overhead(fs, num_blocks) * num_files;
453*6a54128fSAndroid Build Coastguard Worker 		num_blocks = fs_blocks / num_files;
454*6a54128fSAndroid Build Coastguard Worker 	}
455*6a54128fSAndroid Build Coastguard Worker 
456*6a54128fSAndroid Build Coastguard Worker 	num_slack += (calc_overhead(fs, num_blocks ? num_blocks : fs_blocks) *
457*6a54128fSAndroid Build Coastguard Worker 		      num_files);
458*6a54128fSAndroid Build Coastguard Worker 	num_slack += (num_files / 16) + 1; /* space for dir entries */
459*6a54128fSAndroid Build Coastguard Worker 	goal = get_start_block(fs, num_slack);
460*6a54128fSAndroid Build Coastguard Worker 	goal = round_up_align(goal, align, part_offset);
461*6a54128fSAndroid Build Coastguard Worker 
462*6a54128fSAndroid Build Coastguard Worker 	if ((num_blocks ? num_blocks : fs_blocks) >
463*6a54128fSAndroid Build Coastguard Worker 	    (0x80000000UL / fs->blocksize))
464*6a54128fSAndroid Build Coastguard Worker 		ext2fs_set_feature_large_file(fs->super);
465*6a54128fSAndroid Build Coastguard Worker 
466*6a54128fSAndroid Build Coastguard Worker 	if (!quiet) {
467*6a54128fSAndroid Build Coastguard Worker 		if (zero_hugefile && verbose)
468*6a54128fSAndroid Build Coastguard Worker 			printf("%s", _("Huge files will be zero'ed\n"));
469*6a54128fSAndroid Build Coastguard Worker 		printf(_("Creating %lu huge file(s) "), num_files);
470*6a54128fSAndroid Build Coastguard Worker 		if (num_blocks)
471*6a54128fSAndroid Build Coastguard Worker 			printf(_("with %llu blocks each"),
472*6a54128fSAndroid Build Coastguard Worker 			       (unsigned long long) num_blocks);
473*6a54128fSAndroid Build Coastguard Worker 		fputs(": ", stdout);
474*6a54128fSAndroid Build Coastguard Worker 	}
475*6a54128fSAndroid Build Coastguard Worker 	for (i=0; i < num_files; i++) {
476*6a54128fSAndroid Build Coastguard Worker 		ext2_ino_t ino;
477*6a54128fSAndroid Build Coastguard Worker 
478*6a54128fSAndroid Build Coastguard Worker 		retval = mk_hugefile(fs, num_blocks, dir, i, &ino);
479*6a54128fSAndroid Build Coastguard Worker 		if (retval) {
480*6a54128fSAndroid Build Coastguard Worker 			com_err(program_name, retval,
481*6a54128fSAndroid Build Coastguard Worker 				_("while creating huge file %lu"), i);
482*6a54128fSAndroid Build Coastguard Worker 			goto errout;
483*6a54128fSAndroid Build Coastguard Worker 		}
484*6a54128fSAndroid Build Coastguard Worker 	}
485*6a54128fSAndroid Build Coastguard Worker 	if (!quiet)
486*6a54128fSAndroid Build Coastguard Worker 		fputs(_("done\n"), stdout);
487*6a54128fSAndroid Build Coastguard Worker 
488*6a54128fSAndroid Build Coastguard Worker errout:
489*6a54128fSAndroid Build Coastguard Worker 	free(fn_buf);
490*6a54128fSAndroid Build Coastguard Worker 	return retval;
491*6a54128fSAndroid Build Coastguard Worker }
492