Skip to content

Commit

Permalink
Merge tag 'for-linus-5.15-rc1-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 updates from Juergen Gross:

 - some small cleanups

 - a fix for a bug when running as Xen PV guest which could result in
   not all memory being transferred in case of a migration of the guest

 - a small series for getting rid of code for supporting very old Xen
   hypervisor versions nobody should be using since many years now

 - a series for hardening the Xen block frontend driver

 - a fix for Xen PV boot code issuing warning messages due to a stray
   preempt_disable() on the non-boot processors

* tag 'for-linus-5.15-rc1-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/xen/tip:
  xen: remove stray preempt_disable() from PV AP startup code
  xen/pcifront: Removed unnecessary __ref annotation
  x86: xen: platform-pci-unplug: use pr_err() and pr_warn() instead of raw printk()
  drivers/xen/xenbus/xenbus_client.c: fix bugon.cocci warnings
  xen/blkfront: don't trust the backend response data blindly
  xen/blkfront: don't take local copy of a request from the ring page
  xen/blkfront: read response from backend only once
  xen: assume XENFEAT_gnttab_map_avail_bits being set for pv guests
  xen: assume XENFEAT_mmu_pt_update_preserve_ad being set for pv guests
  xen: check required Xen features
  xen: fix setting of max_pfn in shared_info
  • Loading branch information
Linus Torvalds committed Sep 2, 2021
2 parents a2d616b + 58e6360 commit 9ae5fce
Show file tree
Hide file tree
Showing 10 changed files with 141 additions and 115 deletions.
12 changes: 2 additions & 10 deletions arch/x86/xen/enlighten_pv.c
Original file line number Diff line number Diff line change
Expand Up @@ -116,9 +116,8 @@ static void __init xen_banner(void)
HYPERVISOR_xen_version(XENVER_extraversion, &extra);

pr_info("Booting paravirtualized kernel on %s\n", pv_info.name);
printk(KERN_INFO "Xen version: %d.%d%s%s\n",
version >> 16, version & 0xffff, extra.extraversion,
xen_feature(XENFEAT_mmu_pt_update_preserve_ad) ? " (preserve-AD)" : "");
pr_info("Xen version: %d.%d%s (preserve-AD)\n",
version >> 16, version & 0xffff, extra.extraversion);
}

static void __init xen_pv_init_platform(void)
Expand Down Expand Up @@ -1302,13 +1301,6 @@ asmlinkage __visible void __init xen_start_kernel(void)
xen_init_apic();
#endif

if (xen_feature(XENFEAT_mmu_pt_update_preserve_ad)) {
pv_ops.mmu.ptep_modify_prot_start =
xen_ptep_modify_prot_start;
pv_ops.mmu.ptep_modify_prot_commit =
xen_ptep_modify_prot_commit;
}

machine_ops = xen_machine_ops;

