From: Phillip Susi <psusi@ubuntu.com>
Date: Fri, 19 Oct 2012 17:32:00 +0200
Subject: libparted: don't probe every dm device in probe_all
References: bsc#501773, bsc#1092327
Patch-mainline: v3.2
Git-commit: 3cb820632a13a91e0c2e579aedbe8e86b4f0040e

We were probing every dm device.  Only probe dmraid whole disk
(non-partition) devices instead.  This removes the clutter of
LVM logical volumes, and dmraid partitions from the list, which
usually do not make sense to partition.

* libparted/arch/linux.c (_is_dmraid_device): New function.
(_dm_is_part): Likewise.
(_probe_dm_devices): Use the latter.
* tests/t6003-dm-hide.sh: New test.
* tests/Makefile.am (TESTS): Add it.

Acked-by: Sebastian Parschauer <sparschauer@suse.de>
---
 libparted/arch/linux.c |   81 ++++++++++++++++++++++++++++++++++++++++++++++++-
 tests/Makefile.am      |    1 
 tests/t6003-dm-hide.sh |   60 ++++++++++++++++++++++++++++++++++++
 3 files changed, 141 insertions(+), 1 deletion(-)
 create mode 100644 tests/t6003-dm-hide.sh

--- a/libparted/arch/linux.c
+++ b/libparted/arch/linux.c
@@ -65,6 +65,8 @@
 # define _GL_ATTRIBUTE_FORMAT(spec) /* empty */
 #endif
 
+#define STRPREFIX(a, b) (strncmp (a, b, strlen (b)) == 0)
+
 #define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
 
 #ifndef __NR__llseek
@@ -478,6 +480,82 @@ bad:
         return r;
 }
 
+/* Return nonzero if device-mapper device, DEVPATH, is part of a dmraid
+   array.  Use the heuristic of checking for the string "DMRAID-" at the
+   start of its UUID.  */
+static int
+_is_dmraid_device (const char *devpath)
+{
+        int rc = 0;
+
+        char const *dm_name = strrchr (devpath, '/');
+        char const *dm_basename = dm_name && *(++dm_name) ? dm_name : devpath;
+        struct dm_task *task = dm_task_create (DM_DEVICE_DEPS);
+        if (!task)
+                return 0;
+
+        dm_task_set_name (task, dm_basename);
+        if (!dm_task_run (task))
+                goto err;
+
+        const char *dmraid_uuid = dm_task_get_uuid (task);
+        if (STRPREFIX (dmraid_uuid, "DMRAID-"))
+                rc = 1;
+
+err:
+        dm_task_destroy (task);
+        return rc;
+}
+
+/* We consider a dm device that is a linear mapping with a  *
+ * single target that also is a dm device to be a partition */
+
+static int
+_dm_is_part (const char *path)
+{
+        int rc = 0;
+        struct dm_task *task = dm_task_create (DM_DEVICE_DEPS);
+        if (!task)
+                return 0;
+
+        dm_task_set_name(task, path);
+        if (!dm_task_run(task))
+                goto err;
+
+        struct dm_info *info = alloca (sizeof *info);
+        memset(info, '\0', sizeof *info);
+        dm_task_get_info (task, info);
+        if (!info->exists)
+                goto err;
+
+        struct dm_deps *deps = dm_task_get_deps (task);
+        if (!deps)
+                goto err;
+
+        if (deps->count != 1)
+                goto err;
+        if (!_is_dm_major (major (deps->device[0])))
+                goto err;
+        dm_task_destroy (task);
+        if (!(task = dm_task_create (DM_DEVICE_TABLE)))
+                return 0;
+        dm_task_set_name (task, path);
+        if (!dm_task_run (task))
+                goto err;
+
+        char *target_type = NULL;
+        char *params = NULL;
+        uint64_t start, length;
+
+        dm_get_next_target (task, NULL, &start, &length, &target_type, &params);
+        if (strcmp (target_type, "linear"))
+                goto err;
+        rc = 1;
+
+err:
+        dm_task_destroy(task);
+        return rc;
+}
 
 static int
 _probe_dm_devices ()
@@ -504,7 +582,8 @@ _probe_dm_devices ()
                if (stat (buf, &st) != 0)
                        continue;
 
-               if (_is_dm_major(major(st.st_rdev)))
+               if (_is_dm_major(major(st.st_rdev)) && _is_dmraid_device (buf)
+                   && !_dm_is_part(buf))
                        _ped_device_probe (buf);
        }
        closedir (mapper_dir);
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -56,6 +56,7 @@ TESTS = \
   t6000-dm.sh \
   t6001-psep.sh \
   t6002-dm-busy.sh \
+  t6003-dm-hide.sh \
   t6100-mdraid-partitions.sh \
   t7000-scripting.sh \
   t8000-loop.sh \
--- /dev/null
+++ b/tests/t6003-dm-hide.sh
@@ -0,0 +1,60 @@
+#!/bin/sh
+# ensure that parted -l only shows dmraid device-mapper devices
+
+# Copyright (C) 2008-2012 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/init.sh"; path_prepend_ ../parted
+
+require_root_
+lvm_init_root_dir_
+
+test "x$ENABLE_DEVICE_MAPPER" = xyes \
+  || skip_ "no device-mapper support"
+
+# Device maps names - should be random to not conflict with existing ones on
+# the system
+linear_=plinear-$$
+
+d1=
+f1=
+dev=
+cleanup_fn_() {
+    dmsetup remove $linear_
+    test -n "$d1" && losetup -d "$d1"
+    rm -f "$f1"
+}
+
+f1=$(pwd)/1; d1=$(loop_setup_ "$f1") \
+  || fail=1
+
+# setup: create a mapping
+echo "0 2048 linear $d1 0" | dmsetup create $linear_ || fail=1
+dev="$DM_DEV_DIR/mapper/$linear_"
+
+# device should not show up
+
+parted -l >out 2>&1
+! grep $linear_ out || fail=1
+
+dmsetup remove $linear_
+echo "0 2048 linear $d1 0" | dmsetup create $linear_ -u "DMRAID-fake" || fail=1
+
+# device should now show up
+
+parted -l >out 2>&1
+grep $linear_ out || fail=1
+
+Exit $fail
