Blob Blame History Raw
From 66ceb82b6d51707a74174dfb7a74b943ea571a43 Mon Sep 17 00:00:00 2001
From: Vratislav Podzimek <vpodzime@redhat.com>
Date: Thu, 20 Oct 2016 15:43:23 +0200
Subject: [PATCH] Prevent issues between libparted and udev

libparted does committing of a new partition table to disk in two steps:

1. committing (writing and flushing) to disk and
2. telling OS about the partitions.

However, that means that if things go wrong, udev may step in between the above
steps and trigger events when the block device file is closed (from being opened
RW) that could lead to a failure of the second step because some other process
may open the block device file in the reaction to the event.

In order to prevent such issues we need to acquire an exclusive lock on the
block device file, which prevents udev from triggering events, for the time we
let libparted perform the two operations above.

(cherry picked from commit 0a65466154994759cbec15ce984b751b073a891f)
Signed-off-by: Vratislav Podzimek <vpodzime@redhat.com>
---
 src/plugins/part.c | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/src/plugins/part.c b/src/plugins/part.c
index 4634ef8..d5239e3 100644
--- a/src/plugins/part.c
+++ b/src/plugins/part.c
@@ -23,6 +23,8 @@
 #include <stdlib.h>
 #include <math.h>
 #include <inttypes.h>
+#include <unistd.h>
+#include <sys/file.h>
 #include <utils.h>
 
 #include "part.h"
@@ -150,11 +152,22 @@ static const gchar *table_type_str[BD_PART_TABLE_UNDEF] = {"msdos", "gpt"};
 
 static gboolean disk_commit (PedDisk *disk, gchar *path, GError **error) {
     gint ret = 0;
+    gint dev_fd = 0;
+
+    /* XXX: try to grab an exclusive lock for the device so that udev doesn't
+       trigger events for it in between the two operations we need to perform
+       (see below) */
+    dev_fd = open (disk->dev->path, O_RDONLY|O_CLOEXEC);
+    if (dev_fd >= 0)
+        /* if this fails, we can do no better anyway, so just ignore the return
+           value */
+        flock (dev_fd, LOCK_EX);
 
     ret = ped_disk_commit_to_dev (disk);
     if (ret == 0) {
         set_parted_error (error, BD_PART_ERROR_FAIL);
         g_prefix_error (error, "Failed to commit changes to device '%s'", path);
+        close (dev_fd);
         return FALSE;
     }
 
@@ -162,9 +175,11 @@ static gboolean disk_commit (PedDisk *disk, gchar *path, GError **error) {
     if (ret == 0) {
         set_parted_error (error, BD_PART_ERROR_FAIL);
         g_prefix_error (error, "Failed to inform OS about changes on the '%s' device", path);
+        close (dev_fd);
         return FALSE;
     }
 
+    close (dev_fd);
     return TRUE;
 }
 
-- 
2.7.4