xen: fixes for 4.18-rc2

-----BEGIN PGP SIGNATURE-----
 
 iHUEABYIAB0WIQRTLbB6QfY48x44uB6AXGG7T9hjvgUCWy0LEwAKCRCAXGG7T9hj
 vgbIAQD0rMLgEvvpdyvYpaHEBj9w40olCNh8ur49FRSPAdfh/QEArOtqO0OM+6ju
 RGmsIr/A4C8L80HPN4u/iIWXqJDbJwA=
 =DnvK
 -----END PGP SIGNATURE-----

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
This commit is contained in:
Linus Torvalds 2018-06-23 20:44:11 +08:00
commit 4ab59fcfd5
14 changed files with 297 additions and 22 deletions

View File

@ -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;
uint32_t xen_start_flags;
EXPORT_SYMBOL(xen_start_flags);
int xen_remap_domain_gfn_array(struct vm_area_struct *vma,
unsigned long addr,
xen_pfn_t *gfn, int nr,
@ -293,9 +296,7 @@ void __init xen_early_init(void)
xen_setup_features();
if (xen_feature(XENFEAT_dom0))
xen_start_info->flags |= SIF_INITDOMAIN|SIF_PRIVILEGED;
else
xen_start_info->flags &= ~(SIF_INITDOMAIN|SIF_PRIVILEGED);
xen_start_flags |= SIF_INITDOMAIN|SIF_PRIVILEGED;
if (!console_set_on_cmdline && !xen_initial_domain())
add_preferred_console("hvc", 0, NULL);

View File

@ -64,6 +64,13 @@ struct shared_info xen_dummy_shared_info;
__read_mostly int 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
* page as soon as fixmap is up and running.

View File

@ -1203,6 +1203,7 @@ asmlinkage __visible void __init xen_start_kernel(void)
return;
xen_domain_type = XEN_PV_DOMAIN;
xen_start_flags = xen_start_info->flags;
xen_setup_features();

View File

@ -97,6 +97,7 @@ void __init xen_prepare_pvh(void)
}
xen_pvh = 1;
xen_start_flags = pvh_start_info.flags;
msr = cpuid_ebx(xen_cpuid_base() + 2);
pfn = __pa(hypercall_page);

View File

@ -654,10 +654,17 @@ static int scsifront_dev_reset_handler(struct scsi_cmnd *sc)
static int scsifront_sdev_configure(struct scsi_device *sdev)
{
struct vscsifrnt_info *info = shost_priv(sdev->host);
int err;
if (info && current == info->curr)
xenbus_printf(XBT_NIL, info->dev->nodename,
if (info && current == info->curr) {
err = xenbus_printf(XBT_NIL, info->dev->nodename,
info->dev_state_path, "%d", XenbusStateConnected);
if (err) {
xenbus_dev_error(info->dev, err,
"%s: writing dev_state_path", __func__);
return err;
}
}
return 0;
}
@ -665,10 +672,15 @@ static int scsifront_sdev_configure(struct scsi_device *sdev)
static void scsifront_sdev_destroy(struct scsi_device *sdev)
{
struct vscsifrnt_info *info = shost_priv(sdev->host);
int err;
if (info && current == info->curr)
xenbus_printf(XBT_NIL, info->dev->nodename,
if (info && current == info->curr) {
err = xenbus_printf(XBT_NIL, info->dev->nodename,
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 = {
@ -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)) {
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,
"%d", XenbusStateClosed);
if (err)
xenbus_dev_error(dev, err,
"%s: writing dev_state_path", __func__);
}
break;
case VSCSIFRONT_OP_DEL_LUN:
@ -1019,10 +1034,14 @@ static void scsifront_do_lun_hotplug(struct vscsifrnt_info *info, int op)
}
break;
case VSCSIFRONT_OP_READD_LUN:
if (device_state == XenbusStateConnected)
xenbus_printf(XBT_NIL, dev->nodename,
if (device_state == XenbusStateConnected) {
err = xenbus_printf(XBT_NIL, dev->nodename,
info->dev_state_path,
"%d", XenbusStateConnected);
if (err)
xenbus_dev_error(dev, err,
"%s: writing dev_state_path", __func__);
}
break;
default:
break;

View File

@ -41,4 +41,4 @@ obj-$(CONFIG_XEN_PVCALLS_FRONTEND) += pvcalls-front.o
xen-evtchn-y := evtchn.o
xen-gntdev-y := gntdev.o
xen-gntalloc-y := gntalloc.o
xen-privcmd-y := privcmd.o
xen-privcmd-y := privcmd.o privcmd-buf.o

View File

@ -628,8 +628,6 @@ static void __unbind_from_irq(unsigned int irq)
xen_irq_info_cleanup(info);
}
BUG_ON(info_for_irq(irq)->type == IRQT_UNBOUND);
xen_free_irq(irq);
}

View File

@ -799,7 +799,7 @@ int gnttab_alloc_pages(int nr_pages, struct page **pages)
return 0;
}
EXPORT_SYMBOL(gnttab_alloc_pages);
EXPORT_SYMBOL_GPL(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)
}
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) */
#define MAX_DELAY 256

