Commit 7acfd427 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'for-linus-5.11-rc1-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/xen/tip

Pull xen updates from Juergen Gross:
 "Fixes for security issues just having been disclosed:

   - a five patch series for fixing of XSA-349 (DoS via resource
     depletion in Xen dom0)

   - a patch fixing XSA-350 (access of stale pointer in a Xen dom0)"

* tag 'for-linus-5.11-rc1-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/xen/tip:
  xen-blkback: set ring->xenblkd to NULL after kthread_stop()
  xenbus/xenbus_backend: Disallow pending watch messages
  xen/xenbus: Count pending messages for each watch
  xen/xenbus/xen_bus_type: Support will_handle watch callback
  xen/xenbus: Add 'will_handle' callback support in xenbus_watch_path()
  xen/xenbus: Allow watches discard events before queueing
parents 571b12dd 1c728719
...@@ -274,6 +274,7 @@ static int xen_blkif_disconnect(struct xen_blkif *blkif) ...@@ -274,6 +274,7 @@ static int xen_blkif_disconnect(struct xen_blkif *blkif)
if (ring->xenblkd) { if (ring->xenblkd) {
kthread_stop(ring->xenblkd); kthread_stop(ring->xenblkd);
ring->xenblkd = NULL;
wake_up(&ring->shutdown_wq); wake_up(&ring->shutdown_wq);
} }
...@@ -675,7 +676,8 @@ static int xen_blkbk_probe(struct xenbus_device *dev, ...@@ -675,7 +676,8 @@ static int xen_blkbk_probe(struct xenbus_device *dev,
/* setup back pointer */ /* setup back pointer */
be->blkif->be = be; be->blkif->be = be;
err = xenbus_watch_pathfmt(dev, &be->backend_watch, backend_changed, err = xenbus_watch_pathfmt(dev, &be->backend_watch, NULL,
backend_changed,
"%s/%s", dev->nodename, "physical-device"); "%s/%s", dev->nodename, "physical-device");
if (err) if (err)
goto fail; goto fail;
......
...@@ -557,12 +557,14 @@ static int xen_register_credit_watch(struct xenbus_device *dev, ...@@ -557,12 +557,14 @@ static int xen_register_credit_watch(struct xenbus_device *dev,
return -ENOMEM; return -ENOMEM;
snprintf(node, maxlen, "%s/rate", dev->nodename); snprintf(node, maxlen, "%s/rate", dev->nodename);
vif->credit_watch.node = node; vif->credit_watch.node = node;
vif->credit_watch.will_handle = NULL;
vif->credit_watch.callback = xen_net_rate_changed; vif->credit_watch.callback = xen_net_rate_changed;
err = register_xenbus_watch(&vif->credit_watch); err = register_xenbus_watch(&vif->credit_watch);
if (err) { if (err) {
pr_err("Failed to set watcher %s\n", vif->credit_watch.node); pr_err("Failed to set watcher %s\n", vif->credit_watch.node);
kfree(node); kfree(node);
vif->credit_watch.node = NULL; vif->credit_watch.node = NULL;
vif->credit_watch.will_handle = NULL;
vif->credit_watch.callback = NULL; vif->credit_watch.callback = NULL;
} }
return err; return err;
...@@ -609,6 +611,7 @@ static int xen_register_mcast_ctrl_watch(struct xenbus_device *dev, ...@@ -609,6 +611,7 @@ static int xen_register_mcast_ctrl_watch(struct xenbus_device *dev,
snprintf(node, maxlen, "%s/request-multicast-control", snprintf(node, maxlen, "%s/request-multicast-control",
dev->otherend); dev->otherend);
vif->mcast_ctrl_watch.node = node; vif->mcast_ctrl_watch.node = node;
vif->mcast_ctrl_watch.will_handle = NULL;
vif->mcast_ctrl_watch.callback = xen_mcast_ctrl_changed; vif->mcast_ctrl_watch.callback = xen_mcast_ctrl_changed;
err = register_xenbus_watch(&vif->mcast_ctrl_watch); err = register_xenbus_watch(&vif->mcast_ctrl_watch);
if (err) { if (err) {
...@@ -616,6 +619,7 @@ static int xen_register_mcast_ctrl_watch(struct xenbus_device *dev, ...@@ -616,6 +619,7 @@ static int xen_register_mcast_ctrl_watch(struct xenbus_device *dev,
vif->mcast_ctrl_watch.node); vif->mcast_ctrl_watch.node);
kfree(node); kfree(node);
vif->mcast_ctrl_watch.node = NULL; vif->mcast_ctrl_watch.node = NULL;
vif->mcast_ctrl_watch.will_handle = NULL;
vif->mcast_ctrl_watch.callback = NULL; vif->mcast_ctrl_watch.callback = NULL;
} }
return err; return err;
...@@ -820,7 +824,7 @@ static void connect(struct backend_info *be) ...@@ -820,7 +824,7 @@ static void connect(struct backend_info *be)
xenvif_carrier_on(be->vif); xenvif_carrier_on(be->vif);
unregister_hotplug_status_watch(be); unregister_hotplug_status_watch(be);
err = xenbus_watch_pathfmt(dev, &be->hotplug_status_watch, err = xenbus_watch_pathfmt(dev, &be->hotplug_status_watch, NULL,
hotplug_status_changed, hotplug_status_changed,
"%s/%s", dev->nodename, "hotplug-status"); "%s/%s", dev->nodename, "hotplug-status");
if (!err) if (!err)
......
...@@ -689,7 +689,7 @@ static int xen_pcibk_xenbus_probe(struct xenbus_device *dev, ...@@ -689,7 +689,7 @@ static int xen_pcibk_xenbus_probe(struct xenbus_device *dev,
/* watch the backend node for backend configuration information */ /* watch the backend node for backend configuration information */
err = xenbus_watch_path(dev, dev->nodename, &pdev->be_watch, err = xenbus_watch_path(dev, dev->nodename, &pdev->be_watch,
xen_pcibk_be_watch); NULL, xen_pcibk_be_watch);
if (err) if (err)
goto out; goto out;
......
...@@ -44,6 +44,8 @@ struct xen_bus_type { ...@@ -44,6 +44,8 @@ struct xen_bus_type {
int (*get_bus_id)(char bus_id[XEN_BUS_ID_SIZE], const char *nodename); int (*get_bus_id)(char bus_id[XEN_BUS_ID_SIZE], const char *nodename);
int (*probe)(struct xen_bus_type *bus, const char *type, int (*probe)(struct xen_bus_type *bus, const char *type,
const char *dir); const char *dir);
bool (*otherend_will_handle)(struct xenbus_watch *watch,
const char *path, const char *token);
void (*otherend_changed)(struct xenbus_watch *watch, const char *path, void (*otherend_changed)(struct xenbus_watch *watch, const char *path,
const char *token); const char *token);
struct bus_type bus; struct bus_type bus;
......
...@@ -127,18 +127,22 @@ EXPORT_SYMBOL_GPL(xenbus_strstate); ...@@ -127,18 +127,22 @@ EXPORT_SYMBOL_GPL(xenbus_strstate);
*/ */
int xenbus_watch_path(struct xenbus_device *dev, const char *path, int xenbus_watch_path(struct xenbus_device *dev, const char *path,
struct xenbus_watch *watch, struct xenbus_watch *watch,
bool (*will_handle)(struct xenbus_watch *,
const char *, const char *),
void (*callback)(struct xenbus_watch *, void (*callback)(struct xenbus_watch *,
const char *, const char *)) const char *, const char *))
{ {
int err; int err;
watch->node = path; watch->node = path;
watch->will_handle = will_handle;
watch->callback = callback; watch->callback = callback;
err = register_xenbus_watch(watch); err = register_xenbus_watch(watch);
if (err) { if (err) {
watch->node = NULL; watch->node = NULL;
watch->will_handle = NULL;
watch->callback = NULL; watch->callback = NULL;
xenbus_dev_fatal(dev, err, "adding watch on %s", path); xenbus_dev_fatal(dev, err, "adding watch on %s", path);
} }
...@@ -165,6 +169,8 @@ EXPORT_SYMBOL_GPL(xenbus_watch_path); ...@@ -165,6 +169,8 @@ EXPORT_SYMBOL_GPL(xenbus_watch_path);
*/ */
int xenbus_watch_pathfmt(struct xenbus_device *dev, int xenbus_watch_pathfmt(struct xenbus_device *dev,
struct xenbus_watch *watch, struct xenbus_watch *watch,
bool (*will_handle)(struct xenbus_watch *,
const char *, const char *),
void (*callback)(struct xenbus_watch *, void (*callback)(struct xenbus_watch *,
const char *, const char *), const char *, const char *),
const char *pathfmt, ...) const char *pathfmt, ...)
...@@ -181,7 +187,7 @@ int xenbus_watch_pathfmt(struct xenbus_device *dev, ...@@ -181,7 +187,7 @@ int xenbus_watch_pathfmt(struct xenbus_device *dev,
xenbus_dev_fatal(dev, -ENOMEM, "allocating path for watch"); xenbus_dev_fatal(dev, -ENOMEM, "allocating path for watch");
return -ENOMEM; return -ENOMEM;
} }
err = xenbus_watch_path(dev, path, watch, callback); err = xenbus_watch_path(dev, path, watch, will_handle, callback);
if (err) if (err)
kfree(path); kfree(path);
......
...@@ -136,6 +136,7 @@ static int watch_otherend(struct xenbus_device *dev) ...@@ -136,6 +136,7 @@ static int watch_otherend(struct xenbus_device *dev)
container_of(dev->dev.bus, struct xen_bus_type, bus); container_of(dev->dev.bus, struct xen_bus_type, bus);
return xenbus_watch_pathfmt(dev, &dev->otherend_watch, return xenbus_watch_pathfmt(dev, &dev->otherend_watch,
bus->otherend_will_handle,
bus->otherend_changed, bus->otherend_changed,
"%s/%s", dev->otherend, "state"); "%s/%s", dev->otherend, "state");
} }
......
...@@ -180,6 +180,12 @@ static int xenbus_probe_backend(struct xen_bus_type *bus, const char *type, ...@@ -180,6 +180,12 @@ static int xenbus_probe_backend(struct xen_bus_type *bus, const char *type,
return err; return err;
} }
static bool frontend_will_handle(struct xenbus_watch *watch,
const char *path, const char *token)
{
return watch->nr_pending == 0;
}
static void frontend_changed(struct xenbus_watch *watch, static void frontend_changed(struct xenbus_watch *watch,
const char *path, const char *token) const char *path, const char *token)
{ {
...@@ -191,6 +197,7 @@ static struct xen_bus_type xenbus_backend = { ...@@ -191,6 +197,7 @@ static struct xen_bus_type xenbus_backend = {
.levels = 3, /* backend/type/<frontend>/<id> */ .levels = 3, /* backend/type/<frontend>/<id> */
.get_bus_id = backend_bus_id, .get_bus_id = backend_bus_id,
.probe = xenbus_probe_backend, .probe = xenbus_probe_backend,
.otherend_will_handle = frontend_will_handle,
.otherend_changed = frontend_changed, .otherend_changed = frontend_changed,
.bus = { .bus = {
.name = "xen-backend", .name = "xen-backend",
......
...@@ -705,9 +705,13 @@ int xs_watch_msg(struct xs_watch_event *event) ...@@ -705,9 +705,13 @@ int xs_watch_msg(struct xs_watch_event *event)
spin_lock(&watches_lock); spin_lock(&watches_lock);
event->handle = find_watch(event->token); 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); spin_lock(&watch_events_lock);
list_add_tail(&event->list, &watch_events); list_add_tail(&event->list, &watch_events);
event->handle->nr_pending++;
wake_up(&watch_events_waitq); wake_up(&watch_events_waitq);
spin_unlock(&watch_events_lock); spin_unlock(&watch_events_lock);
} else } else
...@@ -765,6 +769,8 @@ int register_xenbus_watch(struct xenbus_watch *watch) ...@@ -765,6 +769,8 @@ int register_xenbus_watch(struct xenbus_watch *watch)
sprintf(token, "%lX", (long)watch); sprintf(token, "%lX", (long)watch);
watch->nr_pending = 0;
down_read(&xs_watch_rwsem); down_read(&xs_watch_rwsem);
spin_lock(&watches_lock); spin_lock(&watches_lock);
...@@ -814,11 +820,14 @@ void unregister_xenbus_watch(struct xenbus_watch *watch) ...@@ -814,11 +820,14 @@ void unregister_xenbus_watch(struct xenbus_watch *watch)
/* Cancel pending watch events. */ /* Cancel pending watch events. */
spin_lock(&watch_events_lock); spin_lock(&watch_events_lock);
list_for_each_entry_safe(event, tmp, &watch_events, list) { if (watch->nr_pending) {
if (event->handle != watch) list_for_each_entry_safe(event, tmp, &watch_events, list) {
continue; if (event->handle != watch)
list_del(&event->list); continue;
kfree(event); list_del(&event->list);
kfree(event);
}
watch->nr_pending = 0;
} }
spin_unlock(&watch_events_lock); spin_unlock(&watch_events_lock);
...@@ -865,7 +874,6 @@ void xs_suspend_cancel(void) ...@@ -865,7 +874,6 @@ void xs_suspend_cancel(void)
static int xenwatch_thread(void *unused) static int xenwatch_thread(void *unused)
{ {
struct list_head *ent;
struct xs_watch_event *event; struct xs_watch_event *event;
xenwatch_pid = current->pid; xenwatch_pid = current->pid;
...@@ -880,13 +888,15 @@ static int xenwatch_thread(void *unused) ...@@ -880,13 +888,15 @@ static int xenwatch_thread(void *unused)
mutex_lock(&xenwatch_mutex); mutex_lock(&xenwatch_mutex);
spin_lock(&watch_events_lock); spin_lock(&watch_events_lock);
ent = watch_events.next; event = list_first_entry_or_null(&watch_events,
if (ent != &watch_events) struct xs_watch_event, list);
list_del(ent); if (event) {
list_del(&event->list);
event->handle->nr_pending--;
}
spin_unlock(&watch_events_lock); spin_unlock(&watch_events_lock);
if (ent != &watch_events) { if (event) {
event = list_entry(ent, struct xs_watch_event, list);
event->handle->callback(event->handle, event->path, event->handle->callback(event->handle, event->path,
event->token); event->token);
kfree(event); kfree(event);
......
...@@ -61,6 +61,15 @@ struct xenbus_watch ...@@ -61,6 +61,15 @@ struct xenbus_watch
/* Path being watched. */ /* Path being watched. */
const char *node; const char *node;
unsigned int nr_pending;
/*
* 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). */ /* Callback (executed in a process context with no locks held). */
void (*callback)(struct xenbus_watch *, void (*callback)(struct xenbus_watch *,
const char *path, const char *token); const char *path, const char *token);
...@@ -197,10 +206,14 @@ void xenbus_probe(struct work_struct *); ...@@ -197,10 +206,14 @@ void xenbus_probe(struct work_struct *);
int xenbus_watch_path(struct xenbus_device *dev, const char *path, int xenbus_watch_path(struct xenbus_device *dev, const char *path,
struct xenbus_watch *watch, struct xenbus_watch *watch,
bool (*will_handle)(struct xenbus_watch *,
const char *, const char *),
void (*callback)(struct xenbus_watch *, void (*callback)(struct xenbus_watch *,
const char *, const char *)); const char *, const char *));
__printf(4, 5) __printf(5, 6)
int xenbus_watch_pathfmt(struct xenbus_device *dev, struct xenbus_watch *watch, int xenbus_watch_pathfmt(struct xenbus_device *dev, struct xenbus_watch *watch,
bool (*will_handle)(struct xenbus_watch *,
const char *, const char *),
void (*callback)(struct xenbus_watch *, void (*callback)(struct xenbus_watch *,
const char *, const char *), const char *, const char *),
const char *pathfmt, ...); const char *pathfmt, ...);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment