diff -r e7efce6f371c -r d4ea70e2848e linux-2.6-xen-sparse/drivers/xen/xenidc/Makefile --- a/linux-2.6-xen-sparse/drivers/xen/xenidc/Makefile Sun Nov 20 17:45:28 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/Makefile Mon Nov 21 11:04:23 2005 @@ -16,3 +16,4 @@ xenidc-objs += xenidc_gateway_initiator_resource.o xenidc-objs += xenidc_gateway_target_resource.o xenidc-objs += xenidc_endpoint.o +xenidc-objs += xenidc_rbr_provider_pool.o diff -r e7efce6f371c -r d4ea70e2848e linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_rbr_provider_pool.c --- /dev/null Sun Nov 20 17:45:28 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_rbr_provider_pool.c Mon Nov 21 11:04:23 2005 @@ -0,0 +1,421 @@ +/*****************************************************************************/ +/* Xen remote buffer reference provider pool. */ +/* */ +/* Copyright (c) 2005 Harry Butterworth IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, but */ +/* WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with this program; if not, write to the Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/*****************************************************************************/ + +#include +#include +#include +#include "xenidc_trace.h" + +static XENIDC_CALLBACK_SERIALISER(xenidc_rbr_provider_pool_callback_serialiser); + +struct xenidc_rbr_provider_pool_struct { + xenidc_buffer_resource_list anti_deadlock_resource_allocation; + + xenidc_buffer_resource_provider *provider; + + spinlock_t lock; + + xenidc_buffer_resource_list head_request_required_resources; + + struct list_head request_list; + + int kicking_requests:1; + int head_request_required_resources_calculated:1; +}; + +static int xenidc_rbr_provider_pool_init_or_exit + (xenidc_rbr_provider_pool * pool, int exit) { + trace(); + + { + int return_value = 0; + + if (exit) { + goto EXIT; + } + + pool->provider = xenidc_allocate_buffer_resource_provider + (pool->anti_deadlock_resource_allocation); + + if (pool->provider == NULL) { + goto EXIT_NO_PROVIDER; + } + + spin_lock_init(&pool->lock); + + INIT_LIST_HEAD(&pool->request_list); + + pool->kicking_requests = 0; + pool->head_request_required_resources_calculated = 0; + + return 0; + + EXIT: + + xenidc_free_buffer_resource_provider(pool->provider); + + EXIT_NO_PROVIDER: + + return return_value; + } +} + +xenidc_rbr_provider_pool *xenidc_allocate_rbr_provider_pool + (xenidc_buffer_resource_list anti_deadlock_resource_allocation) { + trace0("anti-deadlock:"); + + traceonly + (xenidc_buffer_resource_list_trace + (anti_deadlock_resource_allocation) + ); + + { + xenidc_rbr_provider_pool *pool = (xenidc_rbr_provider_pool *) + vmalloc(sizeof(xenidc_rbr_provider_pool)); + + if (pool != NULL) { + pool->anti_deadlock_resource_allocation = + anti_deadlock_resource_allocation; + + if (xenidc_rbr_provider_pool_init_or_exit(pool, 0) != 0) { + vfree(pool); + + pool = NULL; + } + } + + return pool; + } +} + +void xenidc_free_rbr_provider_pool(xenidc_rbr_provider_pool * pool) +{ + trace(); + + (void)xenidc_rbr_provider_pool_init_or_exit(pool, 1); + + vfree(pool); +} + +static void xenidc_rbr_provider_pool_kick_requests + (xenidc_rbr_provider_pool * pool); + +void xenidc_rbr_provider_pool_reserve_and_create_rbrs + (xenidc_rbr_provider_pool * pool, + xenidc_reserve_and_create_rbr_request * request, xenidc_address address) { + trace(); + + /* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */ + + request->pool = pool; + request->address = address; + + { + unsigned long flags; + + spin_lock_irqsave(&pool->lock, flags); + + list_add_tail + (xenidc_reserve_and_create_rbr_request_to_link(request), + &pool->request_list); + + spin_unlock_irqrestore(&pool->lock, flags); + } + + xenidc_rbr_provider_pool_kick_requests(pool); +} + +static int xenidc_rbr_provider_pool_calculate_required_resources + (xenidc_reserve_and_create_rbr_request * request, + xenidc_buffer_resource_list * list) { + trace(); + + *list = xenidc_buffer_resource_list_null(); + + { + xenidc_create_rbr_request_element *element; + + list_for_each_entry(element, &request->request_elements, link) { + xenidc_local_buffer_reference resolved_lbr = + xenidc_local_buffer_reference_resolve(&element-> + lbr); + + if (xenidc_local_buffer_reference_query_byte_count + (&resolved_lbr) + != + xenidc_local_buffer_reference_query_byte_count + (&element->lbr) + ) { + printk + (KERN_WARNING + "xenidc_rbr_provider_pool resolved a virtual local buffer " + "reference to multiple concrete local buffer references. " + "This is currently unsupported. Sorry.\n"); + + return 1; + } + + { + xenidc_buffer_resource_list element_list; + + if (xenidc_local_buffer_reference_calculate_rbr_resources(&resolved_lbr, &request->address, &element_list) + != 0) { + return 1; + } + + trace0("element:"); + + traceonly(xenidc_buffer_resource_list_trace + (element_list)); + + xenidc_buffer_resource_list_plus_equals + (list, &element_list); + } + } + } + + trace0("total:"); + + traceonly(xenidc_buffer_resource_list_trace(*list)); + + return 0; +} + +static void xenidc_rbr_provider_pool_service_request + (xenidc_rbr_provider_pool * pool, + xenidc_reserve_and_create_rbr_request * request) { + trace(); + + /* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */ + + { + xenidc_create_rbr_request_element *element; + + list_for_each_entry(element, &request->request_elements, link) { + xenidc_local_buffer_reference resolved_lbr = + xenidc_local_buffer_reference_resolve(&element-> + lbr); + + element->handle = + xenidc_local_buffer_reference_create_rbr + (&resolved_lbr, &request->address, pool->provider, + &element->rbr, element->access_flags); + } + } + + xenidc_callback_serialiser_complete_callback + (&xenidc_rbr_provider_pool_callback_serialiser, + xenidc_reserve_and_create_rbr_request_to_create_callback(request), + XENIDC_ERROR_SUCCESS); +} + +static void xenidc_rbr_provider_pool_kick_requests + (xenidc_rbr_provider_pool * pool) { + trace(); + + /* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */ + + { + unsigned long flags; + + spin_lock_irqsave(&pool->lock, flags); + + while ((!pool->kicking_requests) + && (!list_empty(&pool->request_list)) + ) { + xenidc_reserve_and_create_rbr_request *request = + xenidc_reserve_and_create_rbr_request_link_to + (pool->request_list.next); + + if (!pool->head_request_required_resources_calculated) { + if ((xenidc_rbr_provider_pool_calculate_required_resources(request, &pool->head_request_required_resources) + != 0) + || + (!xenidc_buffer_resource_list_subset_of + (&pool->head_request_required_resources, + &pool->anti_deadlock_resource_allocation) + ) + ) { + list_del_init + (xenidc_reserve_and_create_rbr_request_to_link + (request) + ); + + xenidc_callback_serialiser_complete_callback + (&xenidc_rbr_provider_pool_callback_serialiser, + xenidc_reserve_and_create_rbr_request_to_create_callback + (request), XENIDC_ERROR_TOO_BIG); + + continue; + } + + pool-> + head_request_required_resources_calculated = + 1; + } + + { + xenidc_buffer_resource_list free_resources = + xenidc_buffer_resource_provider_query_free_resources + (pool->provider); + + trace0("free:"); + + traceonly + (xenidc_buffer_resource_list_trace + (free_resources)); + + trace0("head:"); + + traceonly + (xenidc_buffer_resource_list_trace + (pool->head_request_required_resources) + ); + + if (!xenidc_buffer_resource_list_subset_of + (&pool->head_request_required_resources, + &free_resources) + ) { + trace0 + ("waiting for resources to become available"); + + break; + } + } + + list_del_init + (xenidc_reserve_and_create_rbr_request_to_link + (request)); + + pool->head_request_required_resources_calculated = 0; + + pool->kicking_requests = 1; + + spin_unlock_irqrestore(&pool->lock, flags); + + xenidc_rbr_provider_pool_service_request(pool, request); + + spin_lock_irqsave(&pool->lock, flags); + + pool->kicking_requests = 0; + } + + spin_unlock_irqrestore(&pool->lock, flags); + } +} + +void xenidc_rbr_provider_pool_abort_reserve_and_create_rbrs + (xenidc_reserve_and_create_rbr_request * request, xenidc_error error) { + trace(); + + { + xenidc_rbr_provider_pool *pool = request->pool; + + unsigned long flags; + + spin_lock_irqsave(&pool->lock, flags); + + { + xenidc_reserve_and_create_rbr_request *queued_request; + + list_for_each_entry + (queued_request, + &pool->request_list, + XENIDC_RESERVE_AND_CREATE_RBR_REQUEST_LINK) { + if (request == queued_request) { + list_del_init + (xenidc_reserve_and_create_rbr_request_to_link + (request) + ); + + pool-> + head_request_required_resources_calculated + = 0; + + xenidc_callback_serialiser_complete_callback + (&xenidc_rbr_provider_pool_callback_serialiser, + xenidc_reserve_and_create_rbr_request_to_create_callback + (request), error); + + break; + } + } + } + + spin_unlock_irqrestore(&pool->lock, flags); + } +} + +static void xenidc_rbr_provider_pool_revoke_and_unreserve_rbrs_1 + (xenidc_callback * callback); + +void xenidc_rbr_provider_pool_revoke_and_unreserve_rbrs + (xenidc_reserve_and_create_rbr_request * request) { + trace(); + + xenidc_callback_init + (&request->reserved_callback, + xenidc_rbr_provider_pool_revoke_and_unreserve_rbrs_1); + + xenidc_rbr_provider_pool_revoke_and_unreserve_rbrs_1 + (&request->reserved_callback); +} + +static void xenidc_rbr_provider_pool_revoke_and_unreserve_rbrs_1 + (xenidc_callback * callback) { + trace(); + + { + xenidc_reserve_and_create_rbr_request *request = container_of + (callback, + xenidc_reserve_and_create_rbr_request, + reserved_callback); + + xenidc_create_rbr_request_element *element; + + list_for_each_entry(element, &request->request_elements, link) { + if (element->handle != NULL) { + xenidc_buffer_concrete_class **handle = + element->handle; + + element->handle = NULL; + + xenidc_local_buffer_reference_revoke_rbr(handle, + callback); + + return; + } + } + + xenidc_rbr_provider_pool_kick_requests(request->pool); + + xenidc_callback_serialiser_complete_callback + (&xenidc_rbr_provider_pool_callback_serialiser, + xenidc_reserve_and_create_rbr_request_to_revoke_callback + (request), XENIDC_ERROR_SUCCESS); + } +} + +EXPORT_SYMBOL(xenidc_allocate_rbr_provider_pool); +EXPORT_SYMBOL(xenidc_free_rbr_provider_pool); +EXPORT_SYMBOL(xenidc_rbr_provider_pool_reserve_and_create_rbrs); +EXPORT_SYMBOL(xenidc_rbr_provider_pool_abort_reserve_and_create_rbrs); +EXPORT_SYMBOL(xenidc_rbr_provider_pool_revoke_and_unreserve_rbrs); diff -r e7efce6f371c -r d4ea70e2848e linux-2.6-xen-sparse/include/asm-xen/xenidc_rbr_provider_pool.h --- /dev/null Sun Nov 20 17:45:28 2005 +++ b/linux-2.6-xen-sparse/include/asm-xen/xenidc_rbr_provider_pool.h Mon Nov 21 11:04:23 2005 @@ -0,0 +1,228 @@ +/*****************************************************************************/ +/* Xen inter-domain communication remote buffer reference provider pool. */ +/* This component provides a service used by clients to create remote buffer */ +/* references for buffers in the local address space. The remote buffer */ +/* references can be sent in messages or transactions to other domains where */ +/* they can be used to access the buffers. */ +/* */ +/* Copyright (c) 2005 Harry Butterworth IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, but */ +/* WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with this program; if not, write to the Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/*****************************************************************************/ + +#ifndef __ASM_XEN_XENIDC_RBR_PROVIDER_POOL_H__ +#define __ASM_XEN_XENIDC_RBR_PROVIDER_POOL_H__ + +#include "xenidc_buffer_resource_provider.h" +#include "xenidc_local_buffer_reference.h" +#include "xenidc_remote_buffer_reference.h" + +/* The client uses a xenidc_rbr_provider_pool to create remote buffer */ +/* references for inter-domain bulk data transfer. */ + +typedef struct xenidc_rbr_provider_pool_struct xenidc_rbr_provider_pool; + +/* The client calls xenidc_allocate_rbr_provider_pool to allocate a pool and */ +/* the resources required to use it. */ +/* xenidc_allocate_rbr_provider_pool returns NULL if the pool cannot be */ +/* allocated or the anti-deadlock allocation fails. */ + +extern xenidc_rbr_provider_pool *xenidc_allocate_rbr_provider_pool + (xenidc_buffer_resource_list anti_deadlock_resource_allocation); + +/* The client calls xenidc_free_rbr_provider_pool to free the pool and all */ +/* its resources. The client must quiesce all use of the pool before */ +/* freeing it. */ + +extern void xenidc_free_rbr_provider_pool(xenidc_rbr_provider_pool * pool); + +/* Remote buffer references can be created wirh different classes of allowed */ +/* access for the remote domain. These flags indicate what kind of access */ +/* is allowed. */ + +#define XENIDC_CREATE_RBR_REQUEST_ELEMENT_ACCESS_FLAGS_READ \ + XENIDC_LOCAL_BUFFER_REFERENCE_ACCESS_FLAGS_READ +#define XENIDC_CREATE_RBR_REQUEST_ELEMENT_ACCESS_FLAGS_WRITE \ + XENIDC_LOCAL_BUFFER_REFERENCE_ACCESS_FLAGS_WRITE + +/* The client may create multiple remote buffer references with a single */ +/* request. This is required for the resource management strategy described */ +/* in the xenidc.h file. The parameters for each remote buffer reference */ +/* are passed using a xenidc_create_rbr_request_element structure. The */ +/* request has a list of these structures. */ + +typedef struct xenidc_create_rbr_request_element_struct + xenidc_create_rbr_request_element; + +struct xenidc_create_rbr_request_element_struct { + struct list_head link; + xenidc_local_buffer_reference lbr; + int access_flags; + xenidc_remote_buffer_reference rbr; + xenidc_buffer_concrete_class **handle; +}; + +/* The client must initialise the element before first use. */ + +static inline void xenidc_create_rbr_request_element_init + (xenidc_create_rbr_request_element * element) { + memset(element, 0, sizeof(*element)); + + INIT_LIST_HEAD(&element->link); +} + +/* The client must set a local buffer reference to describe the buffer for */ +/* which a remote buffer reference is to be created. */ + +static inline void xenidc_create_rbr_request_element_set_lbr + (xenidc_create_rbr_request_element * element, + xenidc_local_buffer_reference lbr, int access_flags) { + element->lbr = lbr; + element->access_flags = access_flags; +} + +/* Once the request completes, the client may use */ +/* xenidc_create_rbr_request_element_query_rbr to get a copy of the remote */ +/* buffer reference created. */ + +static inline xenidc_remote_buffer_reference + xenidc_create_rbr_request_element_query_rbr + (xenidc_create_rbr_request_element * element) { + return element->rbr; +} + +/* Elemens are added to the element list on the request and then the request */ +/* is submitted. The xenidc_create_rbr_request_element_ensure_removed */ +/* function may be used at any time after the element is initialised to */ +/* ensure that the element is removed from the request list. */ + +static inline void xenidc_create_rbr_request_element_ensure_removed + (xenidc_create_rbr_request_element * element) { + list_del_init(&element->link); +} + +/* The request structure is used to create a number of remote buffer */ +/* references, one for each element on the list. */ + +typedef struct xenidc_reserve_and_create_rbr_request_struct + xenidc_reserve_and_create_rbr_request; + +struct xenidc_reserve_and_create_rbr_request_struct { + xenidc_callback create_callback; + xenidc_callback revoke_callback; + xenidc_rbr_provider_pool *pool; + xenidc_address address; + struct list_head request_elements; + xenidc_callback reserved_callback; +}; + +#define XENIDC_RESERVE_AND_CREATE_RBR_REQUEST_LINK \ + create_callback.XENIDC_CALLBACK_LINK + +/* The request structure contains two callbacks, one for when the remote */ +/* buffer references are created and one for when they are later revoked. */ +/* Each callback contains a link which may be used by the current owner of */ +/* the request. */ + +static inline xenidc_callback + *xenidc_reserve_and_create_rbr_request_to_create_callback + (xenidc_reserve_and_create_rbr_request * request) { + return &request->create_callback; +} + +static inline xenidc_reserve_and_create_rbr_request + *xenidc_reserve_and_create_rbr_request_create_callback_to(xenidc_callback * + callback) { + return container_of(callback, xenidc_reserve_and_create_rbr_request, + create_callback); +} + +static inline xenidc_callback + *xenidc_reserve_and_create_rbr_request_to_revoke_callback + (xenidc_reserve_and_create_rbr_request * request) { + return &request->revoke_callback; +} + +static inline xenidc_reserve_and_create_rbr_request + *xenidc_reserve_and_create_rbr_request_revoke_callback_to(xenidc_callback * + callback) { + return container_of(callback, xenidc_reserve_and_create_rbr_request, + revoke_callback); +} + +static inline struct list_head *xenidc_reserve_and_create_rbr_request_to_link + (xenidc_reserve_and_create_rbr_request * request) { + return xenidc_callback_to_link + (xenidc_reserve_and_create_rbr_request_to_create_callback(request)); +} + +static inline xenidc_reserve_and_create_rbr_request + *xenidc_reserve_and_create_rbr_request_link_to(struct list_head *link) { + return + xenidc_reserve_and_create_rbr_request_create_callback_to + (xenidc_callback_link_to(link)); +} + +/* The request is initialised by the client with create and revoke callback */ +/* functions that are called, respectively, on completion of the create and */ +/* revoke operations. */ + +static inline void xenidc_reserve_and_create_rbr_request_init + (xenidc_reserve_and_create_rbr_request * request, + xenidc_callback_function * create_callback, + xenidc_callback_function * revoke_callback) { + xenidc_callback_init(&request->create_callback, create_callback); + xenidc_callback_init(&request->revoke_callback, revoke_callback); + + INIT_LIST_HEAD(&request->request_elements); +} + +/* xenidc_reserve_and_create_rbr_request_add_element is used to add an */ +/* element to the request's list of elements to be created. */ + +static inline void xenidc_reserve_and_create_rbr_request_add_element + (xenidc_reserve_and_create_rbr_request * request, + xenidc_create_rbr_request_element * element) { + list_add(&element->link, &request->request_elements); +} + +/* The client calls xenidc_rbr_provider_pool_reserve_and_create_rbrs to */ +/* reserve the required resources and then create the remote buffer */ +/* references for the local buffers referenced by local buffer references in */ +/* the elements of the request list. */ + +extern void xenidc_rbr_provider_pool_reserve_and_create_rbrs + (xenidc_rbr_provider_pool * pool, + xenidc_reserve_and_create_rbr_request * request, xenidc_address address); + +/* The client calls xenidc_rbr_provider_pool_abort_reserve_and_create_rbrs */ +/* to abort an outstanding xenidc_rbr_provider_pool_reserve_and_create_rbrs */ +/* operation. After abort call, the request will either complete */ +/* successfully (sucessful completion may have already been scheduled when */ +/* the abort call is made) or will complete with the provided error value */ +/* after having been aborted. */ + +extern void xenidc_rbr_provider_pool_abort_reserve_and_create_rbrs + (xenidc_reserve_and_create_rbr_request * request, xenidc_error error); + +/* The client calls xenidc_rbr_provider_pool_revoke_and_unreserve_rbrs to */ +/* revoke remote access to the buffers and free and unreserve the resources */ +/* usen when the remote buffer references were created. */ + +extern void xenidc_rbr_provider_pool_revoke_and_unreserve_rbrs + (xenidc_reserve_and_create_rbr_request * request); + +#endif