]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
ceph-disk: multipath support for is_partition and list_partitions
authorLoic Dachary <ldachary@redhat.com>
Mon, 17 Aug 2015 21:25:45 +0000 (23:25 +0200)
committerLoic Dachary <ldachary@redhat.com>
Sat, 29 Aug 2015 00:37:51 +0000 (02:37 +0200)
The is_partition predicate and the list_partitions function support
devices managed by multipath.

A set of helpers dedicated to multipath devices is implemented because
the content of the corresponding /sys directory does not use the same
conventions as regular devices regarding partitions.

Instead of relying on subdirectories such as /sys/block/name/name1, the
devicemapper uuid file is used and expected to start with part\d+. The
holders/slaves directories provide pointers between the whole device and
the partition devices.

Although these structural differences reduce the opportunity for
code factorization, it is easier for backward compatibility since the
multipath specific logic is limited to if is_mpath(dev) branches.

http://tracker.ceph.com/issues/11881 Refs: #11881

Signed-off-by: Loic Dachary <ldachary@redhat.com>
src/ceph-disk

index 65fff4f724ea87ce929a11902e0c6422f2f10f5f..38755ac5ac21005fc886c91a95f4af670c678d32 100755 (executable)
@@ -474,6 +474,14 @@ def get_dev_size(dev, size='megabytes'):
         os.close(fd)
 
 
+def get_partition_mpath(dev, pnum):
+    part_re = "part{pnum}-mpath-".format(pnum=pnum)
+    partitions = list_partitions_mpath(dev, part_re)
+    if partitions:
+        return partitions[0]
+    else:
+        return None
+
 def get_partition_dev(dev, pnum):
     """
     get the device name for a partition
@@ -484,13 +492,16 @@ def get_partition_dev(dev, pnum):
        sda 1 -> sda1
        cciss/c0d1 1 -> cciss!c0d1p1
     """
-    name = get_dev_name(os.path.realpath(dev))
     partname = None
-    for f in os.listdir(os.path.join('/sys/block', name)):
-        if f.startswith(name) and f.endswith(str(pnum)):
-            # we want the shortest name that starts with the base name and ends with the partition number
-            if not partname or len(f) < len(partname):
-                partname = f
+    if is_mpath(dev):
+        partname = get_partition_mpath(dev, pnum)
+    else:
+        name = get_dev_name(os.path.realpath(dev))
+        for f in os.listdir(os.path.join('/sys/block', name)):
+            if f.startswith(name) and f.endswith(str(pnum)):
+                # we want the shortest name that starts with the base name and ends with the partition number
+                if not partname or len(f) < len(partname):
+                    partname = f
     if partname:
         return get_dev_path(partname)
     else:
@@ -503,21 +514,40 @@ def list_all_partitions():
     """
     dev_part_list = {}
     for name in os.listdir('/sys/block'):
+        LOG.debug("list_all_partitions: " + name)
         # /dev/fd0 may hang http://tracker.ceph.com/issues/6827
         if re.match(r'^fd\d$', name):
             continue
-        if not os.path.exists(os.path.join('/sys/block', name, 'device')):
-            continue
-        dev_part_list[name] = list_partitions(name)
+        dev_part_list[name] = list_partitions(os.path.join('/dev', name))
     return dev_part_list
 
+def list_partitions(dev):
+    dev = os.path.realpath(dev)
+    if is_mpath(dev):
+        return list_partitions_mpath(dev)
+    else:
+        return list_partitions_device(dev)
+
+def list_partitions_mpath(dev, part_re="part\d+-mpath-"):
+    p = block_path(dev)
+    partitions = []
+    holders = os.path.join(p, 'holders')
+    for holder in os.listdir(holders):
+        uuid_path = os.path.join(holders, holder, 'dm', 'uuid')
+        uuid = open(uuid_path, 'r').read()
+        LOG.debug("list_partitions_mpath: " + uuid_path + " uuid = " + uuid)
+        if re.match(part_re, uuid):
+            partitions.append(holder)
+    return partitions
+
 
-def list_partitions(basename):
+def list_partitions_device(dev):
     """
     Return a list of partitions on the given device name
     """
     partitions = []
-    for name in os.listdir(os.path.join('/sys/block', basename)):
+    basename = os.path.basename(dev)
+    for name in os.listdir(block_path(dev)):
         if name.startswith(basename):
             partitions.append(name)
     return partitions
@@ -540,10 +570,17 @@ def get_partition_base(dev):
             return '/dev/' + basename
     raise Error('no parent device for partition', dev)
 
+def is_partition_mpath(dev):
+    uuid = get_dm_uuid(dev)
+    return bool(re.match('part\d+-mpath-', uuid))
+
 def is_partition(dev):
     """
     Check whether a given device path is a partition or a full disk.
     """
+    if is_mpath(dev):
+        return is_partition_mpath(dev)
+
     dev = os.path.realpath(dev)
     if not stat.S_ISBLK(os.lstat(dev).st_mode):
         raise Error('not a block device', dev)
@@ -617,8 +654,7 @@ def verify_not_in_use(dev, check_partitions=False):
         raise Error('Device %s is in use by a device-mapper mapping (dm-crypt?)' % dev, ','.join(holders))
 
     if check_partitions and not is_partition(dev):
-        basename = get_dev_name(os.path.realpath(dev))
-        for partname in list_partitions(basename):
+        for partname in list_partitions(dev):
             partition = get_dev_path(partname)
             if is_mounted(partition):
                 raise Error('Device is mounted', partition)