Skip to content

Instantly share code, notes, and snippets.

@coderjo
Last active October 29, 2024 19:15
Show Gist options
  • Save coderjo/c8de3ecc31f1d6450254b5e97ea2c595 to your computer and use it in GitHub Desktop.
Save coderjo/c8de3ecc31f1d6450254b5e97ea2c595 to your computer and use it in GitHub Desktop.
access a disk image read-only with a copy-on-write overlay to allow fsck or the like to write changes
#!/bin/bash
# usage: attach_cow_image.sh [imagefile] [cowfile] [devname]
# imagefile: path to the image file you want to load
# cowfile: path to the file to store writes into. If it doesn't exist, a sparse 1GB file will be created.
# devname: the name you want the drive to show up as in /dev/mapper
imgfile="$1"
cowfile="$2"
dmname="$3"
# create COW file if it doesn't exist (otherwise, assume we are using a file from a previous use)
# the if you don't think 1000MiB will be enough, you can create a larger one.
[ -f "$cowfile" ] || dd if=/dev/zero of="$cowfile" bs=1 count=1 seek=1048576000
# attach the files to loop devices (with the image file read-only)
imgdev=`losetup -f -r --show "$imgfile"`
cowdev=`losetup -f --show "$cowfile"`
# get the size of the image device
imgsz=`blockdev --getsz $imgdev`
# create the devmapper table for a copy-on-write device using the two loop devices
# p means persist the snapshot data
# The 4 is the number of sectors to use per COW image chunk
echo 0 $imgsz snapshot $imgdev $cowdev p 4| dmsetup create $dmname
# and now probe the partition table of the new device
partprobe -s /dev/mapper/$dmname
# to detatch everything:
# dmsetup remove $dmname
# losetup -d $cowdev
# losetup -d $imgdev
@JuniorJPDJ
Copy link

Wow, thanks!
Is there a way to resize new device to larger without changing backing RO one?

@coderjo
Copy link
Author

coderjo commented Jul 3, 2021

You could make a devmapper device with the linear target. You could probably actually append the linear target to this table after the snapshot target. Check out the manpage for dmsetup.

@JuniorJPDJ
Copy link

I did it like that:

# echo "0 $imgsz linear $imgdev 0"$'\n'"$imgsz 204800 zero" | dmsetup create big_xp
# echo "0 $((imgsz+204800)) snapshot /dev/mapper/big_xp $cowdev p 8" | dmsetup create big_xp_rw

man didn't help even a bit, but this gentoo wiki was helpful as hell: https://wiki.gentoo.org/wiki/Device-mapper#Create

@redwil
Copy link

redwil commented Oct 29, 2024

To make sure the loop device is RO can add although not necessary since dm should never write on the $imgdev when 'snapshot target:
blockdev --setro $imgdev

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment