From patchwork Thu Mar 14 18:31:34 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marcelo Henrique Cerri X-Patchwork-Id: 1056657 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.ubuntu.com (client-ip=91.189.94.19; helo=huckleberry.canonical.com; envelope-from=kernel-team-bounces@lists.ubuntu.com; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=canonical.com Received: from huckleberry.canonical.com (huckleberry.canonical.com [91.189.94.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 44Ky3r68KCz9s9N; Fri, 15 Mar 2019 05:32:08 +1100 (AEDT) Received: from localhost ([127.0.0.1] helo=huckleberry.canonical.com) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1h4V97-0007sV-TS; Thu, 14 Mar 2019 18:32:01 +0000 Received: from youngberry.canonical.com ([91.189.89.112]) by huckleberry.canonical.com with esmtps (TLS1.0:DHE_RSA_AES_128_CBC_SHA1:128) (Exim 4.86_2) (envelope-from ) id 1h4V93-0007o8-3J for kernel-team@lists.ubuntu.com; Thu, 14 Mar 2019 18:31:57 +0000 Received: from mail-qk1-f200.google.com ([209.85.222.200]) by youngberry.canonical.com with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.76) (envelope-from ) id 1h4V91-0004Y8-Gs for kernel-team@lists.ubuntu.com; Thu, 14 Mar 2019 18:31:55 +0000 Received: by mail-qk1-f200.google.com with SMTP id 23so5513578qkl.16 for ; Thu, 14 Mar 2019 11:31:55 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references; bh=g0kmdaqgmZ464RcnsqZ9L8pr11giP8C9B+8EHGhtORc=; b=EjBI4MwjVg9kgAgcaZguwf4ybu2+vzidvcMMd1FqJXEm/R9ZqukbRduvOyHE82grSa wK+cb8KQjulnbjR+i8Y9gqXiYJefmq4+gWc5/PZdL5uEzK9wYUCVC1i6DkliQpgXW1Dd +eOQ/H9kdKpSFyIh0ucuz/JU55u5z2mUHno6L7hPJR+zZSUsYZgJv1JcF/pnx+rEpRIY 8lI4oo2REdzwqS4+wagebn0nWRczfB+oqDIGXcsqbanB10K8HVzosV6bZGC8gQcO1Dej 52P+ZoTx+uJv2ubefO5LaOHPHnt51XIv7OBLDCe29ZZQUC7QDaS2up3kiMzKMUuCC8vA 33mg== X-Gm-Message-State: APjAAAUNLAUYRnbWP6gS59a5+Uw79gTXCEB/zDbDF1gZ4shblwb6Uzc4 aDEzAuPFMqDXYa9+m6UJGuihgXFv+7used4FWhFfNRVvN8/eBi408vWdWUdSGNEFyahvZWgmJkJ oMxU8rAF+cn/9oygetXRjXU5KzyzEPLbBKwB55zBA X-Received: by 2002:a05:620a:1348:: with SMTP id c8mr38468923qkl.246.1552588314205; Thu, 14 Mar 2019 11:31:54 -0700 (PDT) X-Google-Smtp-Source: APXvYqwj96TZfzqRWuolTlkerAPyZILiVxhgizZN8S5f9Dhzq8J14bUaNwkBIH/7Xh2DdpCkwcEp0A== X-Received: by 2002:a05:620a:1348:: with SMTP id c8mr38468895qkl.246.1552588313804; Thu, 14 Mar 2019 11:31:53 -0700 (PDT) Received: from gallifrey.lan ([2804:14c:4e3:4a76:8145:c566:46dd:a2ba]) by smtp.gmail.com with ESMTPSA id j64sm1575576qkf.13.2019.03.14.11.31.51 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 14 Mar 2019 11:31:53 -0700 (PDT) From: Marcelo Henrique Cerri To: kernel-team@lists.ubuntu.com Subject: [c/azure][PATCH 7/8] vmbus: split ring buffer allocation from open Date: Thu, 14 Mar 2019 15:31:34 -0300 Message-Id: <20190314183135.20235-8-marcelo.cerri@canonical.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190314183135.20235-1-marcelo.cerri@canonical.com> References: <20190314183135.20235-1-marcelo.cerri@canonical.com> X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.20 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: "kernel-team" From: Stephen Hemminger BugLink: http://bugs.launchpad.net/bugs/1812123 The UIO driver needs the ring buffer to be persistent(reused) across open/close. Split the allocation and setup of ring buffer out of vmbus_open. For normal usage vmbus_open/vmbus_close there are no changes; only impacts uio_hv_generic which needs to keep ring buffer memory and reuse when application restarts. Signed-off-by: Stephen Hemminger Signed-off-by: Greg Kroah-Hartman (cherry picked from commit ae6935ed7d424ffa74d634da00767e7b03c98fd3) Signed-off-by: Marcelo Henrique Cerri --- drivers/hv/channel.c | 267 ++++++++++++++++++++++----------------- drivers/hv/ring_buffer.c | 1 + include/linux/hyperv.h | 9 ++ 3 files changed, 162 insertions(+), 115 deletions(-) diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c index 00ca3008d412..0ecbdcf3ad15 100644 --- a/drivers/hv/channel.c +++ b/drivers/hv/channel.c @@ -78,84 +78,96 @@ void vmbus_setevent(struct vmbus_channel *channel) } EXPORT_SYMBOL_GPL(vmbus_setevent); -/* - * vmbus_open - Open the specified channel. - */ -int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size, - u32 recv_ringbuffer_size, void *userdata, u32 userdatalen, - void (*onchannelcallback)(void *context), void *context) +/* vmbus_free_ring - drop mapping of ring buffer */ +void vmbus_free_ring(struct vmbus_channel *channel) { - struct vmbus_channel_open_channel *open_msg; - struct vmbus_channel_msginfo *open_info = NULL; - unsigned long flags; - int ret, err = 0; - struct page *page; - unsigned int order; + hv_ringbuffer_cleanup(&channel->outbound); + hv_ringbuffer_cleanup(&channel->inbound); - if (send_ringbuffer_size % PAGE_SIZE || - recv_ringbuffer_size % PAGE_SIZE) - return -EINVAL; + if (channel->ringbuffer_page) { + __free_pages(channel->ringbuffer_page, + get_order(channel->ringbuffer_pagecount + << PAGE_SHIFT)); + channel->ringbuffer_page = NULL; + } +} +EXPORT_SYMBOL_GPL(vmbus_free_ring); - order = get_order(send_ringbuffer_size + recv_ringbuffer_size); +/* vmbus_alloc_ring - allocate and map pages for ring buffer */ +int vmbus_alloc_ring(struct vmbus_channel *newchannel, + u32 send_size, u32 recv_size) +{ + struct page *page; + int order; - spin_lock_irqsave(&newchannel->lock, flags); - if (newchannel->state == CHANNEL_OPEN_STATE) { - newchannel->state = CHANNEL_OPENING_STATE; - } else { - spin_unlock_irqrestore(&newchannel->lock, flags); + if (send_size % PAGE_SIZE || recv_size % PAGE_SIZE) return -EINVAL; - } - spin_unlock_irqrestore(&newchannel->lock, flags); - - newchannel->onchannel_callback = onchannelcallback; - newchannel->channel_callback_context = context; /* Allocate the ring buffer */ + order = get_order(send_size + recv_size); page = alloc_pages_node(cpu_to_node(newchannel->target_cpu), GFP_KERNEL|__GFP_ZERO, order); if (!page) page = alloc_pages(GFP_KERNEL|__GFP_ZERO, order); - if (!page) { - err = -ENOMEM; - goto error_set_chnstate; - } + if (!page) + return -ENOMEM; newchannel->ringbuffer_page = page; - newchannel->ringbuffer_pagecount = (send_ringbuffer_size + - recv_ringbuffer_size) >> PAGE_SHIFT; + newchannel->ringbuffer_pagecount = (send_size + recv_size) >> PAGE_SHIFT; + newchannel->ringbuffer_send_offset = send_size >> PAGE_SHIFT; - ret = hv_ringbuffer_init(&newchannel->outbound, page, - send_ringbuffer_size >> PAGE_SHIFT); + return 0; +} +EXPORT_SYMBOL_GPL(vmbus_alloc_ring); - if (ret != 0) { - err = ret; - goto error_free_pages; - } +static int __vmbus_open(struct vmbus_channel *newchannel, + void *userdata, u32 userdatalen, + void (*onchannelcallback)(void *context), void *context) +{ + struct vmbus_channel_open_channel *open_msg; + struct vmbus_channel_msginfo *open_info = NULL; + struct page *page = newchannel->ringbuffer_page; + u32 send_pages, recv_pages; + unsigned long flags; + int err; - ret = hv_ringbuffer_init(&newchannel->inbound, - &page[send_ringbuffer_size >> PAGE_SHIFT], - recv_ringbuffer_size >> PAGE_SHIFT); - if (ret != 0) { - err = ret; - goto error_free_pages; + if (userdatalen > MAX_USER_DEFINED_BYTES) + return -EINVAL; + + send_pages = newchannel->ringbuffer_send_offset; + recv_pages = newchannel->ringbuffer_pagecount - send_pages; + + spin_lock_irqsave(&newchannel->lock, flags); + if (newchannel->state != CHANNEL_OPEN_STATE) { + spin_unlock_irqrestore(&newchannel->lock, flags); + return -EINVAL; } + spin_unlock_irqrestore(&newchannel->lock, flags); + newchannel->state = CHANNEL_OPENING_STATE; + newchannel->onchannel_callback = onchannelcallback; + newchannel->channel_callback_context = context; + + err = hv_ringbuffer_init(&newchannel->outbound, page, send_pages); + if (err) + goto error_clean_ring; + + err = hv_ringbuffer_init(&newchannel->inbound, + &page[send_pages], recv_pages); + if (err) + goto error_clean_ring; /* Establish the gpadl for the ring buffer */ newchannel->ringbuffer_gpadlhandle = 0; - ret = vmbus_establish_gpadl(newchannel, - page_address(page), - send_ringbuffer_size + - recv_ringbuffer_size, + err = vmbus_establish_gpadl(newchannel, + page_address(newchannel->ringbuffer_page), + (send_pages + recv_pages) << PAGE_SHIFT, &newchannel->ringbuffer_gpadlhandle); - - if (ret != 0) { - err = ret; - goto error_free_pages; - } + if (err) + goto error_clean_ring; /* Create and init the channel open message */ open_info = kmalloc(sizeof(*open_info) + @@ -174,15 +186,9 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size, open_msg->openid = newchannel->offermsg.child_relid; open_msg->child_relid = newchannel->offermsg.child_relid; open_msg->ringbuffer_gpadlhandle = newchannel->ringbuffer_gpadlhandle; - open_msg->downstream_ringbuffer_pageoffset = send_ringbuffer_size >> - PAGE_SHIFT; + open_msg->downstream_ringbuffer_pageoffset = newchannel->ringbuffer_send_offset; open_msg->target_vp = newchannel->target_vp; - if (userdatalen > MAX_USER_DEFINED_BYTES) { - err = -EINVAL; - goto error_free_gpadl; - } - if (userdatalen) memcpy(open_msg->userdata, userdata, userdatalen); @@ -193,18 +199,16 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size, if (newchannel->rescind) { err = -ENODEV; - goto error_free_gpadl; + goto error_free_info; } - ret = vmbus_post_msg(open_msg, + err = vmbus_post_msg(open_msg, sizeof(struct vmbus_channel_open_channel), true); - trace_vmbus_open(open_msg, ret); + trace_vmbus_open(open_msg, err); - if (ret != 0) { - err = ret; + if (err != 0) goto error_clean_msglist; - } wait_for_completion(&open_info->waitevent); @@ -214,12 +218,12 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size, if (newchannel->rescind) { err = -ENODEV; - goto error_free_gpadl; + goto error_free_info; } if (open_info->response.open_result.status) { err = -EAGAIN; - goto error_free_gpadl; + goto error_free_info; } newchannel->state = CHANNEL_OPENED_STATE; @@ -230,18 +234,50 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size, spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags); list_del(&open_info->msglistentry); spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags); - +error_free_info: + kfree(open_info); error_free_gpadl: vmbus_teardown_gpadl(newchannel, newchannel->ringbuffer_gpadlhandle); - kfree(open_info); -error_free_pages: + newchannel->ringbuffer_gpadlhandle = 0; +error_clean_ring: hv_ringbuffer_cleanup(&newchannel->outbound); hv_ringbuffer_cleanup(&newchannel->inbound); - __free_pages(page, order); -error_set_chnstate: newchannel->state = CHANNEL_OPEN_STATE; return err; } + +/* + * vmbus_connect_ring - Open the channel but reuse ring buffer + */ +int vmbus_connect_ring(struct vmbus_channel *newchannel, + void (*onchannelcallback)(void *context), void *context) +{ + return __vmbus_open(newchannel, NULL, 0, onchannelcallback, context); +} +EXPORT_SYMBOL_GPL(vmbus_connect_ring); + +/* + * vmbus_open - Open the specified channel. + */ +int vmbus_open(struct vmbus_channel *newchannel, + u32 send_ringbuffer_size, u32 recv_ringbuffer_size, + void *userdata, u32 userdatalen, + void (*onchannelcallback)(void *context), void *context) +{ + int err; + + err = vmbus_alloc_ring(newchannel, send_ringbuffer_size, + recv_ringbuffer_size); + if (err) + return err; + + err = __vmbus_open(newchannel, userdata, userdatalen, + onchannelcallback, context); + if (err) + vmbus_free_ring(newchannel); + + return err; +} EXPORT_SYMBOL_GPL(vmbus_open); /* Used for Hyper-V Socket: a guest client's connect() to the host */ @@ -618,10 +654,8 @@ static int vmbus_close_internal(struct vmbus_channel *channel) * in Hyper-V Manager), the driver's remove() invokes vmbus_close(): * here we should skip most of the below cleanup work. */ - if (channel->state != CHANNEL_OPENED_STATE) { - ret = -EINVAL; - goto out; - } + if (channel->state != CHANNEL_OPENED_STATE) + return -EINVAL; channel->state = CHANNEL_OPEN_STATE; @@ -643,11 +677,10 @@ static int vmbus_close_internal(struct vmbus_channel *channel) * If we failed to post the close msg, * it is perhaps better to leak memory. */ - goto out; } /* Tear down the gpadl for the channel's ring buffer */ - if (channel->ringbuffer_gpadlhandle) { + else if (channel->ringbuffer_gpadlhandle) { ret = vmbus_teardown_gpadl(channel, channel->ringbuffer_gpadlhandle); if (ret) { @@ -656,59 +689,63 @@ static int vmbus_close_internal(struct vmbus_channel *channel) * If we failed to teardown gpadl, * it is perhaps better to leak memory. */ - goto out; } - } - - /* Cleanup the ring buffers for this channel */ - hv_ringbuffer_cleanup(&channel->outbound); - hv_ringbuffer_cleanup(&channel->inbound); - __free_pages(channel->ringbuffer_page, - get_order(channel->ringbuffer_pagecount << PAGE_SHIFT)); + channel->ringbuffer_gpadlhandle = 0; + } -out: return ret; } -/* - * vmbus_close - Close the specified channel - */ -void vmbus_close(struct vmbus_channel *channel) +/* disconnect ring - close all channels */ +int vmbus_disconnect_ring(struct vmbus_channel *channel) { - struct list_head *cur, *tmp; - struct vmbus_channel *cur_channel; + struct vmbus_channel *cur_channel, *tmp; + unsigned long flags; + LIST_HEAD(list); + int ret; - if (channel->primary_channel != NULL) { - /* - * We will only close sub-channels when - * the primary is closed. - */ - return; - } - /* - * Close all the sub-channels first and then close the - * primary channel. - */ - list_for_each_safe(cur, tmp, &channel->sc_list) { - cur_channel = list_entry(cur, struct vmbus_channel, sc_list); - if (cur_channel->rescind) { + if (channel->primary_channel != NULL) + return -EINVAL; + + /* Snapshot the list of subchannels */ + spin_lock_irqsave(&channel->lock, flags); + list_splice_init(&channel->sc_list, &list); + channel->num_sc = 0; + spin_unlock_irqrestore(&channel->lock, flags); + + list_for_each_entry_safe(cur_channel, tmp, &list, sc_list) { + if (cur_channel->rescind) wait_for_completion(&cur_channel->rescind_event); - mutex_lock(&vmbus_connection.channel_mutex); - vmbus_close_internal(cur_channel); - hv_process_channel_removal(cur_channel); - } else { - mutex_lock(&vmbus_connection.channel_mutex); - vmbus_close_internal(cur_channel); + + mutex_lock(&vmbus_connection.channel_mutex); + if (vmbus_close_internal(cur_channel) == 0) { + vmbus_free_ring(cur_channel); + + if (cur_channel->rescind) + hv_process_channel_removal(cur_channel); } mutex_unlock(&vmbus_connection.channel_mutex); } + /* * Now close the primary. */ mutex_lock(&vmbus_connection.channel_mutex); - vmbus_close_internal(channel); + ret = vmbus_close_internal(channel); mutex_unlock(&vmbus_connection.channel_mutex); + + return ret; +} +EXPORT_SYMBOL_GPL(vmbus_disconnect_ring); + +/* + * vmbus_close - Close the specified channel + */ +void vmbus_close(struct vmbus_channel *channel) +{ + if (vmbus_disconnect_ring(channel) == 0) + vmbus_free_ring(channel); } EXPORT_SYMBOL_GPL(vmbus_close); diff --git a/drivers/hv/ring_buffer.c b/drivers/hv/ring_buffer.c index be3c8b10b84a..240774e2bc2e 100644 --- a/drivers/hv/ring_buffer.c +++ b/drivers/hv/ring_buffer.c @@ -241,6 +241,7 @@ int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info, void hv_ringbuffer_cleanup(struct hv_ring_buffer_info *ring_info) { vunmap(ring_info->ring_buffer); + ring_info->ring_buffer = NULL; } /* Write to the ring buffer. */ diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h index 815b0a0102da..89d09b4064a4 100644 --- a/include/linux/hyperv.h +++ b/include/linux/hyperv.h @@ -726,6 +726,7 @@ struct vmbus_channel { /* Allocated memory for ring buffer */ struct page *ringbuffer_page; u32 ringbuffer_pagecount; + u32 ringbuffer_send_offset; struct hv_ring_buffer_info outbound; /* send to parent */ struct hv_ring_buffer_info inbound; /* receive from parent */ @@ -1013,6 +1014,14 @@ struct vmbus_packet_mpb_array { struct hv_mpb_array range; } __packed; +int vmbus_alloc_ring(struct vmbus_channel *channel, + u32 send_size, u32 recv_size); +void vmbus_free_ring(struct vmbus_channel *channel); + +int vmbus_connect_ring(struct vmbus_channel *channel, + void (*onchannel_callback)(void *context), + void *context); +int vmbus_disconnect_ring(struct vmbus_channel *channel); extern int vmbus_open(struct vmbus_channel *channel, u32 send_ringbuffersize,