RHEL Engineering is moving the tracking of its product development work on RHEL 6 through RHEL 9 to Red Hat Jira (issues.redhat.com). If you're a Red Hat customer, please continue to file support cases via the Red Hat customer portal. If you're not, please head to the "RHEL project" in Red Hat Jira and file new tickets here. Individual Bugzilla bugs in the statuses "NEW", "ASSIGNED", and "POST" are being migrated throughout September 2023. Bugs of Red Hat partners with an assigned Engineering Partner Manager (EPM) are migrated in late September as per pre-agreed dates. Bugs against components "kernel", "kernel-rt", and "kpatch" are only migrated if still in "NEW" or "ASSIGNED". If you cannot log in to RH Jira, please consult article #7032570. That failing, please send an e-mail to the RH Jira admins at rh-issues@redhat.com to troubleshoot your issue as a user management inquiry. The email creates a ServiceNow ticket with Red Hat. Individual Bugzilla bugs that are migrated will be moved to status "CLOSED", resolution "MIGRATED", and set with "MigratedToJIRA" in "Keywords". The link to the successor Jira issue will be found under "Links", have a little "two-footprint" icon next to it, and direct you to the "RHEL project" in Red Hat Jira (issue links are of type "https://issues.redhat.com/browse/RHEL-XXXX", where "X" is a digit). This same link will be available in a blue banner at the top of the page informing you that that bug has been migrated.
Bug 1322110 - format of DM_UUID underdocumented (grammar possibly ambiguous)
Summary: format of DM_UUID underdocumented (grammar possibly ambiguous)
Keywords:
Status: CLOSED NOTABUG
Alias: None
Product: Red Hat Enterprise Linux 7
Classification: Red Hat
Component: doc-Logical_Volume_Manager
Version: 7.2
Hardware: Unspecified
OS: Unspecified
unspecified
unspecified
Target Milestone: rc
: ---
Assignee: Steven J. Levine
QA Contact: ecs-bugs
URL:
Whiteboard:
Depends On:
Blocks:
TreeView+ depends on / blocked
 
Reported: 2016-03-29 20:15 UTC by mulhern
Modified: 2019-03-06 01:07 UTC (History)
10 users (show)

Fixed In Version:
Doc Type: Bug Fix
Doc Text:
Clone Of:
Environment:
Last Closed: 2016-03-31 16:53:42 UTC
Target Upstream Version:
Embargoed:


Attachments (Terms of Use)

Description mulhern 2016-03-29 20:15:49 UTC
Description of problem:

This is one of those values in udev that once generated needs to be parsed, and it is surprisingly hard to parse. AFAICT, the grammar is something like:

DM_UUID => [PARTITION] "-" SUBSYSTEM "-" UUID "-" [LAYER]
PARTITION => "part" [PARTITONID]
PARTITIONID => some string of characters, no "-", I hope?
SUBSYSTEM => "LVM" | "mpath" | ...  ?
UUID => some string of characters, may include "-", unfortunately
LAYER => any of the following keywords, {cdata, cmeta, pool, real, tdata, tmeta), I hope

Note that I particularly hope that LAYER expands to a set of keyword that is quite fixed, because otherwise it's not clear where the UUID ends and the optional LAYER begins.

Version-Release number of selected component (if applicable):

Installed Packages
Name        : lvm2
Arch        : x86_64
Epoch       : 7
Version     : 2.02.130
Release     : 5.el7
Size        : 2.1 M
Repo        : installed
From repo   : RHEL-7-RTT

How reproducible:

Quite.

Steps to Reproduce:
1. I have a package for parsing udev denizens called parseudev.
2. I notice that it sometimes fails to parse DM_UUIDs properly, I test it on an existing system pretty regularly.
3. So I try to fix it, by a combination of reading the lvm2 source code, observing actual DM_UUID values, and reading the docs.
4. But ultimately, I have little confidence that the code that I have settled on is even correct, much less robust.

Actual results:

Can not figure out a certainly robust and precise way to parse DM_UUID value.

Expected/desired results:

A certainly unambiguous grammar for DM_UUID, documented.

Additional info:

It is always possible that I misread the lvm/dm source and that I am more uncertain about the DM_UUID grammar than I would have been had I read it correctly. But, that there should be better more accessible documentation should hold, regardless of any confusion I may have experienced.

An example of a DM_UUID, no layer, but '-' in UUID part
(I am sure that WCC4JPFAUX6A is not layer information, but for a parser it is
not so easy).
DM_UUID=part1-mpath-WDC_WD10EFRX-68PJCN0_WD-WCC4JPFAUX6A

