From 66ceb82b6d51707a74174dfb7a74b943ea571a43 Mon Sep 17 00:00:00 2001 From: Vratislav Podzimek 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 --- 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 #include #include +#include +#include #include #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