diff --git a/content/onlide-disk-copy.rst b/content/onlide-disk-copy.rst new file mode 100644 index 0000000000000000000000000000000000000000..c0fc216047d0ab04775308c5c9308f7ad8e9a9d4 --- /dev/null +++ b/content/onlide-disk-copy.rst @@ -0,0 +1,65 @@ + +Copy a drive on a running machine +################################# +:date: 2024-06-08 +:summary: Copying to a new drive while the machine is running + +I was close to running out of disk space the homelab machine I use for running +services with personal data that I run in my home (I feel more comfortable +having physical control). I was too lazy to connect the machine to a monitor +and keyboard and rebooting from a thumbdrive so I tried to copy the old drive +to a new drive while the machine was running. Here's what I did: + +#. Stop running processes that have open files. For me it was stopping Docker + containers, some services (I have most services running in containers so I + have few services). + + .. code:: shell + + docker container ls | awk 'NR>1 {print $1}' | xargs docker stop + sudo systemctl stop fwupd.service systemd-timesyncd.service docker.service docker.socket containerd.service cron.service systemd-journald.service systemd-journald.socket systemd-journald-dev-log.socket + + +#. :code:`cd` to a directory on a different drive to avoid keeping the path + open :code:`cd /tmp`. Remount all partitions as read-only: :code:`sudo mount + --all -o remount,ro -t vfat,btrfs,ext4`. This may fail and you will see an + error with a path that couldn't be remounted due to open files. Run + :code:`lsof /path/that/has/open/files`, find the processes that still have + open files and either stop that service or kill the process (stopping the + service is better as it won't get restarted). Repeat until the partitions + are mounted read-only. Verify with the :code:`mount` command. Run + :code:`sudo sync` and now you should be able to copy the drive as there + won't writes to it while copying and the copy will be consistent. + +#. Start a session on the host using :code:`tmux` and copy + :code:`dd if=/dev/sda of=/dev/nvme0n1`. Now we wait. + +#. Once the copy is complete, run :code:`sudo sync` again and :code:`echo 1 | + sudo tee /sys/block/nvme0n1/device/rescan`. Now we need to resize the data + partition, `sudo parted /dev/nvme0n1 --script resizepart 3 100%` (in my case + the data partition was the 3rd partition after the EFI and root partitions). + Open the encrypted partition :code:`sudo cryptsetup open /dev/nvme0n1p3 + _dev_nvme0n1p2` and resize the encrypted partition :code:`sudo cryptsetup + resize _dev_nvme0n1p3`. Last resize is the filesystem in the encrypted + partition, we mount it :code:`sudo mount /dev/mapper/_dev_nvme0n1p3 /mnt` + and resize it :code:`sudo btrfs filesystem resize max /mnt`. Umount the data + partition :code:`sudo umount /mnt`. + +#. Let's reinstall the boot loader. + + .. code:: shell + + sudo mount /dev/nvme0n1p2 /mnt + sudo mount /dev/nvme0n1p1 /mnt/boot/efi + for dir in dev proc sys; do sudo mount --bind "/${dir}" "/mnt/${dir}"; done + sudo chroot /mnt + grub-install /dev/nvme0n1 + exit + for dir in dev proc sys; do sudo umount "/mnt/${dir}"; done + umount /mnt/boot/efi + umount /mnt + +#. Because we copied the existing partitions, their UUIDs will remain the same + so there's no need to update mounts. Stop the machine, remove the old drive + and boot. With a little luck the UEFI BIOS will not need configuration to + use the new drive and the machine will boot happily.