Index: head/sys/dev/hyperv/include/hyperv.h =================================================================== --- head/sys/dev/hyperv/include/hyperv.h +++ head/sys/dev/hyperv/include/hyperv.h @@ -908,30 +908,6 @@ struct hv_vmbus_channel* vmbus_select_outgoing_channel(struct hv_vmbus_channel *promary); -/* - * Work abstraction defines - */ -typedef struct hv_work_queue { - struct taskqueue* queue; - struct proc* proc; - struct sema* work_sema; -} hv_work_queue; - -typedef struct hv_work_item { - struct task work; - void (*callback)(void *); - void* context; - hv_work_queue* wq; -} hv_work_item; - -struct hv_work_queue* hv_work_queue_create(char* name); - -void hv_work_queue_close(struct hv_work_queue* wq); - -int hv_queue_work_item( - hv_work_queue* wq, - void (*callback)(void *), - void* context); /** * @brief Get physical address from virtual */ @@ -952,8 +928,8 @@ hv_guid guid; /* Hyper-V GUID */ char *name; /* name of service */ boolean_t enabled; /* service enabled */ - hv_work_queue *work_queue; /* background work queue */ - + void* context; + struct task task; /* * function to initialize service */ @@ -963,6 +939,11 @@ * function to process Hyper-V messages */ void (*callback)(void *); + + /* + * function to uninitilize service + */ + int (*uninit)(struct hv_vmbus_service *); } hv_vmbus_service; extern uint8_t* receive_buffer[]; Index: head/sys/dev/hyperv/utilities/hv_kvp.c =================================================================== --- head/sys/dev/hyperv/utilities/hv_kvp.c +++ head/sys/dev/hyperv/utilities/hv_kvp.c @@ -98,7 +98,7 @@ static int hv_kvp_req_in_progress(void); static void hv_kvp_transaction_init(uint32_t, hv_vmbus_channel *, uint64_t, uint8_t *); static void hv_kvp_send_msg_to_daemon(void); -static void hv_kvp_process_request(void *context); +static void hv_kvp_process_request(void *context, int pending); /* hv_kvp character device structure */ static struct cdevsw hv_kvp_cdevsw = @@ -123,9 +123,6 @@ */ static struct { - /* Pre-allocated work item for queue */ - hv_work_item work_item; - /* Unless specified the pending mutex should be * used to alter the values of the following paramters: * 1. req_in_progress @@ -642,7 +639,7 @@ * and interact with daemon */ static void -hv_kvp_process_request(void *context) +hv_kvp_process_request(void *context, int pending) { uint8_t *kvp_buf; hv_vmbus_channel *channel = context; @@ -756,23 +753,18 @@ uint64_t pending_cnt = 0; if (kvp_globals.register_done == false) { - kvp_globals.channelp = context; + TASK_INIT(&service_table[HV_KVP].task, 0, hv_kvp_process_request, context); } else { - mtx_lock(&kvp_globals.pending_mutex); kvp_globals.pending_reqs = kvp_globals.pending_reqs + 1; pending_cnt = kvp_globals.pending_reqs; mtx_unlock(&kvp_globals.pending_mutex); if (pending_cnt == 1) { hv_kvp_log_info("%s: Queuing work item\n", __func__); - hv_queue_work_item( - service_table[HV_KVP].work_queue, - hv_kvp_process_request, - context - ); + taskqueue_enqueue(taskqueue_thread, &service_table[HV_KVP].task); } - } + } } @@ -977,26 +969,13 @@ hv_kvp_init(hv_vmbus_service *srv) { int error = 0; - hv_work_queue *work_queue = NULL; - - memset(&kvp_globals, 0, sizeof(kvp_globals)); - work_queue = hv_work_queue_create("KVP Service"); - if (work_queue == NULL) { - hv_kvp_log_info("%s: Work queue alloc failed\n", __func__); - error = ENOMEM; - hv_kvp_log_error("%s: ENOMEM\n", __func__); - goto Finish; - } - srv->work_queue = work_queue; + memset(&kvp_globals, 0, sizeof(kvp_globals)); error = hv_kvp_dev_init(); mtx_init(&kvp_globals.pending_mutex, "hv-kvp pending mutex", - NULL, MTX_DEF); - kvp_globals.pending_reqs = 0; - + NULL, MTX_DEF); -Finish: return (error); } Index: head/sys/dev/hyperv/utilities/hv_util.c =================================================================== --- head/sys/dev/hyperv/utilities/hv_util.c +++ head/sys/dev/hyperv/utilities/hv_util.c @@ -52,6 +52,8 @@ static void hv_timesync_cb(void *context); static int hv_timesync_init(hv_vmbus_service *serv); +static int hv_timesync_uninit(hv_vmbus_service *serv); +static void hv_set_host_time(void *context, int pending); /* * Note: GUID codes below are predefined by the host hypervisor @@ -73,6 +75,7 @@ .enabled = TRUE, .init = hv_timesync_init, .callback = hv_timesync_cb, + .uninit = hv_timesync_uninit, }, /* Heartbeat Service */ @@ -111,10 +114,16 @@ static int hv_timesync_init(hv_vmbus_service *serv) { + void *time_msg = malloc(sizeof(time_sync_data), M_DEVBUF, M_WAITOK); + TASK_INIT(&serv->task, 1, hv_set_host_time, time_msg); + return (0); +} - serv->work_queue = hv_work_queue_create("Time Sync"); - if (serv->work_queue == NULL) - return (ENOMEM); +static int +hv_timesync_uninit(hv_vmbus_service *serv) +{ + taskqueue_drain(taskqueue_thread, &serv->task); + free(serv->task.ta_context, M_DEVBUF); return (0); } @@ -152,9 +161,9 @@ * Set host time based on time sync message from host */ static void -hv_set_host_time(void *context) +hv_set_host_time(void *context, int pending) { - time_sync_data* time_msg = (time_sync_data*) context; + time_sync_data* time_msg = (time_sync_data*) context; uint64_t hosttime = time_msg->data; struct timespec guest_ts, host_ts; uint64_t host_tns; @@ -166,7 +175,7 @@ host_ts.tv_nsec = (long)(host_tns%HV_NANO_SEC_PER_SEC); nanotime(&guest_ts); - + diff = (int64_t)host_ts.tv_sec - (int64_t)guest_ts.tv_sec; /* @@ -175,12 +184,7 @@ if (diff > 5 || diff < -5) { error = kern_clock_settime(curthread, CLOCK_REALTIME, &host_ts); - } - - /* - * Free the hosttime that was allocated in hv_adj_guesttime() - */ - free(time_msg, M_DEVBUF); + } } /** @@ -197,23 +201,13 @@ static inline void hv_adj_guesttime(uint64_t hosttime, uint8_t flags) { - time_sync_data* time_msg; - - time_msg = malloc(sizeof(time_sync_data), M_DEVBUF, M_NOWAIT); + time_sync_data* time_msg = service_table[HV_TIME_SYNCH].task.ta_context; - if (time_msg == NULL) - return; - time_msg->data = hosttime; - if ((flags & HV_ICTIMESYNCFLAG_SYNC) != 0) { - hv_queue_work_item(service_table[HV_TIME_SYNCH].work_queue, - hv_set_host_time, time_msg); - } else if ((flags & HV_ICTIMESYNCFLAG_SAMPLE) != 0) { - hv_queue_work_item(service_table[HV_TIME_SYNCH].work_queue, - hv_set_host_time, time_msg); - } else { - free(time_msg, M_DEVBUF); + if (((flags & HV_ICTIMESYNCFLAG_SYNC) != 0) || + ((flags & HV_ICTIMESYNCFLAG_SAMPLE) != 0)) { + taskqueue_enqueue(taskqueue_thread, &service_table[HV_TIME_SYNCH].task); } } @@ -452,19 +446,14 @@ service = device_get_softc(dev); receive_buffer_offset = service - &service_table[0]; - if (service->work_queue != NULL) - hv_work_queue_close(service->work_queue); + if (service->uninit != NULL) + service->uninit(service); free(receive_buffer[receive_buffer_offset], M_DEVBUF); receive_buffer[receive_buffer_offset] = NULL; return (0); } -static void -hv_util_init(void) -{ -} - static int hv_util_modevent(module_t mod, int event, void *arg) { @@ -495,6 +484,3 @@ DRIVER_MODULE(hv_utils, vmbus, util_driver, util_devclass, hv_util_modevent, 0); MODULE_VERSION(hv_utils, 1); MODULE_DEPEND(hv_utils, vmbus, 1, 1, 1); - -SYSINIT(hv_util_initx, SI_SUB_KTHREAD_IDLE, SI_ORDER_MIDDLE + 1, - hv_util_init, NULL); Index: head/sys/dev/hyperv/vmbus/hv_channel_mgmt.c =================================================================== --- head/sys/dev/hyperv/vmbus/hv_channel_mgmt.c +++ head/sys/dev/hyperv/vmbus/hv_channel_mgmt.c @@ -36,8 +36,10 @@ */ static void vmbus_channel_on_offer(hv_vmbus_channel_msg_header* hdr); +static void vmbus_channel_on_offer_internal(void* context); static void vmbus_channel_on_open_result(hv_vmbus_channel_msg_header* hdr); static void vmbus_channel_on_offer_rescind(hv_vmbus_channel_msg_header* hdr); +static void vmbus_channel_on_offer_rescind_internal(void* context); static void vmbus_channel_on_gpadl_created(hv_vmbus_channel_msg_header* hdr); static void vmbus_channel_on_gpadl_torndown(hv_vmbus_channel_msg_header* hdr); static void vmbus_channel_on_offers_delivered(hv_vmbus_channel_msg_header* hdr); @@ -49,41 +51,46 @@ hv_vmbus_channel_msg_table_entry g_channel_message_table[HV_CHANNEL_MESSAGE_COUNT] = { { HV_CHANNEL_MESSAGE_INVALID, - 0, NULL }, + NULL }, { HV_CHANNEL_MESSAGE_OFFER_CHANNEL, - 0, vmbus_channel_on_offer }, + vmbus_channel_on_offer }, { HV_CHANNEL_MESSAGE_RESCIND_CHANNEL_OFFER, - 0, vmbus_channel_on_offer_rescind }, + vmbus_channel_on_offer_rescind }, { HV_CHANNEL_MESSAGE_REQUEST_OFFERS, - 0, NULL }, + NULL }, { HV_CHANNEL_MESSAGE_ALL_OFFERS_DELIVERED, - 1, vmbus_channel_on_offers_delivered }, + vmbus_channel_on_offers_delivered }, { HV_CHANNEL_MESSAGE_OPEN_CHANNEL, - 0, NULL }, + NULL }, { HV_CHANNEL_MESSAGE_OPEN_CHANNEL_RESULT, - 1, vmbus_channel_on_open_result }, + vmbus_channel_on_open_result }, { HV_CHANNEL_MESSAGE_CLOSE_CHANNEL, - 0, NULL }, + NULL }, { HV_CHANNEL_MESSAGEL_GPADL_HEADER, - 0, NULL }, + NULL }, { HV_CHANNEL_MESSAGE_GPADL_BODY, - 0, NULL }, + NULL }, { HV_CHANNEL_MESSAGE_GPADL_CREATED, - 1, vmbus_channel_on_gpadl_created }, + vmbus_channel_on_gpadl_created }, { HV_CHANNEL_MESSAGE_GPADL_TEARDOWN, - 0, NULL }, + NULL }, { HV_CHANNEL_MESSAGE_GPADL_TORNDOWN, - 1, vmbus_channel_on_gpadl_torndown }, + vmbus_channel_on_gpadl_torndown }, { HV_CHANNEL_MESSAGE_REL_ID_RELEASED, - 0, NULL }, + NULL }, { HV_CHANNEL_MESSAGE_INITIATED_CONTACT, - 0, NULL }, + NULL }, { HV_CHANNEL_MESSAGE_VERSION_RESPONSE, - 1, vmbus_channel_on_version_response }, + vmbus_channel_on_version_response }, { HV_CHANNEL_MESSAGE_UNLOAD, - 0, NULL } + NULL } }; +typedef struct hv_work_item { + struct task work; + void (*callback)(void *); + void* context; +} hv_work_item; /** * Implementation of the work abstraction. @@ -93,120 +100,30 @@ { struct hv_work_item *w = (struct hv_work_item *)work; - /* - * Serialize work execution. - */ - if (w->wq->work_sema != NULL) { - sema_wait(w->wq->work_sema); - } - w->callback(w->context); - if (w->wq->work_sema != NULL) { - sema_post(w->wq->work_sema); - } - free(w, M_DEVBUF); } -struct hv_work_queue* -hv_work_queue_create(char* name) -{ - static unsigned int qid = 0; - char qname[64]; - int pri; - struct hv_work_queue* wq; - - wq = malloc(sizeof(struct hv_work_queue), M_DEVBUF, M_NOWAIT | M_ZERO); - KASSERT(wq != NULL, ("Error VMBUS: Failed to allocate work_queue\n")); - if (wq == NULL) - return (NULL); - - /* - * We use work abstraction to handle messages - * coming from the host and these are typically offers. - * Some FreeBsd drivers appear to have a concurrency issue - * where probe/attach needs to be serialized. We ensure that - * by having only one thread process work elements in a - * specific queue by serializing work execution. - * - */ - if (strcmp(name, "vmbusQ") == 0) { - pri = PI_DISK; - } else { /* control */ - pri = PI_NET; - /* - * Initialize semaphore for this queue by pointing - * to the globale semaphore used for synchronizing all - * control messages. - */ - wq->work_sema = &hv_vmbus_g_connection.control_sema; - } - - sprintf(qname, "hv_%s_%u", name, qid); - - /* - * Fixme: FreeBSD 8.2 has a different prototype for - * taskqueue_create(), and for certain other taskqueue functions. - * We need to research the implications of these changes. - * Fixme: Not sure when the changes were introduced. - */ - wq->queue = taskqueue_create(qname, M_NOWAIT, taskqueue_thread_enqueue, - &wq->queue - #if __FreeBSD_version < 800000 - , &wq->proc - #endif - ); - - if (wq->queue == NULL) { - free(wq, M_DEVBUF); - return (NULL); - } - - if (taskqueue_start_threads(&wq->queue, 1, pri, "%s taskq", qname)) { - taskqueue_free(wq->queue); - free(wq, M_DEVBUF); - return (NULL); - } - - qid++; - - return (wq); -} - -void -hv_work_queue_close(struct hv_work_queue *wq) -{ - /* - * KYS: Need to drain the taskqueue - * before we close the hv_work_queue. - */ - /*KYS: taskqueue_drain(wq->tq, ); */ - taskqueue_free(wq->queue); - free(wq, M_DEVBUF); -} - /** * @brief Create work item */ -int +static int hv_queue_work_item( - struct hv_work_queue *wq, void (*callback)(void *), void *context) { struct hv_work_item *w = malloc(sizeof(struct hv_work_item), - M_DEVBUF, M_NOWAIT | M_ZERO); + M_DEVBUF, M_NOWAIT); KASSERT(w != NULL, ("Error VMBUS: Failed to allocate WorkItem\n")); if (w == NULL) return (ENOMEM); w->callback = callback; w->context = context; - w->wq = wq; TASK_INIT(&w->work, 0, work_item_callback, w); - return (taskqueue_enqueue(wq->queue, &w->work)); + return (taskqueue_enqueue(taskqueue_thread, &w->work)); } @@ -221,10 +138,7 @@ channel = (hv_vmbus_channel*) malloc( sizeof(hv_vmbus_channel), M_DEVBUF, - M_NOWAIT | M_ZERO); - KASSERT(channel != NULL, ("Error VMBUS: Failed to allocate channel!")); - if (channel == NULL) - return (NULL); + M_WAITOK | M_ZERO); mtx_init(&channel->inbound_lock, "channel inbound", NULL, MTX_DEF); mtx_init(&channel->sc_lock, "vmbus multi channel", NULL, MTX_DEF); @@ -235,16 +149,6 @@ } /** - * @brief Release the vmbus channel object itself - */ -static inline void -ReleaseVmbusChannel(void *context) -{ - hv_vmbus_channel* channel = (hv_vmbus_channel*) context; - free(channel, M_DEVBUF); -} - -/** * @brief Release the resources used by the vmbus channel object */ void @@ -252,13 +156,8 @@ { mtx_destroy(&channel->sc_lock); mtx_destroy(&channel->inbound_lock); - /* - * We have to release the channel's workqueue/thread in - * the vmbus's workqueue/thread context - * ie we can't destroy ourselves - */ - hv_queue_work_item(hv_vmbus_g_connection.work_queue, - ReleaseVmbusChannel, (void *) channel); + + free(channel, M_DEVBUF); } /** @@ -456,7 +355,7 @@ vmbus_channel_on_offer(hv_vmbus_channel_msg_header* hdr) { hv_vmbus_channel_offer_channel* offer; - hv_vmbus_channel* new_channel; + hv_vmbus_channel_offer_channel* copied; offer = (hv_vmbus_channel_offer_channel*) hdr; @@ -466,10 +365,25 @@ guidType = &offer->offer.interface_type; guidInstance = &offer->offer.interface_instance; + // copy offer data + copied = malloc(sizeof(*copied), M_DEVBUF, M_NOWAIT); + if (copied == NULL) { + printf("fail to allocate memory\n"); + return; + } + + memcpy(copied, hdr, sizeof(*copied)); + hv_queue_work_item(vmbus_channel_on_offer_internal, copied); +} + +static void +vmbus_channel_on_offer_internal(void* context) +{ + hv_vmbus_channel* new_channel; + + hv_vmbus_channel_offer_channel* offer = (hv_vmbus_channel_offer_channel*)context; /* Allocate the channel object and save this offer */ new_channel = hv_vmbus_allocate_channel(); - if (new_channel == NULL) - return; /* * By default we setup state to enable batched @@ -509,6 +423,8 @@ new_channel->monitor_bit = (uint8_t) offer->monitor_id % 32; vmbus_channel_process_offer(new_channel); + + free(offer, M_DEVBUF); } /** @@ -526,13 +442,20 @@ rescind = (hv_vmbus_channel_rescind_offer*) hdr; channel = hv_vmbus_g_connection.channels[rescind->child_rel_id]; - if (channel == NULL) + if (channel == NULL) return; - hv_vmbus_child_device_unregister(channel->device); - mtx_lock(&hv_vmbus_g_connection.channel_lock); + hv_queue_work_item(vmbus_channel_on_offer_rescind_internal, channel); hv_vmbus_g_connection.channels[rescind->child_rel_id] = NULL; - mtx_unlock(&hv_vmbus_g_connection.channel_lock); +} + +static void +vmbus_channel_on_offer_rescind_internal(void *context) +{ + hv_vmbus_channel* channel; + + channel = (hv_vmbus_channel*)context; + hv_vmbus_child_device_unregister(channel->device); } /** @@ -709,35 +632,6 @@ } /** - * @brief Handler for channel protocol messages. - * - * This is invoked in the vmbus worker thread context. - */ -void -hv_vmbus_on_channel_message(void *context) -{ - hv_vmbus_message* msg; - hv_vmbus_channel_msg_header* hdr; - int size; - - msg = (hv_vmbus_message*) context; - hdr = (hv_vmbus_channel_msg_header*) msg->u.payload; - size = msg->header.payload_size; - - if (hdr->message_type >= HV_CHANNEL_MESSAGE_COUNT) { - free(msg, M_DEVBUF); - return; - } - - if (g_channel_message_table[hdr->message_type].messageHandler) { - g_channel_message_table[hdr->message_type].messageHandler(hdr); - } - - /* Free the msg that was allocated in VmbusOnMsgDPC() */ - free(msg, M_DEVBUF); -} - -/** * @brief Send a request to get all our pending offers. */ int @@ -762,8 +656,7 @@ ret = hv_vmbus_post_message(msg, sizeof(hv_vmbus_channel_msg_header)); - if (msg_info) - free(msg_info, M_DEVBUF); + free(msg_info, M_DEVBUF); return (ret); } Index: head/sys/dev/hyperv/vmbus/hv_connection.c =================================================================== --- head/sys/dev/hyperv/vmbus/hv_connection.c +++ head/sys/dev/hyperv/vmbus/hv_connection.c @@ -164,8 +164,6 @@ * Initialize the vmbus connection */ hv_vmbus_g_connection.connect_state = HV_CONNECTING; - hv_vmbus_g_connection.work_queue = hv_work_queue_create("vmbusQ"); - sema_init(&hv_vmbus_g_connection.control_sema, 1, "control_sema"); TAILQ_INIT(&hv_vmbus_g_connection.channel_msg_anchor); mtx_init(&hv_vmbus_g_connection.channel_msg_lock, "vmbus channel msg", @@ -269,8 +267,6 @@ hv_vmbus_g_connection.connect_state = HV_DISCONNECTED; - hv_work_queue_close(hv_vmbus_g_connection.work_queue); - sema_destroy(&hv_vmbus_g_connection.control_sema); mtx_destroy(&hv_vmbus_g_connection.channel_lock); mtx_destroy(&hv_vmbus_g_connection.channel_msg_lock); @@ -323,9 +319,6 @@ mtx_destroy(&hv_vmbus_g_connection.channel_msg_lock); - hv_work_queue_close(hv_vmbus_g_connection.work_queue); - sema_destroy(&hv_vmbus_g_connection.control_sema); - free(hv_vmbus_g_connection.channels, M_DEVBUF); hv_vmbus_g_connection.connect_state = HV_DISCONNECTED; Index: head/sys/dev/hyperv/vmbus/hv_vmbus_drv_freebsd.c =================================================================== --- head/sys/dev/hyperv/vmbus/hv_vmbus_drv_freebsd.c +++ head/sys/dev/hyperv/vmbus/hv_vmbus_drv_freebsd.c @@ -83,8 +83,6 @@ hv_vmbus_channel_msg_table_entry *entry; hv_vmbus_channel_msg_type msg_type; hv_vmbus_message* msg; - hv_vmbus_message* copied; - static bool warned = false; cpu = (int)(long)arg; KASSERT(cpu <= mp_maxid, ("VMBUS: vmbus_msg_swintr: " @@ -100,31 +98,15 @@ hdr = (hv_vmbus_channel_msg_header *)msg->u.payload; msg_type = hdr->message_type; - if (msg_type >= HV_CHANNEL_MESSAGE_COUNT && !warned) { - warned = true; + if (msg_type >= HV_CHANNEL_MESSAGE_COUNT) { printf("VMBUS: unknown message type = %d\n", msg_type); goto handled; } entry = &g_channel_message_table[msg_type]; - if (entry->handler_no_sleep) + if (entry->messageHandler) entry->messageHandler(hdr); - else { - - copied = malloc(sizeof(hv_vmbus_message), - M_DEVBUF, M_NOWAIT); - KASSERT(copied != NULL, - ("Error VMBUS: malloc failed to allocate" - " hv_vmbus_message!")); - if (copied == NULL) - continue; - - memcpy(copied, msg, sizeof(hv_vmbus_message)); - hv_queue_work_item(hv_vmbus_g_connection.work_queue, - hv_vmbus_on_channel_message, - copied); - } handled: msg->header.message_type = HV_MESSAGE_TYPE_NONE; Index: head/sys/dev/hyperv/vmbus/hv_vmbus_priv.h =================================================================== --- head/sys/dev/hyperv/vmbus/hv_vmbus_priv.h +++ head/sys/dev/hyperv/vmbus/hv_vmbus_priv.h @@ -362,10 +362,8 @@ /** * channel table for fast lookup through id. - */ + */ hv_vmbus_channel **channels; - hv_vmbus_handle work_queue; - struct sema control_sema; } hv_vmbus_connection; typedef union { @@ -632,7 +630,6 @@ typedef struct hv_vmbus_channel_msg_table_entry { hv_vmbus_channel_msg_type messageType; - bool handler_no_sleep; /* true: the handler doesn't sleep */ vmbus_msg_handler messageHandler; } hv_vmbus_channel_msg_table_entry; @@ -682,7 +679,6 @@ hv_vmbus_channel* hv_vmbus_allocate_channel(void); void hv_vmbus_free_vmbus_channel(hv_vmbus_channel *channel); -void hv_vmbus_on_channel_message(void *context); int hv_vmbus_request_channel_offers(void); void hv_vmbus_release_unattached_channels(void); int hv_vmbus_init(void);