]> git.ipfire.org Git - thirdparty/kernel/stable.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>
Sat, 9 Jan 2021 12:35:50 +0000 (13:35 +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 b44f37fff8903258d8345748e160a13011b54019..5cb9dbf62816a7471c8c5c704f95026773f3bd30 100644 (file)
@@ -770,12 +770,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;
index 266f446ba331cb136574ecc7d176564d91ca0002..d02d25f784c960bc3eef3425de5e5f2136054a9e 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 22f7cd711c5792e25eac035f0aa138c9992d9bd9..d200aa70798862c428cb2dbb771ef355b987257b 100644 (file)
@@ -901,7 +901,12 @@ static int process_msg(void)
                spin_lock(&watches_lock);
                msg->u.watch.handle = find_watch(
                        msg->u.watch.vec[XS_WATCH_TOKEN]);
-               if (msg->u.watch.handle != NULL) {
+               if (msg->u.watch.handle != NULL &&
+                               (!msg->u.watch.handle->will_handle ||
+                                msg->u.watch.handle->will_handle(
+                                        msg->u.watch.handle,
+                                        (const char **)msg->u.watch.vec,
+                                        msg->u.watch.vec_size))) {
                        spin_lock(&watch_events_lock);
                        list_add_tail(&msg->list, &watch_events);
                        wake_up(&watch_events_waitq);
index 32b944b7cebd1eab42e78b6a3e56ec4a9ce5f693..11697aa023b5963206c2c80f6e738d50980975b2 100644 (file)
@@ -58,6 +58,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 **vec, unsigned int len);
+
        /* Callback (executed in a process context with no locks held). */
        void (*callback)(struct xenbus_watch *,
                         const char **vec, unsigned int len);