How To Create and Measure NTFS & ext3 Disk Fragmentation

From time to time I need to test things related to disk fragmentation, like the performance of fragmented versus unfragmented disks, or how well a disk defragmenter works. Rather than trying to find machines with fragmented disks I decided to generate fragmentation on my own.

It’s actually quite easy to generate a fragmented disk on NTFS or ext3 filesystems. Fragmentation happens when you don’t have much free space on disk and a filesystem is forced to use non-contiguous blocks to fulfill requests. So we just encourage that behavior by filling the drive with a bunch of small files, then freeing some space by truncating those files to a smaller size. Then we fill the free space again by growing those files. Wash. Rinse. Repeat. Do this a few times and we end up with decent amounts of fragmentation.

I use the following short bash shell script under Linux natively, and on Windows with cygwin installed. This is probably easily done in PowerShell using something like dd for Windows but I will leave that to someone who knows more PowerShell than I do.

You’ll want to adjust the numbers below, particularly the “2217” in the loop. I adjust that by taking the amount of space I have on disk, in megabytes, subtract 32 MB for working space, and divide the result by 32. Then I round down. So if I have 71000 MB free it would be:

(71000 MB – 32 MB)/ 32 MB = 2217.75

#!/bin/bash
for size in 30 31 32 30 32
do
        for i in {0..2217}
        do
                dd if=/dev/zero of=$i bs=1M count=$size
        done
done

You can also vary the block size (the “bs=” parameter) if you desire larger files initially. That can be helpful if your volume is bigger. For example, on an 80 GB ext3 filesystem I get 33% fragmentation with a block size of 1 MB, but I get 56% if I increase that to 2 MB (bs=2M). You’ll need to do the math for 64 MB files, though, so you get the number of iterations right.

As for measuring the fragmentation, on Windows there is a myriad of programs, including free ones, that will measure the fragmentation (and then defragment if you would like). Some of my favorites beyond the Disk Defragmenter shipped with Windows (Programs->Accessories->System Tools) include Piriform’s Defraggler and MyDefrag.

On Linux you have a couple of options. First, the fsck utility will report the percentage of non-contiguous files when it checks your filesystems:

$ sudo e2fsck -f /dev/Volume00/test_lv
e2fsck 1.39 (29-May-2006)
Pass 1: Checking inodes, blocks, and sizes
Pass 2: Checking directory structure
Pass 3: Checking directory connectivity
Pass 4: Checking reference counts
Pass 5: Checking group summary information
/dev/Volume00/test_lv: 1110/9175040 files (55.7% non-contiguous), 18344624/18350080 blocks

Normally this requires the filesystem to be unmounted, which is what I recommend, but you can walk on the wild side and ask e2fsck to do a read-only check with “-n”. If you try it on a live filesystem you will likely get errors – do not act on them! A mounted, functioning filesystem will always look like it has errors.

$ sudo e2fsck -n -f /dev/Volume00/LogVol00
e2fsck 1.39 (29-May-2006)
Warning!  /dev/Volume00/LogVol00 is mounted.
Warning: skipping journal recovery because doing a read-only filesystem check.
Pass 1: Checking inodes, blocks, and sizes
Pass 2: Checking directory structure
Pass 3: Checking directory connectivity
Pass 4: Checking reference counts
Pass 5: Checking group summary information
Free inodes count wrong (124627, counted=124626).
Fix? no
/dev/Volume00/LogVol00: ********** WARNING: Filesystem still has errors **********
/dev/Volume00/LogVol00: 6445/131072 files (7.0% non-contiguous), 401060/524288 blocks

Alternately, you can use the ‘filefrag’ utility to report on the individual fragmentation of files. Using it in conjunction with the ‘find’ and ‘sort’ commands might be handy:

$ sudo find /mnt -type f -exec /usr/sbin/filefrag {} ; | sort -k 2 –n
/mnt/649: 28 extents found, perfection would be 1 extent
/mnt/449: 29 extents found, perfection would be 1 extent
/mnt/876: 29 extents found, perfection would be 1 extent
/mnt/1032: 31 extents found, perfection would be 1 extent
/mnt/507: 31 extents found, perfection would be 1 extent
/mnt/821: 33 extents found, perfection would be 1 extent
/mnt/313: 40 extents found, perfection would be 1 extent

Replace /mnt with the path you’d like to search.