Comment 2 Zdenek Kabelac 2016-03-29 20:41:07 UTC
There is definitely NO grammar for  DM-UUID - except its it's just  128bytes +'\0' string and should be unique.

There are certain  undocumented  INTERNAL rules in lvm2 for  UUID generation - but lvm2 is FREE to change them any time it needs to.

The rule for lvm2 user accessible devices is:

LVM-VGuuidLVuuid

Every other lvm2 device uuid is  lvm2  PRIVATE uuid which noone else should evere try to understand.

Generic plan we aim for to simplify  'blkid' detection of lvm2 private device is to always add some -suffix  -  once there is -suffix  noone else is supposed to read such device.

So whoever gets an idea to detect  i.e. raid/thin-pool images is doing just useless work.

Just wondering  where you get the idea to write grammar for it??
Is that some new  project ??

Comment 3 Alasdair Kergon 2016-03-29 20:50:09 UTC
What information is missing from the udev database that is leading to this attempt to parse the private content of the uuid?

If people can identify the missing information and explain why it's needed, then we can try to update the standard udev rules for the component that owns the private part of the uuid in question to provide this extra information directly in the database.

Comment 4 Alasdair Kergon 2016-03-29 20:57:58 UTC
As far as grammar is concerned, each component that uses dm devices is encouraged to register a unique prefix, such as "LVM-" and then the recommended format is that prefix followed by a private part under the complete specification and control of the component itself.  This is not fixed, has changed already, and will change further over time, so don't try to write any code that depends on this please - use the supported interfaces instead.

Comment 5 RHEL Program Management 2016-03-29 21:05:40 UTC
Development Management has reviewed and declined this request.
You may appeal this decision by reopening this request.

Comment 6 Alasdair Kergon 2016-03-29 21:07:27 UTC
Your example:

DM_UUID=part1-mpath-WDC_WD10EFRX-68PJCN0_WD-WCC4JPFAUX6A

part1- is a prefix owned by kpartx.
So this means you ask kpartx to interpret the rest of the uuid.

You'll find that kpartx gives you the answer that you should treat the rest as a standalone uuid in its own right.

So you then see the mpath prefix.
Strip it off and ask multipath to interpret it.  It'll say it's the private uuid it's chosen to use to refer to the underlying device.

Comment 7 Alasdair Kergon 2016-03-29 21:11:04 UTC
None of this is for end users.

Developers see libdevmapper.h:

 * Configure default UUID prefix string.
 * Conventionally this is a short capitalised prefix indicating the subsystem
 * that is managing the devices, e.g. "LVM-" or "MPATH-".
 * To support stacks of devices from different subsystems, recursive functions
 * stop recursing if they reach a device with a different prefix.

Comment 8 mulhern 2016-03-30 15:00:08 UTC
Thanks for the comments. I'm seeking further clarification.

Aside: The comment from libdevmapper.h is slightly misleading,
"mpath" is actually _not_ capitalized :)
DM_UUID=mpath-WDC_WD10EFRX-68PJCN0_WD-WCC4J5VFRFV3

Comment #2: I'm not familiar with every storage/udev related utility or library. But I know that at least blivet and lsblk parse out DM_UUID (or dm/uuid) as the case may be. In both cases, they are looking for a subsystem value, e.g., "LVM", "mpath". blivet seems to be looking for the last or primary subsystem value, lsblk for the first. My own enthusiasm for parsing values in udev is a good deal less than 0. However, sometimes it seems there is no other option, and I'ld rather be doing this parsing separately from the application or library that needs this information. Hence a separate and privately used library that I run separate tests on. Library is probably too grand a word for what it is, but test _is_ a good description of what I do with it.

Comment #3: In the cases that I have seen, it seems to be _some_ device-mapper subsystem which is being extracted from the DM_UUID value. Evidently that is not available any other way, or at least that's what the developers of blivet and lsblk think.

AFAICT, from comments #4 and following, the grammar is really something like:
DM_UUID -> G
G -> SUBSYSTEM_STR | SUBSYSTEM_STR "-" G
SUBSYSTEM_STR -> SUBSYSTEM_PREFIX "-" SUBSYSTEM_SPECIFIC_STR
SUBSYSTEM_PREFIX -> "part" PARTITIONID | "LVM" | "mpath" | ...
SUBSYSTEM_SPECIFIC_STR -> <just about anything>

I _think_ that it is this SUBSYSTEM_SPECIFIC_STR which is considered to be private in the above comments.

