Working with disk image files in linux

Disk images are a common way to copy existing drives for forensic analysis, backup or migration between machines. With the help of loop devices, they can also be mounted directly as virtual block devices, behaving just like any other disk.

Supported disk image types

There are two types of image formats we will cover in this article:

  1. Raw disk copies. Typically use the .img file extension and contain a literal copy of all bytes of a physical disk with either a single filesystem, or a complete partition layout with partition table.

  2. ISO 9660 images using the .iso extension. Initially used as read-only media for CDs, they are now mostly used as boot files, often with a hybrid layout containing both a partition table with an EFI partition and a legacy ISO9660 filesystem.

Other formats used as virtual machine disks, like vdi, vmdk or qcow2 are not directly mountable using loop devices alone, as they require specific drivers and software dependencies.

Loop devices

A loop device is a virtual device file in linux systems that allows treating a file like a raw block device. A block device is the linux term for "anything that can store data", like disks, thumb drives, dvd writers etc.

Typically, mounting a block device like a disk involves three steps:

  1. Find the device (eg /dev/sda)

  2. Find the target partition on the device

  3. Mount the filesystem in that partition

A loop device repeats these steps twice, first for the raw physical device, then within the disk image file:

  1. Find the device (eg (/dev/sda

  2. Find the target partition on the device

  3. Find the disk image file on the filesystem on the partition

  4. Find the target partition inside the image file

  5. Mount the filesystem in that partition

Effectively, it loops through the normal mounting process twice, thus the name "loop device".

Creating sample disk images

Let's create two disk images to use in sample commands.

The first is a plain disk without partitions:

fallocate -l 1GiB simple.img
sudo mkfs.ext4 simple.img

The second is a multi-partition disk image with a GPT partition table, a 300MB partition and a larger one covering the remaining space.

fallocate -l 1GiB partitioned.img
sudo parted -s partitioned.img \
  mklabel gpt \
  mkpart primary ext4 1MiB 301MiB \
  mkpart primary ext4 301MiB 100%
LOOP_DEV=$(sudo losetup -Pf --show partitioned.img)
sudo mkfs.ext4 "${LOOP_DEV}p1"
sudo mkfs.ext4 "${LOOP_DEV}p2"
sudo losetup -d "$LOOP_DEV"

Both image types are perfectly supported by loop devices and mount. You can use an existing .iso file instead, the commands for mounting and setting up loop devices are the same for both.

Mounting plain images

If you have a .imgor .iso file that does not contain a partition table, the mount has a shortcut:

mount -o loop simple.img /mnt

You should prefer this version for simple images and iso files, as it automatically manages loop devices and lifetimes for you, reusing or creating a new one during mount and detaching it when unmounting.

Mounting partitioned images

Loop devices are accessible as files in /dev/loopX, where X is either a number (e.g. loop1) or a number plus partition identifier (e.g. loop1p1). Modern linux systems automatically create, reuse and remove loop devices as needed, through the /dev/loop-control interface.

You will likely only ever interact with the loop device controller through the losetup command.


To mount a partitioned disk image file, first a new loop device needs to be attached:

sudo losetup -Pf --show partitioned.img

The command will print the name of the loop device attached to the image file, for example loop1.

Partitions within the disk image are made available through devices with partition identifiers. You can run lsblk to see more information about partitions available through the loop device:

loop1           7:1    0    1G  0 loop  
├─loop1p1     259:4    0  300M  0 part  
└─loop1p2     259:5    0  722M  0 part  

The image contains two partitions, available as loop1p1 and loop1p2 (your loop device names may be different).


You can now mount the partitions like you would any other with mount:

mount /dev/loop1p1 /mnt

After unmounting, you will need to detach the loop device from the image file again:

sudo losetup -d loop1

Remember to always unmount any partitions before detaching loop devices and use the loop device name (e.g. loop4) instead of the partition identifier ((e.g. loop4p2) when detaching.

Resolving out of device errors

When running losetup commands, you may see errors like:

losetup: cannot find an unused loop device

This can be caused by two separate issues. Loop devices are managed dynamically and created on the fly as needed - within limits. The most likely problem is that you are using all available loop devices. You can check all loop devices in use with:

sudo losetup -a

Output may look like:

/dev/loop1: [0042]:410560 (/tmp/disk/partitioned.img)

You can then use sudo losetup -d <name> to detach one, or sudo losetup -D to detach them all (careful, may break services like incus!).


If you do not want to detach any of your existing loop devices, the only way forward is to increase the limit of total available loop devices.

Check the current limit with:

cat /sys/module/loop/parameters/max_loop

To increase it, write the new setting for the loop kernel module:

echo "options loop max_loop=128" > /etc/modprobe.d/loop.conf

Restart your machine to apply the changes.


You could also increase the limit at runtime, but that would require detaching all existing loop devices and would vanish after a reboot, so it is not reliable to use.

If you absolutely cannot reboot and need a higher limit, detach all loop devices, then unload the loop kernel module and load it with a higher limit:

sudo losetup -D
sudo modprobe -r loop
sudo modprobe loop max_loop=128

This approach is really only useful for ephemeral systems like CI runners and should not be used on long-running servers.

More articles

Reducing internal tool sprawl with homarr

Replace scattered links with a role-aware web launcher

Setting up Local LLM voice conversations

Talking with your graphics card in real-time