Commit 4ab59fcf authored by Linus Torvalds's avatar Linus Torvalds

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

Pull xen fixes from Juergen Gross:
 "This contains the following fixes/cleanups:

   - the removal of a BUG_ON() which wasn't necessary and which could
     trigger now due to a recent change

   - a correction of a long standing bug happening very rarely in Xen
     dom0 when a hypercall buffer from user land was not accessible by
     the hypervisor for very short periods of time due to e.g. page
     migration or compaction

   - usage of EXPORT_SYMBOL_GPL() instead of EXPORT_SYMBOL() in a
     Xen-related driver (no breakage possible as using those symbols
     without others already exported via EXPORT-SYMBOL_GPL() wouldn't
     make any sense)

   - a simplification for Xen PVH or Xen ARM guests

   - some additional error handling for callers of xenbus_printf()"

* tag 'for-linus-4.18-rc2-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/xen/tip:
  xen: Remove unnecessary BUG_ON from __unbind_from_irq()
  xen: add new hypercall buffer mapping device
  xen/scsiback: add error handling for xenbus_printf
  scsi: xen-scsifront: add error handling for xenbus_printf
  xen/grant-table: Export gnttab_{alloc|free}_pages as GPL
  xen: add error handling for xenbus_printf
  xen: share start flags between PV and PVH
