]> granicus.if.org Git - strace/commitdiff
dm: add support for event_nr in DM_LIST_DEVICES result
authorEugene Syromyatnikov <evgsyr@gmail.com>
Sun, 17 Sep 2017 02:58:49 +0000 (04:58 +0200)
committerDmitry V. Levin <ldv@altlinux.org>
Sun, 21 Jan 2018 01:46:04 +0000 (01:46 +0000)
Commit v4.13-rc1~137^2~13 (and a follow-up fix v4.14-rc4~20^2~3
that changed alignment) introduced an additional hidden field
in the structure returned by DM_LIST_DEVICES ioctl command
that contains event_nr information.

Unfortunately, we can't test it for now, but looks like it kinda works:

  # ./strace -v -eioctl -y dmsetup ls
  ioctl(3</dev/mapper/control>, DM_VERSION, {version=4.0.0,
  data_size=16384, flags=DM_EXISTS_FLAG} => {version=4.37.0,
  data_size=16384, flags=DM_EXISTS_FLAG}) = 0
  ioctl(3</dev/mapper/control>, DM_LIST_DEVICES, {version=4.0.0,
  data_size=16384, data_start=312, flags=DM_EXISTS_FLAG} =>
  {version=4.37.0, data_size=408, data_start=312, flags=DM_EXISTS_FLAG,
  {dev=makedev(253, 1), name="fedoratesting--30-swap", event_nr=0},
  {dev=makedev(253, 0), name="fedoratesting--30-root"}}) = 0
  fedoratesting--30-swap (253:1)
  fedoratesting--30-root (253:0)

* dm.c (dm_decode_dm_name_list): Obtain the amount of bytes copied
during printing device name, print event number if there's a suitable
gap present and the DM version is high enough.
* NEWS: Mention it.

NEWS
dm.c

diff --git a/NEWS b/NEWS
index 550fc38e0b38f6412a05a62c2ff9a6c187ec5d28..0b30ec3206cd711ddf4c1e6ea52885cf2710b61d 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -14,7 +14,7 @@ Noteworthy changes in release ?.?? (????-??-??)
     and BPF_OBJ_GET_INFO_BY_FD commands of bpf syscall.
   * Enhanced decoding of get_thread_area, memfd_create, modify_ldt,
     perf_event_open, reboot, set_thread_area, and shmget syscalls.
-  * Implemented decoding of KVM_* ioctl commands.
+  * Implemented decoding of KVM_* and DM_LIST_DEVICES ioctl commands.
   * Enhanced decoding of getsockopt and setsockopt syscalls for SOL_NETLINK
     level.
   * Enhanced decoding of BPF_MAP_CREATE command of bpf syscall.
diff --git a/dm.c b/dm.c
index 28863a871df662b52c438a7dfc415c402306746f..32b331011651b2e7e7bfedc642516cd15b835e76 100644 (file)
--- a/dm.c
+++ b/dm.c
@@ -258,6 +258,7 @@ dm_decode_dm_name_list(struct tcb *const tcp, const kernel_ulong_t addr,
        uint32_t offset = ioc->data_start;
        uint32_t offset_end = 0;
        uint32_t count;
+       int rc;
 
        if (ioc->data_start == ioc->data_size)
                return;
@@ -288,8 +289,36 @@ dm_decode_dm_name_list(struct tcb *const tcp, const kernel_ulong_t addr,
 
                PRINT_FIELD_DEV("{", s, dev);
                tprints(", name=");
-               printstr_ex(tcp, addr + offset_end, ioc->data_size - offset_end,
-                           QUOTE_0_TERMINATED);
+               rc = printstr_ex(tcp, addr + offset_end,
+                                ioc->data_size - offset_end,
+                                QUOTE_0_TERMINATED);
+
+               /*
+                * In Linux v4.13-rc1~137^2~13 it has been decided to cram in
+                * one more undocumented field after the device name, as if the
+                * format decoding was not twisted enough already. So, we have
+                * to check "next" now, and if it _looks like_ that there is
+                * a space for one additional integer, let's print it. As if the
+                * perversity with "name string going further than pointer to
+                * the next one" wasn't enough. Moreover, the calculation was
+                * broken for m32 on 64-bit kernels until v4.14-rc4~20^2~3, and
+                * we have no ability to detect kernel bit-ness (on x86, at
+                * least), so refrain from printing it for the DM versions below
+                * 4.37 (the original version was also aligned differently than
+                * now even on 64 bit).
+                */
+
+               if ((rc > 0) && ioc->version[1] >= 37) {
+                       kernel_ulong_t event_addr =
+                               (addr + offset_end + rc + 7) & ~7;
+                       uint32_t event_nr;
+
+                       if ((event_addr + sizeof(event_nr)) <=
+                           (addr + offset + s.next) &&
+                           !umove(tcp, event_addr, &event_nr))
+                               tprintf(", event_nr=%" PRIu32, event_nr);
+               }
+
                tprints("}");
 
                if (!s.next)