What do to when a recovery hard disk image is larger than new disk?

1 post / 0 new
What do to when a recovery hard disk image is larger than new disk?

Skip to end of metadata
Go to start of metadata

I just encountered an awaited failure on a Raspberry Pi SD-Card. That "disk" went to an unrepairable state.

Please note that while this is now a Raspberry, the issue and the solution goes with any Linux disk image created with dd or similar tool.

Recovery

I have backup image files for all my Raspberrys and important servers. And because those go  obsolete and out of date pretty soon, I also have daily backups using Bacula Network Backup. So, no worries.

Writing the image to a new SD-Card

I have the backup image in file sd-20151025.img and the real SD-Card as device /dev/sdc.

First, we want to see the contents of the SD-card image:

# fdisk -l sd-20151025.img
Disk sd-20151025.img: 7969 MB, 7969177600 bytes, 15564800 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk label type: dos
Disk identifier: 0x000c7b31
          Device Boot      Start         End      Blocks   Id  System
sd-20151025.img1            8192      122879       57344    c  W95 FAT32 (LBA)
sd-20151025.img2          122880    15564799     7720960   83  Linux

Next, get the size of the real SD-Card:

# lsblk -bdno size -- /dev/sdc
7948206080


So, the image is 7969177600 bytes, and the new SD Card is smaller: only 7948206080 bytes could be written to it. The resulting file system for partition 2 would be unmountable.

We need to shrink the filesystem, which is possible as that is in ext4 format.

Shrinking the partition 2

Ext4 filesystem can be resized by using Linux utility resize2fs. In order to access the partition we must first establish an interface to it, so resize2fs can do its job.

# losetup --offset $((122880 * 512)) /dev/loop0 sd-20151025.img

We give offset of starting sector 122880 (in the above picture) as bytes, and setup /dev/loop0 as the new device for it.

The current size of the partition is 7720960 blocks.

The new size for the partition will be  7680000, which we can see by issuing:

# echo $(( 7720960 - ((7969177600 - 7948206080) / 512) ))

e2fsck must be run before we do the shrink.

# e2fsck -f /dev/loop0
e2fsck 1.42.9 (28-Dec-2013)
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/loop0: 128382/483328 files (0.3% non-contiguous), 735380/1930240 blocks

The shrink!

# resize2fs /dev/loop0 $(( 7680000 / 4 ))
resize2fs 1.42.9 (28-Dec-2013)
Resizing the filesystem on /dev/loop0 to 1920000 (4k) blocks.
The filesystem on /dev/loop0 is now 1920000 blocks long.

Truncate the end of the image file

# truncate -s 7948206080 sd-20151025.img

Fix the wrong partition size with fdisk


The partition table on the  SD-Card still has wrong partition size for the partition 2. We use fdisk to correct that. We will delete the partition using it, and create new, smaller, using the same start sector. Fdisk is just an editor for partition table and nothing more. The partition contents, the file system, will stay intact in this operation.

# fdisk sd-20151025.img
Welcome to fdisk (util-linux 2.23.2).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.
Command (m for help): p
Disk sd-20151025.img: 7948 MB, 7948206080 bytes, 15523840 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk label type: dos
Disk identifier: 0x000c7b31
          Device Boot      Start         End      Blocks   Id  System
sd-20151025.img1            8192      122879       57344    c  W95 FAT32 (LBA)
sd-20151025.img2          122880    15564799     7720960   83  Linux
Command (m for help): d
Partition number (1,2, default 2): 2
Partition 2 is deleted
Command (m for help): p
Disk sd-20151025.img: 7948 MB, 7948206080 bytes, 15523840 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk label type: dos
Disk identifier: 0x000c7b31
          Device Boot      Start         End      Blocks   Id  System
sd-20151025.img1            8192      122879       57344    c  W95 FAT32 (LBA)
Command (m for help): n
Partition type:
  p   primary (1 primary, 0 extended, 3 free)
  e   extended
Select (default p): p
Partition number (2-4, default 2): 
First sector (2048-15523839, default 2048): 122880
Last sector, +sectors or +size{K,M,G} (122880-15523839, default 15523839):
Using default value 15523839
Partition 2 of type Linux and of size 7.4 GiB is set
Command (m for help): p
Disk sd-20151025.img: 7948 MB, 7948206080 bytes, 15523840 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk label type: dos
Disk identifier: 0x000c7b31
          Device Boot      Start         End      Blocks   Id  System
sd-20151025.img1            8192      122879       57344    c  W95 FAT32 (LBA)
sd-20151025.img2          122880    15523839     7700480   83  Linux
Command (m for help): w

 NB! It is important to note that the first sector for out new (recreated) partition is 122880! fdisk suggest by default the first sector of the device.


Finally: We get to write the image to new SD-Card

# dd if=sd-20151025.img of=/dev/sdc bs=4M
1895+0 records in
1895+0 records out
7948206080 bytes (7.9 GB) copied, 778.866 s, 10.2 MB/s