This grammar is unambiguous and context-free only if SUBSYSTEM_PREFIX can be unambiguously identified.
That would be possible if the SUBSYSTEM_PREFIX production could not intersect with the SUBSYSTEM_STR production. e.g., if all the prefixes were known and unused in SUBSYSTEM_SPECIFIC_STR.

If my understanding of the grammar is correct, then the way blivet at least does the parsing is wrong according to the grammar, but "works" because kpartx, which uses the "part..." prefix, currently has a value for SUBSYSTEM_SPECIFIC_STR of "". See example like:

def device_dm_subsystem_match(info, subsystem):
    """ Return True if the device matches a given device-mapper subsystem. """
    uuid = info.get("DM_UUID", "")
    uuid_fields = uuid.split("-")
    _subsystem = uuid_fields[0]
    if _subsystem.lower().startswith("part") and len(uuid_fields) > 1:
        # kpartx uses partN- as a subsystem prefix, which we ignore because
        # we only care about the subsystem of the partitions' parent device.
        _subsystem = uuid_fields[1]

    if _subsystem == uuid or not _subsystem:
        return False

    return _subsystem.lower() == subsystem.lower()

Is my understanding correct?

I would be happy with either:
1. An umambigous grammar for DM_UUID where I did not dig into the SUBSYSTEM_SPECIFIC_STR part at all that is robust to future changes.
2. A robust alternative for identifying the subsystem(s) that manage a particular device.

But the fact of the matter is that currently, and since 2011 at least in the case of lsblk, parsing DM_UUID has been the established way of doing it and, if my understanding is correct, parsing it without understanding of the intended grammar is pretty well-established, too.

Comment 9 Milan Broz 2016-03-30 15:12:08 UTC
lsblk parses _only_ prefix (subsystem), it never expects something from the rest of dm-uuid, IOW the first substring before "-". 

(And it is just for convenience to display name of subsystem to user - if this fails, it will simply display device type as "dm", nothing should depend on it.)

Comment 10 mulhern 2016-03-30 18:39:13 UTC
Comment #9: Thanks for confirming...lsblk parses the _first_ subsystem only.

So, it does not distinguish between a partition on a multipath device and one that is not, as it looks no deeper. By contrast, blivet does.

Comment 11 Milan Broz 2016-03-30 18:54:11 UTC
lsblk traverses through holders in sysfs, it doesn't need to guess storage stack from private part of DM-UUID. That was the whole idea behind lsblk.
(And you can parse output from lsblk in scripts.)

(BTW LUKS uses the same device-mapper UUID convention, internally it parses own created info from DM-UUID but this is not interface for anyone except libcryptsetup itself. Private DM_UUID part can change anytime, despite it has fixed structure now.)

Comment 12 Alasdair Kergon 2016-03-30 22:56:49 UTC
(In reply to mulhern from comment #8)
> Aside: The comment from libdevmapper.h is slightly misleading,
> "mpath" is actually _not_ capitalized :)
> DM_UUID=mpath-WDC_WD10EFRX-68PJCN0_WD-WCC4J5VFRFV3

I know: I hope one day that will change.  I can try hard to get other components to meet the standard here, but it's not an enforced standard and I was content there just to have achieved the use of a prefix!

> Comment #2: I'm not familiar with every storage/udev related utility or
> library. But I know that at least blivet and lsblk parse out DM_UUID (or
> dm/uuid) as the case may be. In both cases, they are looking for a subsystem
> value, e.g., "LVM", "mpath". blivet seems to be looking for the last or
> primary subsystem value, lsblk for the first.

They do that at their own risk.  'lsblk' behaves reasonably and understands the issues as Milan explained in the previous comments.

If blivet is looking more deeply using an unsupported procedure, that sounds fragile to me.
 
> AFAICT, from comments #4 and following, the grammar is really something like:
> DM_UUID -> G
> G -> SUBSYSTEM_STR | SUBSYSTEM_STR "-" G
> SUBSYSTEM_STR -> SUBSYSTEM_PREFIX "-" SUBSYSTEM_SPECIFIC_STR
> SUBSYSTEM_PREFIX -> "part" PARTITIONID | "LVM" | "mpath" | ...
> SUBSYSTEM_SPECIFIC_STR -> <just about anything>

Nope - it is simply PREFIX PRIVATE_CONTENT. Each subsystem has chosen its own PREFIX (not used by any other subsystem).  PRIVATE_CONTENT is defined by the subsystem that owns the prefix and its format is not tied down but is free to change in any future release.  (The hyphen is technically considered part of the prefix - not all subsystem prefixes end with a hyphen.)

