Shink system image of Jetson Nano for smaller size SD card

Hi,

I’m trying to create a system image .

My current SD card for Jetson Nano is 64 GB. But I want to move my current system to 16 GB sd card.

I have tried to use dd command and gparted to resize the partition, and truncate the image.

However, the image after truncate is damaged. (I am sure I carefully left enough space when I truncate)

Is there a detail explanation on how to do this? Please list the steps in detail if possible, I’m not familiar with all of this.

Thanks

Shrinking partitions are hard, because you need to shrink the file system on the partition before you shrink the partition itself.

Did you run resize2fs on the root file system before you resized the partition?

Another option is to mount a card of the target size on another device, and transfer the contents of the root file system using something like

cd / && find . -depth -print -xdef | cpio o | (cd /mnt/newroot && cpio i)

emm, sorry, I dont quit follow, I tried follow the steps in https://softwarebakery.com//shrinking-images-on-linux which proved to be useful for PI. But somehow it does not work on Jetson Nano.

Everything is fine before I truncate the .img file I get from dd command.

The disk/partition layout on the Raspberry Pi is different from the disk/partition layout on the Nano.

I’m assuming that you know what a partition table is, what a partition is, and what a file system is. If not, you’ll probably enjoy googling those things!

You need to first shrink the amount of size used by the root file system on the root partition. Assuming you’re using the default NVIDIA SDCard image, then that looks something like:

# sudo resize2fs partition-name 14G

Note that partition-name is the name of your partition, not the full disk device (that you might have mounted using -o loop)

Then you need to resize the partition to be smaller, but still fit the data in the file system. This is best done interactively in gdisk, but can probably be done from the command line using sgdisk if you’re good with math in shell scripts.

Then you can re-resize the filesystem to exactly fill the partition again:

# sudo resize2fs partition-name

Unfortunately, you cannot shrink a file system while it’s mounted, so you can’t really do this in-place on a booted system.

Im so sorry, maybe I did not express myself clear…

I have a sd card that has 10GB used for the Jetson Nano, while 54 GB are unallocated. The ‘dd’ command will give me a .img file that has 64GB.

The resize2fs can reduce the partition size but does not seem to reduce the .img file size.

In fact, as I mentioned I use the gparted to resize the partition to make it like a 10GB used while 54 G are unallocated. The gparted itself calls the resize2fs to shrink the partition to smaller amount.(to th3 10G)

My problem is that right now the .img is 64 GB, it cannot flash the .img to a new sd card. But it should be able to flash it to a 16 GB sd card because im only using 10G for the system, the rest of 54GB in the .img file are unallocated.

OR am I mistaken your solution?

You can dd an individual partition. 64GB implies you used dd on the SD as a whole.

If you are working with a loopback image of a partition (not an SD card as a whole…dd can be used to extract an individual partition), then after you resize under loopback the extents are changed, but not the total amount of memory. If you were to then use “truncate” correctly to trim off the extra bytes of the partition file (make sure it is no longer loopback mounted), then the actual file size would be reduced as well as the logical extents. Or…you could just use dd to extract the reduced content from the old larger partition file into a new file. Truncate of original or dd extract from the reduced original have the same result, but truncate is destructive and if you fail you have to start over.

If you look at naming conventions, these are all devices as a whole:

/dev/<b>sdb</b>
/dev/<b>mmcblk1</b>

(in this case “sdb” is the second SATA drive, the first is “sda”; mmcblk1 is the second eMMC/SD, while “mmcblk0” is the first)

As a contrast, these are the first partitions of those same devices:

/dev/sdb<b>1</b>
/dev/mmcblk1<b>p1</b>

Thanks for the reply. I notice if I dd each partition, there wont be unallocated space.
However, if I dd individual partitions and cat them together, it will not become a boot-able image.

Is there any chance you can give me a step by step solution?

If you know what the final block of the main partition is, you can cut off at a certain limit.
if you know that /dev/mmcblk0p1 ends before the 16 GB mark (you can check this with gdisk,) you can create a 16 GB image by doing:

dd if=/dev/mmcblk0 of=my-image.img bs=1M count=16384

This will copy 16384 megabytes from the start of the disk, into the .img. Again, if there is no partition that lives anywhere after that limit, that will work fine.

