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:
Коммит
4ab59fcfd5
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
};
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
Загрузка…
Ссылка в новой задаче