Skip to content

Commit

Permalink
xen/xenbus: Allow watches discard events before queueing
Browse files Browse the repository at this point in the history
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: [email protected]
Signed-off-by: SeongJae Park <[email protected]>
Reported-by: Michael Kurth <[email protected]>
Reported-by: Pawel Wieczorkiewicz <[email protected]>
Reviewed-by: Juergen Gross <[email protected]>
Signed-off-by: Juergen Gross <[email protected]>
  • Loading branch information
sj-aws authored and jgross1 committed Dec 14, 2020
1 parent 2c85ebc commit fed1755
Show file tree
Hide file tree
Showing 4 changed files with 16 additions and 1 deletion.
4 changes: 4 additions & 0 deletions drivers/net/xen-netback/xenbus.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -609,13 +611,15 @@ 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) {
pr_err("Failed to set watcher %s\n",
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;
Expand Down
1 change: 1 addition & 0 deletions drivers/xen/xenbus/xenbus_client.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
5 changes: 4 additions & 1 deletion drivers/xen/xenbus/xenbus_xs.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
7 changes: 7 additions & 0 deletions include/xen/xenbus.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down

0 comments on commit fed1755

Please sign in to comment.