Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit de66402f authored by SeongJae Park's avatar SeongJae Park Committed by Greg Kroah-Hartman
Browse files

xen/xenbus: Allow watches discard events before queueing



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: default avatarSeongJae Park <sjpark@amazon.de>
Reported-by: default avatarMichael Kurth <mku@amazon.de>
Reported-by: default avatarPawel Wieczorkiewicz <wipawel@amazon.de>
Reviewed-by: default avatarJuergen Gross <jgross@suse.com>
Signed-off-by: default avatarJuergen Gross <jgross@suse.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent d8b0d52e
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -697,12 +697,14 @@ static int xen_register_watchers(struct xenbus_device *dev, struct xenvif *vif)
		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;
+1 −0
Original line number Diff line number Diff line
@@ -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);
+6 −1
Original line number Diff line number Diff line
@@ -903,7 +903,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);
+7 −0
Original line number Diff line number Diff line
@@ -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);