]> git.droids-corp.org - dpdk.git/commitdiff
net/enic: allocate stats DMA buffer upfront during probe
authorHyong Youb Kim <hyonkim@cisco.com>
Thu, 8 Mar 2018 02:46:58 +0000 (18:46 -0800)
committerFerruh Yigit <ferruh.yigit@intel.com>
Fri, 30 Mar 2018 12:08:43 +0000 (14:08 +0200)
The driver provides a DMA buffer to the firmware when it requests port
stats. The NIC then fills that buffer with latest stats. Currently,
the driver allocates the DMA buffer the first time it requests stats
and saves it for later use. This can lead to crashes when
primary/secondary processes are involved. For example, the following
sequence crashes the secondary process.

1. Start a primary app that does not call rte_eth_stats_get()
2. dpdk-procinfo -- --stats

dpdk-procinfo crashes while trying to allocate the stats DMA buffer
because the alloc function pointer (vdev.alloc_consistent) is valid
only in the primary process, not in the secondary process.

Overwriting the alloc function pointer in the secondary process is not
an option, as it will simply make the pointer invalid in the primary
process. Instead, allocate the DMA buffer during probe so that only
the primary process does both allocate and free. This allows the
secondary process to dump stats as well.

Fixes: 9913fbb91df0 ("enic/base: common code")
Cc: stable@dpdk.org
Signed-off-by: Hyong Youb Kim <hyonkim@cisco.com>
Reviewed-by: John Daley <johndale@cisco.com>
drivers/net/enic/base/vnic_dev.c
drivers/net/enic/base/vnic_dev.h
drivers/net/enic/enic_main.c

index 05b595eb88433ba1b3f51a216df949f1b4968f6e..1f8d222fc94931c0fdf5f2ff6c398f63e986c3a7 100644 (file)
@@ -587,17 +587,9 @@ int vnic_dev_stats_dump(struct vnic_dev *vdev, struct vnic_stats **stats)
 {
        u64 a0, a1;
        int wait = 1000;
-       static u32 instance;
-       char name[NAME_MAX];
 
-       if (!vdev->stats) {
-               snprintf((char *)name, sizeof(name),
-                       "vnic_stats-%u", instance++);
-               vdev->stats = vdev->alloc_consistent(vdev->priv,
-                       sizeof(struct vnic_stats), &vdev->stats_pa, (u8 *)name);
-               if (!vdev->stats)
-                       return -ENOMEM;
-       }
+       if (!vdev->stats)
+               return -ENOMEM;
 
        *stats = vdev->stats;
        a0 = vdev->stats_pa;
@@ -922,6 +914,18 @@ u32 vnic_dev_get_intr_coal_timer_max(struct vnic_dev *vdev)
        return vdev->intr_coal_timer_info.max_usec;
 }
 
+int vnic_dev_alloc_stats_mem(struct vnic_dev *vdev)
+{
+       char name[NAME_MAX];
+       static u32 instance;
+
+       snprintf((char *)name, sizeof(name), "vnic_stats-%u", instance++);
+       vdev->stats = vdev->alloc_consistent(vdev->priv,
+                                            sizeof(struct vnic_stats),
+                                            &vdev->stats_pa, (u8 *)name);
+       return vdev->stats == NULL ? -ENOMEM : 0;
+}
+
 void vnic_dev_unregister(struct vnic_dev *vdev)
 {
        if (vdev) {
index 8c099206360ad27b03a0d53553a9423f8edf5376..7e5736b4dadccee4b4e76af52433598f3d6b2bb0 100644 (file)
@@ -165,6 +165,7 @@ struct vnic_dev *vnic_dev_register(struct vnic_dev *vdev,
        void *priv, struct rte_pci_device *pdev, struct vnic_dev_bar *bar,
        unsigned int num_bars);
 struct rte_pci_device *vnic_dev_get_pdev(struct vnic_dev *vdev);
+int vnic_dev_alloc_stats_mem(struct vnic_dev *vdev);
 int vnic_dev_cmd_init(struct vnic_dev *vdev, int fallback);
 int vnic_dev_get_size(void);
 int vnic_dev_int13(struct vnic_dev *vdev, u64 arg, u32 op);
index c3796c5438c204b58a4d9684872ed8d83be10be8..235ef59405c8d506918e83738d6e27f0f8074b1f 100644 (file)
@@ -1478,6 +1478,15 @@ int enic_probe(struct enic *enic)
                enic_alloc_consistent,
                enic_free_consistent);
 
+       /*
+        * Allocate the consistent memory for stats upfront so both primary and
+        * secondary processes can dump stats.
+        */
+       err = vnic_dev_alloc_stats_mem(enic->vdev);
+       if (err) {
+               dev_err(enic, "Failed to allocate cmd memory, aborting\n");
+               goto err_out_unregister;
+       }
        /* Issue device open to get device in known state */
        err = enic_dev_open(enic);
        if (err) {