Just a note to keep in mind: Every hard drive (especially solid state) has content of metadata about partitions in addition to actual partitions. When you copy a partition it can be put in place of another partition, but copy of an entire drive will be larger than the sum of the partitions…some space will be for metadata.

What @snarky is now showing is how to copy an entire disk, including metadata. Rearranging this could work for some cases, but odds go up any rearrangement you make would break something. Applications like dd understand binary data only and will gladly do whatever you want with your data, but if you break the the disk layout requirements, dd will neither be aware, nor care, that you are breaking something during a reorder.

Also, you need to make sure that the “partition end block” vaue of the last partition, actually ends before the cut-off size you give the new image. I forgot to explicitly re-emphasize that.

Sorry for the late reply! Thanks for your help.
I think im getting close to there…but still, not working.

The commands I use to export Jetson nano system image from a microSD card:

sudo dd if=/dev/sdb of=JetsonNano.img

After I use ‘fdisk -l’ to check the image:

Disk JetsonNano.img: 59.5 GiB, 63864569856 bytes, 124735488 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
Disklabel type: gpt
Disk identifier: xxxxxx-xxxxxx-xxxxx-xxxxxx

Device Start End Sectors Size Type
JetsonNano.img1 24576 72605695 72581120 34.6G Linux filesystem
JetsonNano.img2 2048 2303 256 128K Linux filesystem
JetsonNano.img3 4096 4991 896 448K Linux filesystem
JetsonNano.img4 6144 7295 1152 576K Linux filesystem
JetsonNano.img5 8192 8319 128 64K Linux filesystem
JetsonNano.img6 10240 10623 384 192K Linux filesystem
JetsonNano.img7 12288 13439 1152 576K Linux filesystem
JetsonNano.img8 14336 14463 128 64K Linux filesystem
JetsonNano.img9 16384 17663 1280 640K Linux filesystem
JetsonNano.img10 18432 19327 896 448K Linux filesystem
JetsonNano.img11 20480 20735 256 128K Linux filesystem
JetsonNano.img12 22528 22687 160 80K Linux filesystem[/code]

As you can see, I only use less than 36G, the rest are unallocated memory(my sd card is 64 GB).
but my image file ‘JetsonNano.img’ is actually 63.9G.
I suppose it ends in 72605695.

I used

dd if=JetsonNano.img of=new.img bs=1M count=38000

And I also tried

sudo truncate --size=$[(72605695+1)*512] JetsonNano.img

The generated .img files from both commands are not boot-able.
Did I do something wrong?

FYI, use “gdisk” instead of “fdisk”.

Haven’t done this lately, but if you were to take the full image, and cover it with loopback, then you should be able to use gparted to resize things via the loop device pretending to be a disk. Once things are cut down that way I would expect truncate to do the job, or dd. The disk is more than individual partitions, so you need to use applications aware of filesystem types and other disk metadata.

I would expect those truncated images to work. If you try to mount some partition on them with loopback, do you get an error? If so, what error?

Im not getting any error during all the process. I used gparted and loopback to resize the APP partition so that it only occupies 34.6G. Otherwise, it will be 64G in total.

Use

gdisk -l

on original system image:

GPT fdisk (gdisk) version 1.0.1

Partition table scan:
MBR: protective
BSD: not present
APM: not present
GPT: present

Found valid GPT with protective MBR; using GPT.
Disk JetsonNano23Aug.img: 124735488 sectors, 59.5 GiB
Logical sector size: 512 bytes
Disk identifier (GUID): xxxxxx-xxxx-xxxxxx-xxxxxxx
Partition table holds up to 128 entries
First usable sector is 34, last usable sector is 124735454
Partitions will be aligned on 2048-sector boundaries
Total free space is 52147613 sectors (24.9 GiB)

Number Start (sector) End (sector) Size Code Name
1 24576 72605695 34.6 GiB 8300 APP
2 2048 2303 128.0 KiB 8300 TBC
3 4096 4991 448.0 KiB 8300 RP1
4 6144 7295 576.0 KiB 8300 EBT
5 8192 8319 64.0 KiB 8300 WB0
6 10240 10623 192.0 KiB 8300 BPF
7 12288 13439 576.0 KiB 8300 TOS
8 14336 14463 64.0 KiB 8300 EKS
9 16384 17663 640.0 KiB 8300 LNX
10 18432 19327 448.0 KiB 8300 DTB
11 20480 20735 128.0 KiB 8300 RP4
12 22528 22687 80.0 KiB 8300 BMP

