]> www.infradead.org Git - users/dwmw2/linux.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)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 29 Dec 2020 12:47:11 +0000 (13:47 +0100)
commit fed1755b118147721f2c87b37b9d66e62c39b668 upstream.

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>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/net/xen-netback/xenbus.c
drivers/xen/xenbus/xenbus_client.c
drivers/xen/xenbus/xenbus_xs.c
include/xen/xenbus.h

index a56d3eab35dd650c4acfcda9e981c0220cba9e61..e46276f8e4a5d0ba5f7506f33d39b7e6f43909cc 100644 (file)
@@ -777,12 +777,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;
@@ -829,6 +831,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) {
@@ -836,6 +839,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 f7b553faadb1014a2336cc363bd23dc8af09cb14..5a8bd3baa6e5d34d596141a492acd4fdec2d7034 100644 (file)
@@ -120,6 +120,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 b609c6e08796e45bebdc1fbb79f5f97c892a66c6..63f1d3fd4d5b4b474f4c696542ccc6a8fe79dfd7 100644 (file)
@@ -700,7 +700,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 869c816d5f8c3097b09298a9d086e7f75fff540e..55f543fe0bd8c48e4bfaf7b1288a4b715bdb6db2 100644 (file)
@@ -59,6 +59,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);