Skip to content

Commit

Permalink
Merge tag 'for-linus-4.18-rc2-tag' of git://git.kernel.org/pub/scm/li…
Browse files Browse the repository at this point in the history
…nux/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
  • Loading branch information
torvalds committed Jun 23, 2018
2 parents 894b8c0 + eef04c7 commit 4ab59fc
Show file tree
Hide file tree
Showing 14 changed files with 297 additions and 22 deletions.
7 changes: 4 additions & 3 deletions arch/arm/xen/enlighten.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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);
Expand Down
7 changes: 7 additions & 0 deletions arch/x86/xen/enlighten.c
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
1 change: 1 addition & 0 deletions arch/x86/xen/enlighten_pv.c
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down
1 change: 1 addition & 0 deletions arch/x86/xen/enlighten_pvh.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
33 changes: 26 additions & 7 deletions drivers/scsi/xen-scsifront.c
Original file line number Diff line number Diff line change
Expand Up @@ -654,21 +654,33 @@ 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;
}

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 = {
Expand Down Expand Up @@ -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:
Expand All @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion drivers/xen/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
2 changes: 0 additions & 2 deletions drivers/xen/events/events_base.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down
4 changes: 2 additions & 2 deletions drivers/xen/grant-table.c
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -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
Expand Down
18 changes: 15 additions & 3 deletions drivers/xen/manage.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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;
Expand Down
210 changes: 210 additions & 0 deletions drivers/xen/privcmd-buf.c
Original file line number Diff line number Diff line change
@@ -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,
};
Loading

0 comments on commit 4ab59fc

Please sign in to comment.