View File

@ -289,8 +289,15 @@ static void sysrq_handler(struct xenbus_watch *watch, const char *path,
return;
}
if (sysrq_key != '\0')
xenbus_printf(xbt, "control", "sysrq", "%c", '\0');
if (sysrq_key != '\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);
if (err == -EAGAIN)
@ -342,7 +349,12 @@ static int setup_shutdown_watcher(void)
continue;
snprintf(node, FEATURE_PATH_SIZE, "feature-%s",
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;

210
drivers/xen/privcmd-buf.c Normal file
View File

@ -0,0 +1,210 @@
// 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,
};

View File

@ -1007,12 +1007,21 @@ static int __init privcmd_init(void)
pr_err("Could not register Xen privcmd device\n");
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;
}
static void __exit privcmd_exit(void)
{
misc_deregister(&privcmd_dev);
misc_deregister(&xen_privcmdbuf_dev);
}
module_init(privcmd_init);

View File

@ -1,3 +1,6 @@
#include <linux/fs.h>
extern const struct file_operations xen_privcmd_fops;
extern const struct file_operations xen_privcmdbuf_fops;
extern struct miscdevice xen_privcmdbuf_dev;

View File

@ -1012,6 +1012,7 @@ static void scsiback_do_add_lun(struct vscsibk_info *info, const char *state,
{
struct v2p_entry *entry;
unsigned long flags;
int err;
if (try) {
spin_lock_irqsave(&info->v2p_lock, flags);
@ -1027,8 +1028,11 @@ static void scsiback_do_add_lun(struct vscsibk_info *info, const char *state,
scsiback_del_translation_entry(info, vir);
}
} else if (!try) {
xenbus_printf(XBT_NIL, info->dev->nodename, state,
err = xenbus_printf(XBT_NIL, info->dev->nodename, state,
"%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,
snprintf(str, sizeof(str), "vscsi-devs/%s/p-dev", ent);
val = xenbus_read(XBT_NIL, dev->nodename, str, NULL);
if (IS_ERR(val)) {
xenbus_printf(XBT_NIL, dev->nodename, state,
err = xenbus_printf(XBT_NIL, dev->nodename, state,
"%d", XenbusStateClosed);
if (err)
xenbus_dev_error(info->dev, err,
"%s: writing %s", __func__, state);
return;
}
strlcpy(phy, val, VSCSI_NAMELEN);
@ -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",
&vir.hst, &vir.chn, &vir.tgt, &vir.lun);
if (XENBUS_EXIST_ERR(err)) {
xenbus_printf(XBT_NIL, dev->nodename, state,
err = xenbus_printf(XBT_NIL, dev->nodename, state,
"%d", XenbusStateClosed);
if (err)
xenbus_dev_error(info->dev, err,
"%s: writing %s", __func__, state);
return;
}

View File

@ -25,12 +25,16 @@ extern bool xen_pvh;
#define xen_hvm_domain() (xen_domain_type == XEN_HVM_DOMAIN)
#define xen_pvh_domain() (xen_pvh)
#include <linux/types.h>
extern uint32_t xen_start_flags;
#ifdef CONFIG_XEN_DOM0
#include <xen/interface/xen.h>
#include <asm/xen/hypervisor.h>
#define xen_initial_domain() (xen_domain() && \
xen_start_info && xen_start_info->flags & SIF_INITDOMAIN)
(xen_start_flags & SIF_INITDOMAIN))
#else /* !CONFIG_XEN_DOM0 */
#define xen_initial_domain() (0)
#endif /* CONFIG_XEN_DOM0 */