[PATCHv2,11/12] installer: Add code to proper unmount the BTRFS layout

Message ID 20240323105629.371511-11-stefan.schantl@ipfire.org
State Staged
Commit 2a98139628459d1d7f59951f30b8dc858a327691
Headers
Series [PATCHv2,01/12] btrfs-progs: New package |

Commit Message

Stefan Schantl March 23, 2024, 10:56 a.m. UTC
  Signed-off-by: Stefan Schantl <stefan.schantl@ipfire.org>
---
 src/installer/hw.c | 72 +++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 71 insertions(+), 1 deletion(-)
  

Patch

diff --git a/src/installer/hw.c b/src/installer/hw.c
index 5665cb955..3b26920d1 100644
--- a/src/installer/hw.c
+++ b/src/installer/hw.c
@@ -1123,13 +1123,83 @@  int hw_umount_filesystems(struct hw_destination* dest, const char* prefix) {
 		return -1;
 
 	// root
-	r = hw_umount(prefix, NULL);
+	if(dest->filesystem == HW_FS_BTRFS) {
+		r = hw_umount_btrfs_layout();
+	} else {
+		r = hw_umount(prefix, NULL);
+	}
+
 	if (r)
 		return -1;
 
 	return 0;
 }
 
+int hw_umount_btrfs_layout() {
+	const struct btrfs_subvolumes* subvolume = NULL;
+	char path[STRING_SIZE];
+	int counter = 0;
+	int retry = 1;
+	int r;
+
+	do {
+		// Reset the retry marker
+		retry = 0;
+
+		// Loop through the list of subvolumes
+		for (subvolume = btrfs_subvolumes; subvolume->name; subvolume++) {
+			// Abort if the subvolume path could not be assigned.
+			r = snprintf(path, sizeof(path), "%s%s", DESTINATION_MOUNT_PATH, subvolume->mount_path);
+
+			if (r < 0) {
+				return r;
+			}
+
+			// Try to umount the subvolume.
+			r = umount2(path, 0);
+
+			// Handle return codes.
+			if (r) {
+				switch(errno) {
+					case EBUSY:
+						// Set marker to retry the umount.
+						retry = 1;
+
+						// Ignore if the subvolume could not be unmounted yet,
+						// because it is still used.
+						continue;
+
+					case EINVAL:
+						// Ignore if the subvolume already has been unmounted
+						continue;
+					case ENOENT:
+						// Ignore if the directory does not longer exist.
+						continue;
+					default:
+						fprintf(flog, "Could not umount %s from %s - Error: %d\n", subvolume->name, path, r);
+						return r;
+				}
+			}
+
+			// Print log message
+			fprintf(flog, "Umounted %s from %s\n", subvolume->name, path);
+		}
+
+		// Abort loop if all mountpoins got umounted
+		if (retry == 0) {
+			return 0;
+		}
+
+		// Abort after five failed umount attempts
+		if (counter == 5) {
+			return -1;
+		}
+
+		// Increment counter.
+		counter++;
+	} while (1);
+}
+
 int hw_destroy_raid_superblocks(const struct hw_destination* dest, const char* output) {
 	char cmd[STRING_SIZE];