Drivers: hv: Miscellaneous cleanups and bug fixes
cover Drivers: hv: Miscellaneous cleanups and bug fixes
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(-)
Signature · 1 line
1.7.4.1
PATCH 1/7 hv: run non-blocking message handlers in the dispatch tasklet
From: Dexuan Cui <[email protected]>
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.
--- 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(-)
drivers/hv/channel_mgmt.c +18 -23
@@ -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 }, };/*
drivers/hv/hyperv_vmbus.h +17 -0
@@ -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,
drivers/hv/vmbus_drv.c +18 -3
@@ -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 ;/*
Signature · 1 line
1.7.4.1
PATCH 2/7 hv: don't schedule new works in vmbus_onoffer()/vmbus_onoffer_rescind()
From: Dexuan Cui <[email protected]>
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.
--- drivers/hv/channel_mgmt.c | 157 ++++++++------------------------------------- drivers/hv/connection.c | 6 +-- drivers/hv/hyperv_vmbus.h | 2 +- 3 files changed, 30 insertions(+), 135 deletions(-)
drivers/hv/channel_mgmt.c +28 -129
@@ -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); }/*
drivers/hv/connection.c +1 -5
@@ -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 ; } }
drivers/hv/hyperv_vmbus.h +1 -1
@@ -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 );
Signature · 1 line
1.7.4.1
PATCH 3/7 hv: remove the per-channel workqueue
In reply to K. Y. SrinivasanFrom: Dexuan Cui <[email protected]>
It's not necessary any longer, since we can safely run the blocking message handlers in vmbus_connection.work_queue now.
--- drivers/hv/channel_mgmt.c | 30 +----------------------------- include/linux/hyperv.h | 3 --- 2 files changed, 1 insertions(+), 32 deletions(-)
drivers/hv/channel_mgmt.c +1 -29
@@ -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)
include/linux/hyperv.h +0 -3
@@ -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;
Signature · 1 line
1.7.4.1
PATCH 4/7 Drivers: hv: hv_balloon: do not online pages in offline blocks
In reply to K. Y. SrinivasanFrom: Vitaly Kuznetsov <[email protected]>
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.
--- drivers/hv/hv_balloon.c | 12 +++++++++++- 1 files changed, 11 insertions(+), 1 deletions(-)
drivers/hv/hv_balloon.c +11 -1
@@ -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; }
Signature · 1 line
1.7.4.1
PATCH 5/7 Drivers: hv: hv_balloon: eliminate jumps in piecewiese linear floor function
In reply to K. Y. SrinivasanFrom: Vitaly Kuznetsov <[email protected]>
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)
--- drivers/hv/hv_balloon.c | 8 ++++---- 1 files changed, 4 insertions(+), 4 deletions(-)
drivers/hv/hv_balloon.c +4 -4
@@ -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 MB2PAGESreturn min_pages; }
Signature · 1 line
1.7.4.1
PATCH 6/7 Drivers: hv: hv_balloon: survive ballooning request with num_pages=0
In reply to K. Y. SrinivasanFrom: Vitaly Kuznetsov <[email protected]>
... 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.
--- drivers/hv/hv_balloon.c | 19 ++++++------------- 1 files changed, 6 insertions(+), 13 deletions(-)
drivers/hv/hv_balloon.c +6 -13
@@ -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 ;
Signature · 1 line
1.7.4.1
PATCH 7/7 hv_vmbus: Add gradually increased delay for retries in vmbus_post_msg()
In reply to K. Y. SrinivasanFrom: Haiyang Zhang <[email protected]>
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.
--- drivers/hv/connection.c | 7 +++++-- 1 files changed, 5 insertions(+), 2 deletions(-)
drivers/hv/connection.c +5 -2
@@ -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; }
Signature · 1 line
1.7.4.1