> I would be happy with either:
> 1. An umambigous grammar for DM_UUID where I did not dig into the
> SUBSYSTEM_SPECIFIC_STR part at all that is robust to future changes.
> 2. A robust alternative for identifying the subsystem(s) that manage a
> particular device.

The PREFIX defines the subsystem.  That's all you can rely upon.  Once you know the subsystem, you should obtain information about what is underneath it from the subsystem itself, either by asking it or by looking in the udev database or sysfs or wherever else the required information is (or could be) stored.

Comment 13 Zdenek Kabelac 2016-03-31 11:47:47 UTC
There is nothing for fixed in  'lvm2' neither in 'dm' package - closing....

For further discussion I'd suggest to use dm-devel list
(i.e. for impact on  mpath...)

Comment 14 mulhern 2016-03-31 13:51:44 UTC
Comment #11: This is really an aside, but I think that storage is complex enough that holders/slaves relationship is not really adequate to describe some of the relationships between devices, see: https://bugzilla.redhat.com/show_bug.cgi?id=1195374.

But the real reason to reopen is that the DM_UUID grammar is still unclear to me.

According to agk, the grammar is really very simple:

DM_UUID -> G
G -> PREFIX PRIVATE_CONTENT
PREFIX -> <anything>
PRIVATE_CONTENT -> <anything>

In particular, PREFIX may or may not have a '-' at the end.

But, in that case, the grammar is ambiguous and lsblk is wrong, as it explicitly assumes a '-' as a delimiter between the PREFIX and the rest, i.e., its assumed grammar is more like:

DM_UUID -> G
G -> PREFIX '-' PRIVATE_CONTENT
PREFIX -> <anything except a '-'>
PRIVATE_CONTENT -> <anything>
PREFIX -> "part" PARTITIONID | NONPARTPREFIX
NONPARTPREFIX -> <anything>
PARTITIONID -> [1-9][0-9]*

See excerpted code below:

static char *get_type(struct blkdev_cxt *cxt)
{
    char *res = NULL, *p;

    if (is_dm(cxt->name)) {
        char *dm_uuid = sysfs_strdup(&cxt->sysfs, "dm/uuid");

        /* The DM_UUID prefix should be set to subsystem owning
         * the device - LVM, CRYPT, DMRAID, MPATH, PART */
        if (dm_uuid) {
            char *tmp = dm_uuid;
            char *dm_uuid_prefix = strsep(&tmp, "-");

            if (dm_uuid_prefix) {
                /* kpartx hack to remove partition number */
                if (strncasecmp(dm_uuid_prefix, "part", 4) == 0)
                    dm_uuid_prefix[4] = '\0';

                res = xstrdup(dm_uuid_prefix);
            }
        }
...

The only way to make the grammar unambiguous is to add a complete list of productions for PREFIX, like:

PREFIX -> "mpath-" | "LVM-" | "part" PARTITIONID "-" | ... <must be complete>
PARTITIONID -> [1-9][0-9]*

=================================================

The only other way for this to make sense is for each dm subsystem to
have its own separate grammar, like:

DM_UUID => G
G => MYPREFIX MYSTUFF NOTMYSTUFF | NOTMYSTUFF
MYPREFIX => [subsystem appropriate prefix]
MYSTUFF => [subsystem appropriate]
NOTMYSTUFF => "" | <anything>

so that, for mpath, the MYPREFIX production is:

MYPREFIX => "mpath-"
MYSTUFF => <I'm not sure, kinda complicated> 

for lvm,

MYPREFIX => "LVM-"
MYSTUFF => <I'm not quite sure, kinda complicated>

for kpartx,

MYPREFIX => "part" PARTITIONID '-'
PARTITIONID => [1-9][0-9]*
MYSTUFF => ""

and so on.

Maybe this is the case? If it is, then _no_ external entity should be parsing DM_UUID because no external entity has its own grammar. Which would solve my immediate problem nicely, but not lsblk's or blivet's ongoing ones.

Comment 16 Alasdair Kergon 2016-03-31 16:53:42 UTC
(In reply to mulhern from comment #14)
> _no_ external entity should be
> parsing DM_UUID 

Correct.  Anything that attempts to parse it is very likely doing something wrong because all the information it should need should already be available elsewhere through supported mechanisms.

This is *developer* information.  I doubt we need to write anything about this in the user guides aimed at sysadmins.


Note You need to log in before you can comment on or make changes to this bug.