/*
Expand Down
4 changes: 2 additions & 2 deletions arch/x86/xen/mmu_pv.c
Original file line number Diff line number Diff line change
Expand Up @@ -2099,8 +2099,8 @@ static const struct pv_mmu_ops xen_mmu_ops __initconst = {
.set_pte = xen_set_pte_init,
.set_pmd = xen_set_pmd_hyper,

.ptep_modify_prot_start = __ptep_modify_prot_start,
.ptep_modify_prot_commit = __ptep_modify_prot_commit,
.ptep_modify_prot_start = xen_ptep_modify_prot_start,
.ptep_modify_prot_commit = xen_ptep_modify_prot_commit,

.pte_val = PV_CALLEE_SAVE(xen_pte_val),
.pgd_val = PV_CALLEE_SAVE(xen_pgd_val),
Expand Down
4 changes: 2 additions & 2 deletions arch/x86/xen/p2m.c
Original file line number Diff line number Diff line change
Expand Up @@ -618,8 +618,8 @@ int xen_alloc_p2m_entry(unsigned long pfn)
}

/* Expanded the p2m? */
if (pfn > xen_p2m_last_pfn) {
xen_p2m_last_pfn = pfn;
if (pfn >= xen_p2m_last_pfn) {
xen_p2m_last_pfn = ALIGN(pfn + 1, P2M_PER_PAGE);
HYPERVISOR_shared_info->arch.max_pfn = xen_p2m_last_pfn;
}

Expand Down
16 changes: 9 additions & 7 deletions arch/x86/xen/platform-pci-unplug.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
* Copyright (c) 2010, Citrix
*/

#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

#include <linux/init.h>
#include <linux/io.h>
#include <linux/export.h>
Expand All @@ -30,26 +32,26 @@ static int check_platform_magic(void)

magic = inw(XEN_IOPORT_MAGIC);
if (magic != XEN_IOPORT_MAGIC_VAL) {
printk(KERN_ERR "Xen Platform PCI: unrecognised magic value\n");
pr_err("Xen Platform PCI: unrecognised magic value\n");
return XEN_PLATFORM_ERR_MAGIC;
}

protocol = inb(XEN_IOPORT_PROTOVER);

printk(KERN_DEBUG "Xen Platform PCI: I/O protocol version %d\n",
pr_debug("Xen Platform PCI: I/O protocol version %d\n",
protocol);

switch (protocol) {
case 1:
outw(XEN_IOPORT_LINUX_PRODNUM, XEN_IOPORT_PRODNUM);
outl(XEN_IOPORT_LINUX_DRVVER, XEN_IOPORT_DRVVER);
if (inw(XEN_IOPORT_MAGIC) != XEN_IOPORT_MAGIC_VAL) {
printk(KERN_ERR "Xen Platform: blacklisted by host\n");
pr_err("Xen Platform: blacklisted by host\n");
return XEN_PLATFORM_ERR_BLACKLIST;
}
break;
default:
printk(KERN_WARNING "Xen Platform PCI: unknown I/O protocol version\n");
pr_warn("Xen Platform PCI: unknown I/O protocol version\n");
return XEN_PLATFORM_ERR_PROTOCOL;
}

Expand Down Expand Up @@ -155,12 +157,12 @@ void xen_unplug_emulated_devices(void)
* been compiled for this kernel (modules or built-in are both OK). */
if (!xen_emul_unplug) {
if (xen_must_unplug_nics()) {
printk(KERN_INFO "Netfront and the Xen platform PCI driver have "
pr_info("Netfront and the Xen platform PCI driver have "
"been compiled for this kernel: unplug emulated NICs.\n");
xen_emul_unplug |= XEN_UNPLUG_ALL_NICS;
}
if (xen_must_unplug_disks()) {
printk(KERN_INFO "Blkfront and the Xen platform PCI driver have "
pr_info("Blkfront and the Xen platform PCI driver have "
"been compiled for this kernel: unplug emulated disks.\n"
"You might have to change the root device\n"
"from /dev/hd[a-d] to /dev/xvd[a-d]\n"
Expand Down Expand Up @@ -200,7 +202,7 @@ static int __init parse_xen_emul_unplug(char *arg)
else if (!strncmp(p, "never", l))
xen_emul_unplug |= XEN_UNPLUG_NEVER;
else
printk(KERN_WARNING "unrecognised option '%s' "
pr_warn("unrecognised option '%s' "
"in parameter 'xen_emul_unplug'\n", p);
}
return 0;
Expand Down
1 change: 0 additions & 1 deletion arch/x86/xen/smp_pv.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@ static void cpu_bringup(void)
cr4_init();
cpu_init();
touch_softlockup_watchdog();
preempt_disable();

/* PVH runs in ring 0 and allows us to do native syscalls. Yay! */
if (!xen_feature(XENFEAT_supervisor_mode_kernel)) {
Expand Down
126 changes: 84 additions & 42 deletions drivers/block/xen-blkfront.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ enum blkif_state {
BLKIF_STATE_DISCONNECTED,
BLKIF_STATE_CONNECTED,
BLKIF_STATE_SUSPENDED,
BLKIF_STATE_ERROR,
};

struct grant {
Expand All @@ -89,6 +90,7 @@ struct grant {
};

enum blk_req_status {
REQ_PROCESSING,
REQ_WAITING,
REQ_DONE,
REQ_ERROR,
Expand Down Expand Up @@ -530,22 +532,23 @@ static unsigned long blkif_ring_get_request(struct blkfront_ring_info *rinfo,

id = get_id_from_freelist(rinfo);
rinfo->shadow[id].request = req;
rinfo->shadow[id].status = REQ_WAITING;
rinfo->shadow[id].status = REQ_PROCESSING;
rinfo->shadow[id].associated_id = NO_ASSOCIATED_ID;

(*ring_req)->u.rw.id = id;
rinfo->shadow[id].req.u.rw.id = id;

return id;
}

static int blkif_queue_discard_req(struct request *req, struct blkfront_ring_info *rinfo)
{
struct blkfront_info *info = rinfo->dev_info;
struct blkif_request *ring_req;
struct blkif_request *ring_req, *final_ring_req;
unsigned long id;

/* Fill out a communications ring structure. */
id = blkif_ring_get_request(rinfo, req, &ring_req);
id = blkif_ring_get_request(rinfo, req, &final_ring_req);
ring_req = &rinfo->shadow[id].req;

ring_req->operation = BLKIF_OP_DISCARD;
ring_req->u.discard.nr_sectors = blk_rq_sectors(req);
Expand All @@ -556,8 +559,9 @@ static int blkif_queue_discard_req(struct request *req, struct blkfront_ring_inf
else
ring_req->u.discard.flag = 0;

/* Keep a private copy so we can reissue requests when recovering. */
rinfo->shadow[id].req = *ring_req;
/* Copy the request to the ring page. */
*final_ring_req = *ring_req;
rinfo->shadow[id].status = REQ_WAITING;

return 0;
}
Expand Down Expand Up @@ -690,6 +694,7 @@ static int blkif_queue_rw_req(struct request *req, struct blkfront_ring_info *ri
{
struct blkfront_info *info = rinfo->dev_info;
struct blkif_request *ring_req, *extra_ring_req = NULL;
struct blkif_request *final_ring_req, *final_extra_ring_req = NULL;
unsigned long id, extra_id = NO_ASSOCIATED_ID;
bool require_extra_req = false;
int i;
Expand Down Expand Up @@ -734,7 +739,8 @@ static int blkif_queue_rw_req(struct request *req, struct blkfront_ring_info *ri
}

/* Fill out a communications ring structure. */
id = blkif_ring_get_request(rinfo, req, &ring_req);
id = blkif_ring_get_request(rinfo, req, &final_ring_req);
ring_req = &rinfo->shadow[id].req;

num_sg = blk_rq_map_sg(req->q, req, rinfo->shadow[id].sg);
num_grant = 0;
Expand Down Expand Up @@ -785,7 +791,9 @@ static int blkif_queue_rw_req(struct request *req, struct blkfront_ring_info *ri
ring_req->u.rw.nr_segments = num_grant;
if (unlikely(require_extra_req)) {
extra_id = blkif_ring_get_request(rinfo, req,
&extra_ring_req);
&final_extra_ring_req);
extra_ring_req = &rinfo->shadow[extra_id].req;

/*
* Only the first request contains the scatter-gather
* list.
Expand Down Expand Up @@ -827,10 +835,13 @@ static int blkif_queue_rw_req(struct request *req, struct blkfront_ring_info *ri
if (setup.segments)
kunmap_atomic(setup.segments);

/* Keep a private copy so we can reissue requests when recovering. */
rinfo->shadow[id].req = *ring_req;
if (unlikely(require_extra_req))
rinfo->shadow[extra_id].req = *extra_ring_req;
/* Copy request(s) to the ring page. */
*final_ring_req = *ring_req;
rinfo->shadow[id].status = REQ_WAITING;
if (unlikely(require_extra_req)) {
*final_extra_ring_req = *extra_ring_req;
rinfo->shadow[extra_id].status = REQ_WAITING;
}

if (new_persistent_gnts)
gnttab_free_grant_references(setup.gref_head);
Expand Down Expand Up @@ -1353,8 +1364,8 @@ static enum blk_req_status blkif_rsp_to_req_status(int rsp)
static int blkif_get_final_status(enum blk_req_status s1,
enum blk_req_status s2)
{
BUG_ON(s1 == REQ_WAITING);
BUG_ON(s2 == REQ_WAITING);
BUG_ON(s1 < REQ_DONE);
BUG_ON(s2 < REQ_DONE);

if (s1 == REQ_ERROR || s2 == REQ_ERROR)
return BLKIF_RSP_ERROR;
Expand Down Expand Up @@ -1387,7 +1398,7 @@ static bool blkif_completion(unsigned long *id,
s->status = blkif_rsp_to_req_status(bret->status);

/* Wait the second response if not yet here. */
if (s2->status == REQ_WAITING)
if (s2->status < REQ_DONE)
return false;

bret->status = blkif_get_final_status(s->status,
Expand Down Expand Up @@ -1495,7 +1506,7 @@ static bool blkif_completion(unsigned long *id,
static irqreturn_t blkif_interrupt(int irq, void *dev_id)
{
struct request *req;
struct blkif_response *bret;
struct blkif_response bret;
RING_IDX i, rp;
unsigned long flags;
struct blkfront_ring_info *rinfo = (struct blkfront_ring_info *)dev_id;
Expand All @@ -1506,54 +1517,76 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id)

spin_lock_irqsave(&rinfo->ring_lock, flags);
again:
rp = rinfo->ring.sring->rsp_prod;
rmb(); /* Ensure we see queued responses up to 'rp'. */
rp = READ_ONCE(rinfo->ring.sring->rsp_prod);
virt_rmb(); /* Ensure we see queued responses up to 'rp'. */
if (RING_RESPONSE_PROD_OVERFLOW(&rinfo->ring, rp)) {
pr_alert("%s: illegal number of responses %u\n",
info->gd->disk_name, rp - rinfo->ring.rsp_cons);
goto err;
}

for (i = rinfo->ring.rsp_cons; i != rp; i++) {
unsigned long id;
unsigned int op;

RING_COPY_RESPONSE(&rinfo->ring, i, &bret);
id = bret.id;

bret = RING_GET_RESPONSE(&rinfo->ring, i);
id = bret->id;
/*
* The backend has messed up and given us an id that we would
* never have given to it (we stamp it up to BLK_RING_SIZE -
* look in get_id_from_freelist.
*/
if (id >= BLK_RING_SIZE(info)) {
WARN(1, "%s: response to %s has incorrect id (%ld)\n",
info->gd->disk_name, op_name(bret->operation), id);
/* We can't safely get the 'struct request' as
* the id is busted. */
continue;
pr_alert("%s: response has incorrect id (%ld)\n",
info->gd->disk_name, id);
goto err;
}
if (rinfo->shadow[id].status != REQ_WAITING) {
pr_alert("%s: response references no pending request\n",
info->gd->disk_name);
goto err;
}

rinfo->shadow[id].status = REQ_PROCESSING;
req = rinfo->shadow[id].request;

if (bret->operation != BLKIF_OP_DISCARD) {
op = rinfo->shadow[id].req.operation;
if (op == BLKIF_OP_INDIRECT)
op = rinfo->shadow[id].req.u.indirect.indirect_op;
if (bret.operation != op) {
pr_alert("%s: response has wrong operation (%u instead of %u)\n",
info->gd->disk_name, bret.operation, op);
goto err;
}

if (bret.operation != BLKIF_OP_DISCARD) {
/*
* We may need to wait for an extra response if the
* I/O request is split in 2
*/
if (!blkif_completion(&id, rinfo, bret))
if (!blkif_completion(&id, rinfo, &bret))
continue;
}

if (add_id_to_freelist(rinfo, id)) {
WARN(1, "%s: response to %s (id %ld) couldn't be recycled!\n",
info->gd->disk_name, op_name(bret->operation), id);
info->gd->disk_name, op_name(bret.operation), id);
continue;
}

if (bret->status == BLKIF_RSP_OKAY)
if (bret.status == BLKIF_RSP_OKAY)
blkif_req(req)->error = BLK_STS_OK;
else
blkif_req(req)->error = BLK_STS_IOERR;

switch (bret->operation) {
switch (bret.operation) {
case BLKIF_OP_DISCARD:
if (unlikely(bret->status == BLKIF_RSP_EOPNOTSUPP)) {
if (unlikely(bret.status == BLKIF_RSP_EOPNOTSUPP)) {
struct request_queue *rq = info->rq;
printk(KERN_WARNING "blkfront: %s: %s op failed\n",
info->gd->disk_name, op_name(bret->operation));

pr_warn_ratelimited("blkfront: %s: %s op failed\n",
info->gd->disk_name, op_name(bret.operation));
blkif_req(req)->error = BLK_STS_NOTSUPP;
info->feature_discard = 0;
info->feature_secdiscard = 0;
Expand All @@ -1563,15 +1596,15 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id)
break;
case BLKIF_OP_FLUSH_DISKCACHE:
case BLKIF_OP_WRITE_BARRIER:
if (unlikely(bret->status == BLKIF_RSP_EOPNOTSUPP)) {
printk(KERN_WARNING "blkfront: %s: %s op failed\n",
info->gd->disk_name, op_name(bret->operation));
if (unlikely(bret.status == BLKIF_RSP_EOPNOTSUPP)) {
pr_warn_ratelimited("blkfront: %s: %s op failed\n",
info->gd->disk_name, op_name(bret.operation));
blkif_req(req)->error = BLK_STS_NOTSUPP;
}
if (unlikely(bret->status == BLKIF_RSP_ERROR &&
if (unlikely(bret.status == BLKIF_RSP_ERROR &&
rinfo->shadow[id].req.u.rw.nr_segments == 0)) {
printk(KERN_WARNING "blkfront: %s: empty %s op failed\n",
info->gd->disk_name, op_name(bret->operation));
pr_warn_ratelimited("blkfront: %s: empty %s op failed\n",
info->gd->disk_name, op_name(bret.operation));
blkif_req(req)->error = BLK_STS_NOTSUPP;
}
if (unlikely(blkif_req(req)->error)) {
Expand All @@ -1584,9 +1617,10 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id)
fallthrough;
case BLKIF_OP_READ:
case BLKIF_OP_WRITE:
if (unlikely(bret->status != BLKIF_RSP_OKAY))
dev_dbg(&info->xbdev->dev, "Bad return from blkdev data "
"request: %x\n", bret->status);
if (unlikely(bret.status != BLKIF_RSP_OKAY))
dev_dbg_ratelimited(&info->xbdev->dev,
"Bad return from blkdev data request: %#x\n",
bret.status);

break;
default:
Expand All @@ -1612,6 +1646,14 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id)
spin_unlock_irqrestore(&rinfo->ring_lock, flags);

return IRQ_HANDLED;

err:
info->connected = BLKIF_STATE_ERROR;

spin_unlock_irqrestore(&rinfo->ring_lock, flags);

pr_alert("%s disabled for further use\n", info->gd->disk_name);
return IRQ_HANDLED;
}


Expand Down
Loading

0 comments on commit 9ae5fce

Please sign in to comment.