xen: fixes for 5.0-rc3
-----BEGIN PGP SIGNATURE----- iHUEABYIAB0WIQRTLbB6QfY48x44uB6AXGG7T9hjvgUCXEGhYwAKCRCAXGG7T9hj vu/qAP4ljV1QwAicTP2IosIpmSojJV4BkkJOs36dgF1u4DscPAEA7YhvTzGYcZr6 7rmBIbGve6Yb24Uh4aL3ir4w+LUvSAg= =Jm9L -----END PGP SIGNATURE----- Merge tag 'for-linus-5.0-rc3-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/xen/tip Pull xen fixes from Juergen Gross: - Several fixes for the Xen pvcalls drivers (1 fix for the backend and 8 for the frontend). - A fix for a rather longstanding bug in the Xen sched_clock() interface which led to weird time jumps when migrating the system. - A fix for avoiding accesses to x2apic MSRs in Xen PV guests. * tag 'for-linus-5.0-rc3-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/xen/tip: xen: Fix x86 sched_clock() interface for xen pvcalls-front: fix potential null dereference always clear the X2APIC_ENABLE bit for PV guest pvcalls-front: Avoid get_free_pages(GFP_KERNEL) under spinlock xen/pvcalls: remove set but not used variable 'intf' pvcalls-back: set -ENOTCONN in pvcalls_conn_back_read pvcalls-front: don't return error when the ring is full pvcalls-front: properly allocate sk pvcalls-front: don't try to free unallocated rings pvcalls-front: read all data before closing the connection
This commit is contained in:
commit
e6ec2fda2d
|
@ -898,10 +898,7 @@ static u64 xen_read_msr_safe(unsigned int msr, int *err)
|
||||||
val = native_read_msr_safe(msr, err);
|
val = native_read_msr_safe(msr, err);
|
||||||
switch (msr) {
|
switch (msr) {
|
||||||
case MSR_IA32_APICBASE:
|
case MSR_IA32_APICBASE:
|
||||||
#ifdef CONFIG_X86_X2APIC
|
val &= ~X2APIC_ENABLE;
|
||||||
if (!(cpuid_ecx(1) & (1 << (X86_FEATURE_X2APIC & 31))))
|
|
||||||
#endif
|
|
||||||
val &= ~X2APIC_ENABLE;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return val;
|
return val;
|
||||||
|
|
|
@ -361,8 +361,6 @@ void xen_timer_resume(void)
|
||||||
{
|
{
|
||||||
int cpu;
|
int cpu;
|
||||||
|
|
||||||
pvclock_resume();
|
|
||||||
|
|
||||||
if (xen_clockevent != &xen_vcpuop_clockevent)
|
if (xen_clockevent != &xen_vcpuop_clockevent)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -379,12 +377,15 @@ static const struct pv_time_ops xen_time_ops __initconst = {
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct pvclock_vsyscall_time_info *xen_clock __read_mostly;
|
static struct pvclock_vsyscall_time_info *xen_clock __read_mostly;
|
||||||
|
static u64 xen_clock_value_saved;
|
||||||
|
|
||||||
void xen_save_time_memory_area(void)
|
void xen_save_time_memory_area(void)
|
||||||
{
|
{
|
||||||
struct vcpu_register_time_memory_area t;
|
struct vcpu_register_time_memory_area t;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
xen_clock_value_saved = xen_clocksource_read() - xen_sched_clock_offset;
|
||||||
|
|
||||||
if (!xen_clock)
|
if (!xen_clock)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -404,7 +405,7 @@ void xen_restore_time_memory_area(void)
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (!xen_clock)
|
if (!xen_clock)
|
||||||
return;
|
goto out;
|
||||||
|
|
||||||
t.addr.v = &xen_clock->pvti;
|
t.addr.v = &xen_clock->pvti;
|
||||||
|
|
||||||
|
@ -421,6 +422,11 @@ void xen_restore_time_memory_area(void)
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
pr_notice("Cannot restore secondary vcpu_time_info (err %d)",
|
pr_notice("Cannot restore secondary vcpu_time_info (err %d)",
|
||||||
ret);
|
ret);
|
||||||
|
|
||||||
|
out:
|
||||||
|
/* Need pvclock_resume() before using xen_clocksource_read(). */
|
||||||
|
pvclock_resume();
|
||||||
|
xen_sched_clock_offset = xen_clocksource_read() - xen_clock_value_saved;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void xen_setup_vsyscall_time_info(void)
|
static void xen_setup_vsyscall_time_info(void)
|
||||||
|
|
|
@ -1650,7 +1650,7 @@ void xen_callback_vector(void)
|
||||||
xen_have_vector_callback = 0;
|
xen_have_vector_callback = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
pr_info("Xen HVM callback vector for event delivery is enabled\n");
|
pr_info_once("Xen HVM callback vector for event delivery is enabled\n");
|
||||||
alloc_intr_gate(HYPERVISOR_CALLBACK_VECTOR,
|
alloc_intr_gate(HYPERVISOR_CALLBACK_VECTOR,
|
||||||
xen_hvm_callback_vector);
|
xen_hvm_callback_vector);
|
||||||
}
|
}
|
||||||
|
|
|
@ -160,9 +160,10 @@ static void pvcalls_conn_back_read(void *opaque)
|
||||||
|
|
||||||
/* write the data, then modify the indexes */
|
/* write the data, then modify the indexes */
|
||||||
virt_wmb();
|
virt_wmb();
|
||||||
if (ret < 0)
|
if (ret < 0) {
|
||||||
|
atomic_set(&map->read, 0);
|
||||||
intf->in_error = ret;
|
intf->in_error = ret;
|
||||||
else
|
} else
|
||||||
intf->in_prod = prod + ret;
|
intf->in_prod = prod + ret;
|
||||||
/* update the indexes, then notify the other end */
|
/* update the indexes, then notify the other end */
|
||||||
virt_wmb();
|
virt_wmb();
|
||||||
|
@ -282,13 +283,11 @@ static int pvcalls_back_socket(struct xenbus_device *dev,
|
||||||
static void pvcalls_sk_state_change(struct sock *sock)
|
static void pvcalls_sk_state_change(struct sock *sock)
|
||||||
{
|
{
|
||||||
struct sock_mapping *map = sock->sk_user_data;
|
struct sock_mapping *map = sock->sk_user_data;
|
||||||
struct pvcalls_data_intf *intf;
|
|
||||||
|
|
||||||
if (map == NULL)
|
if (map == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
intf = map->ring;
|
atomic_inc(&map->read);
|
||||||
intf->in_error = -ENOTCONN;
|
|
||||||
notify_remote_via_irq(map->irq);
|
notify_remote_via_irq(map->irq);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,12 @@
|
||||||
#define PVCALLS_NR_RSP_PER_RING __CONST_RING_SIZE(xen_pvcalls, XEN_PAGE_SIZE)
|
#define PVCALLS_NR_RSP_PER_RING __CONST_RING_SIZE(xen_pvcalls, XEN_PAGE_SIZE)
|
||||||
#define PVCALLS_FRONT_MAX_SPIN 5000
|
#define PVCALLS_FRONT_MAX_SPIN 5000
|
||||||
|
|
||||||
|
static struct proto pvcalls_proto = {
|
||||||
|
.name = "PVCalls",
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
.obj_size = sizeof(struct sock),
|
||||||
|
};
|
||||||
|
|
||||||
struct pvcalls_bedata {
|
struct pvcalls_bedata {
|
||||||
struct xen_pvcalls_front_ring ring;
|
struct xen_pvcalls_front_ring ring;
|
||||||
grant_ref_t ref;
|
grant_ref_t ref;
|
||||||
|
@ -335,6 +341,42 @@ int pvcalls_front_socket(struct socket *sock)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void free_active_ring(struct sock_mapping *map)
|
||||||
|
{
|
||||||
|
if (!map->active.ring)
|
||||||
|
return;
|
||||||
|
|
||||||
|
free_pages((unsigned long)map->active.data.in,
|
||||||
|
map->active.ring->ring_order);
|
||||||
|
free_page((unsigned long)map->active.ring);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int alloc_active_ring(struct sock_mapping *map)
|
||||||
|
{
|
||||||
|
void *bytes;
|
||||||
|
|
||||||
|
map->active.ring = (struct pvcalls_data_intf *)
|
||||||
|
get_zeroed_page(GFP_KERNEL);
|
||||||
|
if (!map->active.ring)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
map->active.ring->ring_order = PVCALLS_RING_ORDER;
|
||||||
|
bytes = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO,
|
||||||
|
PVCALLS_RING_ORDER);
|
||||||
|
if (!bytes)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
map->active.data.in = bytes;
|
||||||
|
map->active.data.out = bytes +
|
||||||
|
XEN_FLEX_RING_SIZE(PVCALLS_RING_ORDER);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
out:
|
||||||
|
free_active_ring(map);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
static int create_active(struct sock_mapping *map, int *evtchn)
|
static int create_active(struct sock_mapping *map, int *evtchn)
|
||||||
{
|
{
|
||||||
void *bytes;
|
void *bytes;
|
||||||
|
@ -343,15 +385,7 @@ static int create_active(struct sock_mapping *map, int *evtchn)
|
||||||
*evtchn = -1;
|
*evtchn = -1;
|
||||||
init_waitqueue_head(&map->active.inflight_conn_req);
|
init_waitqueue_head(&map->active.inflight_conn_req);
|
||||||
|
|
||||||
map->active.ring = (struct pvcalls_data_intf *)
|
bytes = map->active.data.in;
|
||||||
__get_free_page(GFP_KERNEL | __GFP_ZERO);
|
|
||||||
if (map->active.ring == NULL)
|
|
||||||
goto out_error;
|
|
||||||
map->active.ring->ring_order = PVCALLS_RING_ORDER;
|
|
||||||
bytes = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO,
|
|
||||||
PVCALLS_RING_ORDER);
|
|
||||||
if (bytes == NULL)
|
|
||||||
goto out_error;
|
|
||||||
for (i = 0; i < (1 << PVCALLS_RING_ORDER); i++)
|
for (i = 0; i < (1 << PVCALLS_RING_ORDER); i++)
|
||||||
map->active.ring->ref[i] = gnttab_grant_foreign_access(
|
map->active.ring->ref[i] = gnttab_grant_foreign_access(
|
||||||
pvcalls_front_dev->otherend_id,
|
pvcalls_front_dev->otherend_id,
|
||||||
|
@ -361,10 +395,6 @@ static int create_active(struct sock_mapping *map, int *evtchn)
|
||||||
pvcalls_front_dev->otherend_id,
|
pvcalls_front_dev->otherend_id,
|
||||||
pfn_to_gfn(virt_to_pfn((void *)map->active.ring)), 0);
|
pfn_to_gfn(virt_to_pfn((void *)map->active.ring)), 0);
|
||||||
|
|
||||||
map->active.data.in = bytes;
|
|
||||||
map->active.data.out = bytes +
|
|
||||||
XEN_FLEX_RING_SIZE(PVCALLS_RING_ORDER);
|
|
||||||
|
|
||||||
ret = xenbus_alloc_evtchn(pvcalls_front_dev, evtchn);
|
ret = xenbus_alloc_evtchn(pvcalls_front_dev, evtchn);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out_error;
|
goto out_error;
|
||||||
|
@ -385,8 +415,6 @@ static int create_active(struct sock_mapping *map, int *evtchn)
|
||||||
out_error:
|
out_error:
|
||||||
if (*evtchn >= 0)
|
if (*evtchn >= 0)
|
||||||
xenbus_free_evtchn(pvcalls_front_dev, *evtchn);
|
xenbus_free_evtchn(pvcalls_front_dev, *evtchn);
|
||||||
free_pages((unsigned long)map->active.data.in, PVCALLS_RING_ORDER);
|
|
||||||
free_page((unsigned long)map->active.ring);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -406,17 +434,24 @@ int pvcalls_front_connect(struct socket *sock, struct sockaddr *addr,
|
||||||
return PTR_ERR(map);
|
return PTR_ERR(map);
|
||||||
|
|
||||||
bedata = dev_get_drvdata(&pvcalls_front_dev->dev);
|
bedata = dev_get_drvdata(&pvcalls_front_dev->dev);
|
||||||
|
ret = alloc_active_ring(map);
|
||||||
|
if (ret < 0) {
|
||||||
|
pvcalls_exit_sock(sock);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
spin_lock(&bedata->socket_lock);
|
spin_lock(&bedata->socket_lock);
|
||||||
ret = get_request(bedata, &req_id);
|
ret = get_request(bedata, &req_id);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
spin_unlock(&bedata->socket_lock);
|
spin_unlock(&bedata->socket_lock);
|
||||||
|
free_active_ring(map);
|
||||||
pvcalls_exit_sock(sock);
|
pvcalls_exit_sock(sock);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
ret = create_active(map, &evtchn);
|
ret = create_active(map, &evtchn);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
spin_unlock(&bedata->socket_lock);
|
spin_unlock(&bedata->socket_lock);
|
||||||
|
free_active_ring(map);
|
||||||
pvcalls_exit_sock(sock);
|
pvcalls_exit_sock(sock);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -469,8 +504,10 @@ static int __write_ring(struct pvcalls_data_intf *intf,
|
||||||
virt_mb();
|
virt_mb();
|
||||||
|
|
||||||
size = pvcalls_queued(prod, cons, array_size);
|
size = pvcalls_queued(prod, cons, array_size);
|
||||||
if (size >= array_size)
|
if (size > array_size)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
if (size == array_size)
|
||||||
|
return 0;
|
||||||
if (len > array_size - size)
|
if (len > array_size - size)
|
||||||
len = array_size - size;
|
len = array_size - size;
|
||||||
|
|
||||||
|
@ -560,15 +597,13 @@ static int __read_ring(struct pvcalls_data_intf *intf,
|
||||||
error = intf->in_error;
|
error = intf->in_error;
|
||||||
/* get pointers before reading from the ring */
|
/* get pointers before reading from the ring */
|
||||||
virt_rmb();
|
virt_rmb();
|
||||||
if (error < 0)
|
|
||||||
return error;
|
|
||||||
|
|
||||||
size = pvcalls_queued(prod, cons, array_size);
|
size = pvcalls_queued(prod, cons, array_size);
|
||||||
masked_prod = pvcalls_mask(prod, array_size);
|
masked_prod = pvcalls_mask(prod, array_size);
|
||||||
masked_cons = pvcalls_mask(cons, array_size);
|
masked_cons = pvcalls_mask(cons, array_size);
|
||||||
|
|
||||||
if (size == 0)
|
if (size == 0)
|
||||||
return 0;
|
return error ?: size;
|
||||||
|
|
||||||
if (len > size)
|
if (len > size)
|
||||||
len = size;
|
len = size;
|
||||||
|
@ -780,25 +815,36 @@ int pvcalls_front_accept(struct socket *sock, struct socket *newsock, int flags)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
map2 = kzalloc(sizeof(*map2), GFP_KERNEL);
|
||||||
|
if (map2 == NULL) {
|
||||||
|
clear_bit(PVCALLS_FLAG_ACCEPT_INFLIGHT,
|
||||||
|
(void *)&map->passive.flags);
|
||||||
|
pvcalls_exit_sock(sock);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
ret = alloc_active_ring(map2);
|
||||||
|
if (ret < 0) {
|
||||||
|
clear_bit(PVCALLS_FLAG_ACCEPT_INFLIGHT,
|
||||||
|
(void *)&map->passive.flags);
|
||||||
|
kfree(map2);
|
||||||
|
pvcalls_exit_sock(sock);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
spin_lock(&bedata->socket_lock);
|
spin_lock(&bedata->socket_lock);
|
||||||
ret = get_request(bedata, &req_id);
|
ret = get_request(bedata, &req_id);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
clear_bit(PVCALLS_FLAG_ACCEPT_INFLIGHT,
|
clear_bit(PVCALLS_FLAG_ACCEPT_INFLIGHT,
|
||||||
(void *)&map->passive.flags);
|
(void *)&map->passive.flags);
|
||||||
spin_unlock(&bedata->socket_lock);
|
spin_unlock(&bedata->socket_lock);
|
||||||
|
free_active_ring(map2);
|
||||||
|
kfree(map2);
|
||||||
pvcalls_exit_sock(sock);
|
pvcalls_exit_sock(sock);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
map2 = kzalloc(sizeof(*map2), GFP_ATOMIC);
|
|
||||||
if (map2 == NULL) {
|
|
||||||
clear_bit(PVCALLS_FLAG_ACCEPT_INFLIGHT,
|
|
||||||
(void *)&map->passive.flags);
|
|
||||||
spin_unlock(&bedata->socket_lock);
|
|
||||||
pvcalls_exit_sock(sock);
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
ret = create_active(map2, &evtchn);
|
ret = create_active(map2, &evtchn);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
free_active_ring(map2);
|
||||||
kfree(map2);
|
kfree(map2);
|
||||||
clear_bit(PVCALLS_FLAG_ACCEPT_INFLIGHT,
|
clear_bit(PVCALLS_FLAG_ACCEPT_INFLIGHT,
|
||||||
(void *)&map->passive.flags);
|
(void *)&map->passive.flags);
|
||||||
|
@ -839,7 +885,7 @@ int pvcalls_front_accept(struct socket *sock, struct socket *newsock, int flags)
|
||||||
|
|
||||||
received:
|
received:
|
||||||
map2->sock = newsock;
|
map2->sock = newsock;
|
||||||
newsock->sk = kzalloc(sizeof(*newsock->sk), GFP_KERNEL);
|
newsock->sk = sk_alloc(sock_net(sock->sk), PF_INET, GFP_KERNEL, &pvcalls_proto, false);
|
||||||
if (!newsock->sk) {
|
if (!newsock->sk) {
|
||||||
bedata->rsp[req_id].req_id = PVCALLS_INVALID_ID;
|
bedata->rsp[req_id].req_id = PVCALLS_INVALID_ID;
|
||||||
map->passive.inflight_req_id = PVCALLS_INVALID_ID;
|
map->passive.inflight_req_id = PVCALLS_INVALID_ID;
|
||||||
|
@ -1032,8 +1078,8 @@ int pvcalls_front_release(struct socket *sock)
|
||||||
spin_lock(&bedata->socket_lock);
|
spin_lock(&bedata->socket_lock);
|
||||||
list_del(&map->list);
|
list_del(&map->list);
|
||||||
spin_unlock(&bedata->socket_lock);
|
spin_unlock(&bedata->socket_lock);
|
||||||
if (READ_ONCE(map->passive.inflight_req_id) !=
|
if (READ_ONCE(map->passive.inflight_req_id) != PVCALLS_INVALID_ID &&
|
||||||
PVCALLS_INVALID_ID) {
|
READ_ONCE(map->passive.inflight_req_id) != 0) {
|
||||||
pvcalls_front_free_map(bedata,
|
pvcalls_front_free_map(bedata,
|
||||||
map->passive.accept_map);
|
map->passive.accept_map);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue