4

I have generated an image file with dd. The image contains two partitions.

I created a loop virtual disk: losetup -P /dev/loop0 $image_file. I mounted the two loop created partitions (loop0p1, loop0p2) to two mounting points.

My problem is the loop disk is too small for the files I want to add. I looked into the options of losetup, without avail.

Is there a way to increase the loop disk?

sugarman
  • 193
  • Yes, you have to increase the underlying image and re-create the loop device. – eblock Jun 29 '20 at 09:08
  • the image comes from a SD card. It has already full capacity. I would like to increase the size of the virtual loop device. I'm afraid this option is not available for losetup. With gparted/parted you can only shrink the loop partitions. The limitation comes from the static loop image mapping. – sugarman Jun 29 '20 at 09:15
  • Are you OK with only growing the last partition? What is the file system on both of them? – fra-san Jun 29 '20 at 11:55
  • Yes, thank you. The answer of Artem is good. I comment over there. – sugarman Jun 29 '20 at 15:15

2 Answers2

10

The usual warning: resizing file systems and partitions may cause data loss because of software bugs, faulty hardware, power loss, human errors. Make sure you always backup your data.

A loop device is a block device, logically analogous to a physical disk. As such, partition managers are not meant to directly resize it.

The couple of useful pieces you haven't found yet are losetup -c, to make the loop driver update the size of a block device when its backing file's size changes, and partprobe, to make the kernel update its internal representation of the partitions on a device. (Though you likely don't need to explicitly invoke the latter if you use a GUI partition manager such as GParted).

Let's set up a working example:

$ fallocate -l 100M volume
$ sudo parted <<'EOT'
select ./volume
mklabel msdos
mkpart primary ext4 1MiB 50M
mkpart primary ext4 50M 100%FREE
quit
EOT
$ sudo losetup -P /dev/loop0 volume
$ sudo mkfs.ext4 /dev/loop0p1
$ sudo mkfs.ext4 /dev/loop0p2
$ mkdir mp1 mp2
$ sudo mount /dev/loop0p1 mp1
$ sudo mount /dev/loop0p2 mp2

This gives:

$ lsblk /dev/loop0
NAME      MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
loop0       7:0    0  100M  0 loop
├─loop0p1 259:0    0   47M  0 part /path/to/mp1
└─loop0p2 259:1    0   52M  0 part /path/to/mp2
$ df -h /dev/loop0p*
Filesystem      Size  Used Avail Use% Mounted on
/dev/loop0p1     42M  1.1M   38M   3% /path/to/mp1
/dev/loop0p2     47M  1.1M   42M   3% /path/to/mp2

Then we can grow the file that backs our loop device and let losetup re-read the file's size to update the capacity of loop0:

$ fallocate -l 200M volume
$ sudo losetup -c /dev/loop0

Without unmounting the two partitions, we will only be able to grow them and the contained file systems by the amount of free space on their right (only /dev/loop0p2 can be extended in our case). Also, to be able to resize the file systems we need to make the kernel know about the changed partition table:

$ sudo parted <<'EOT'
select ./volume
resizepart 2 100%FREE
quit
EOT
$ sudo partprobe -s /dev/loop0
$ sudo resize2fs /dev/loop0p2

(Unmounting the two file systems will also allow you to shrink or move your partitions around. Note that, when shrinking a partition, the order of these steps is the other way round: first, resize the file system, then resize the partition (and tell the kernel about the changes if needed), then reduce the size of the backing file).

Finally obtaining:

$ lsblk /dev/loop0
NAME      MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
loop0       7:0    0  200M  0 loop
├─loop0p1 259:0    0   47M  0 part /path/to/mp1
└─loop0p2 259:1    0  152M  0 part /path/to/mp2
$ df -h /dev/loop0p*
Filesystem      Size  Used Avail Use% Mounted on
/dev/loop0p1     42M  1.1M   38M   3% /path/to/mp1
/dev/loop0p2    144M  1.6M  135M   2% /path/to/mp2
fra-san
  • 10,205
  • 2
  • 22
  • 43
  • thank you a lot for your post :-) I have a problem upstream, I want to shrink the image file first from 8GB down to 5GB. I posted another question here for clarity https://unix.stackexchange.com/questions/595921/how-to-shrink-a-file-image-produced-with-dd – sugarman Jun 30 '20 at 16:27
  • If underlying filesystem does not support fallocate syscall switch to POSIX using -x. Also to grow a file you can use -o – Antonio Bardazzi Jan 16 '22 at 11:06
2

You cannot do that: the way the loopback device in the Linux kernel works it uses the image file size to operate on it and it won't write beyond it.

The only way to achieve what you want is to umount the image, increase its size/repartition it, run resize2fs or whatever FS you're using to resize partitions and then mount it back.

  • The image is a blob file. Is it possible to resize it? Could you give more details please? – sugarman Jun 29 '20 at 09:30
  • https://unix.stackexchange.com/questions/196715/how-to-pad-a-file-to-a-desired-size and the you'll need to enlarge the second partition and resize it. I'd just recommend starting from scratch because it's all technical. – Artem S. Tashkinov Jun 29 '20 at 09:32
  • thank you, it is the right answer. I padded the image file with zeros, but not just the last byte using seek. The only method which actually works in my case (two partitions, 1 FAT32, 1 ext4) is padding zeros all over to the specified end: dd if=/dev/zero bs=4M count=xxx >> largerfile.txt - the "hole method" scrambles the inner partitions. After mounting the bigger image on loop device, the size of the device is increased accordingly. Then, as Artem wrote, I only had to resize the second partition, et voilà. – sugarman Jun 29 '20 at 15:24