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

[PATCH 5/7] xen/events: add per-xenbus device event statistics and settings



Add sysfs 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>
---
 drivers/xen/events/events_base.c  | 27 ++++++++++++-
 drivers/xen/xenbus/xenbus_probe.c | 66 +++++++++++++++++++++++++++++++
 include/xen/xenbus.h              |  7 ++++
 3 files changed, 98 insertions(+), 2 deletions(-)

diff --git a/drivers/xen/events/events_base.c b/drivers/xen/events/events_base.c
index 8c620c11e32a..d0c57c5664c0 100644
--- a/drivers/xen/events/events_base.c
+++ b/drivers/xen/events/events_base.c
@@ -327,6 +327,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;
 }
@@ -572,18 +574,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;
        }
@@ -920,6 +932,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);
 
@@ -930,6 +943,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;
                }
@@ -1593,6 +1611,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)
@@ -1622,6 +1641,10 @@ void handle_irq_for_port(evtchn_port_t port, struct 
evtchn_loop_ctrl *ctrl)
 
        info = info_for_irq(irq);
 
+       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 18ffd0551b54..9494ecad3c92 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 2c43b0ef1e4d..13ee375a1f05 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®.