| Index: UPDATING |
| =================================================================== |
| --- UPDATING (版本 303304) |
| +++ UPDATING (版本 303984) |
| @@ -16,6 +16,22 @@ |
| stable/10, and then rebuild without this option. The bootstrap process from |
| older version of current is a bit fragile. |
| |
| +20160811 p7 FreeBSD-EN-16:10.dhclient |
| + FreeBSD-EN-16:11.vmbus |
| + FreeBSD-EN-16:12.hv_storvsc |
| + FreeBSD-EN-16:13.vmbus |
| + FreeBSD-EN-16:14.hv_storvsc |
| + FreeBSD-EN-16:15.vmbus |
| + FreeBSD-EN-16:16.hv_storvsc |
| + |
| + Fix handling of unknown options from a DHCP server. [EN-16:10] |
| + Fix a panic in hv_vmbus(4). [EN-16:11] |
| + Fix missing hotplugged disk in hv_storvsc(4). [EN-16:12] |
| + Fix the timecounter emulation in hv_vmbus(4). [EN-16:13] |
| + Fix callout(9) handling in hv_storvsc(4). [EN-16:14] |
| + Fix memory allocation issues in hv_vmbus(4). [EN-16:15] |
| + Fix SCSI command handling in hv_storvsc(4). [EN-16:16] |
| + |
| 20160725 p6 FreeBSD-SA-16:25.bspatch |
| FreeBSD-EN-16:09.freebsd-update |
| |
| Index: sbin/dhclient/dhclient.c |
| =================================================================== |
| --- sbin/dhclient/dhclient.c (版本 303304) |
| +++ sbin/dhclient/dhclient.c (版本 303984) |
| @@ -2277,6 +2277,17 @@ |
| { |
| int i, j, namelen; |
| |
| + /* No `` or $() command substitution allowed in environment values! */ |
| + for (j=0; j < strlen(value); j++) |
| + switch (value[j]) { |
| + case '`': |
| + case '$': |
| + warning("illegal character (%c) in value '%s'", |
| + value[j], value); |
| + /* Ignore this option */ |
| + return; |
| + } |
| + |
| namelen = strlen(name); |
| |
| for (i = 0; client->scriptEnv[i]; i++) |
| @@ -2313,16 +2324,6 @@ |
| strlen(value) + 1); |
| if (client->scriptEnv[i] == NULL) |
| error("script_set_env: no memory for variable assignment"); |
| - |
| - /* No `` or $() command substitution allowed in environment values! */ |
| - for (j=0; j < strlen(value); j++) |
| - switch (value[j]) { |
| - case '`': |
| - case '$': |
| - error("illegal character (%c) in value '%s'", value[j], |
| - value); |
| - /* not reached */ |
| - } |
| snprintf(client->scriptEnv[i], strlen(prefix) + strlen(name) + |
| 1 + strlen(value) + 1, "%s%s=%s", prefix, name, value); |
| } |
| Index: sys/conf/newvers.sh |
| =================================================================== |
| --- sys/conf/newvers.sh (版本 303304) |
| +++ sys/conf/newvers.sh (版本 303984) |
| @@ -32,7 +32,7 @@ |
| |
| TYPE="FreeBSD" |
| REVISION="10.3" |
| -BRANCH="RELEASE-p6" |
| +BRANCH="RELEASE-p7" |
| if [ "X${BRANCH_OVERRIDE}" != "X" ]; then |
| BRANCH=${BRANCH_OVERRIDE} |
| fi |
| Index: sys/dev/hyperv/storvsc/hv_storvsc_drv_freebsd.c |
| =================================================================== |
| --- sys/dev/hyperv/storvsc/hv_storvsc_drv_freebsd.c (版本 303304) |
| +++ sys/dev/hyperv/storvsc/hv_storvsc_drv_freebsd.c (版本 303984) |
| @@ -81,12 +81,6 @@ |
| #define BLKVSC_MAX_IO_REQUESTS STORVSC_MAX_IO_REQUESTS |
| #define STORVSC_MAX_TARGETS (2) |
| |
| -#define STORVSC_WIN7_MAJOR 4 |
| -#define STORVSC_WIN7_MINOR 2 |
| - |
| -#define STORVSC_WIN8_MAJOR 5 |
| -#define STORVSC_WIN8_MINOR 1 |
| - |
| #define VSTOR_PKT_SIZE (sizeof(struct vstor_packet) - vmscsi_size_delta) |
| |
| #define HV_ALIGN(x, a) roundup2(x, a) |
| @@ -208,7 +202,7 @@ |
| * Sense buffer size changed in win8; have a run-time |
| * variable to track the size we should use. |
| */ |
| -static int sense_buffer_size; |
| +static int sense_buffer_size = PRE_WIN8_STORVSC_SENSE_BUFFER_SIZE; |
| |
| /* |
| * The size of the vmscsi_request has changed in win8. The |
| @@ -218,10 +212,47 @@ |
| * Track the correct size we need to apply. |
| */ |
| static int vmscsi_size_delta; |
| +/* |
| + * The storage protocol version is determined during the |
| + * initial exchange with the host. It will indicate which |
| + * storage functionality is available in the host. |
| +*/ |
| +static int vmstor_proto_version; |
| |
| -static int storvsc_current_major; |
| -static int storvsc_current_minor; |
| +struct vmstor_proto { |
| + int proto_version; |
| + int sense_buffer_size; |
| + int vmscsi_size_delta; |
| +}; |
| |
| +static const struct vmstor_proto vmstor_proto_list[] = { |
| + { |
| + VMSTOR_PROTOCOL_VERSION_WIN10, |
| + POST_WIN7_STORVSC_SENSE_BUFFER_SIZE, |
| + 0 |
| + }, |
| + { |
| + VMSTOR_PROTOCOL_VERSION_WIN8_1, |
| + POST_WIN7_STORVSC_SENSE_BUFFER_SIZE, |
| + 0 |
| + }, |
| + { |
| + VMSTOR_PROTOCOL_VERSION_WIN8, |
| + POST_WIN7_STORVSC_SENSE_BUFFER_SIZE, |
| + 0 |
| + }, |
| + { |
| + VMSTOR_PROTOCOL_VERSION_WIN7, |
| + PRE_WIN8_STORVSC_SENSE_BUFFER_SIZE, |
| + sizeof(struct vmscsi_win8_extension), |
| + }, |
| + { |
| + VMSTOR_PROTOCOL_VERSION_WIN6, |
| + PRE_WIN8_STORVSC_SENSE_BUFFER_SIZE, |
| + sizeof(struct vmscsi_win8_extension), |
| + } |
| +}; |
| + |
| /* static functions */ |
| static int storvsc_probe(device_t dev); |
| static int storvsc_attach(device_t dev); |
| @@ -435,7 +466,7 @@ |
| static int |
| hv_storvsc_channel_init(struct hv_device *dev) |
| { |
| - int ret = 0; |
| + int ret = 0, i; |
| struct hv_storvsc_request *request; |
| struct vstor_packet *vstor_packet; |
| struct storvsc_softc *sc; |
| @@ -484,19 +515,20 @@ |
| goto cleanup; |
| } |
| |
| - /* reuse the packet for version range supported */ |
| + for (i = 0; i < nitems(vmstor_proto_list); i++) { |
| + /* reuse the packet for version range supported */ |
| |
| - memset(vstor_packet, 0, sizeof(struct vstor_packet)); |
| - vstor_packet->operation = VSTOR_OPERATION_QUERYPROTOCOLVERSION; |
| - vstor_packet->flags = REQUEST_COMPLETION_FLAG; |
| + memset(vstor_packet, 0, sizeof(struct vstor_packet)); |
| + vstor_packet->operation = VSTOR_OPERATION_QUERYPROTOCOLVERSION; |
| + vstor_packet->flags = REQUEST_COMPLETION_FLAG; |
| |
| - vstor_packet->u.version.major_minor = |
| - VMSTOR_PROTOCOL_VERSION(storvsc_current_major, storvsc_current_minor); |
| + vstor_packet->u.version.major_minor = |
| + vmstor_proto_list[i].proto_version; |
| |
| - /* revision is only significant for Windows guests */ |
| - vstor_packet->u.version.revision = 0; |
| + /* revision is only significant for Windows guests */ |
| + vstor_packet->u.version.revision = 0; |
| |
| - ret = hv_vmbus_channel_send_packet( |
| + ret = hv_vmbus_channel_send_packet( |
| dev->channel, |
| vstor_packet, |
| VSTOR_PKT_SIZE, |
| @@ -504,20 +536,34 @@ |
| HV_VMBUS_PACKET_TYPE_DATA_IN_BAND, |
| HV_VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); |
| |
| - if (ret != 0) |
| - goto cleanup; |
| + if (ret != 0) |
| + goto cleanup; |
| |
| - /* wait 5 seconds */ |
| - ret = sema_timedwait(&request->synch_sema, 5 * hz); |
| + /* wait 5 seconds */ |
| + ret = sema_timedwait(&request->synch_sema, 5 * hz); |
| |
| - if (ret) |
| - goto cleanup; |
| + if (ret) |
| + goto cleanup; |
| |
| - /* TODO: Check returned version */ |
| - if (vstor_packet->operation != VSTOR_OPERATION_COMPLETEIO || |
| - vstor_packet->status != 0) |
| + if (vstor_packet->operation != VSTOR_OPERATION_COMPLETEIO) { |
| + ret = EINVAL; |
| + goto cleanup; |
| + } |
| + if (vstor_packet->status == 0) { |
| + vmstor_proto_version = |
| + vmstor_proto_list[i].proto_version; |
| + sense_buffer_size = |
| + vmstor_proto_list[i].sense_buffer_size; |
| + vmscsi_size_delta = |
| + vmstor_proto_list[i].vmscsi_size_delta; |
| + break; |
| + } |
| + } |
| + |
| + if (vstor_packet->status != 0) { |
| + ret = EINVAL; |
| goto cleanup; |
| - |
| + } |
| /** |
| * Query channel properties |
| */ |
| @@ -767,6 +813,13 @@ |
| |
| vm_srb = &vstor_packet->u.vm_srb; |
| |
| + /* |
| + * Copy some fields of the host's response into the request structure, |
| + * because the fields will be used later in storvsc_io_done(). |
| + */ |
| + request->vstor_packet.u.vm_srb.scsi_status = vm_srb->scsi_status; |
| + request->vstor_packet.u.vm_srb.transfer_len = vm_srb->transfer_len; |
| + |
| if (((vm_srb->scsi_status & 0xFF) == SCSI_STATUS_CHECK_COND) && |
| (vm_srb->srb_status & SRB_STATUS_AUTOSENSE_VALID)) { |
| /* Autosense data available */ |
| @@ -916,19 +969,6 @@ |
| int ata_disk_enable = 0; |
| int ret = ENXIO; |
| |
| - if (hv_vmbus_protocal_version == HV_VMBUS_VERSION_WS2008 || |
| - hv_vmbus_protocal_version == HV_VMBUS_VERSION_WIN7) { |
| - sense_buffer_size = PRE_WIN8_STORVSC_SENSE_BUFFER_SIZE; |
| - vmscsi_size_delta = sizeof(struct vmscsi_win8_extension); |
| - storvsc_current_major = STORVSC_WIN7_MAJOR; |
| - storvsc_current_minor = STORVSC_WIN7_MINOR; |
| - } else { |
| - sense_buffer_size = POST_WIN7_STORVSC_SENSE_BUFFER_SIZE; |
| - vmscsi_size_delta = 0; |
| - storvsc_current_major = STORVSC_WIN8_MAJOR; |
| - storvsc_current_minor = STORVSC_WIN8_MINOR; |
| - } |
| - |
| switch (storvsc_get_storage_type(dev)) { |
| case DRIVER_BLKVSC: |
| if(bootverbose) |
| @@ -1273,6 +1313,7 @@ |
| } |
| #endif /* HVS_TIMEOUT_TEST */ |
| |
| +#ifdef notyet |
| /** |
| * @brief timeout handler for requests |
| * |
| @@ -1320,6 +1361,7 @@ |
| storvsc_timeout_test(reqp, MODE_SELECT_10, 1); |
| #endif |
| } |
| +#endif |
| |
| /** |
| * @brief StorVSC device poll function |
| @@ -1472,6 +1514,7 @@ |
| return; |
| } |
| |
| +#ifdef notyet |
| if (ccb->ccb_h.timeout != CAM_TIME_INFINITY) { |
| callout_init(&reqp->callout, CALLOUT_MPSAFE); |
| callout_reset_sbt(&reqp->callout, |
| @@ -1491,6 +1534,7 @@ |
| } |
| #endif /* HVS_TIMEOUT_TEST */ |
| } |
| +#endif |
| |
| if ((res = hv_storvsc_io_request(sc->hs_dev, reqp)) != 0) { |
| xpt_print(ccb->ccb_h.path, |
| @@ -1924,9 +1968,11 @@ |
| } |
| |
| /* |
| - * Modified based on scsi_print_inquiry which is responsible to |
| - * print the detail information for scsi_inquiry_data. |
| - * |
| + * SCSI Inquiry checks qualifier and type. |
| + * If qualifier is 011b, means the device server is not capable |
| + * of supporting a peripheral device on this logical unit, and |
| + * the type should be set to 1Fh. |
| + * |
| * Return 1 if it is valid, 0 otherwise. |
| */ |
| static inline int |
| @@ -1933,53 +1979,13 @@ |
| is_inquiry_valid(const struct scsi_inquiry_data *inq_data) |
| { |
| uint8_t type; |
| - char vendor[16], product[48], revision[16]; |
| - |
| - /* |
| - * Check device type and qualifier |
| - */ |
| - if (!(SID_QUAL_IS_VENDOR_UNIQUE(inq_data) || |
| - SID_QUAL(inq_data) == SID_QUAL_LU_CONNECTED)) |
| + if (SID_QUAL(inq_data) != SID_QUAL_LU_CONNECTED) { |
| return (0); |
| - |
| + } |
| type = SID_TYPE(inq_data); |
| - switch (type) { |
| - case T_DIRECT: |
| - case T_SEQUENTIAL: |
| - case T_PRINTER: |
| - case T_PROCESSOR: |
| - case T_WORM: |
| - case T_CDROM: |
| - case T_SCANNER: |
| - case T_OPTICAL: |
| - case T_CHANGER: |
| - case T_COMM: |
| - case T_STORARRAY: |
| - case T_ENCLOSURE: |
| - case T_RBC: |
| - case T_OCRW: |
| - case T_OSD: |
| - case T_ADC: |
| - break; |
| - case T_NODEVICE: |
| - default: |
| + if (type == T_NODEVICE) { |
| return (0); |
| } |
| - |
| - /* |
| - * Check vendor, product, and revision |
| - */ |
| - cam_strvis(vendor, inq_data->vendor, sizeof(inq_data->vendor), |
| - sizeof(vendor)); |
| - cam_strvis(product, inq_data->product, sizeof(inq_data->product), |
| - sizeof(product)); |
| - cam_strvis(revision, inq_data->revision, sizeof(inq_data->revision), |
| - sizeof(revision)); |
| - if (strlen(vendor) == 0 || |
| - strlen(product) == 0 || |
| - strlen(revision) == 0) |
| - return (0); |
| - |
| return (1); |
| } |
| |
| @@ -2039,6 +2045,7 @@ |
| mtx_unlock(&sc->hs_lock); |
| } |
| |
| +#ifdef notyet |
| /* |
| * callout_drain() will wait for the timer handler to finish |
| * if it is running. So we don't need any lock to synchronize |
| @@ -2049,12 +2056,12 @@ |
| if (ccb->ccb_h.timeout != CAM_TIME_INFINITY) { |
| callout_drain(&reqp->callout); |
| } |
| +#endif |
| |
| ccb->ccb_h.status &= ~CAM_SIM_QUEUED; |
| ccb->ccb_h.status &= ~CAM_STATUS_MASK; |
| if (vm_srb->scsi_status == SCSI_STATUS_OK) { |
| const struct scsi_generic *cmd; |
| - |
| /* |
| * Check whether the data for INQUIRY cmd is valid or |
| * not. Windows 10 and Windows 2016 send all zero |
| @@ -2063,16 +2070,59 @@ |
| cmd = (const struct scsi_generic *) |
| ((ccb->ccb_h.flags & CAM_CDB_POINTER) ? |
| csio->cdb_io.cdb_ptr : csio->cdb_io.cdb_bytes); |
| - if (cmd->opcode == INQUIRY && |
| - is_inquiry_valid( |
| - (const struct scsi_inquiry_data *)csio->data_ptr) == 0) { |
| + if (cmd->opcode == INQUIRY) { |
| + /* |
| + * The host of Windows 10 or 2016 server will response |
| + * the inquiry request with invalid data for unexisted device: |
| + [0x7f 0x0 0x5 0x2 0x1f ... ] |
| + * But on windows 2012 R2, the response is: |
| + [0x7f 0x0 0x0 0x0 0x0 ] |
| + * That is why here wants to validate the inquiry response. |
| + * The validation will skip the INQUIRY whose response is short, |
| + * which is less than SHORT_INQUIRY_LENGTH (36). |
| + * |
| + * For more information about INQUIRY, please refer to: |
| + * ftp://ftp.avc-pioneer.com/Mtfuji_7/Proposal/Jun09/INQUIRY.pdf |
| + */ |
| + const struct scsi_inquiry_data *inq_data = |
| + (const struct scsi_inquiry_data *)csio->data_ptr; |
| + uint8_t* resp_buf = (uint8_t*)csio->data_ptr; |
| + /* Get the buffer length reported by host */ |
| + int resp_xfer_len = vm_srb->transfer_len; |
| + /* Get the available buffer length */ |
| + int resp_buf_len = resp_xfer_len >= 5 ? resp_buf[4] + 5 : 0; |
| + int data_len = (resp_buf_len < resp_xfer_len) ? resp_buf_len : resp_xfer_len; |
| + if (data_len < SHORT_INQUIRY_LENGTH) { |
| + ccb->ccb_h.status |= CAM_REQ_CMP; |
| + if (bootverbose && data_len >= 5) { |
| + mtx_lock(&sc->hs_lock); |
| + xpt_print(ccb->ccb_h.path, |
| + "storvsc skips the validation for short inquiry (%d)" |
| + " [%x %x %x %x %x]\n", |
| + data_len,resp_buf[0],resp_buf[1],resp_buf[2], |
| + resp_buf[3],resp_buf[4]); |
| + mtx_unlock(&sc->hs_lock); |
| + } |
| + } else if (is_inquiry_valid(inq_data) == 0) { |
| ccb->ccb_h.status |= CAM_DEV_NOT_THERE; |
| + if (bootverbose && data_len >= 5) { |
| + mtx_lock(&sc->hs_lock); |
| + xpt_print(ccb->ccb_h.path, |
| + "storvsc uninstalled invalid device" |
| + " [%x %x %x %x %x]\n", |
| + resp_buf[0],resp_buf[1],resp_buf[2],resp_buf[3],resp_buf[4]); |
| + mtx_unlock(&sc->hs_lock); |
| + } |
| + } else { |
| + ccb->ccb_h.status |= CAM_REQ_CMP; |
| if (bootverbose) { |
| mtx_lock(&sc->hs_lock); |
| xpt_print(ccb->ccb_h.path, |
| - "storvsc uninstalled device\n"); |
| + "storvsc has passed inquiry response (%d) validation\n", |
| + data_len); |
| mtx_unlock(&sc->hs_lock); |
| } |
| + } |
| } else { |
| ccb->ccb_h.status |= CAM_REQ_CMP; |
| } |
| Index: sys/dev/hyperv/storvsc/hv_vstorage.h |
| =================================================================== |
| --- sys/dev/hyperv/storvsc/hv_vstorage.h (版本 303304) |
| +++ sys/dev/hyperv/storvsc/hv_vstorage.h (版本 303984) |
| @@ -41,6 +41,11 @@ |
| #define VMSTOR_PROTOCOL_VERSION(MAJOR_, MINOR_) ((((MAJOR_) & 0xff) << 8) | \ |
| (((MINOR_) & 0xff) )) |
| |
| +#define VMSTOR_PROTOCOL_VERSION_WIN6 VMSTOR_PROTOCOL_VERSION(2, 0) |
| +#define VMSTOR_PROTOCOL_VERSION_WIN7 VMSTOR_PROTOCOL_VERSION(4, 2) |
| +#define VMSTOR_PROTOCOL_VERSION_WIN8 VMSTOR_PROTOCOL_VERSION(5, 1) |
| +#define VMSTOR_PROTOCOL_VERSION_WIN8_1 VMSTOR_PROTOCOL_VERSION(6, 0) |
| +#define VMSTOR_PROTOCOL_VERSION_WIN10 VMSTOR_PROTOCOL_VERSION(6, 2) |
| /* |
| * Invalid version. |
| */ |
| Index: sys/dev/hyperv/vmbus/hv_channel.c |
| =================================================================== |
| --- sys/dev/hyperv/vmbus/hv_channel.c (版本 303304) |
| +++ sys/dev/hyperv/vmbus/hv_channel.c (版本 303984) |
| @@ -180,12 +180,12 @@ |
| if (user_data_len) |
| memcpy(open_msg->user_data, user_data, user_data_len); |
| |
| - mtx_lock_spin(&hv_vmbus_g_connection.channel_msg_lock); |
| + mtx_lock(&hv_vmbus_g_connection.channel_msg_lock); |
| TAILQ_INSERT_TAIL( |
| &hv_vmbus_g_connection.channel_msg_anchor, |
| open_info, |
| msg_list_entry); |
| - mtx_unlock_spin(&hv_vmbus_g_connection.channel_msg_lock); |
| + mtx_unlock(&hv_vmbus_g_connection.channel_msg_lock); |
| |
| ret = hv_vmbus_post_message( |
| open_msg, sizeof(hv_vmbus_channel_open_channel)); |
| @@ -212,12 +212,12 @@ |
| } |
| |
| cleanup: |
| - mtx_lock_spin(&hv_vmbus_g_connection.channel_msg_lock); |
| + mtx_lock(&hv_vmbus_g_connection.channel_msg_lock); |
| TAILQ_REMOVE( |
| &hv_vmbus_g_connection.channel_msg_anchor, |
| open_info, |
| msg_list_entry); |
| - mtx_unlock_spin(&hv_vmbus_g_connection.channel_msg_lock); |
| + mtx_unlock(&hv_vmbus_g_connection.channel_msg_lock); |
| sema_destroy(&open_info->wait_sema); |
| free(open_info, M_DEVBUF); |
| |
| @@ -401,13 +401,13 @@ |
| gpadl_msg->child_rel_id = channel->offer_msg.child_rel_id; |
| gpadl_msg->gpadl = next_gpadl_handle; |
| |
| - mtx_lock_spin(&hv_vmbus_g_connection.channel_msg_lock); |
| + mtx_lock(&hv_vmbus_g_connection.channel_msg_lock); |
| TAILQ_INSERT_TAIL( |
| &hv_vmbus_g_connection.channel_msg_anchor, |
| msg_info, |
| msg_list_entry); |
| |
| - mtx_unlock_spin(&hv_vmbus_g_connection.channel_msg_lock); |
| + mtx_unlock(&hv_vmbus_g_connection.channel_msg_lock); |
| |
| ret = hv_vmbus_post_message( |
| gpadl_msg, |
| @@ -446,10 +446,10 @@ |
| |
| cleanup: |
| |
| - mtx_lock_spin(&hv_vmbus_g_connection.channel_msg_lock); |
| + mtx_lock(&hv_vmbus_g_connection.channel_msg_lock); |
| TAILQ_REMOVE(&hv_vmbus_g_connection.channel_msg_anchor, |
| msg_info, msg_list_entry); |
| - mtx_unlock_spin(&hv_vmbus_g_connection.channel_msg_lock); |
| + mtx_unlock(&hv_vmbus_g_connection.channel_msg_lock); |
| |
| sema_destroy(&msg_info->wait_sema); |
| free(msg_info, M_DEVBUF); |
| @@ -488,10 +488,10 @@ |
| msg->child_rel_id = channel->offer_msg.child_rel_id; |
| msg->gpadl = gpadl_handle; |
| |
| - mtx_lock_spin(&hv_vmbus_g_connection.channel_msg_lock); |
| + mtx_lock(&hv_vmbus_g_connection.channel_msg_lock); |
| TAILQ_INSERT_TAIL(&hv_vmbus_g_connection.channel_msg_anchor, |
| info, msg_list_entry); |
| - mtx_unlock_spin(&hv_vmbus_g_connection.channel_msg_lock); |
| + mtx_unlock(&hv_vmbus_g_connection.channel_msg_lock); |
| |
| ret = hv_vmbus_post_message(msg, |
| sizeof(hv_vmbus_channel_gpadl_teardown)); |
| @@ -504,10 +504,10 @@ |
| /* |
| * Received a torndown response |
| */ |
| - mtx_lock_spin(&hv_vmbus_g_connection.channel_msg_lock); |
| + mtx_lock(&hv_vmbus_g_connection.channel_msg_lock); |
| TAILQ_REMOVE(&hv_vmbus_g_connection.channel_msg_anchor, |
| info, msg_list_entry); |
| - mtx_unlock_spin(&hv_vmbus_g_connection.channel_msg_lock); |
| + mtx_unlock(&hv_vmbus_g_connection.channel_msg_lock); |
| sema_destroy(&info->wait_sema); |
| free(info, M_DEVBUF); |
| |
| Index: sys/dev/hyperv/vmbus/hv_channel_mgmt.c |
| =================================================================== |
| --- sys/dev/hyperv/vmbus/hv_channel_mgmt.c (版本 303304) |
| +++ sys/dev/hyperv/vmbus/hv_channel_mgmt.c (版本 303984) |
| @@ -567,7 +567,7 @@ |
| /* |
| * Find the open msg, copy the result and signal/unblock the wait event |
| */ |
| - mtx_lock_spin(&hv_vmbus_g_connection.channel_msg_lock); |
| + mtx_lock(&hv_vmbus_g_connection.channel_msg_lock); |
| |
| TAILQ_FOREACH(msg_info, &hv_vmbus_g_connection.channel_msg_anchor, |
| msg_list_entry) { |
| @@ -585,7 +585,7 @@ |
| } |
| } |
| } |
| - mtx_unlock_spin(&hv_vmbus_g_connection.channel_msg_lock); |
| + mtx_unlock(&hv_vmbus_g_connection.channel_msg_lock); |
| |
| } |
| |
| @@ -609,7 +609,7 @@ |
| /* Find the establish msg, copy the result and signal/unblock |
| * the wait event |
| */ |
| - mtx_lock_spin(&hv_vmbus_g_connection.channel_msg_lock); |
| + mtx_lock(&hv_vmbus_g_connection.channel_msg_lock); |
| TAILQ_FOREACH(msg_info, &hv_vmbus_g_connection.channel_msg_anchor, |
| msg_list_entry) { |
| request_header = (hv_vmbus_channel_msg_header*) msg_info->msg; |
| @@ -628,7 +628,7 @@ |
| } |
| } |
| } |
| - mtx_unlock_spin(&hv_vmbus_g_connection.channel_msg_lock); |
| + mtx_unlock(&hv_vmbus_g_connection.channel_msg_lock); |
| } |
| |
| /** |
| @@ -653,7 +653,7 @@ |
| * wait event. |
| */ |
| |
| - mtx_lock_spin(&hv_vmbus_g_connection.channel_msg_lock); |
| + mtx_lock(&hv_vmbus_g_connection.channel_msg_lock); |
| |
| TAILQ_FOREACH(msg_info, &hv_vmbus_g_connection.channel_msg_anchor, |
| msg_list_entry) { |
| @@ -673,7 +673,7 @@ |
| } |
| } |
| } |
| - mtx_unlock_spin(&hv_vmbus_g_connection.channel_msg_lock); |
| + mtx_unlock(&hv_vmbus_g_connection.channel_msg_lock); |
| } |
| |
| /** |
| @@ -693,7 +693,7 @@ |
| |
| versionResponse = (hv_vmbus_channel_version_response*)hdr; |
| |
| - mtx_lock_spin(&hv_vmbus_g_connection.channel_msg_lock); |
| + mtx_lock(&hv_vmbus_g_connection.channel_msg_lock); |
| TAILQ_FOREACH(msg_info, &hv_vmbus_g_connection.channel_msg_anchor, |
| msg_list_entry) { |
| requestHeader = (hv_vmbus_channel_msg_header*) msg_info->msg; |
| @@ -707,7 +707,7 @@ |
| sema_post(&msg_info->wait_sema); |
| } |
| } |
| - mtx_unlock_spin(&hv_vmbus_g_connection.channel_msg_lock); |
| + mtx_unlock(&hv_vmbus_g_connection.channel_msg_lock); |
| |
| } |
| |
| Index: sys/dev/hyperv/vmbus/hv_connection.c |
| =================================================================== |
| --- sys/dev/hyperv/vmbus/hv_connection.c (版本 303304) |
| +++ sys/dev/hyperv/vmbus/hv_connection.c (版本 303984) |
| @@ -101,7 +101,7 @@ |
| * Add to list before we send the request since we may receive the |
| * response before returning from this routine |
| */ |
| - mtx_lock_spin(&hv_vmbus_g_connection.channel_msg_lock); |
| + mtx_lock(&hv_vmbus_g_connection.channel_msg_lock); |
| |
| TAILQ_INSERT_TAIL( |
| &hv_vmbus_g_connection.channel_msg_anchor, |
| @@ -108,7 +108,7 @@ |
| msg_info, |
| msg_list_entry); |
| |
| - mtx_unlock_spin(&hv_vmbus_g_connection.channel_msg_lock); |
| + mtx_unlock(&hv_vmbus_g_connection.channel_msg_lock); |
| |
| ret = hv_vmbus_post_message( |
| msg, |
| @@ -115,12 +115,12 @@ |
| sizeof(hv_vmbus_channel_initiate_contact)); |
| |
| if (ret != 0) { |
| - mtx_lock_spin(&hv_vmbus_g_connection.channel_msg_lock); |
| + mtx_lock(&hv_vmbus_g_connection.channel_msg_lock); |
| TAILQ_REMOVE( |
| &hv_vmbus_g_connection.channel_msg_anchor, |
| msg_info, |
| msg_list_entry); |
| - mtx_unlock_spin(&hv_vmbus_g_connection.channel_msg_lock); |
| + mtx_unlock(&hv_vmbus_g_connection.channel_msg_lock); |
| return (ret); |
| } |
| |
| @@ -129,12 +129,12 @@ |
| */ |
| ret = sema_timedwait(&msg_info->wait_sema, 5 * hz); /* KYS 5 seconds */ |
| |
| - mtx_lock_spin(&hv_vmbus_g_connection.channel_msg_lock); |
| + mtx_lock(&hv_vmbus_g_connection.channel_msg_lock); |
| TAILQ_REMOVE( |
| &hv_vmbus_g_connection.channel_msg_anchor, |
| msg_info, |
| msg_list_entry); |
| - mtx_unlock_spin(&hv_vmbus_g_connection.channel_msg_lock); |
| + mtx_unlock(&hv_vmbus_g_connection.channel_msg_lock); |
| |
| /** |
| * Check if successful |
| @@ -173,7 +173,7 @@ |
| |
| TAILQ_INIT(&hv_vmbus_g_connection.channel_msg_anchor); |
| mtx_init(&hv_vmbus_g_connection.channel_msg_lock, "vmbus channel msg", |
| - NULL, MTX_SPIN); |
| + NULL, MTX_DEF); |
| |
| TAILQ_INIT(&hv_vmbus_g_connection.channel_anchor); |
| mtx_init(&hv_vmbus_g_connection.channel_lock, "vmbus channel", |
| @@ -476,31 +476,35 @@ |
| /** |
| * Send a msg on the vmbus's message connection |
| */ |
| -int hv_vmbus_post_message(void *buffer, size_t bufferLen) { |
| - int ret = 0; |
| +int hv_vmbus_post_message(void *buffer, size_t bufferLen) |
| +{ |
| hv_vmbus_connection_id connId; |
| - unsigned retries = 0; |
| + sbintime_t time = SBT_1MS; |
| + int retries; |
| + int ret; |
| |
| - /* NetScaler delays from previous code were consolidated here */ |
| - static int delayAmount[] = {100, 100, 100, 500, 500, 5000, 5000, 5000}; |
| + connId.as_uint32_t = 0; |
| + connId.u.id = HV_VMBUS_MESSAGE_CONNECTION_ID; |
| |
| - /* for(each entry in delayAmount) try to post message, |
| - * delay a little bit before retrying |
| + /* |
| + * We retry to cope with transient failures caused by host side's |
| + * insufficient resources. 20 times should suffice in practice. |
| */ |
| - for (retries = 0; |
| - retries < sizeof(delayAmount)/sizeof(delayAmount[0]); retries++) { |
| - connId.as_uint32_t = 0; |
| - connId.u.id = HV_VMBUS_MESSAGE_CONNECTION_ID; |
| - ret = hv_vmbus_post_msg_via_msg_ipc(connId, 1, buffer, bufferLen); |
| - if (ret != HV_STATUS_INSUFFICIENT_BUFFERS) |
| - break; |
| - /* TODO: KYS We should use a blocking wait call */ |
| - DELAY(delayAmount[retries]); |
| + for (retries = 0; retries < 20; retries++) { |
| + ret = hv_vmbus_post_msg_via_msg_ipc(connId, 1, buffer, |
| + bufferLen); |
| + if (ret == HV_STATUS_SUCCESS) |
| + return (0); |
| + |
| + pause_sbt("pstmsg", time, 0, C_HARDCLOCK); |
| + if (time < SBT_1S * 2) |
| + time *= 2; |
| } |
| |
| - KASSERT(ret == 0, ("Error VMBUS: Message Post Failed\n")); |
| + KASSERT(ret == HV_STATUS_SUCCESS, |
| + ("Error VMBUS: Message Post Failed, ret=%d\n", ret)); |
| |
| - return (ret); |
| + return (EAGAIN); |
| } |
| |
| /** |
| Index: sys/dev/hyperv/vmbus/hv_hv.c |
| =================================================================== |
| --- sys/dev/hyperv/vmbus/hv_hv.c (版本 303304) |
| +++ sys/dev/hyperv/vmbus/hv_hv.c (版本 303984) |
| @@ -33,6 +33,7 @@ |
| __FBSDID("$FreeBSD$"); |
| |
| #include <sys/param.h> |
| +#include <sys/kernel.h> |
| #include <sys/malloc.h> |
| #include <sys/pcpu.h> |
| #include <sys/timetc.h> |
| @@ -50,6 +51,9 @@ |
| |
| static u_int hv_get_timecount(struct timecounter *tc); |
| |
| +u_int hyperv_features; |
| +u_int hyperv_recommends; |
| + |
| /** |
| * Globals |
| */ |
| @@ -211,8 +215,6 @@ |
| |
| hv_vmbus_g_context.hypercall_page = virt_addr; |
| |
| - tc_init(&hv_timecounter); /* register virtual timecount */ |
| - |
| hv_et_init(); |
| |
| return (0); |
| @@ -427,3 +429,93 @@ |
| wrmsr(HV_X64_MSR_SIEFP, siefp.as_uint64_t); |
| } |
| |
| +static bool |
| +hyperv_identify(void) |
| +{ |
| + u_int regs[4]; |
| + unsigned int maxLeaf; |
| + unsigned int op; |
| + |
| + if (vm_guest != VM_GUEST_HV) |
| + return (false); |
| + |
| + op = HV_CPU_ID_FUNCTION_HV_VENDOR_AND_MAX_FUNCTION; |
| + do_cpuid(op, regs); |
| + maxLeaf = regs[0]; |
| + if (maxLeaf < HV_CPU_ID_FUNCTION_MS_HV_IMPLEMENTATION_LIMITS) |
| + return (false); |
| + |
| + op = HV_CPU_ID_FUNCTION_HV_INTERFACE; |
| + do_cpuid(op, regs); |
| + if (regs[0] != 0x31237648 /* HV#1 */) |
| + return (false); |
| + |
| + op = HV_CPU_ID_FUNCTION_MS_HV_FEATURES; |
| + do_cpuid(op, regs); |
| + if ((regs[0] & HV_FEATURE_MSR_HYPERCALL) == 0) { |
| + /* |
| + * Hyper-V w/o Hypercall is impossible; someone |
| + * is faking Hyper-V. |
| + */ |
| + return (false); |
| + } |
| + hyperv_features = regs[0]; |
| + |
| + op = HV_CPU_ID_FUNCTION_MS_HV_VERSION; |
| + do_cpuid(op, regs); |
| + printf("Hyper-V Version: %d.%d.%d [SP%d]\n", |
| + regs[1] >> 16, regs[1] & 0xffff, regs[0], regs[2]); |
| + |
| + printf(" Features: 0x%b\n", hyperv_features, |
| + "\020" |
| + "\001VPRUNTIME" |
| + "\002TMREFCNT" |
| + "\003SYNCIC" |
| + "\004SYNCTM" |
| + "\005APIC" |
| + "\006HYERCALL" |
| + "\007VPINDEX" |
| + "\010RESET" |
| + "\011STATS" |
| + "\012REFTSC" |
| + "\013IDLE" |
| + "\014TMFREQ" |
| + "\015DEBUG"); |
| + |
| + op = HV_CPU_ID_FUNCTION_MS_HV_ENLIGHTENMENT_INFORMATION; |
| + do_cpuid(op, regs); |
| + hyperv_recommends = regs[0]; |
| + if (bootverbose) |
| + printf(" Recommends: %08x %08x\n", regs[0], regs[1]); |
| + |
| + op = HV_CPU_ID_FUNCTION_MS_HV_IMPLEMENTATION_LIMITS; |
| + do_cpuid(op, regs); |
| + if (bootverbose) { |
| + printf(" Limits: Vcpu:%d Lcpu:%d Int:%d\n", |
| + regs[0], regs[1], regs[2]); |
| + } |
| + |
| + if (maxLeaf >= HV_CPU_ID_FUNCTION_MS_HV_HARDWARE_FEATURE) { |
| + op = HV_CPU_ID_FUNCTION_MS_HV_HARDWARE_FEATURE; |
| + do_cpuid(op, regs); |
| + if (bootverbose) { |
| + printf(" HW Features: %08x AMD: %08x\n", |
| + regs[0], regs[3]); |
| + } |
| + } |
| + |
| + return (true); |
| +} |
| + |
| +static void |
| +hyperv_init(void *dummy __unused) |
| +{ |
| + if (!hyperv_identify()) |
| + return; |
| + |
| + if (hyperv_features & HV_FEATURE_MSR_TIME_REFCNT) { |
| + /* Register virtual timecount */ |
| + tc_init(&hv_timecounter); |
| + } |
| +} |
| +SYSINIT(hyperv_initialize, SI_SUB_HYPERVISOR, SI_ORDER_FIRST, hyperv_init, NULL); |
| Index: sys/dev/hyperv/vmbus/hv_vmbus_priv.h |
| =================================================================== |
| --- sys/dev/hyperv/vmbus/hv_vmbus_priv.h (版本 303304) |
| +++ sys/dev/hyperv/vmbus/hv_vmbus_priv.h (版本 303984) |
| @@ -70,6 +70,7 @@ |
| * You did not supply enough message buffers to send a message. |
| */ |
| |
| +#define HV_STATUS_SUCCESS ((uint16_t)0) |
| #define HV_STATUS_INSUFFICIENT_BUFFERS ((uint16_t)0x0013) |
| |
| typedef void (*hv_vmbus_channel_callback)(void *context); |
| @@ -471,10 +472,17 @@ |
| HV_CPU_ID_FUNCTION_MS_HV_VERSION = 0x40000002, |
| HV_CPU_ID_FUNCTION_MS_HV_FEATURES = 0x40000003, |
| HV_CPU_ID_FUNCTION_MS_HV_ENLIGHTENMENT_INFORMATION = 0x40000004, |
| - HV_CPU_ID_FUNCTION_MS_HV_IMPLEMENTATION_LIMITS = 0x40000005 |
| - |
| + HV_CPU_ID_FUNCTION_MS_HV_IMPLEMENTATION_LIMITS = 0x40000005, |
| + HV_CPU_ID_FUNCTION_MS_HV_HARDWARE_FEATURE = 0x40000006 |
| } hv_vmbus_cpuid_function; |
| |
| +#define HV_FEATURE_MSR_TIME_REFCNT (1 << 1) |
| +#define HV_FEATURE_MSR_SYNCIC (1 << 2) |
| +#define HV_FEATURE_MSR_STIMER (1 << 3) |
| +#define HV_FEATURE_MSR_APIC (1 << 4) |
| +#define HV_FEATURE_MSR_HYPERCALL (1 << 5) |
| +#define HV_FEATURE_MSR_GUEST_IDLE (1 << 10) |
| + |
| /* |
| * Define the format of the SIMP register |
| */ |
| @@ -628,6 +636,9 @@ |
| extern hv_vmbus_context hv_vmbus_g_context; |
| extern hv_vmbus_connection hv_vmbus_g_connection; |
| |
| +extern u_int hyperv_features; |
| +extern u_int hyperv_recommends; |
| + |
| typedef void (*vmbus_msg_handler)(hv_vmbus_channel_msg_header *msg); |
| |
| typedef struct hv_vmbus_channel_msg_table_entry { |
| Index: . |
| =================================================================== |
| --- . (版本 303304) |
| +++ . (版本 303984) |
| |
| 属性改变: . |
| ___________________________________________________________________ |
| Modified: svn:mergeinfo |
| ## -0,0 +0,2 ## |
| 已经合并 /head:r297219,297635,297802-297804,298038,298385,299505,302541,302605 |
| 已经合并 /stable/10:r299153,299156,300656,301924-301925,301942,302863 |