parents 894b8c00 eef04c7b
...@@ -59,6 +59,9 @@ struct xen_memory_region xen_extra_mem[XEN_EXTRA_MEM_MAX_REGIONS] __initdata; ...@@ -59,6 +59,9 @@ struct xen_memory_region xen_extra_mem[XEN_EXTRA_MEM_MAX_REGIONS] __initdata;
static __read_mostly unsigned int xen_events_irq; static __read_mostly unsigned int xen_events_irq;
uint32_t xen_start_flags;
EXPORT_SYMBOL(xen_start_flags);
int xen_remap_domain_gfn_array(struct vm_area_struct *vma, int xen_remap_domain_gfn_array(struct vm_area_struct *vma,
unsigned long addr, unsigned long addr,
xen_pfn_t *gfn, int nr, xen_pfn_t *gfn, int nr,
...@@ -293,9 +296,7 @@ void __init xen_early_init(void) ...@@ -293,9 +296,7 @@ void __init xen_early_init(void)
xen_setup_features(); xen_setup_features();
if (xen_feature(XENFEAT_dom0)) if (xen_feature(XENFEAT_dom0))
xen_start_info->flags |= SIF_INITDOMAIN|SIF_PRIVILEGED; xen_start_flags |= SIF_INITDOMAIN|SIF_PRIVILEGED;
else
xen_start_info->flags &= ~(SIF_INITDOMAIN|SIF_PRIVILEGED);
if (!console_set_on_cmdline && !xen_initial_domain()) if (!console_set_on_cmdline && !xen_initial_domain())
add_preferred_console("hvc", 0, NULL); add_preferred_console("hvc", 0, NULL);
......
...@@ -64,6 +64,13 @@ struct shared_info xen_dummy_shared_info; ...@@ -64,6 +64,13 @@ struct shared_info xen_dummy_shared_info;
__read_mostly int xen_have_vector_callback; __read_mostly int xen_have_vector_callback;
EXPORT_SYMBOL_GPL(xen_have_vector_callback); EXPORT_SYMBOL_GPL(xen_have_vector_callback);
/*
* NB: needs to live in .data because it's used by xen_prepare_pvh which runs
* before clearing the bss.
*/
uint32_t xen_start_flags __attribute__((section(".data"))) = 0;
EXPORT_SYMBOL(xen_start_flags);
/* /*
* Point at some empty memory to start with. We map the real shared_info * Point at some empty memory to start with. We map the real shared_info
* page as soon as fixmap is up and running. * page as soon as fixmap is up and running.
......
...@@ -1203,6 +1203,7 @@ asmlinkage __visible void __init xen_start_kernel(void) ...@@ -1203,6 +1203,7 @@ asmlinkage __visible void __init xen_start_kernel(void)
return; return;
xen_domain_type = XEN_PV_DOMAIN; xen_domain_type = XEN_PV_DOMAIN;
xen_start_flags = xen_start_info->flags;
xen_setup_features(); xen_setup_features();
......
...@@ -97,6 +97,7 @@ void __init xen_prepare_pvh(void) ...@@ -97,6 +97,7 @@ void __init xen_prepare_pvh(void)
} }
xen_pvh = 1; xen_pvh = 1;
xen_start_flags = pvh_start_info.flags;
msr = cpuid_ebx(xen_cpuid_base() + 2); msr = cpuid_ebx(xen_cpuid_base() + 2);
pfn = __pa(hypercall_page); pfn = __pa(hypercall_page);
......
...@@ -654,10 +654,17 @@ static int scsifront_dev_reset_handler(struct scsi_cmnd *sc) ...@@ -654,10 +654,17 @@ static int scsifront_dev_reset_handler(struct scsi_cmnd *sc)
static int scsifront_sdev_configure(struct scsi_device *sdev) static int scsifront_sdev_configure(struct scsi_device *sdev)
{ {
struct vscsifrnt_info *info = shost_priv(sdev->host); struct vscsifrnt_info *info = shost_priv(sdev->host);
int err;
if (info && current == info->curr) if (info && current == info->curr) {
xenbus_printf(XBT_NIL, info->dev->nodename, err = xenbus_printf(XBT_NIL, info->dev->nodename,
info->dev_state_path, "%d", XenbusStateConnected); info->dev_state_path, "%d", XenbusStateConnected);
if (err) {
xenbus_dev_error(info->dev, err,
"%s: writing dev_state_path", __func__);
return err;
}
}
return 0; return 0;
} }
...@@ -665,10 +672,15 @@ static int scsifront_sdev_configure(struct scsi_device *sdev) ...@@ -665,10 +672,15 @@ static int scsifront_sdev_configure(struct scsi_device *sdev)
static void scsifront_sdev_destroy(struct scsi_device *sdev) static void scsifront_sdev_destroy(struct scsi_device *sdev)
{ {
struct vscsifrnt_info *info = shost_priv(sdev->host); struct vscsifrnt_info *info = shost_priv(sdev->host);
int err;
if (info && current == info->curr) if (info && current == info->curr) {
xenbus_printf(XBT_NIL, info->dev->nodename, err = xenbus_printf(XBT_NIL, info->dev->nodename,
info->dev_state_path, "%d", XenbusStateClosed); info->dev_state_path, "%d", XenbusStateClosed);
if (err)
xenbus_dev_error(info->dev, err,
"%s: writing dev_state_path", __func__);
}
} }
static struct scsi_host_template scsifront_sht = { static struct scsi_host_template scsifront_sht = {
...@@ -1003,9 +1015,12 @@ static void scsifront_do_lun_hotplug(struct vscsifrnt_info *info, int op) ...@@ -1003,9 +1015,12 @@ static void scsifront_do_lun_hotplug(struct vscsifrnt_info *info, int op)
if (scsi_add_device(info->host, chn, tgt, lun)) { if (scsi_add_device(info->host, chn, tgt, lun)) {
dev_err(&dev->dev, "scsi_add_device\n"); dev_err(&dev->dev, "scsi_add_device\n");
xenbus_printf(XBT_NIL, dev->nodename, err = xenbus_printf(XBT_NIL, dev->nodename,
info->dev_state_path, info->dev_state_path,
"%d", XenbusStateClosed); "%d", XenbusStateClosed);
if (err)
xenbus_dev_error(dev, err,
"%s: writing dev_state_path", __func__);
} }
break; break;
case VSCSIFRONT_OP_DEL_LUN: case VSCSIFRONT_OP_DEL_LUN:
...@@ -1019,10 +1034,14 @@ static void scsifront_do_lun_hotplug(struct vscsifrnt_info *info, int op) ...@@ -1019,10 +1034,14 @@ static void scsifront_do_lun_hotplug(struct vscsifrnt_info *info, int op)
} }
break; break;
case VSCSIFRONT_OP_READD_LUN: case VSCSIFRONT_OP_READD_LUN:
if (device_state == XenbusStateConnected) if (device_state == XenbusStateConnected) {
xenbus_printf(XBT_NIL, dev->nodename, err = xenbus_printf(XBT_NIL, dev->nodename,
info->dev_state_path, info->dev_state_path,
"%d", XenbusStateConnected); "%d", XenbusStateConnected);
if (err)
xenbus_dev_error(dev, err,
"%s: writing dev_state_path", __func__);
}
break; break;
default: default:
break; break;
......
...@@ -41,4 +41,4 @@ obj-$(CONFIG_XEN_PVCALLS_FRONTEND) += pvcalls-front.o ...@@ -41,4 +41,4 @@ obj-$(CONFIG_XEN_PVCALLS_FRONTEND) += pvcalls-front.o
xen-evtchn-y := evtchn.o xen-evtchn-y := evtchn.o
xen-gntdev-y := gntdev.o xen-gntdev-y := gntdev.o
xen-gntalloc-y := gntalloc.o xen-gntalloc-y := gntalloc.o
xen-privcmd-y := privcmd.o xen-privcmd-y := privcmd.o privcmd-buf.o
...@@ -628,8 +628,6 @@ static void __unbind_from_irq(unsigned int irq) ...@@ -628,8 +628,6 @@ static void __unbind_from_irq(unsigned int irq)
xen_irq_info_cleanup(info); xen_irq_info_cleanup(info);
} }
BUG_ON(info_for_irq(irq)->type == IRQT_UNBOUND);
xen_free_irq(irq); xen_free_irq(irq);
} }
......
...@@ -799,7 +799,7 @@ int gnttab_alloc_pages(int nr_pages, struct page **pages) ...@@ -799,7 +799,7 @@ int gnttab_alloc_pages(int nr_pages, struct page **pages)
return 0; return 0;
} }
EXPORT_SYMBOL(gnttab_alloc_pages); EXPORT_SYMBOL_GPL(gnttab_alloc_pages);
/** /**
* gnttab_free_pages - free pages allocated by gnttab_alloc_pages() * gnttab_free_pages - free pages allocated by gnttab_alloc_pages()
...@@ -820,7 +820,7 @@ void gnttab_free_pages(int nr_pages, struct page **pages) ...@@ -820,7 +820,7 @@ void gnttab_free_pages(int nr_pages, struct page **pages)
} }
free_xenballooned_pages(nr_pages, pages); free_xenballooned_pages(nr_pages, pages);
} }
EXPORT_SYMBOL(gnttab_free_pages); EXPORT_SYMBOL_GPL(gnttab_free_pages);
/* Handling of paged out grant targets (GNTST_eagain) */ /* Handling of paged out grant targets (GNTST_eagain) */
#define MAX_DELAY 256 #define MAX_DELAY 256
......
...@@ -289,8 +289,15 @@ static void sysrq_handler(struct xenbus_watch *watch, const char *path, ...@@ -289,8 +289,15 @@ static void sysrq_handler(struct xenbus_watch *watch, const char *path,
return; return;
} }
if (sysrq_key != '\0') if (sysrq_key != '\0') {
xenbus_printf(xbt, "control", "sysrq", "%c", '\0'); err = xenbus_printf(xbt, "control", "sysrq", "%c", '\0');
if (err) {
pr_err("%s: Error %d writing sysrq in control/sysrq\n",
__func__, err);
xenbus_transaction_end(xbt, 1);
return;
}
}
err = xenbus_transaction_end(xbt, 0); err = xenbus_transaction_end(xbt, 0);
if (err == -EAGAIN) if (err == -EAGAIN)
...@@ -342,7 +349,12 @@ static int setup_shutdown_watcher(void) ...@@ -342,7 +349,12 @@ static int setup_shutdown_watcher(void)
continue; continue;
snprintf(node, FEATURE_PATH_SIZE, "feature-%s", snprintf(node, FEATURE_PATH_SIZE, "feature-%s",
shutdown_handlers[idx].command); shutdown_handlers[idx].command);
xenbus_printf(XBT_NIL, "control", node, "%u", 1); err = xenbus_printf(XBT_NIL, "control", node, "%u", 1);
if (err) {
pr_err("%s: Error %d writing %s\n", __func__,
err, node);
return err;
}
} }
return 0; return 0;
......
// SPDX-License-Identifier: GPL-2.0 OR MIT
/******************************************************************************
* privcmd-buf.c
*
* Mmap of hypercall buffers.
*
* Copyright (c) 2018 Juergen Gross
*/
#define pr_fmt(fmt) "xen:" KBUILD_MODNAME ": " fmt
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/list.h>
#include <linux/miscdevice.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include "privcmd.h"
MODULE_LICENSE("GPL");
static unsigned int limit = 64;
module_param(limit, uint, 0644);
MODULE_PARM_DESC(limit, "Maximum number of pages that may be allocated by "
"the privcmd-buf device per open file");
struct privcmd_buf_private {
struct mutex lock;
struct list_head list;
unsigned int allocated;
};
struct privcmd_buf_vma_private {
struct privcmd_buf_private *file_priv;
struct list_head list;
unsigned int users;
unsigned int n_pages;
struct page *pages[];
};
static int privcmd_buf_open(struct inode *ino, struct file *file)
{
struct privcmd_buf_private *file_priv;
file_priv = kzalloc(sizeof(*file_priv), GFP_KERNEL);
if (!file_priv)
return -ENOMEM;
mutex_init(&file_priv->lock);
INIT_LIST_HEAD(&file_priv->list);
file->private_data = file_priv;
return 0;
}
static void privcmd_buf_vmapriv_free(struct privcmd_buf_vma_private *vma_priv)
{
unsigned int i;
vma_priv->file_priv->allocated -= vma_priv->n_pages;
list_del(&vma_priv->list);
for (i = 0; i < vma_priv->n_pages; i++)
if (vma_priv->pages[i])
__free_page(vma_priv->pages[i]);
kfree(vma_priv);
}
static int privcmd_buf_release(struct inode *ino, struct file *file)
{
struct privcmd_buf_private *file_priv = file->private_data;
struct privcmd_buf_vma_private *vma_priv;
mutex_lock(&file_priv->lock);
while (!list_empty(&file_priv->list)) {
vma_priv = list_first_entry(&file_priv->list,
struct privcmd_buf_vma_private,
list);
privcmd_buf_vmapriv_free(vma_priv);
}
mutex_unlock(&file_priv->lock);
kfree(file_priv);
return 0;
}
static void privcmd_buf_vma_open(struct vm_area_struct *vma)
{
struct privcmd_buf_vma_private *vma_priv = vma->vm_private_data;
if (!vma_priv)
return;
mutex_lock(&vma_priv->file_priv->lock);
vma_priv->users++;
mutex_unlock(&vma_priv->file_priv->lock);
}
static void privcmd_buf_vma_close(struct vm_area_struct *vma)
{
struct privcmd_buf_vma_private *vma_priv = vma->vm_private_data;
struct privcmd_buf_private *file_priv;
if (!vma_priv)
return;
file_priv = vma_priv->file_priv;
mutex_lock(&file_priv->lock);
vma_priv->users--;
if (!vma_priv->users)
privcmd_buf_vmapriv_free(vma_priv);
mutex_unlock(&file_priv->lock);
}
static vm_fault_t privcmd_buf_vma_fault(struct vm_fault *vmf)
{
pr_debug("fault: vma=%p %lx-%lx, pgoff=%lx, uv=%p\n",
vmf->vma, vmf->vma->vm_start, vmf->vma->vm_end,
vmf->pgoff, (void *)vmf->address);
return VM_FAULT_SIGBUS;
}
static const struct vm_operations_struct privcmd_buf_vm_ops = {
.open = privcmd_buf_vma_open,
.close = privcmd_buf_vma_close,
.fault = privcmd_buf_vma_fault,
};
static int privcmd_buf_mmap(struct file *file, struct vm_area_struct *vma)
{
struct privcmd_buf_private *file_priv = file->private_data;
struct privcmd_buf_vma_private *vma_priv;
unsigned long count = vma_pages(vma);
unsigned int i;
int ret = 0;
if (!(vma->vm_flags & VM_SHARED) || count > limit ||
file_priv->allocated + count > limit)
return -EINVAL;
vma_priv = kzalloc(sizeof(*vma_priv) + count * sizeof(void *),
GFP_KERNEL);
if (!vma_priv)
return -ENOMEM;
vma_priv->n_pages = count;
count = 0;
for (i = 0; i < vma_priv->n_pages; i++) {
vma_priv->pages[i] = alloc_page(GFP_KERNEL | __GFP_ZERO);
if (!vma_priv->pages[i])
break;
count++;
}
mutex_lock(&file_priv->lock);
file_priv->allocated += count;
vma_priv->file_priv = file_priv;
vma_priv->users = 1;
vma->vm_flags |= VM_IO | VM_DONTEXPAND;
vma->vm_ops = &privcmd_buf_vm_ops;
vma->vm_private_data = vma_priv;
list_add(&vma_priv->list, &file_priv->list);
if (vma_priv->n_pages != count)
ret = -ENOMEM;
else
for (i = 0; i < vma_priv->n_pages; i++) {
ret = vm_insert_page(vma, vma->vm_start + i * PAGE_SIZE,
vma_priv->pages[i]);
if (ret)
break;
}
if (ret)
privcmd_buf_vmapriv_free(vma_priv);
mutex_unlock(&file_priv->lock);
return ret;
}
const struct file_operations xen_privcmdbuf_fops = {
.owner = THIS_MODULE,
.open = privcmd_buf_open,
.release = privcmd_buf_release,
.mmap = privcmd_buf_mmap,
};
EXPORT_SYMBOL_GPL(xen_privcmdbuf_fops);
struct miscdevice xen_privcmdbuf_dev = {
.minor = MISC_DYNAMIC_MINOR,
.name = "xen/hypercall",
.fops = &xen_privcmdbuf_fops,
};
...@@ -1007,12 +1007,21 @@ static int __init privcmd_init(void) ...@@ -1007,12 +1007,21 @@ static int __init privcmd_init(void)
pr_err("Could not register Xen privcmd device\n"); pr_err("Could not register Xen privcmd device\n");
return err; return err;
} }
err = misc_register(&xen_privcmdbuf_dev);
if (err != 0) {
pr_err("Could not register Xen hypercall-buf device\n");
misc_deregister(&privcmd_dev);
return err;
}
return 0; return 0;
} }
static void __exit privcmd_exit(void) static void __exit privcmd_exit(void)
{ {
misc_deregister(&privcmd_dev); misc_deregister(&privcmd_dev);
misc_deregister(&xen_privcmdbuf_dev);
} }
module_init(privcmd_init); module_init(privcmd_init);
......
#include <linux/fs.h> #include <linux/fs.h>
extern const struct file_operations xen_privcmd_fops; extern const struct file_operations xen_privcmd_fops;
extern const struct file_operations xen_privcmdbuf_fops;
extern struct miscdevice xen_privcmdbuf_dev;
...@@ -1012,6 +1012,7 @@ static void scsiback_do_add_lun(struct vscsibk_info *info, const char *state, ...@@ -1012,6 +1012,7 @@ static void scsiback_do_add_lun(struct vscsibk_info *info, const char *state,
{ {
struct v2p_entry *entry; struct v2p_entry *entry;
unsigned long flags; unsigned long flags;
int err;
if (try) { if (try) {
spin_lock_irqsave(&info->v2p_lock, flags); spin_lock_irqsave(&info->v2p_lock, flags);
...@@ -1027,8 +1028,11 @@ static void scsiback_do_add_lun(struct vscsibk_info *info, const char *state, ...@@ -1027,8 +1028,11 @@ static void scsiback_do_add_lun(struct vscsibk_info *info, const char *state,
scsiback_del_translation_entry(info, vir); scsiback_del_translation_entry(info, vir);
} }
} else if (!try) { } else if (!try) {
xenbus_printf(XBT_NIL, info->dev->nodename, state, err = xenbus_printf(XBT_NIL, info->dev->nodename, state,
"%d", XenbusStateClosed); "%d", XenbusStateClosed);
if (err)
xenbus_dev_error(info->dev, err,
"%s: writing %s", __func__, state);
} }
} }
...@@ -1067,8 +1071,11 @@ static void scsiback_do_1lun_hotplug(struct vscsibk_info *info, int op, ...@@ -1067,8 +1071,11 @@ static void scsiback_do_1lun_hotplug(struct vscsibk_info *info, int op,
snprintf(str, sizeof(str), "vscsi-devs/%s/p-dev", ent); snprintf(str, sizeof(str), "vscsi-devs/%s/p-dev", ent);
val = xenbus_read(XBT_NIL, dev->nodename, str, NULL); val = xenbus_read(XBT_NIL, dev->nodename, str, NULL);
if (IS_ERR(val)) { if (IS_ERR(val)) {
xenbus_printf(XBT_NIL, dev->nodename, state, err = xenbus_printf(XBT_NIL, dev->nodename, state,
"%d", XenbusStateClosed); "%d", XenbusStateClosed);
if (err)
xenbus_dev_error(info->dev, err,
"%s: writing %s", __func__, state);
return; return;
} }
strlcpy(phy, val, VSCSI_NAMELEN); strlcpy(phy, val, VSCSI_NAMELEN);
...@@ -1079,8 +1086,11 @@ static void scsiback_do_1lun_hotplug(struct vscsibk_info *info, int op, ...@@ -1079,8 +1086,11 @@ static void scsiback_do_1lun_hotplug(struct vscsibk_info *info, int op,
err = xenbus_scanf(XBT_NIL, dev->nodename, str, "%u:%u:%u:%u", err = xenbus_scanf(XBT_NIL, dev->nodename, str, "%u:%u:%u:%u",
&vir.hst, &vir.chn, &vir.tgt, &vir.lun); &vir.hst, &vir.chn, &vir.tgt, &vir.lun);
if (XENBUS_EXIST_ERR(err)) { if (XENBUS_EXIST_ERR(err)) {
xenbus_printf(XBT_NIL, dev->nodename, state, err = xenbus_printf(XBT_NIL, dev->nodename, state,
"%d", XenbusStateClosed); "%d", XenbusStateClosed);
if (err)
xenbus_dev_error(info->dev, err,
"%s: writing %s", __func__, state);
return; return;
} }
......
...@@ -25,12 +25,16 @@ extern bool xen_pvh; ...@@ -25,12 +25,16 @@ extern bool xen_pvh;
#define xen_hvm_domain() (xen_domain_type == XEN_HVM_DOMAIN) #define xen_hvm_domain() (xen_domain_type == XEN_HVM_DOMAIN)
#define xen_pvh_domain() (xen_pvh) #define xen_pvh_domain() (xen_pvh)
#include <linux/types.h>
extern uint32_t xen_start_flags;
#ifdef CONFIG_XEN_DOM0 #ifdef CONFIG_XEN_DOM0
#include <xen/interface/xen.h> #include <xen/interface/xen.h>
#include <asm/xen/hypervisor.h> #include <asm/xen/hypervisor.h>
#define xen_initial_domain() (xen_domain() && \ #define xen_initial_domain() (xen_domain() && \
xen_start_info && xen_start_info->flags & SIF_INITDOMAIN) (xen_start_flags & SIF_INITDOMAIN))
#else /* !CONFIG_XEN_DOM0 */ #else /* !CONFIG_XEN_DOM0 */
#define xen_initial_domain() (0) #define xen_initial_domain() (0)
#endif /* CONFIG_XEN_DOM0 */ #endif /* CONFIG_XEN_DOM0 */
......
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