diff --git a/libblockdev.spec b/libblockdev.spec index 75fc84f..6704e9e 100644 --- a/libblockdev.spec +++ b/libblockdev.spec @@ -1,6 +1,6 @@ Name: libblockdev Version: 1.9 -Release: 6%{?dist} +Release: 7%{?dist} Summary: A library for low-level manipulation with block devices License: LGPLv2+ URL: https://github.com/rhinstaller/libblockdev @@ -14,6 +14,8 @@ Patch4: mdadm_examine_uuid.patch Patch5: mdadm_fw_raid_device.patch Patch6: obj_path_signatures.patch Patch7: parted_udev_issues.patch +Patch8: md_examine_migrated.patch +Patch9: part_rdwr_commit.patch BuildRequires: glib2-devel BuildRequires: gobject-introspection-devel @@ -392,6 +394,8 @@ A meta-package that pulls all the libblockdev plugins as dependencies. %patch5 -p1 %patch6 -p1 %patch7 -p1 +%patch8 -p1 +%patch9 -p1 %build %configure @@ -589,6 +593,11 @@ find %{buildroot} -type f -name "*.la" | xargs %{__rm} %files plugins-all %changelog +* Thu Oct 27 2016 Vratislav Podzimek - 1.9-7 +- Open the device file as RDWR when committing parts (vpodzime) +- Handle mdadm --examine output during migration (adamw) + Resolves: rhbz#1381996 + * Mon Oct 24 2016 Vratislav Podzimek - 1.9-6 - Prevent issues between libparted and udev (vpodzime) diff --git a/md_examine_migrated.patch b/md_examine_migrated.patch new file mode 100644 index 0000000..c58c034 --- /dev/null +++ b/md_examine_migrated.patch @@ -0,0 +1,160 @@ +From 673422da37ce9f96b44a182addd1aa922a9b047f Mon Sep 17 00:00:00 2001 +From: Adam Williamson +Date: Mon, 24 Oct 2016 14:41:47 -0700 +Subject: [PATCH] Handle mdadm --examine output during migration + +If a RAID set is undergoing any operation considered to be a +'migration' - which includes initialization of a new set at any +RAID level that includes redundancy - mdadm --examine will have +lines like this: + + RAID Level : 5 <-- 5 + Members : 3 <-- 3 + Map State : normal <-- uninitialized + +At present we don't understand this at all. This is a fairly +minimal fix which just has parse_mdadm_vars notice such lines, +split the 'value' on "<--", and stuff the first value (the one +being migrated *to*, which is usually what we care about, I +think) into the table. We could do something more elaborate +like store both values and make `get_examine_data_from_table` +understand that, but it's more complicated and this should be +all we truly need for now. + +(cherry picked from commit 07aec87385e2fdbe3f0855d697facf04b9ea6521) +Signed-off-by: Vratislav Podzimek +--- + src/plugins/mdraid.c | 13 +++++- + tests/md_test.py | 8 ++++ + tests/mdadm_fw_RAID_examine_migrate/mdadm | 69 +++++++++++++++++++++++++++++++ + 3 files changed, 88 insertions(+), 2 deletions(-) + create mode 100755 tests/mdadm_fw_RAID_examine_migrate/mdadm + +diff --git a/src/plugins/mdraid.c b/src/plugins/mdraid.c +index 9cb0cc7..c4780eb 100644 +--- a/src/plugins/mdraid.c ++++ b/src/plugins/mdraid.c +@@ -155,6 +155,7 @@ static GHashTable* parse_mdadm_vars (gchar *str, gchar *item_sep, gchar *key_val + gchar **items = NULL; + gchar **item_p = NULL; + gchar **key_val = NULL; ++ gchar **vals = NULL; + + table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); + *num_items = 0; +@@ -165,8 +166,16 @@ static GHashTable* parse_mdadm_vars (gchar *str, gchar *item_sep, gchar *key_val + if (g_strv_length (key_val) == 2) { + /* we only want to process valid lines (with the separator) */ + /* only use the first value for the given key */ +- if (!g_hash_table_contains (table, g_strstrip (key_val[0]))) +- g_hash_table_insert (table, g_strstrip (key_val[0]), g_strstrip (key_val[1])); ++ if (!g_hash_table_contains (table, g_strstrip (key_val[0]))) { ++ if (strstr (key_val[1], "<--")) { ++ /* mdadm --examine output for a set being migrated */ ++ vals = g_strsplit (key_val[1], "<--", 2); ++ g_hash_table_insert (table, g_strstrip (key_val[0]), g_strstrip (vals[0])); ++ g_free (vals[1]); ++ } else { ++ g_hash_table_insert (table, g_strstrip (key_val[0]), g_strstrip (key_val[1])); ++ } ++ } + (*num_items)++; + } else + /* invalid line, just free key_val */ +diff --git a/tests/md_test.py b/tests/md_test.py +index d7e007a..926d0c5 100644 +--- a/tests/md_test.py ++++ b/tests/md_test.py +@@ -415,6 +415,14 @@ class FakeMDADMutilTest(unittest.TestCase): + + self.assertIs(ex_data.metadata, None) + ++ def test_fw_raid_migrating(self): ++ """Verify that md_examine works when array is migrating ("foo <-- bar" values in output) """ ++ ++ with fake_utils("tests/mdadm_fw_RAID_examine_migrate"): ++ ex_data = BlockDev.md_examine("fake_dev") ++ ++ self.assertEqual(ex_data.chunk_size, 128 * 1024) ++ + + class MDUnloadTest(unittest.TestCase): + def setUp(self): +diff --git a/tests/mdadm_fw_RAID_examine_migrate/mdadm b/tests/mdadm_fw_RAID_examine_migrate/mdadm +new file mode 100755 +index 0000000..36ab0ca +--- /dev/null ++++ b/tests/mdadm_fw_RAID_examine_migrate/mdadm +@@ -0,0 +1,69 @@ ++#!/bin/bash ++ ++echo "$@"|grep -- "--brief" &>/dev/null ++is_brief=$? ++ ++echo "$@"|grep -- "--export" &>/dev/null ++is_export=$? ++ ++if [ $is_brief -eq 0 ]; then ++ cat < +Date: Wed, 26 Oct 2016 16:13:58 +0200 +Subject: [PATCH] Open the device file as RDWR when committing parts + +We block udev from generating events for the device while we are between +committing changes to disk and informing kernel about the changes. If we close +the file descriptor later, no udev changes are generated either unless we open +is as RDWR. Here's the difference: + +RDONLY: + # udevadm monitor + monitor will print the received events for: + UDEV - the event which udev sends out after rule processing + KERNEL - the kernel uevent + + KERNEL[68221.911864] change /devices/virtual/block/loop0 (block) + KERNEL[68221.913442] change /devices/virtual/block/loop0 (block) + KERNEL[68221.913794] add /devices/virtual/block/loop0/loop0p1 (block) + KERNEL[68221.915019] change /devices/virtual/block/loop0 (block) + KERNEL[68221.915217] change /devices/virtual/block/loop0/loop0p1 (block) + UDEV [68221.941293] change /devices/virtual/block/loop0 (block) + UDEV [68221.954214] change /devices/virtual/block/loop0/loop0p1 (block) + +RDWR: + # udevadm monitor + monitor will print the received events for: + UDEV - the event which udev sends out after rule processing + KERNEL - the kernel uevent + + KERNEL[68161.533114] change /devices/virtual/block/loop0 (block) + KERNEL[68161.533165] change /devices/virtual/block/loop0 (block) + UDEV [68161.533219] change /devices/virtual/block/loop0 (block) + KERNEL[68161.533262] add /devices/virtual/block/loop0/loop0p1 (block) + KERNEL[68161.533292] change /devices/virtual/block/loop0 (block) + KERNEL[68161.533326] change /devices/virtual/block/loop0/loop0p1 (block) + UDEV [68161.539255] add /devices/virtual/block/loop0/loop0p1 (block) + UDEV [68161.560215] change /devices/virtual/block/loop0 (block) + UDEV [68161.572345] change /devices/virtual/block/loop0/loop0p1 (block) + +As seen above, there's no 'add' udev event in case we open the device file as +RDONLY. + +(cherry picked from commit 44fdb3953eb05ff4f43a576f15d508928dca3eb7) +Signed-off-by: Vratislav Podzimek +--- + src/plugins/part.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/src/plugins/part.c b/src/plugins/part.c +index d5239e3..0f8e678 100644 +--- a/src/plugins/part.c ++++ b/src/plugins/part.c +@@ -157,7 +157,7 @@ static gboolean disk_commit (PedDisk *disk, gchar *path, GError **error) { + /* 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); ++ dev_fd = open (disk->dev->path, O_RDWR|O_CLOEXEC); + if (dev_fd >= 0) + /* if this fails, we can do no better anyway, so just ignore the return + value */ +@@ -167,6 +167,7 @@ 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 commit changes to device '%s'", path); ++ flock (dev_fd, LOCK_UN); + close (dev_fd); + return FALSE; + } +@@ -175,10 +176,12 @@ 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); ++ flock (dev_fd, LOCK_UN); + close (dev_fd); + return FALSE; + } + ++ flock (dev_fd, LOCK_UN); + close (dev_fd); + return TRUE; + } +-- +2.7.4 +