mdadm: add --no-devices to avoid component devices detail information
authorColy Li <colyli@suse.de>
Wed, 31 Jul 2019 05:29:29 +0000 (13:29 +0800)
committerJes Sorensen <jsorensen@fb.com>
Mon, 12 Aug 2019 20:16:36 +0000 (16:16 -0400)
When people assemble a md raid device with a large number of
component deivces (e.g. 1500 DASD disks), the raid device detail
information generated by 'mdadm --detail --export $devnode' is very
large. It is because the detail information contains information of
all the component disks (even the missing/failed ones).

In such condition, when udev-md-raid-arrays.rules is triggered and
internally calls "mdadm --detail --no-devices --export $devnode",
user may observe systemd error message ""invalid message length". It
is because the following on-stack raw message buffer in systemd code
is not big enough,
        systemd/src/libudev/libudev-monitor.c
        _public_ struct udev_device *udev_monito ...
                struct ucred *cred;
                union {
                        struct udev_monitor_netlink_header nlh;
                        char raw[8192];
                } buf;
Even change size of raw[] from 8KB to larger size, it may still be not
enough for detail message of a md raid device with much larger number of
component devices.

To fix this problem, an extra option '--no-devices' is added (the
original idea is proposed by Neil Brown). When printing detailed
information of a md raid device, if '--no-devices' is specified, then
all component devices information will not be printed, then the output
message size can be restricted to a small number, even with the systemd
only has 8KB on-disk raw buffer, the md raid array udev rules can work
correctly without failure message.

Signed-off-by: Coly Li <colyli@suse.de>
Reviewed-by: NeilBrown <neilb@suse.com>
Signed-off-by: Jes Sorensen <jsorensen@fb.com>
Detail.c
ReadMe.c
mdadm.c
mdadm.h

index 20ea03a..ad60434 100644 (file)
--- a/Detail.c
+++ b/Detail.c
@@ -56,7 +56,7 @@ int Detail(char *dev, struct context *c)
         */
        int fd = open(dev, O_RDONLY);
        mdu_array_info_t array;
-       mdu_disk_info_t *disks;
+       mdu_disk_info_t *disks = NULL;
        int next;
        int d;
        time_t atime;
@@ -280,7 +280,7 @@ int Detail(char *dev, struct context *c)
                        }
                        map_free(map);
                }
-               if (sra) {
+               if (!c->no_devices && sra) {
                        struct mdinfo *mdi;
                        for (mdi  = sra->devs; mdi; mdi = mdi->next) {
                                char *path;
@@ -655,12 +655,17 @@ This is pretty boring
                        printf("\n\n");
                }
 
-               if (array.raid_disks)
-                       printf("    Number   Major   Minor   RaidDevice State\n");
-               else
-                       printf("    Number   Major   Minor   RaidDevice\n");
+               if (!c->no_devices) {
+                       if (array.raid_disks)
+                               printf("    Number   Major   Minor   RaidDevice State\n");
+                       else
+                               printf("    Number   Major   Minor   RaidDevice\n");
+               }
        }
-       free(info);
+
+       /* if --no_devices specified, not print component devices info */
+       if (c->no_devices)
+               goto skip_devices_state;
 
        for (d = 0; d < max_disks * 2; d++) {
                char *dv;
@@ -747,6 +752,8 @@ This is pretty boring
                if (!c->brief)
                        printf("\n");
        }
+
+skip_devices_state:
        if (spares && c->brief && array.raid_disks)
                printf(" spares=%d", spares);
        if (c->brief && st && st->sb)
@@ -766,8 +773,9 @@ This is pretty boring
            !enough(array.level, array.raid_disks, array.layout, 1, avail))
                rv = 2;
 
-       free(disks);
 out:
+       free(info);
+       free(disks);
        close(fd);
        free(subarray);
        free(avail);
index 12ccf83..eaf1042 100644 (file)
--- a/ReadMe.c
+++ b/ReadMe.c
@@ -181,6 +181,7 @@ struct option long_options[] = {
 
     /* For Detail/Examine */
     {"brief",    0, 0, Brief},
+    {"no-devices",0, 0, NoDevices},
     {"export",   0, 0, 'Y'},
     {"sparc2.2",  0, 0, Sparc22},
     {"test",      0, 0, 't'},
diff --git a/mdadm.c b/mdadm.c
index 25a1abd..1fb8086 100644 (file)
--- a/mdadm.c
+++ b/mdadm.c
@@ -159,6 +159,10 @@ int main(int argc, char *argv[])
                        c.brief = 1;
                        continue;
 
+               case NoDevices:
+                       c.no_devices = 1;
+                       continue;
+
                case 'Y': c.export++;
                        continue;
 
diff --git a/mdadm.h b/mdadm.h
index d61a9ca..43b07d5 100644 (file)
--- a/mdadm.h
+++ b/mdadm.h
@@ -440,6 +440,7 @@ enum special_options {
        NoSharing,
        HelpOptions,
        Brief,
+       NoDevices,
        ManageOpt,
        Add,
        AddSpare,
@@ -550,6 +551,7 @@ struct context {
        int     runstop;
        int     verbose;
        int     brief;
+       int     no_devices;
        int     force;
        char    *homehost;
        int     require_homehost;