* [PATCH 0/7] Drivers: hv: Miscellaneous cleanups and bug fixes
@ 2015-03-27 16:09 K. Y. Srinivasan
2015-03-27 16:10 ` [PATCH 1/7] hv: run non-blocking message handlers in the dispatch tasklet K. Y. Srinivasan
0 siblings, 1 reply; 8+ messages in thread
From: K. Y. Srinivasan @ 2015-03-27 16:09 UTC (permalink / raw)
To: gregkh, linux-kernel, devel, olaf, apw, vkuznets, jasowang
Cc: K. Y. Srinivasan
Some miscellaneous cleanup and bug fixes.
Dexuan Cui (3):
hv: run non-blocking message handlers in the dispatch tasklet
hv: don't schedule new works in
vmbus_onoffer()/vmbus_onoffer_rescind()
hv: remove the per-channel workqueue
Haiyang Zhang (1):
hv_vmbus: Add gradually increased delay for retries in
vmbus_post_msg()
Vitaly Kuznetsov (3):
Drivers: hv: hv_balloon: do not online pages in offline blocks
Drivers: hv: hv_balloon: eliminate jumps in piecewiese linear floor
function
Drivers: hv: hv_balloon: survive ballooning request with num_pages=0
drivers/hv/channel_mgmt.c | 228 +++++++++-----------------------------------
drivers/hv/connection.c | 13 +--
drivers/hv/hv_balloon.c | 39 ++++----
drivers/hv/hyperv_vmbus.h | 19 ++++-
drivers/hv/vmbus_drv.c | 21 ++++-
include/linux/hyperv.h | 3 -
6 files changed, 110 insertions(+), 213 deletions(-)
--
1.7.4.1
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 1/7] hv: run non-blocking message handlers in the dispatch tasklet
2015-03-27 16:09 [PATCH 0/7] Drivers: hv: Miscellaneous cleanups and bug fixes K. Y. Srinivasan
@ 2015-03-27 16:10 ` K. Y. Srinivasan
2015-03-27 16:10 ` [PATCH 2/7] hv: don't schedule new works in vmbus_onoffer()/vmbus_onoffer_rescind() K. Y. Srinivasan
` (5 more replies)
0 siblings, 6 replies; 8+ messages in thread
From: K. Y. Srinivasan @ 2015-03-27 16:10 UTC (permalink / raw)
To: gregkh, linux-kernel, devel, olaf, apw, vkuznets, jasowang
Cc: Dexuan Cui, K. Y. Srinivasan
From: Dexuan Cui <decui@microsoft.com>
A work item in vmbus_connection.work_queue can sleep, waiting for a new
host message (usually it is some kind of "completion" message). Currently
the new message will be handled in the same workqueue, but since work items
in the workqueue is serialized, we actually have no chance to handle
the new message if the current work item is sleeping -- as as result, the
current work item will hang forever.
K. Y. has posted the below fix to resolve the issue:
Drivers: hv: vmbus: Perform device register in the per-channel work element
Actually we can simplify the fix by directly running non-blocking message
handlers in the dispatch tasklet (inspired by K. Y.).
This patch is the fundamental change. The following 2 patches will simplify
the message offering and rescind-offering handling a lot.
Signed-off-by: Dexuan Cui <decui@microsoft.com>
Cc: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
---
drivers/hv/channel_mgmt.c | 41 ++++++++++++++++++-----------------------
drivers/hv/hyperv_vmbus.h | 17 +++++++++++++++++
drivers/hv/vmbus_drv.c | 21 ++++++++++++++++++---
3 files changed, 53 insertions(+), 26 deletions(-)
diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c
index bb39705..287f07b 100644
--- a/drivers/hv/channel_mgmt.c
+++ b/drivers/hv/channel_mgmt.c
@@ -33,11 +33,6 @@
#include "hyperv_vmbus.h"
-struct vmbus_channel_message_table_entry {
- enum vmbus_channel_message_type message_type;
- void (*message_handler)(struct vmbus_channel_message_header *msg);
-};
-
struct vmbus_rescind_work {
struct work_struct work;
struct vmbus_channel *channel;
@@ -827,25 +822,25 @@ static void vmbus_onversion_response(
}
/* Channel message dispatch table */
-static struct vmbus_channel_message_table_entry
+struct vmbus_channel_message_table_entry
channel_message_table[CHANNELMSG_COUNT] = {
- {CHANNELMSG_INVALID, NULL},
- {CHANNELMSG_OFFERCHANNEL, vmbus_onoffer},
- {CHANNELMSG_RESCIND_CHANNELOFFER, vmbus_onoffer_rescind},
- {CHANNELMSG_REQUESTOFFERS, NULL},
- {CHANNELMSG_ALLOFFERS_DELIVERED, vmbus_onoffers_delivered},
- {CHANNELMSG_OPENCHANNEL, NULL},
- {CHANNELMSG_OPENCHANNEL_RESULT, vmbus_onopen_result},
- {CHANNELMSG_CLOSECHANNEL, NULL},
- {CHANNELMSG_GPADL_HEADER, NULL},
- {CHANNELMSG_GPADL_BODY, NULL},
- {CHANNELMSG_GPADL_CREATED, vmbus_ongpadl_created},
- {CHANNELMSG_GPADL_TEARDOWN, NULL},
- {CHANNELMSG_GPADL_TORNDOWN, vmbus_ongpadl_torndown},
- {CHANNELMSG_RELID_RELEASED, NULL},
- {CHANNELMSG_INITIATE_CONTACT, NULL},
- {CHANNELMSG_VERSION_RESPONSE, vmbus_onversion_response},
- {CHANNELMSG_UNLOAD, NULL},
+ {CHANNELMSG_INVALID, 0, NULL},
+ {CHANNELMSG_OFFERCHANNEL, 0, vmbus_onoffer},
+ {CHANNELMSG_RESCIND_CHANNELOFFER, 0, vmbus_onoffer_rescind},
+ {CHANNELMSG_REQUESTOFFERS, 0, NULL},
+ {CHANNELMSG_ALLOFFERS_DELIVERED, 1, vmbus_onoffers_delivered},
+ {CHANNELMSG_OPENCHANNEL, 0, NULL},
+ {CHANNELMSG_OPENCHANNEL_RESULT, 1, vmbus_onopen_result},
+ {CHANNELMSG_CLOSECHANNEL, 0, NULL},
+ {CHANNELMSG_GPADL_HEADER, 0, NULL},
+ {CHANNELMSG_GPADL_BODY, 0, NULL},
+ {CHANNELMSG_GPADL_CREATED, 1, vmbus_ongpadl_created},
+ {CHANNELMSG_GPADL_TEARDOWN, 0, NULL},
+ {CHANNELMSG_GPADL_TORNDOWN, 1, vmbus_ongpadl_torndown},
+ {CHANNELMSG_RELID_RELEASED, 0, NULL},
+ {CHANNELMSG_INITIATE_CONTACT, 0, NULL},
+ {CHANNELMSG_VERSION_RESPONSE, 1, vmbus_onversion_response},
+ {CHANNELMSG_UNLOAD, 0, NULL},
};
/*
diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h
index c8e27e0..f40a5a9 100644
--- a/drivers/hv/hyperv_vmbus.h
+++ b/drivers/hv/hyperv_vmbus.h
@@ -685,6 +685,23 @@ struct vmbus_msginfo {
extern struct vmbus_connection vmbus_connection;
+enum vmbus_message_handler_type {
+ /* The related handler can sleep. */
+ VMHT_BLOCKING = 0,
+
+ /* The related handler must NOT sleep. */
+ VMHT_NON_BLOCKING = 1,
+};
+
+struct vmbus_channel_message_table_entry {
+ enum vmbus_channel_message_type message_type;
+ enum vmbus_message_handler_type handler_type;
+ void (*message_handler)(struct vmbus_channel_message_header *msg);
+};
+
+extern struct vmbus_channel_message_table_entry
+ channel_message_table[CHANNELMSG_COUNT];
+
/* General vmbus interface */
struct hv_device *vmbus_device_create(const uuid_le *type,
diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c
index 8313e25..c85235e 100644
--- a/drivers/hv/vmbus_drv.c
+++ b/drivers/hv/vmbus_drv.c
@@ -657,21 +657,36 @@ static void vmbus_on_msg_dpc(unsigned long data)
void *page_addr = hv_context.synic_message_page[cpu];
struct hv_message *msg = (struct hv_message *)page_addr +
VMBUS_MESSAGE_SINT;
+ struct vmbus_channel_message_header *hdr;
+ struct vmbus_channel_message_table_entry *entry;
struct onmessage_work_context *ctx;
while (1) {
- if (msg->header.message_type == HVMSG_NONE) {
+ if (msg->header.message_type == HVMSG_NONE)
/* no msg */
break;
- } else {
+
+ hdr = (struct vmbus_channel_message_header *)msg->u.payload;
+
+ if (hdr->msgtype >= CHANNELMSG_COUNT) {
+ WARN_ONCE(1, "unknown msgtype=%d\n", hdr->msgtype);
+ goto msg_handled;
+ }
+
+ entry = &channel_message_table[hdr->msgtype];
+ if (entry->handler_type == VMHT_BLOCKING) {
ctx = kmalloc(sizeof(*ctx), GFP_ATOMIC);
if (ctx == NULL)
continue;
+
INIT_WORK(&ctx->work, vmbus_onmessage_work);
memcpy(&ctx->msg, msg, sizeof(*msg));
+
queue_work(vmbus_connection.work_queue, &ctx->work);
- }
+ } else
+ entry->message_handler(hdr);
+msg_handled:
msg->header.message_type = HVMSG_NONE;
/*
--
1.7.4.1
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 2/7] hv: don't schedule new works in vmbus_onoffer()/vmbus_onoffer_rescind()
2015-03-27 16:10 ` [PATCH 1/7] hv: run non-blocking message handlers in the dispatch tasklet K. Y. Srinivasan
@ 2015-03-27 16:10 ` K. Y. Srinivasan
2015-03-27 16:10 ` [PATCH 3/7] hv: remove the per-channel workqueue K. Y. Srinivasan
` (4 subsequent siblings)
5 siblings, 0 replies; 8+ messages in thread
From: K. Y. Srinivasan @ 2015-03-27 16:10 UTC (permalink / raw)
To: gregkh, linux-kernel, devel, olaf, apw, vkuznets, jasowang
Cc: Dexuan Cui, K. Y. Srinivasan
From: Dexuan Cui <decui@microsoft.com>
Since the 2 fucntions can safely run in vmbus_connection.work_queue without
hang, we don't need to schedule new work items into the per-channel workqueue.
Actally we can even remove the per-channel workqueue now -- we'll do it
in the next patch.
Signed-off-by: Dexuan Cui <decui@microsoft.com>
Cc: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
---
drivers/hv/channel_mgmt.c | 157 ++++++++-------------------------------------
drivers/hv/connection.c | 6 +--
drivers/hv/hyperv_vmbus.h | 2 +-
3 files changed, 30 insertions(+), 135 deletions(-)
diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c
index 287f07b..d69864d 100644
--- a/drivers/hv/channel_mgmt.c
+++ b/drivers/hv/channel_mgmt.c
@@ -23,7 +23,6 @@
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/wait.h>
-#include <linux/delay.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/list.h>
@@ -33,11 +32,6 @@
#include "hyperv_vmbus.h"
-struct vmbus_rescind_work {
- struct work_struct work;
- struct vmbus_channel *channel;
-};
-
/**
* vmbus_prep_negotiate_resp() - Create default response for Hyper-V Negotiate message
* @icmsghdrp: Pointer to msg header structure
@@ -134,20 +128,6 @@ fw_error:
EXPORT_SYMBOL_GPL(vmbus_prep_negotiate_resp);
-static void vmbus_sc_creation_cb(struct work_struct *work)
-{
- struct vmbus_channel *newchannel = container_of(work,
- struct vmbus_channel,
- work);
- struct vmbus_channel *primary_channel = newchannel->primary_channel;
-
- /*
- * On entry sc_creation_callback has been already verified to
- * be non-NULL.
- */
- primary_channel->sc_creation_callback(newchannel);
-}
-
/*
* alloc_channel - Allocate and initialize a vmbus channel object
*/
@@ -206,40 +186,6 @@ static void free_channel(struct vmbus_channel *channel)
queue_work(vmbus_connection.work_queue, &channel->work);
}
-static void process_rescind_fn(struct work_struct *work)
-{
- struct vmbus_rescind_work *rc_work;
- struct vmbus_channel *channel;
- struct device *dev;
-
- rc_work = container_of(work, struct vmbus_rescind_work, work);
- channel = rc_work->channel;
-
- /*
- * We have already acquired a reference on the channel
- * and so it cannot vanish underneath us.
- * It is possible (while very unlikely) that we may
- * get here while the processing of the initial offer
- * is still not complete. Deal with this situation by
- * just waiting until the channel is in the correct state.
- */
-
- while (channel->work.func != release_channel)
- msleep(1000);
-
- if (channel->device_obj) {
- dev = get_device(&channel->device_obj->device);
- if (dev) {
- vmbus_device_unregister(channel->device_obj);
- put_device(dev);
- }
- } else {
- hv_process_channel_removal(channel,
- channel->offermsg.child_relid);
- }
- kfree(work);
-}
-
static void percpu_channel_enq(void *arg)
{
struct vmbus_channel *channel = arg;
@@ -302,46 +248,6 @@ void vmbus_free_channels(void)
}
}
-static void vmbus_do_device_register(struct work_struct *work)
-{
- struct hv_device *device_obj;
- int ret;
- unsigned long flags;
- struct vmbus_channel *newchannel = container_of(work,
- struct vmbus_channel,
- work);
-
- ret = vmbus_device_register(newchannel->device_obj);
- if (ret != 0) {
- pr_err("unable to add child device object (relid %d)\n",
- newchannel->offermsg.child_relid);
- spin_lock_irqsave(&vmbus_connection.channel_lock, flags);
- list_del(&newchannel->listentry);
- device_obj = newchannel->device_obj;
- newchannel->device_obj = NULL;
- spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags);
-
- if (newchannel->target_cpu != get_cpu()) {
- put_cpu();
- smp_call_function_single(newchannel->target_cpu,
- percpu_channel_deq, newchannel, true);
- } else {
- percpu_channel_deq(newchannel);
- put_cpu();
- }
-
- kfree(device_obj);
- if (!newchannel->rescind) {
- free_channel(newchannel);
- return;
- }
- }
- /*
- * The next state for this channel is to be freed.
- */
- INIT_WORK(&newchannel->work, release_channel);
-}
-
/*
* vmbus_process_offer - Process the offer by creating a channel/device
* associated with this offer
@@ -410,19 +316,8 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel)
newchannel->state = CHANNEL_OPEN_STATE;
channel->num_sc++;
- if (channel->sc_creation_callback != NULL) {
- /*
- * We need to invoke the sub-channel creation
- * callback; invoke this in a seperate work
- * context since we are currently running on
- * the global work context in which we handle
- * messages from the host.
- */
- INIT_WORK(&newchannel->work,
- vmbus_sc_creation_cb);
- queue_work(newchannel->controlwq,
- &newchannel->work);
- }
+ if (channel->sc_creation_callback != NULL)
+ channel->sc_creation_callback(newchannel);
return;
}
@@ -453,13 +348,13 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel)
* Add the new device to the bus. This will kick off device-driver
* binding which eventually invokes the device driver's AddDevice()
* method.
- * Invoke this call on the per-channel work context.
- * Until we return from this function, rescind offer message
- * cannot be processed as we are running on the global message
- * handling work.
*/
- INIT_WORK(&newchannel->work, vmbus_do_device_register);
- queue_work(newchannel->controlwq, &newchannel->work);
+ if (vmbus_device_register(newchannel->device_obj) != 0) {
+ pr_err("unable to add child device object (relid %d)\n",
+ newchannel->offermsg.child_relid);
+ kfree(newchannel->device_obj);
+ goto err_deq_chan;
+ }
return;
err_deq_chan:
@@ -613,31 +508,35 @@ static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr)
{
struct vmbus_channel_rescind_offer *rescind;
struct vmbus_channel *channel;
- struct vmbus_rescind_work *rc_work;
+ unsigned long flags;
+ struct device *dev;
rescind = (struct vmbus_channel_rescind_offer *)hdr;
- channel = relid2channel(rescind->child_relid, true);
+ channel = relid2channel(rescind->child_relid);
if (channel == NULL) {
hv_process_channel_removal(NULL, rescind->child_relid);
return;
}
- /*
- * We have acquired a reference on the channel and have posted
- * the rescind state. Perform further cleanup in a work context
- * that is different from the global work context in which
- * we process messages from the host (we are currently executing
- * on that global context.
- */
- rc_work = kzalloc(sizeof(struct vmbus_rescind_work), GFP_KERNEL);
- if (!rc_work) {
- pr_err("Unable to allocate memory for rescind processing ");
- return;
+ spin_lock_irqsave(&channel->lock, flags);
+ channel->rescind = true;
+ spin_unlock_irqrestore(&channel->lock, flags);
+
+ if (channel->device_obj) {
+ /*
+ * We will have to unregister this device from the
+ * driver core.
+ */
+ dev = get_device(&channel->device_obj->device);
+ if (dev) {
+ vmbus_device_unregister(channel->device_obj);
+ put_device(dev);
+ }
+ } else {
+ hv_process_channel_removal(channel,
+ channel->offermsg.child_relid);
}
- rc_work->channel = channel;
- INIT_WORK(&rc_work->work, process_rescind_fn);
- schedule_work(&rc_work->work);
}
/*
diff --git a/drivers/hv/connection.c b/drivers/hv/connection.c
index 8bcd307..583d7d4 100644
--- a/drivers/hv/connection.c
+++ b/drivers/hv/connection.c
@@ -270,7 +270,7 @@ static struct vmbus_channel *pcpu_relid2channel(u32 relid)
* relid2channel - Get the channel object given its
* child relative id (ie channel id)
*/
-struct vmbus_channel *relid2channel(u32 relid, bool rescind)
+struct vmbus_channel *relid2channel(u32 relid)
{
struct vmbus_channel *channel;
struct vmbus_channel *found_channel = NULL;
@@ -282,8 +282,6 @@ struct vmbus_channel *relid2channel(u32 relid, bool rescind)
list_for_each_entry(channel, &vmbus_connection.chn_list, listentry) {
if (channel->offermsg.child_relid == relid) {
found_channel = channel;
- if (rescind)
- found_channel->rescind = true;
break;
} else if (!list_empty(&channel->sc_list)) {
/*
@@ -294,8 +292,6 @@ struct vmbus_channel *relid2channel(u32 relid, bool rescind)
sc_list);
if (cur_sc->offermsg.child_relid == relid) {
found_channel = cur_sc;
- if (rescind)
- found_channel->rescind = true;
break;
}
}
diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h
index f40a5a9..887287a 100644
--- a/drivers/hv/hyperv_vmbus.h
+++ b/drivers/hv/hyperv_vmbus.h
@@ -715,7 +715,7 @@ void vmbus_device_unregister(struct hv_device *device_obj);
/* VmbusChildDeviceDestroy( */
/* struct hv_device *); */
-struct vmbus_channel *relid2channel(u32 relid, bool rescind);
+struct vmbus_channel *relid2channel(u32 relid);
void vmbus_free_channels(void);
--
1.7.4.1
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 3/7] hv: remove the per-channel workqueue
2015-03-27 16:10 ` [PATCH 1/7] hv: run non-blocking message handlers in the dispatch tasklet K. Y. Srinivasan
2015-03-27 16:10 ` [PATCH 2/7] hv: don't schedule new works in vmbus_onoffer()/vmbus_onoffer_rescind() K. Y. Srinivasan
@ 2015-03-27 16:10 ` K. Y. Srinivasan
2015-03-27 16:10 ` [PATCH 4/7] Drivers: hv: hv_balloon: do not online pages in offline blocks K. Y. Srinivasan
` (3 subsequent siblings)
5 siblings, 0 replies; 8+ messages in thread
From: K. Y. Srinivasan @ 2015-03-27 16:10 UTC (permalink / raw)
To: gregkh, linux-kernel, devel, olaf, apw, vkuznets, jasowang
Cc: Dexuan Cui, K. Y. Srinivasan
From: Dexuan Cui <decui@microsoft.com>
It's not necessary any longer, since we can safely run the blocking
message handlers in vmbus_connection.work_queue now.
Signed-off-by: Dexuan Cui <decui@microsoft.com>
Cc: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
---
drivers/hv/channel_mgmt.c | 30 +-----------------------------
include/linux/hyperv.h | 3 ---
2 files changed, 1 insertions(+), 32 deletions(-)
diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c
index d69864d..0eeb1b3 100644
--- a/drivers/hv/channel_mgmt.c
+++ b/drivers/hv/channel_mgmt.c
@@ -147,43 +147,15 @@ static struct vmbus_channel *alloc_channel(void)
INIT_LIST_HEAD(&channel->sc_list);
INIT_LIST_HEAD(&channel->percpu_list);
- channel->controlwq = alloc_workqueue("hv_vmbus_ctl/%d", WQ_MEM_RECLAIM,
- 1, channel->id);
- if (!channel->controlwq) {
- kfree(channel);
- return NULL;
- }
-
return channel;
}
/*
- * release_hannel - Release the vmbus channel object itself
- */
-static void release_channel(struct work_struct *work)
-{
- struct vmbus_channel *channel = container_of(work,
- struct vmbus_channel,
- work);
-
- destroy_workqueue(channel->controlwq);
-
- kfree(channel);
-}
-
-/*
* free_channel - Release the resources used by the vmbus channel object
*/
static void free_channel(struct vmbus_channel *channel)
{
-
- /*
- * We have to release the channel's workqueue/thread in the vmbus's
- * workqueue/thread context
- * ie we can't destroy ourselves.
- */
- INIT_WORK(&channel->work, release_channel);
- queue_work(vmbus_connection.work_queue, &channel->work);
+ kfree(channel);
}
static void percpu_channel_enq(void *arg)
diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h
index 80e444b..902c37a 100644
--- a/include/linux/hyperv.h
+++ b/include/linux/hyperv.h
@@ -653,8 +653,6 @@ struct vmbus_channel {
struct hv_device *device_obj;
- struct work_struct work;
-
enum vmbus_channel_state state;
struct vmbus_channel_offer_channel offermsg;
@@ -675,7 +673,6 @@ struct vmbus_channel {
struct hv_ring_buffer_info outbound; /* send to parent */
struct hv_ring_buffer_info inbound; /* receive from parent */
spinlock_t inbound_lock;
- struct workqueue_struct *controlwq;
struct vmbus_close_msg close_msg;
--
1.7.4.1
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 4/7] Drivers: hv: hv_balloon: do not online pages in offline blocks
2015-03-27 16:10 ` [PATCH 1/7] hv: run non-blocking message handlers in the dispatch tasklet K. Y. Srinivasan
2015-03-27 16:10 ` [PATCH 2/7] hv: don't schedule new works in vmbus_onoffer()/vmbus_onoffer_rescind() K. Y. Srinivasan
2015-03-27 16:10 ` [PATCH 3/7] hv: remove the per-channel workqueue K. Y. Srinivasan
@ 2015-03-27 16:10 ` K. Y. Srinivasan
2015-03-27 16:10 ` [PATCH 5/7] Drivers: hv: hv_balloon: eliminate jumps in piecewiese linear floor function K. Y. Srinivasan
` (2 subsequent siblings)
5 siblings, 0 replies; 8+ messages in thread
From: K. Y. Srinivasan @ 2015-03-27 16:10 UTC (permalink / raw)
To: gregkh, linux-kernel, devel, olaf, apw, vkuznets, jasowang
Cc: K. Y. Srinivasan
From: Vitaly Kuznetsov <vkuznets@redhat.com>
Currently we add memory in 128Mb blocks but the request from host can be
aligned differently. In such case we add a partially backed block and
when this block goes online we skip onlining pages which are not backed
(hv_online_page() callback serves this purpose). When we receive next
request for the same host add region we online pages which were not backed
before with hv_bring_pgs_online(). However, we don't check if the the block
in question was onlined and online this tail unconditionally. This is bad as
we avoid all online_pages() logic: these pages are not accounted, we don't
send notifications (and hv_balloon is not the only receiver of them),...
And, first of all, nobody asked as to online these pages. Solve the issue by
checking if the last previously backed page was onlined and onlining the tail
only in case it was.
Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com>
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
---
drivers/hv/hv_balloon.c | 12 +++++++++++-
1 files changed, 11 insertions(+), 1 deletions(-)
diff --git a/drivers/hv/hv_balloon.c b/drivers/hv/hv_balloon.c
index 014256a..99afef9 100644
--- a/drivers/hv/hv_balloon.c
+++ b/drivers/hv/hv_balloon.c
@@ -778,7 +778,17 @@ static unsigned long handle_pg_range(unsigned long pg_start,
pgs_ol = has->ha_end_pfn - start_pfn;
if (pgs_ol > pfn_cnt)
pgs_ol = pfn_cnt;
- hv_bring_pgs_online(start_pfn, pgs_ol);
+
+ /*
+ * Check if the corresponding memory block is already
+ * online by checking its last previously backed page.
+ * In case it is we need to bring rest (which was not
+ * backed previously) online too.
+ */
+ if (start_pfn > has->start_pfn &&
+ !PageReserved(pfn_to_page(start_pfn - 1)))
+ hv_bring_pgs_online(start_pfn, pgs_ol);
+
has->covered_end_pfn += pgs_ol;
pfn_cnt -= pgs_ol;
}
--
1.7.4.1
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 5/7] Drivers: hv: hv_balloon: eliminate jumps in piecewiese linear floor function
2015-03-27 16:10 ` [PATCH 1/7] hv: run non-blocking message handlers in the dispatch tasklet K. Y. Srinivasan
` (2 preceding siblings ...)
2015-03-27 16:10 ` [PATCH 4/7] Drivers: hv: hv_balloon: do not online pages in offline blocks K. Y. Srinivasan
@ 2015-03-27 16:10 ` K. Y. Srinivasan
2015-03-27 16:10 ` [PATCH 6/7] Drivers: hv: hv_balloon: survive ballooning request with num_pages=0 K. Y. Srinivasan
2015-03-27 16:10 ` [PATCH 7/7] hv_vmbus: Add gradually increased delay for retries in vmbus_post_msg() K. Y. Srinivasan
5 siblings, 0 replies; 8+ messages in thread
From: K. Y. Srinivasan @ 2015-03-27 16:10 UTC (permalink / raw)
To: gregkh, linux-kernel, devel, olaf, apw, vkuznets, jasowang
Cc: K. Y. Srinivasan
From: Vitaly Kuznetsov <vkuznets@redhat.com>
Commit 79208c57da53 ("Drivers: hv: hv_balloon: Make adjustments in computing
the floor") was inacurate as it introduced a jump in our piecewiese linear
'floor' function:
At 2048MB we have:
Left limit:
104 + 2048/8 = 360
Right limit:
256 + 2048/16 = 384 (so the right value is 232)
We now have to make an adjustment at 8192 boundary:
232 + 8192/16 = 744
512 + 8192/32 = 768 (so the right value is 488)
Suggested-by: Laszlo Ersek <lersek@redhat.com>
Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com>
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
---
drivers/hv/hv_balloon.c | 8 ++++----
1 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/hv/hv_balloon.c b/drivers/hv/hv_balloon.c
index 99afef9..4f5323c 100644
--- a/drivers/hv/hv_balloon.c
+++ b/drivers/hv/hv_balloon.c
@@ -976,8 +976,8 @@ static unsigned long compute_balloon_floor(void)
* 128 72 (1/2)
* 512 168 (1/4)
* 2048 360 (1/8)
- * 8192 768 (1/16)
- * 32768 1536 (1/32)
+ * 8192 744 (1/16)
+ * 32768 1512 (1/32)
*/
if (totalram_pages < MB2PAGES(128))
min_pages = MB2PAGES(8) + (totalram_pages >> 1);
@@ -986,9 +986,9 @@ static unsigned long compute_balloon_floor(void)
else if (totalram_pages < MB2PAGES(2048))
min_pages = MB2PAGES(104) + (totalram_pages >> 3);
else if (totalram_pages < MB2PAGES(8192))
- min_pages = MB2PAGES(256) + (totalram_pages >> 4);
+ min_pages = MB2PAGES(232) + (totalram_pages >> 4);
else
- min_pages = MB2PAGES(512) + (totalram_pages >> 5);
+ min_pages = MB2PAGES(488) + (totalram_pages >> 5);
#undef MB2PAGES
return min_pages;
}
--
1.7.4.1
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 6/7] Drivers: hv: hv_balloon: survive ballooning request with num_pages=0
2015-03-27 16:10 ` [PATCH 1/7] hv: run non-blocking message handlers in the dispatch tasklet K. Y. Srinivasan
` (3 preceding siblings ...)
2015-03-27 16:10 ` [PATCH 5/7] Drivers: hv: hv_balloon: eliminate jumps in piecewiese linear floor function K. Y. Srinivasan
@ 2015-03-27 16:10 ` K. Y. Srinivasan
2015-03-27 16:10 ` [PATCH 7/7] hv_vmbus: Add gradually increased delay for retries in vmbus_post_msg() K. Y. Srinivasan
5 siblings, 0 replies; 8+ messages in thread
From: K. Y. Srinivasan @ 2015-03-27 16:10 UTC (permalink / raw)
To: gregkh, linux-kernel, devel, olaf, apw, vkuznets, jasowang
Cc: K. Y. Srinivasan
From: Vitaly Kuznetsov <vkuznets@redhat.com>
... and simplify alloc_balloon_pages() interface by removing redundant
alloc_error from it.
If we happen to enter balloon_up() with balloon_wrk.num_pages = 0 we will enter
infinite 'while (!done)' loop as alloc_balloon_pages() will be always returning
0 and not setting alloc_error. We will also be sending a meaningless message to
the host on every iteration.
The 'alloc_unit == 1 && alloc_error -> num_ballooned == 0' change and
alloc_error elimination requires a special comment. We do alloc_balloon_pages()
with 2 different alloc_unit values and there are 4 different
alloc_balloon_pages() results, let's check them all.
alloc_unit = 512:
1) num_ballooned = 0, alloc_error = 0: we do 'alloc_unit=1' and retry pre- and
post-patch.
2) num_ballooned > 0, alloc_error = 0: we check 'num_ballooned == num_pages'
and act accordingly, pre- and post-patch.
3) num_ballooned > 0, alloc_error > 0: we report this chunk and remain within
the loop, no changes here.
4) num_ballooned = 0, alloc_error > 0: we do 'alloc_unit=1' and retry pre- and
post-patch.
alloc_unit = 1:
1) num_ballooned = 0, alloc_error = 0: this can happen in two cases: when we
passed 'num_pages=0' to alloc_balloon_pages() or when there was no space in
bl_resp to place a single response. The second option is not possible as
bl_resp is of PAGE_SIZE size and single response 'union dm_mem_page_range' is
8 bytes, but the first one is (in theory, I think that Hyper-V host never
places such requests). Pre-patch code loops forever, post-patch code sends
a reply with more_pages = 0 and finishes.
2) num_ballooned > 0, alloc_error = 0: we ran out of space in bl_resp, we
report partial success and remain within the loop, no changes pre- and
post-patch.
3) num_ballooned > 0, alloc_error > 0: pre-patch code finishes, post-patch code
does one more try and if there is no progress (we finish with
'num_ballooned = 0') we finish. So we try a bit harder with this patch.
4) num_ballooned = 0, alloc_error > 0: both pre- and post-patch code enter
'more_pages = 0' branch and finish.
So this patch has two real effects:
1) We reply with an empty response to 'num_pages=0' request.
2) We try a bit harder on alloc_unit=1 allocations (and reply with an empty
tail reply in case we fail).
An empty reply should be supported by host as we were able to send it even with
pre-patch code when we were not able to allocate a single page.
Suggested-by: Laszlo Ersek <lersek@redhat.com>
Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com>
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
---
drivers/hv/hv_balloon.c | 19 ++++++-------------
1 files changed, 6 insertions(+), 13 deletions(-)
diff --git a/drivers/hv/hv_balloon.c b/drivers/hv/hv_balloon.c
index 4f5323c..74312c8 100644
--- a/drivers/hv/hv_balloon.c
+++ b/drivers/hv/hv_balloon.c
@@ -1081,9 +1081,9 @@ static void free_balloon_pages(struct hv_dynmem_device *dm,
-static int alloc_balloon_pages(struct hv_dynmem_device *dm, int num_pages,
- struct dm_balloon_response *bl_resp, int alloc_unit,
- bool *alloc_error)
+static int alloc_balloon_pages(struct hv_dynmem_device *dm, int num_pages,
+ struct dm_balloon_response *bl_resp,
+ int alloc_unit)
{
int i = 0;
struct page *pg;
@@ -1104,11 +1104,8 @@ static int alloc_balloon_pages(struct hv_dynmem_device *dm, int num_pages,
__GFP_NOMEMALLOC | __GFP_NOWARN,
get_order(alloc_unit << PAGE_SHIFT));
- if (!pg) {
- *alloc_error = true;
+ if (!pg)
return i * alloc_unit;
- }
-
dm->num_pages_ballooned += alloc_unit;
@@ -1140,7 +1137,6 @@ static void balloon_up(struct work_struct *dummy)
struct dm_balloon_response *bl_resp;
int alloc_unit;
int ret;
- bool alloc_error;
bool done = false;
int i;
struct sysinfo val;
@@ -1173,18 +1169,15 @@ static void balloon_up(struct work_struct *dummy)
num_pages -= num_ballooned;
- alloc_error = false;
num_ballooned = alloc_balloon_pages(&dm_device, num_pages,
- bl_resp, alloc_unit,
- &alloc_error);
+ bl_resp, alloc_unit);
if (alloc_unit != 1 && num_ballooned == 0) {
alloc_unit = 1;
continue;
}
- if ((alloc_unit == 1 && alloc_error) ||
- (num_ballooned == num_pages)) {
+ if (num_ballooned == 0 || num_ballooned == num_pages) {
bl_resp->more_pages = 0;
done = true;
dm_device.state = DM_INITIALIZED;
--
1.7.4.1
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 7/7] hv_vmbus: Add gradually increased delay for retries in vmbus_post_msg()
2015-03-27 16:10 ` [PATCH 1/7] hv: run non-blocking message handlers in the dispatch tasklet K. Y. Srinivasan
` (4 preceding siblings ...)
2015-03-27 16:10 ` [PATCH 6/7] Drivers: hv: hv_balloon: survive ballooning request with num_pages=0 K. Y. Srinivasan
@ 2015-03-27 16:10 ` K. Y. Srinivasan
5 siblings, 0 replies; 8+ messages in thread
From: K. Y. Srinivasan @ 2015-03-27 16:10 UTC (permalink / raw)
To: gregkh, linux-kernel, devel, olaf, apw, vkuznets, jasowang
Cc: Haiyang Zhang, K. Y. Srinivasan
From: Haiyang Zhang <haiyangz@microsoft.com>
Most of the retries can be done within a millisecond successfully, so we
sleep 1ms before the first retry, then gradually increase the retry
interval to 2^n with max value of 2048ms. Doing so, we will have shorter
overall delay time, because most of the cases succeed within 1-2 attempts.
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
Reviewed-by: K. Y. Srinivasan <kys@microsoft.com>
Reviewed-by: Dexuan Cui <decui@microsoft.com>
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
---
drivers/hv/connection.c | 7 +++++--
1 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/drivers/hv/connection.c b/drivers/hv/connection.c
index 583d7d4..b27220a 100644
--- a/drivers/hv/connection.c
+++ b/drivers/hv/connection.c
@@ -422,6 +422,7 @@ int vmbus_post_msg(void *buffer, size_t buflen)
union hv_connection_id conn_id;
int ret = 0;
int retries = 0;
+ u32 msec = 1;
conn_id.asu32 = 0;
conn_id.u.id = VMBUS_MESSAGE_CONNECTION_ID;
@@ -431,7 +432,7 @@ int vmbus_post_msg(void *buffer, size_t buflen)
* insufficient resources. Retry the operation a couple of
* times before giving up.
*/
- while (retries < 10) {
+ while (retries < 20) {
ret = hv_post_message(conn_id, 1, buffer, buflen);
switch (ret) {
@@ -454,7 +455,9 @@ int vmbus_post_msg(void *buffer, size_t buflen)
}
retries++;
- msleep(1000);
+ msleep(msec);
+ if (msec < 2048)
+ msec *= 2;
}
return ret;
}
--
1.7.4.1
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2015-03-27 14:54 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-03-27 16:09 [PATCH 0/7] Drivers: hv: Miscellaneous cleanups and bug fixes K. Y. Srinivasan
2015-03-27 16:10 ` [PATCH 1/7] hv: run non-blocking message handlers in the dispatch tasklet K. Y. Srinivasan
2015-03-27 16:10 ` [PATCH 2/7] hv: don't schedule new works in vmbus_onoffer()/vmbus_onoffer_rescind() K. Y. Srinivasan
2015-03-27 16:10 ` [PATCH 3/7] hv: remove the per-channel workqueue K. Y. Srinivasan
2015-03-27 16:10 ` [PATCH 4/7] Drivers: hv: hv_balloon: do not online pages in offline blocks K. Y. Srinivasan
2015-03-27 16:10 ` [PATCH 5/7] Drivers: hv: hv_balloon: eliminate jumps in piecewiese linear floor function K. Y. Srinivasan
2015-03-27 16:10 ` [PATCH 6/7] Drivers: hv: hv_balloon: survive ballooning request with num_pages=0 K. Y. Srinivasan
2015-03-27 16:10 ` [PATCH 7/7] hv_vmbus: Add gradually increased delay for retries in vmbus_post_msg() K. Y. Srinivasan
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Powered by JetHome