67 lines
		
	
	
		
			2.2 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
			
		
		
	
	
			67 lines
		
	
	
		
			2.2 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
| #!/bin/sh
 | |
| 
 | |
| dir="$1"
 | |
| dev="$2"
 | |
| 
 | |
| if [ "$1" = "--help" ] || [ ! -d "${dir}" ]; then
 | |
| 	echo "Usage: $0 dir [mke2fs args] dev"
 | |
| 	exit 1
 | |
| fi
 | |
| 
 | |
| shift
 | |
| 
 | |
| # Goal: Put all the files at the beginning (which mke2fs does) and minimize
 | |
| # the number of free inodes given the minimum number of blocks required.
 | |
| # Hence all this math to get the inode ratio just right.
 | |
| 
 | |
| bytes="$(du -ks "${dir}" | awk '{print $1}')"
 | |
| bytes="$((bytes * 1024))"
 | |
| inodes="$(find "${dir}" -print0 | xargs -0 stat -c '%i' | sort -g | uniq | wc -l)"
 | |
| block_sz=4096
 | |
| inode_sz=256
 | |
| sb_overhead=4096
 | |
| blocks_per_group="$((block_sz * 8))"
 | |
| bytes_per_group="$((blocks_per_group * block_sz))"
 | |
| inode_bytes="$((inodes * inode_sz))"
 | |
| 
 | |
| # Estimate overhead with the minimum number of groups...
 | |
| nr_groups="$(( (bytes + inode_bytes + bytes_per_group - 1) / bytes_per_group))"
 | |
| inode_bytes_per_group="$((inode_bytes / nr_groups))"
 | |
| inode_blocks_per_group="$(( (inode_bytes_per_group + (block_sz - 1)) / block_sz ))"
 | |
| per_grp_overhead="$(( ((3 + inode_blocks_per_group) * block_sz) + 64 ))"
 | |
| overhead="$(( sb_overhead + (per_grp_overhead * nr_groups) ))"
 | |
| used_bytes="$((bytes + overhead))"
 | |
| 
 | |
| # Then do it again with the real number of groups.
 | |
| nr_groups="$(( (used_bytes + (bytes_per_group - 1)) / bytes_per_group))"
 | |
| tot_blocks="$((nr_groups * blocks_per_group))"
 | |
| tot_bytes="$((tot_blocks * block_sz))"
 | |
| 
 | |
| ratio="$((bytes / inodes))"
 | |
| mkfs_blocks="$((tot_blocks * 4 / 3))"
 | |
| 
 | |
| mke2fs -i "${ratio}" -T ext4 -d "${dir}" -O ^resize_inode,sparse_super2,metadata_csum,64bit,^has_journal -E packed_meta_blocks=1,num_backup_sb=0 -b "${block_sz}" -I "${inodesz}" -F "${dev}" "${mkfs_blocks}" || exit
 | |
| 
 | |
| e2fsck -fyD "${dev}"
 | |
| 
 | |
| blocks="$(dumpe2fs -h "${dev}" 2>&1 | grep 'Block count:' | awk '{print $3}')"
 | |
| while resize2fs -f -M "${dev}"; do
 | |
| 	new_blocks="$(dumpe2fs -h "${dev}" 2>&1 | grep 'Block count:' | awk '{print $3}')"
 | |
| 	if [ "${new_blocks}" -eq "${blocks}" ]; then
 | |
| 		break;
 | |
| 	fi
 | |
| 	blocks="${new_blocks}"
 | |
| done
 | |
| 
 | |
| if [ ! -b "${dev}" ]; then
 | |
|     truncate -s "$((blocks * block_sz))" "${dev}" || (e2image -ar "${dev}" "${dev}.min"; mv "${dev}.min" "${dev}")
 | |
| fi
 | |
| 
 | |
| e2fsck -fy "${dev}"
 | |
| 
 | |
| dir_blocks="$((bytes / block_sz))"
 | |
| overhead="$((blocks - dir_blocks))"
 | |
| echo "Minimized image overhead: $((100 * overhead / dir_blocks))%"
 | |
| 
 | |
| exit 0
 |