[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH v3 6/8] xen/events: add per-xenbus device event statistics and settings



Add syfs nodes for each xenbus device showing event statistics (number
of events and spurious events, number of associated event channels)
and for setting a spurious event threshold in case a frontend is
sending too many events without being rogue on purpose.

Signed-off-by: Juergen Gross <jgross@xxxxxxxx>
Reviewed-by: Boris Ostrovsky <boris.ostrovsky@xxxxxxxxxx>
---
V2:
- add documentation (Boris Ostrovsky)
---
 .../ABI/testing/sysfs-devices-xenbus          | 41 ++++++++++++
 drivers/xen/events/events_base.c              | 27 +++++++-
 drivers/xen/xenbus/xenbus_probe.c             | 66 +++++++++++++++++++
 include/xen/xenbus.h                          |  7 ++
 4 files changed, 139 insertions(+), 2 deletions(-)
 create mode 100644 Documentation/ABI/testing/sysfs-devices-xenbus

diff --git a/Documentation/ABI/testing/sysfs-devices-xenbus 
b/Documentation/ABI/testing/sysfs-devices-xenbus
new file mode 100644
index 000000000000..fd796cb4f315
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-devices-xenbus
@@ -0,0 +1,41 @@
+What:          /sys/devices/*/xenbus/event_channels
+Date:          February 2021
+Contact:       Xen Developers mailing list <xen-devel@xxxxxxxxxxxxxxxxxxxx>
+Description:
+               Number of Xen event channels associated with a kernel based
+               paravirtualized device frontend or backend.
+
+What:          /sys/devices/*/xenbus/events
+Date:          February 2021
+Contact:       Xen Developers mailing list <xen-devel@xxxxxxxxxxxxxxxxxxxx>
+Description:
+               Total number of Xen events received for a Xen pv device
+               frontend or backend.
+
+What:          /sys/devices/*/xenbus/jiffies_eoi_delayed
+Date:          February 2021
+Contact:       Xen Developers mailing list <xen-devel@xxxxxxxxxxxxxxxxxxxx>
+Description:
+               Summed up time in jiffies the EOI of an interrupt for a Xen
+               pv device has been delayed in order to avoid stalls due to
+               event storms. This value rising is a first sign for a rogue
+               other end of the pv device.
+
+What:          /sys/devices/*/xenbus/spurious_events
+Date:          February 2021
+Contact:       Xen Developers mailing list <xen-devel@xxxxxxxxxxxxxxxxxxxx>
+Description:
+               Number of events received for a Xen pv device which did not
+               require any action. Too many spurious events in a row will
+               trigger delayed EOI processing.
+
+What:          /sys/devices/*/xenbus/spurious_threshold
+Date:          February 2021
+Contact:       Xen Developers mailing list <xen-devel@xxxxxxxxxxxxxxxxxxxx>
+Description:
+               Controls the tolerated number of subsequent spurious events
+               before delayed EOI processing is triggered for a Xen pv
+               device. Default is 1. This can be modified in case the other
+               end of the pv device is issuing spurious events on a regular
+               basis and is known not to be malicious on purpose. Raising
+               the value for such cases can improve pv device performance.
diff --git a/drivers/xen/events/events_base.c b/drivers/xen/events/events_base.c
index b60df189ecbc..a3636fb03417 100644
--- a/drivers/xen/events/events_base.c
+++ b/drivers/xen/events/events_base.c
@@ -332,6 +332,8 @@ static int xen_irq_info_evtchn_setup(unsigned irq,
 
        ret = xen_irq_info_common_setup(info, irq, IRQT_EVTCHN, evtchn, 0);
        info->u.interdomain = dev;
+       if (dev)
+               atomic_inc(&dev->event_channels);
 
        return ret;
 }
@@ -606,18 +608,28 @@ static void xen_irq_lateeoi_locked(struct irq_info *info, 
bool spurious)
                return;
 
        if (spurious) {
+               struct xenbus_device *dev = info->u.interdomain;
+               unsigned int threshold = 1;
+
+               if (dev && dev->spurious_threshold)
+                       threshold = dev->spurious_threshold;
+
                if ((1 << info->spurious_cnt) < (HZ << 2)) {
                        if (info->spurious_cnt != 0xFF)
                                info->spurious_cnt++;
                }
-               if (info->spurious_cnt > 1) {
-                       delay = 1 << (info->spurious_cnt - 2);
+               if (info->spurious_cnt > threshold) {
+                       delay = 1 << (info->spurious_cnt - 1 - threshold);
                        if (delay > HZ)
                                delay = HZ;
                        if (!info->eoi_time)
                                info->eoi_cpu = smp_processor_id();
                        info->eoi_time = get_jiffies_64() + delay;
+                       if (dev)
+                               atomic_add(delay, &dev->jiffies_eoi_delayed);
                }
+               if (dev)
+                       atomic_inc(&dev->spurious_events);
        } else {
                info->spurious_cnt = 0;
        }
@@ -954,6 +966,7 @@ static void __unbind_from_irq(unsigned int irq)
 
        if (VALID_EVTCHN(evtchn)) {
                unsigned int cpu = cpu_from_irq(irq);
+               struct xenbus_device *dev;
 
                xen_evtchn_close(evtchn);
 
@@ -964,6 +977,11 @@ static void __unbind_from_irq(unsigned int irq)
                case IRQT_IPI:
                        per_cpu(ipi_to_irq, cpu)[ipi_from_irq(irq)] = -1;
                        break;
+               case IRQT_EVTCHN:
+                       dev = info->u.interdomain;
+                       if (dev)
+                               atomic_dec(&dev->event_channels);
+                       break;
                default:
                        break;
                }
@@ -1627,6 +1645,7 @@ void handle_irq_for_port(evtchn_port_t port, struct 
evtchn_loop_ctrl *ctrl)
 {
        int irq;
        struct irq_info *info;
+       struct xenbus_device *dev;
 
        irq = get_evtchn_to_irq(port);
        if (irq == -1)
@@ -1658,6 +1677,10 @@ void handle_irq_for_port(evtchn_port_t port, struct 
evtchn_loop_ctrl *ctrl)
        if (xchg_acquire(&info->is_active, 1))
                return;
 
+       dev = (info->type == IRQT_EVTCHN) ? info->u.interdomain : NULL;
+       if (dev)
+               atomic_inc(&dev->events);
+
        if (ctrl->defer_eoi) {
                info->eoi_cpu = smp_processor_id();
                info->irq_epoch = __this_cpu_read(irq_epoch);
diff --git a/drivers/xen/xenbus/xenbus_probe.c 
b/drivers/xen/xenbus/xenbus_probe.c
index 8a75092bb148..97f0d234482d 100644
--- a/drivers/xen/xenbus/xenbus_probe.c
+++ b/drivers/xen/xenbus/xenbus_probe.c
@@ -206,6 +206,65 @@ void xenbus_otherend_changed(struct xenbus_watch *watch,
 }
 EXPORT_SYMBOL_GPL(xenbus_otherend_changed);
 
+#define XENBUS_SHOW_STAT(name)                                         \
+static ssize_t show_##name(struct device *_dev,                                
\
+                          struct device_attribute *attr,               \
+                          char *buf)                                   \
+{                                                                      \
+       struct xenbus_device *dev = to_xenbus_device(_dev);             \
+                                                                       \
+       return sprintf(buf, "%d\n", atomic_read(&dev->name));           \
+}                                                                      \
+static DEVICE_ATTR(name, 0444, show_##name, NULL)
+
+XENBUS_SHOW_STAT(event_channels);
+XENBUS_SHOW_STAT(events);
+XENBUS_SHOW_STAT(spurious_events);
+XENBUS_SHOW_STAT(jiffies_eoi_delayed);
+
+static ssize_t show_spurious_threshold(struct device *_dev,
+                                      struct device_attribute *attr,
+                                      char *buf)
+{
+       struct xenbus_device *dev = to_xenbus_device(_dev);
+
+       return sprintf(buf, "%d\n", dev->spurious_threshold);
+}
+
+static ssize_t set_spurious_threshold(struct device *_dev,
+                                     struct device_attribute *attr,
+                                     const char *buf, size_t count)
+{
+       struct xenbus_device *dev = to_xenbus_device(_dev);
+       unsigned int val;
+       ssize_t ret;
+
+       ret = kstrtouint(buf, 0, &val);
+       if (ret)
+               return ret;
+
+       dev->spurious_threshold = val;
+
+       return count;
+}
+
+static DEVICE_ATTR(spurious_threshold, 0644, show_spurious_threshold,
+                  set_spurious_threshold);
+
+static struct attribute *xenbus_attrs[] = {
+       &dev_attr_event_channels.attr,
+       &dev_attr_events.attr,
+       &dev_attr_spurious_events.attr,
+       &dev_attr_jiffies_eoi_delayed.attr,
+       &dev_attr_spurious_threshold.attr,
+       NULL
+};
+
+static const struct attribute_group xenbus_group = {
+       .name = "xenbus",
+       .attrs = xenbus_attrs,
+};
+
 int xenbus_dev_probe(struct device *_dev)
 {
        struct xenbus_device *dev = to_xenbus_device(_dev);
@@ -253,6 +312,11 @@ int xenbus_dev_probe(struct device *_dev)
                return err;
        }
 
+       dev->spurious_threshold = 1;
+       if (sysfs_create_group(&dev->dev.kobj, &xenbus_group))
+               dev_warn(&dev->dev, "sysfs_create_group on %s failed.\n",
+                        dev->nodename);
+
        return 0;
 fail_put:
        module_put(drv->driver.owner);
@@ -269,6 +333,8 @@ int xenbus_dev_remove(struct device *_dev)
 
        DPRINTK("%s", dev->nodename);
 
+       sysfs_remove_group(&dev->dev.kobj, &xenbus_group);
+
        free_otherend_watch(dev);
 
        if (drv->remove) {
diff --git a/include/xen/xenbus.h b/include/xen/xenbus.h
index bf3cfc7c35d0..0b1386073d49 100644
--- a/include/xen/xenbus.h
+++ b/include/xen/xenbus.h
@@ -88,6 +88,13 @@ struct xenbus_device {
        struct completion down;
        struct work_struct work;
        struct semaphore reclaim_sem;
+
+       /* Event channel based statistics and settings. */
+       atomic_t event_channels;
+       atomic_t events;
+       atomic_t spurious_events;
+       atomic_t jiffies_eoi_delayed;
+       unsigned int spurious_threshold;
 };
 
 static inline struct xenbus_device *to_xenbus_device(struct device *dev)
-- 
2.26.2




 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.