整件事情是这样的:某一天我尝试在树莓派上安装一个 vim 的编辑器插件 YouCompleteMe,需要从源码编译。编译这个比较耗费内存,可能我分配的 SWAP 不够大(1024MB),导致内存不足,然后 sshd 就挂了。嗯,并且已经过去了一个小时我也没法连接上去。于是我就拔电源重启了,这下可好,SD 卡彻底启动不了了,估计是文件系统损坏之类的。上网搜了一下这种现象似乎非常常见,只要在断电时 SD 卡还在写入就可能出现。于是我就想到要把系统装在外置硬盘上。
首先硬件配置是这样的:我手上有 8GB 和 16GB 的 C10 SD 卡各一张,500GB 的移动硬盘一个(之前笔记本的机械硬盘,换 SSD 的时候拆下来装在移动硬盘盒里),有源 USB Hub 一个,树莓派一个。其中移动硬盘上有两个 NTFS 分区(Windows 的 C盘和 D盘)和一个 ext4 分区(很久以前的 Ubuntu 系统,所有数据都在里面)。
我想实现的效果是这样的:清空旧的 Windows C盘(90GB),分出 30GB 给 Raspbian,然后树莓派要从硬盘启动。
简单搜索了一下发现直接从硬盘启动是不行的,因为树莓派启动的时候固定是从 SD 卡的第一个分区(/boot)读取
config.txt
、cmdline.txt
和 kernel.img
这三个文件。但是除此之外,各个外接设备的挂载点则是没有限制的。于是我们可以将 /boot
分区放在 SD 卡上,并设置为只读的,避免意外关机时损坏上面的文件系统;同时我们把系统的其他部分都放在外置硬盘上,通过 USB 连接到树莓派,这部分是可读写的。# 首先将 SD 卡插入适配器,连接到 Mac
# 打开终端
# 在列出的磁盘中找到你的 SD 卡设备,例如 /dev/disk4
diskutil list
# unmount
diskutil unmountDisk /dev/disk4 # 这里替换成你的 SD 卡设备
# 找到你下载的镜像(解压的 .img 文件),写入到你的 SD 卡设备
sudo dd bs=1m if=image.img of=/dev/rdisk4 # 这里注意是 rdisk
# 写入完成后从 Finder 里弹出 SD 卡就好了
然后按照正常方式进行第一次启动,也可以做一些简单设置的调整。我是接了键盘和显示器启动的,进去后首先打开
raspi-config
把图形界面关掉了,然后打开了摄像头、I2C 和 SPI 设备,然后我就重启了。接下来我都是通过 ssh 进行的操作。
通过 USB 连接移动硬盘。
sudo fdisk -l
看一下是哪个设备,一般都是 /dev/sda
之类的。
如果有不想要的分区需要删掉腾出空间的话,
sudo fdisk /dev/sda
打开 fdisk 工具,把不要的分区删掉,新建一个 30GB 分区。具体怎么操作,交互模式下有帮助,注意不要删掉了想保留的分区即可。在你输入 w
命令执行写入之前,所有改动都是在内存中的,你觉得有问题的话,Ctrl-C
退出重来就好。
创建好分区之后格式化成 ext4:
sudo mkfs.ext4 /dev/sda1
。
运行
sudo gdisk /dev/sda
进入 gdisk 工具的交互模式。在这里检视一下你想用于 Raspbian 的分区,获取到 UUID。以下例子来自 Stefan's Blogroot@raspberrypi:/home/pi# gdisk /dev/sda
GPT fdisk (gdisk) version 0.8.5
Partition table scan:
MBR: hybrid
BSD: not present
APM: not present
GPT: present
Found valid GPT with hybrid MBR; using GPT.
Command (? for help): i
Partition number (1-3): 2
Partition GUID code: 0FC63DAF-8483-4772-8E79-3D69D8477DE4 (Linux filesystem)
Partition unique GUID: 176ADF0D-357D-4C4B-ADC0-371342F444AB
First sector: 2099200 (at 1.0 GiB)
Last sector: 23070719 (at 11.0 GiB)
Partition size: 20971520 sectors (10.0 GiB)
Attribute flags: 0000000000000000
Partition name: ''
Command (? for help): q
UUID 是跟在 “Partition unique GUID” 后面那串字母,在这个例子中也就是
176ADF0D-357D-4C4B-ADC0-371342F444AB
。
接下来编辑
/boot/cmdline.txt
,将其中 root=/dev/mmcblk0p2
改为 root=PARTUUID=分区的UUID
然后保存。
随后,编辑
/etc/fstab
将 /boot
挂载为只读模式,将移动硬盘也添加进去,挂载为可读写。默认的内容是这样的:proc /proc proc defaults 0 0
/dev/mmcblk0p1 /boot vfat defaults 0 2
/dev/mmcblk0p2 / ext4 defaults,noatime 0 1
# a swapfile is not a swap partition, no line here
# use dphys-swapfile swap[on|off] for that
更改之后内容大概像这样:
proc /proc proc defaults 0 0
/dev/mmcblk0p1 /boot vfat ro 0 2
/dev/sda1 / ext4 defaults,errors=remount-ro 0 1
#/dev/mmcblk0p2 / ext4 defaults,noatime 0 1
# a swapfile is not a swap partition, no line here
# use dphys-swapfile swap[on|off] for that
最后,将
/
下的内容全部写入到移动硬盘中。以我自己的配置为例,使用 /dev/sda1
分区:dd if=/dev/mmcblk0p2 of=/dev/sda1
因为 Raspbian 默认是将 SD 卡的第二个分区(也就是
/dev/mmcblk0p2
)挂载到 /
的,所以我们直接从这个分区读取,写入到目标分区就可以。
写入完成之后,
/dev/sda1
的大小与 /dev/mmcblk0p2
是完全一致的,会远远小于你创建这个分区时指定的大小。可以使用 sudo resize2fs /dev/sda1
来展开到完整的大小。
接下来重启就好了。
在过程中如果不慎修改错了参数,或者将不正确的分区挂载为只读了,不必惊慌,也不需要马上重装系统。只要将树莓派断电,SD 卡拔出来连接到别的电脑上,修改
/boot/cmdline.txt
里的参数,改为默认的挂载 SD 卡第二分区即可。重启后可以通过 sudo mount -o remount,rw /dev/sda1
将 /etc/fstab
中指定的分区重新挂载为可读写模式来进行修改。