[arch-projects] [devtools][PATCH 03/13] makechrootpkg: sync_chroot: Make more general.

Luke Shumaker lukeshu at parabola.nu
Fri May 5 22:41:00 UTC 2017


This is inspired by the thought that went in to the delete_chroot
is_subvolume commit.

sync_chroot($chrootdir, $copydir) copies `$chrootdir/root` to `$copydir`.
That seems a little silly; why do we care about "$chrootdir"?  Have it just
be sync_chroot(source, destination) like every other sync/copy command.

Where this becomes tricky is check to decide if we are going to use btrfs
subvolumes or not.  We don't care if "$source/.." is on btrfs; the root
could be a directly-mounted subvolume, but and the destination could be
another subvolume of the same btrfs mounted somewhere else.

The things we do care about are:

 - The source is a btrfs subvolume (so that we can snapshot it)
 - The source is on the same filesystem as the directory that the copy will
   be created in.
 - If the destination exists:
   * that it is not a mountpoint (so that we can delete and recreate it)
   * that it is a btrfs subvolume (so that we can quickly delete it)

On the last point, it isn't necessary for creating the new snapshot, just
for quick deletion.  That can be a separate check, where we use regular
`rm` for deleting the existing copy, but use subvolume snapshots for
creating the new one.
---
 lib/archroot.sh  |  8 ++++++++
 makechrootpkg.in | 32 +++++++++++++++++++-------------
 2 files changed, 27 insertions(+), 13 deletions(-)

diff --git a/lib/archroot.sh b/lib/archroot.sh
index 87c28a2..6b1b52e 100644
--- a/lib/archroot.sh
+++ b/lib/archroot.sh
@@ -34,6 +34,14 @@ is_subvolume() {
 }
 
 ##
+#  usage : is_same_fs( $path_a, $path_b )
+# return : whether $path_a and $path_b are on the same filesystem
+##
+is_same_fs() {
+	[[ "$(stat -c %d "$1")" == "$(stat -c %d "$1")" ]]
+}
+
+##
 #  usage : subvolume_delete_recursive( $path )
 #
 #    Find all btrfs subvolumes under and including $path and delete them.
diff --git a/makechrootpkg.in b/makechrootpkg.in
index d92d6ab..cc3c738 100644
--- a/makechrootpkg.in
+++ b/makechrootpkg.in
@@ -98,31 +98,37 @@ load_vars() {
 	return 0
 }
 
-# Usage: sync_chroot $chrootdir $copydir [$copy]
+# Usage: sync_chroot $rootdir $copydir [$copy]
 sync_chroot() {
-	local chrootdir=$1
+	local rootdir=$1
 	local copydir=$2
 	local copy=${3:-$2}
 
-	if [[ "$chrootdir/root" -ef "$copydir" ]]; then
+	if [[ "$rootdir" -ef "$copydir" ]]; then
 		error 'Cannot sync copy with itself: %s' "$copydir"
 		return 1
 	fi
 
 	# Get a read lock on the root chroot to make
 	# sure we don't clone a half-updated chroot
-	slock 8 "$chrootdir/root.lock" \
-		"Locking clean chroot [%s]" "$chrootdir/root"
-
-	stat_busy "Synchronizing chroot copy [%s] -> [%s]" "$chrootdir/root" "$copy"
-	if is_btrfs "$chrootdir" && ! mountpoint -q "$copydir"; then
-		subvolume_delete_recursive "$copydir" ||
-			die "Unable to delete subvolume %s" "$copydir"
-		btrfs subvolume snapshot "$chrootdir/root" "$copydir" >/dev/null ||
+	slock 8 "$rootdir.lock" \
+		"Locking clean chroot [%s]" "$rootdir"
+
+	stat_busy "Synchronizing chroot copy [%s] -> [%s]" "$rootdir" "$copy"
+	if is_subvolume "$rootdir" && is_same_fs "$rootdir" "$(dirname -- "$copydir")" && ! mountpoint -q "$copydir"; then
+		if is_subvolume "$copydir"; then
+			subvolume_delete_recursive "$copydir" ||
+				die "Unable to delete subvolume %s" "$copydir"
+		else
+			# avoid change of filesystem in case of an umount failure
+			rm --recursive --force --one-file-system "$copydir" ||
+				die "Unable to delete %s" "$copydir"
+		fi
+		btrfs subvolume snapshot "$rootdir" "$copydir" >/dev/null ||
 			die "Unable to create subvolume %s" "$copydir"
 	else
 		mkdir -p "$copydir"
-		rsync -a --delete -q -W -x "$chrootdir/root/" "$copydir"
+		rsync -a --delete -q -W -x "$rootdir/" "$copydir"
 	fi
 	stat_done
 
@@ -374,7 +380,7 @@ main() {
 	lock 9 "$copydir.lock" "Locking chroot copy [%s]" "$copy"
 
 	if [[ ! -d $copydir ]] || $clean_first; then
-		sync_chroot "$chrootdir" "$copydir" "$copy"
+		sync_chroot "$chrootdir/root" "$copydir" "$copy"
 	fi
 
 	$update_first && arch-nspawn "$copydir" \
-- 
2.12.2


More information about the arch-projects mailing list