]> www.infradead.org Git - linux-platform-drivers-x86.git/commitdiff
xen/xenbus: Allow watches discard events before queueing
authorSeongJae Park <sjpark@amazon.de>
Mon, 14 Dec 2020 09:02:45 +0000 (10:02 +0100)
committerJuergen Gross <jgross@suse.com>
Mon, 14 Dec 2020 09:02:45 +0000 (10:02 +0100)
If handling logics of watch events are slower than the events enqueue
logic and the events can be created from the guests, the guests could
trigger memory pressure by intensively inducing the events, because it
will create a huge number of pending events that exhausting the memory.

Fortunately, some watch events could be ignored, depending on its
handler callback.  For example, if the callback has interest in only one
single path, the watch wouldn't want multiple pending events.  Or, some
watches could ignore events to same path.

To let such watches to volutarily help avoiding the memory pressure
situation, this commit introduces new watch callback, 'will_handle'.  If
it is not NULL, it will be called for each new event just before
enqueuing it.  Then, if the callback returns false, the event will be
discarded.  No watch is using the callback for now, though.

This is part of XSA-349

Cc: stable@vger.kernel.org
Signed-off-by: SeongJae Park <sjpark@amazon.de>
Reported-by: Michael Kurth <mku@amazon.de>
Reported-by: Pawel Wieczorkiewicz <wipawel@amazon.de>
Reviewed-by: Juergen Gross <jgross@suse.com>
Signed-off-by: Juergen Gross <jgross@suse.com>
drivers/net/xen-netback/xenbus.c
drivers/xen/xenbus/xenbus_client.c
drivers/xen/xenbus/xenbus_xs.c
include/xen/xenbus.h

index f1c1624cec8f5dffe6f57a3486187f9c4667dc5c..00f6f8dc56c8f8ff3814cea9000954ca1577c131 100644 (file)
@@ -557,12 +557,14 @@ static int xen_register_credit_watch(struct xenbus_device *dev,
                return -ENOMEM;
        snprintf(node, maxlen, "%s/rate", dev->nodename);
        vif->credit_watch.node = node;
+       vif->credit_watch.will_handle = NULL;
        vif->credit_watch.callback = xen_net_rate_changed;
        err = register_xenbus_watch(&vif->credit_watch);
        if (err) {
                pr_err("Failed to set watcher %s\n", vif->credit_watch.node);
                kfree(node);
                vif->credit_watch.node = NULL;
+               vif->credit_watch.will_handle = NULL;
                vif->credit_watch.callback = NULL;
        }
        return err;
@@ -609,6 +611,7 @@ static int xen_register_mcast_ctrl_watch(struct xenbus_device *dev,
        snprintf(node, maxlen, "%s/request-multicast-control",
                 dev->otherend);
        vif->mcast_ctrl_watch.node = node;
+       vif->mcast_ctrl_watch.will_handle = NULL;
        vif->mcast_ctrl_watch.callback = xen_mcast_ctrl_changed;
        err = register_xenbus_watch(&vif->mcast_ctrl_watch);
        if (err) {
@@ -616,6 +619,7 @@ static int xen_register_mcast_ctrl_watch(struct xenbus_device *dev,
                       vif->mcast_ctrl_watch.node);
                kfree(node);
                vif->mcast_ctrl_watch.node = NULL;
+               vif->mcast_ctrl_watch.will_handle = NULL;
                vif->mcast_ctrl_watch.callback = NULL;
        }
        return err;
index fd80e318b99cc7808548ee92af6f9dbd0a5aad0f..0a21a12d9c34dbeb41dd02228c8291fcafe171f4 100644 (file)
@@ -133,6 +133,7 @@ int xenbus_watch_path(struct xenbus_device *dev, const char *path,
        int err;
 
        watch->node = path;
+       watch->will_handle = NULL;
        watch->callback = callback;
 
        err = register_xenbus_watch(watch);
index 3a06eb699f33309f1d836235e6ba160a59c484fb..e8bdbd0a1e2669d57aac6a2a99d171718d67a077 100644 (file)
@@ -705,7 +705,10 @@ int xs_watch_msg(struct xs_watch_event *event)
 
        spin_lock(&watches_lock);
        event->handle = find_watch(event->token);
-       if (event->handle != NULL) {
+       if (event->handle != NULL &&
+                       (!event->handle->will_handle ||
+                        event->handle->will_handle(event->handle,
+                                event->path, event->token))) {
                spin_lock(&watch_events_lock);
                list_add_tail(&event->list, &watch_events);
                wake_up(&watch_events_waitq);
index 5a8315e6d8a6074a2aa5038ddc2f0325e7b3ff45..baa88bf0b9bce26f68c79cddb62b69749870d1c1 100644 (file)
@@ -61,6 +61,13 @@ struct xenbus_watch
        /* Path being watched. */
        const char *node;
 
+       /*
+        * Called just before enqueing new event while a spinlock is held.
+        * The event will be discarded if this callback returns false.
+        */
+       bool (*will_handle)(struct xenbus_watch *,
+                             const char *path, const char *token);
+
        /* Callback (executed in a process context with no locks held). */
        void (*callback)(struct xenbus_watch *,
                         const char *path, const char *token);