.. _usb_boot_jetson: ======================= 使用USB存储启动Jetson ======================= .. note:: 我现在尚未采购合适的USB外接存储,虽然可以使用普通的USB移动硬盘来提高Jetson的存储性能(SD卡的性能实在太差了)。但是,我依然推荐采用固态存储设备,例如SSD移动硬盘,不过,为了配合移动设备的高效小巧,我非常推荐采用 NVMe SSD 存储通过 M.2 转接 USB方式的U盘。 默认情况下,Jetston Nano和 :ref:`raspberry_pi` 一样,使用TF卡作为存储。但是由于SD/TF卡的读写性能很弱,使得系统性能无法充分发挥。所以,和 :ref:`usb_boot_ubuntu_pi_4` 相似,我也把Jetson Nano的操作系统迁移到移动硬盘上运行(通过USB 3.0接口)。 我的实践是采用USB移动HDD硬盘,虽然性能普通,但是比TF卡运行性能要好很多。 - 为了节约成本,我仅使用了非常普通的TF卡,所以读写性能极弱。 `Jetson Nano – Run From USB Drive `_ 在GitHub上开源了 `JetsonHacksNano / rootOnUSB `_ 的脚本,可以方便我们将NVIDIA的Jetson Nano启动rootfs修改成USB设备。 和 :ref:`usb_boot_ubuntu_pi_4` 有所不同,Jetson Nano没有提供从外接存储启动的设置,启动分为两步: - boot loader从所支持关键连接设备,也就是TF卡启动一个最小支持的内存镜像。这个步骤是通过 ``initrd`` (initial ramdisk) 实现,将一个临时文件系统加载到内存来启动Linux内核。这个步骤我们不做修改,所以我们通过USB存储启动Jetson依然需要TF卡,关键修改是第二步。 - 默认情况下,bootloader从TF卡加载好Linux内核以后,就会配置rootfs指向TF卡中的文件系统,这才是完整的文件系统,也就是我们平时使用操作系统最主要访问的文件系统,对运行性能影响极大。我们改造的就是这步,通过修改配置,将rootfs修改到USB外接磁盘设备上,通过外接磁盘设备来加速Linux文件系统性能。 需要注意的是,要在上述第二步中实现读写USB外接存储,不仅需要Linux内核内建USB驱动(默认已经build in),而且需要USB设备的firmware。很不幸,USB设备的firmware默认没有加载,所以就无法在启动过程中挂载尚未初始化的USB控制器的外接存储设备上的root文件系统。我们需要重新编译Linux内核来把关键的USB firmware编译到内核中。在 `Jetson Nano Developer Forum帖子解析了构建initramfs方法 `_ ,实现将USB firmware添加到initramfs的步骤。 rootOnUSB脚本 ================ JetsonHacks提供了 `JetsonHacksNano / rootOnUSB `_ 脚本方便完成整个迁移过程。通过以下方式获取:: git clone https://github.com/JetsonHacksNano/rootOnUSB cd rootOnUSB .. note:: 为了能够完整系统掌握这个迁移过程,我的实践操作是通过分析rootOnUSB脚本,通过独立的命令行操作来完成整个步骤。所以本文看上去比较繁琐,但是更容易理解原理。如果你只是需要完成操作,则可以直接执行脚本即可。 构建支持USB的initramfs ======================= .. note:: 这步可以通过脚本完成:: ./addUSBToInitramfs.sh - 创建一个名为 ``usb-firmware`` 脚本如下:: if [ "$1" = "prereqs" ]; then exit 0; fi . /usr/share/initramfs-tools/hook-functions copy_file firmware /lib/firmware/tegra21x_xusb_firmware 这里 ``/usr/share/initramfs-tools/hook-functions`` 是initramfs-tools的hook功能脚本,由操作系统提供。这个 ``usb-firmware`` 脚本复制到 ``/etc/initramfs-tools/hooks`` 目录下,然后通过 ``/usr/share/initramfs-tools/hook-functions`` 提供的脚本函数 ``copy_file`` 来复制firmware,再通过 ``mkinitramfs`` 来构建镜像。 - 执行命令:: cp usb-firmware /etc/initramfs-tools/hooks cd /etc/initramfs-tools/hooks mkinitramfs -o /boot/initrd-xusb.img 这里有3个报错:: Warning: couldn't identify filesystem type for fsck hook, ignoring. /sbin/ldconfig.real: Warning: ignoring configuration file that cannot be opened: /etc/ld.so.conf.d/aarch64-linux-gnu_EGL.conf: No such file or directory /sbin/ldconfig.real: Warning: ignoring configuration file that cannot be opened: /etc/ld.so.conf.d/aarch64-linux-gnu_GL.conf: No such file or directory 我检查了一下,实际上配置文件存在:: /etc/ld.so.conf.d/aarch64-linux-gnu_EGL.conf -> /etc/alternatives/aarch64-linux-gnu_egl_conf /etc/ld.so.conf.d/aarch64-linux-gnu_GL.conf -> /etc/alternatives/aarch64-linux-gnu_gl_conf 不过都是软链接,最终分别链接到:: /usr/lib/aarch64-linux-gnu/tegra-egl/ld.so.conf /usr/lib/aarch64-linux-gnu/tegra/ld.so.conf 所以通过以下命令先复制成实际文件,处理完以后再恢复之前的软链接:: unlink /etc/ld.so.conf.d/aarch64-linux-gnu_EGL.conf cp /usr/lib/aarch64-linux-gnu/tegra-egl/ld.so.conf /etc/ld.so.conf.d/aarch64-linux-gnu_EGL.conf unlink /etc/ld.so.conf.d/aarch64-linux-gnu_GL.conf cp /usr/lib/aarch64-linux-gnu/tegra/ld.so.conf /etc/ld.so.conf.d/aarch64-linux-gnu_GL.conf 上述 ``Warning: couldn't identify filesystem type for fsck hook`` 是因为 ``mkinitramfs`` 是通过 ``/etc/fstab`` 来检测文件系统的。 参考 `UPDATE-INITRAMFS FAILS TO INCLUDE FSCK IN INITRD `_ 我检查了 ``/etc/fstab`` 内容是:: /dev/root / ext4 defaults 0 1 实际上并没有设备 ``/dev/root`` ,Jetson Nano挂载根文件系统没有使用这个配置,通过 ``cat /proc/mounts`` 可以看到根挂载是:: /dev/mmcblk0p1 / ext4 rw,relatime,data=ordered 0 0 所以我暂时修改 ``/etc/fstab`` 如下:: /dev/mmcblk0p1 / ext4 defaults 0 1 再次执行就不再报错:: mkinitramfs -o /boot/initrd-xusb.img 完成以后,恢复 ``/etc/fstab`` 配置,然后执行以下命令恢复文件软链接:: rm -f /etc/ld.so.conf.d/aarch64-linux-gnu_EGL.conf ln -s /etc/alternatives/aarch64-linux-gnu_egl_conf /etc/ld.so.conf.d/aarch64-linux-gnu_EGL.conf rm -f /etc/ld.so.conf.d/aarch64-linux-gnu_GL.conf ln -s /etc/alternatives/aarch64-linux-gnu_gl_conf /etc/ld.so.conf.d/aarch64-linux-gnu_GL.conf USB移动硬盘准备 ================= - 格式化移动硬盘 USB移动硬盘需要建立一个 ``ext4`` 分区,用于存储rootfs。注意,该分区必须是ext4文件系统。我的移动磁盘在Linux下识别名字是 ``/dev/sda`` ,你的设备名字可能不同:: fdisk /dev/sda 我划分了 128G 给 ``/dev/sda1`` 用于操作系统:: Disk /dev/sda: 465.8 GiB, 500107862016 bytes, 976773168 sectors Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 4096 bytes I/O size (minimum/optimal): 4096 bytes / 33553920 bytes Disklabel type: dos Disk identifier: 0x5e878358 Device Boot Start End Sectors Size Id Type /dev/sda1 2048 268437503 268435456 128G 83 Linux Filesystem/RAID signature on partition 1 will be wiped. 创建ext4文件系统:: mkfs.ext4 /dev/sda1 复制Jetson操作系统 ====================== .. note:: 简单执行脚本:: ./copyRootToUSB.sh -p /dev/sda1 或者像我一样用命令行完成,见下文。 - 将移动硬盘连接到Jetson Nano上,然后执行命令:: sudo mount /dev/sda1 /mnt - 检查挂载:: sudo findmnt -rno TARGET /dev/sda1 可以看到输出信息:: /media/78961b21-c52a-4aa2-ac83-c5fc757f6666 /mnt - 同步数据:: sudo rsync -axHAWX --numeric-ids --info=progress2 --exclude=/proc / /mnt ``rsync`` 参数解析: - ``-a`` .. note:: 注意,由于Jetson Nano当前只有一个TF卡,所以首次插入移动硬盘识别为 ``/dev/sda`` 设备,所以上述命令我的目标磁盘分区是 ``/dev/sda1`` 修改启动配置 ============== Jetson Nano启动配置是 ``/boot/extlinux/extlinux.conf`` ,其中有一个入口就是指向 rootfs ,我们需要修改成移动硬盘:: cp /boot/extlinux/extlinux.conf /boot/extlinux/extlinux.conf.bak - 检查移动硬盘分区的UUID,这个UUID需要配置到启动配置中:: find /dev/disk/by-uuid -lname '*/'sda1 -printf %f 输出类似:: 78961b21-c52a-4aa2-ac83-c5fc757f6666 也可以通过 参考 ====== - `Jetson Nano – Run From USB Drive `_