gdisk display after I truncate or dd the .img to smaller .img file:

GPT fdisk (gdisk) version 1.0.1

Warning! Disk size is smaller than the main header indicates! Loading
secondary header from the last sector of the disk! You should use ‘v’ to
verify disk integrity, and perhaps options on the experts’ menu to repair
the disk.
Caution: invalid backup GPT header, but valid main header; regenerating
backup header from main header.

Warning! Error 25 reading partition table for CRC check!
Warning! One or more CRCs don’t match. You should repair the disk!

Partition table scan:
MBR: protective
BSD: not present
APM: not present
GPT: damaged


Caution: Found protective or hybrid MBR and corrupt GPT. Using GPT, but disk
verification and recovery are STRONGLY recommended.


Disk new.img: 81920000 sectors, 39.1 GiB
Logical sector size: 512 bytes
Disk identifier (GUID): xxxxxxxx-xxxx-xxxx-xxxx-xxxxxx
Partition table holds up to 128 entries
First usable sector is 34, last usable sector is 124735454
Partitions will be aligned on 2048-sector boundaries
Total free space is 52147613 sectors (24.9 GiB)

Number Start (sector) End (sector) Size Code Name
1 24576 72605695 34.6 GiB 8300 APP
2 2048 2303 128.0 KiB 8300 TBC
3 4096 4991 448.0 KiB 8300 RP1
4 6144 7295 576.0 KiB 8300 EBT
5 8192 8319 64.0 KiB 8300 WB0
6 10240 10623 192.0 KiB 8300 BPF
7 12288 13439 576.0 KiB 8300 TOS
8 14336 14463 64.0 KiB 8300 EKS
9 16384 17663 640.0 KiB 8300 LNX
10 18432 19327 448.0 KiB 8300 DTB
11 20480 20735 128.0 KiB 8300 RP4
12 22528 22687 80.0 KiB 8300 BMP

There is a header issue here, it seems this is causing the problem?

Did you resize first with something like gparted first? I have not done this recently (nor with Nano), but in the past I’ve done this on other images. The trick was always to use a tool which is both GPT and ext4 aware prior to the truncate. The other “gotcha” is that sometimes truncation is off by one. Also, truncation should be in 512 byte chunks since this is the sector size from gdisk. There are other notes in there that partitions remain aligned in 2048 byte boundaries. If you fail to truncate 512 bytes at a time, then it might fail; if something you do moves a partition off of 2048 byte boundaries, then it is guaranteed it will fail.

If its still actual for someone, how to clone sd card to smaller size:
**Make a copy of jetson-sd card before using this commands. **
Check device names with ‘sudo dfisk -l’. Device names can be different on your system. This commands can wipe all data from sd cards. Be carefull.

  1. I used other linux machine with two sd card readers. 1 - jetsonsd card copy 128G(/dev/sda), 2 - target sd card 16G (/dev/sdb)

  2. sudo resize2fs PARTITIN_NAME TARGET_GIGS
    (i used ‘sudo resize2fs /dev/sda1 14G’) all root fs files must fit this size, check it before resize

  3. open gdisk and delete your root partitin and create smaller one to fit FS
    (i used ‘sudo gdisk’ set ‘/dev/sda’ removed ‘/dev/sda1’ created new partition to fit fs with size approx 30000000 blocks (14.3 G) and write changes on the disk. After this step my partiton is 14.3 G and its normally bootable.

  4. open gdisk on jetson card (i opened /dev/sda) and choose option ‘replicate partitin table on new device’ and choose target device ( i choosed /dev/sdb). Write to disk.

  5. at this point you can check with ‘sudo fdisk -l’ what /dev/sda and /dev/sdb have similar partiton tables

  6. now you can dd each partition from jetson-sd to target-sd
    (sudo dd if=/dev/sda1 of=/dev/sdb1)
    (sudo dd if=/dev/sda2 of=/dev/sdb2)
    (sudo dd if=/dev/sda3 of=/dev/sdb3)
    (sudo dd if=/dev/sdaX of=/dev/sdbX) 12 times in my case

and you have working copy of your jetson-sd-card on smaller size.
Hope it will help someone.