* Re: [PATCH 1/2] Staging: hv: Applied all the patches already in the staging queue
From: Greg KH @ 2012-01-26 17:37 UTC (permalink / raw)
To: K. Y. Srinivasan
Cc: linux-kernel, devel, virtualization, ohering, jbottomley, hch,
linux-scsi
In-Reply-To: <1327599515-12679-1-git-send-email-kys@microsoft.com>
On Thu, Jan 26, 2012 at 09:38:34AM -0800, K. Y. Srinivasan wrote:
> This patch gets the storage driver to the same level as in the staging tree.
>
> Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
> ---
> drivers/staging/hv/storvsc_drv.c | 1301 ++++++++++++++++++-------------------
> 1 files changed, 633 insertions(+), 668 deletions(-)
What? That changelog comment makes no sense at all, as you are patching
the staging version of the driver. This isn't an acceptable patch at
all.
Yes, I have pending patches for this driver in my "to-apply" queue, but
that is for 3.4, not now.
So, how about I just apply those patches, and then apply a patch that
moves it out of staging into drivers/scsi/, and queue all of those up
for 3.4.
James, any objection to that?
thanks,
greg k-h
^ permalink raw reply
* [PATCH 1/2] Staging: hv: Applied all the patches already in the staging queue
From: K. Y. Srinivasan @ 2012-01-26 17:38 UTC (permalink / raw)
To: gregkh, linux-kernel, devel, virtualization, ohering, jbottomley,
hch, linux-scsi
Cc: K. Y. Srinivasan
In-Reply-To: <1327599460-12593-1-git-send-email-kys@microsoft.com>
This patch gets the storage driver to the same level as in the staging tree.
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
---
drivers/staging/hv/storvsc_drv.c | 1301 ++++++++++++++++++-------------------
1 files changed, 633 insertions(+), 668 deletions(-)
diff --git a/drivers/staging/hv/storvsc_drv.c b/drivers/staging/hv/storvsc_drv.c
index ddbdec8..695ffc3 100644
--- a/drivers/staging/hv/storvsc_drv.c
+++ b/drivers/staging/hv/storvsc_drv.c
@@ -42,56 +42,23 @@
#include <scsi/scsi_devinfo.h>
#include <scsi/scsi_dbg.h>
+/*
+ * All wire protocol details (storage protocol between the guest and the host)
+ * are consolidated here.
+ *
+ * Begin protocol definitions.
+ */
-#define STORVSC_MIN_BUF_NR 64
-#define STORVSC_RING_BUFFER_SIZE (20*PAGE_SIZE)
-static int storvsc_ringbuffer_size = STORVSC_RING_BUFFER_SIZE;
-
-module_param(storvsc_ringbuffer_size, int, S_IRUGO);
-MODULE_PARM_DESC(storvsc_ringbuffer_size, "Ring buffer size (bytes)");
-
-/* to alert the user that structure sizes may be mismatched even though the */
-/* protocol versions match. */
-
-
-#define REVISION_STRING(REVISION_) #REVISION_
-#define FILL_VMSTOR_REVISION(RESULT_LVALUE_) \
- do { \
- char *revision_string \
- = REVISION_STRING($Rev : 6 $) + 6; \
- RESULT_LVALUE_ = 0; \
- while (*revision_string >= '0' \
- && *revision_string <= '9') { \
- RESULT_LVALUE_ *= 10; \
- RESULT_LVALUE_ += *revision_string - '0'; \
- revision_string++; \
- } \
- } while (0)
-
-/* Major/minor macros. Minor version is in LSB, meaning that earlier flat */
-/* version numbers will be interpreted as "0.x" (i.e., 1 becomes 0.1). */
-#define VMSTOR_PROTOCOL_MAJOR(VERSION_) (((VERSION_) >> 8) & 0xff)
-#define VMSTOR_PROTOCOL_MINOR(VERSION_) (((VERSION_)) & 0xff)
-#define VMSTOR_PROTOCOL_VERSION(MAJOR_, MINOR_) ((((MAJOR_) & 0xff) << 8) | \
- (((MINOR_) & 0xff)))
-#define VMSTOR_INVALID_PROTOCOL_VERSION (-1)
-
-/* Version history: */
-/* V1 Beta 0.1 */
-/* V1 RC < 2008/1/31 1.0 */
-/* V1 RC > 2008/1/31 2.0 */
-#define VMSTOR_PROTOCOL_VERSION_CURRENT VMSTOR_PROTOCOL_VERSION(4, 2)
-
-
-
+/*
+ * Version history:
+ * V1 Beta: 0.1
+ * V1 RC < 2008/1/31: 1.0
+ * V1 RC > 2008/1/31: 2.0
+ * Win7: 4.2
+ */
-/* This will get replaced with the max transfer length that is possible on */
-/* the host adapter. */
-/* The max transfer length will be published when we offer a vmbus channel. */
-#define MAX_TRANSFER_LENGTH 0x40000
-#define DEFAULT_PACKET_SIZE (sizeof(struct vmdata_gpa_direct) + \
- sizeof(struct vstor_packet) + \
- sizesizeof(u64) * (MAX_TRANSFER_LENGTH / PAGE_SIZE)))
+#define VMSTOR_CURRENT_MAJOR 4
+#define VMSTOR_CURRENT_MINOR 2
/* Packet structure describing virtual storage requests. */
@@ -115,35 +82,31 @@ enum vstor_packet_operation {
* this remains the same across the write regardless of 32/64 bit
* note: it's patterned off the SCSI_PASS_THROUGH structure
*/
-#define CDB16GENERIC_LENGTH 0x10
-
-#ifndef SENSE_BUFFER_SIZE
-#define SENSE_BUFFER_SIZE 0x12
-#endif
-
-#define MAX_DATA_BUF_LEN_WITH_PADDING 0x14
+#define STORVSC_MAX_CMD_LEN 0x10
+#define STORVSC_SENSE_BUFFER_SIZE 0x12
+#define STORVSC_MAX_BUF_LEN_WITH_PADDING 0x14
struct vmscsi_request {
- unsigned short length;
- unsigned char srb_status;
- unsigned char scsi_status;
+ u16 length;
+ u8 srb_status;
+ u8 scsi_status;
- unsigned char port_number;
- unsigned char path_id;
- unsigned char target_id;
- unsigned char lun;
+ u8 port_number;
+ u8 path_id;
+ u8 target_id;
+ u8 lun;
- unsigned char cdb_length;
- unsigned char sense_info_length;
- unsigned char data_in;
- unsigned char reserved;
+ u8 cdb_length;
+ u8 sense_info_length;
+ u8 data_in;
+ u8 reserved;
- unsigned int data_transfer_length;
+ u32 data_transfer_length;
union {
- unsigned char cdb[CDB16GENERIC_LENGTH];
- unsigned char sense_data[SENSE_BUFFER_SIZE];
- unsigned char reserved_array[MAX_DATA_BUF_LEN_WITH_PADDING];
+ u8 cdb[STORVSC_MAX_CMD_LEN];
+ u8 sense_data[STORVSC_SENSE_BUFFER_SIZE];
+ u8 reserved_array[STORVSC_MAX_BUF_LEN_WITH_PADDING];
};
} __attribute((packed));
@@ -153,32 +116,36 @@ struct vmscsi_request {
* properties of the channel.
*/
struct vmstorage_channel_properties {
- unsigned short protocol_version;
- unsigned char path_id;
- unsigned char target_id;
+ u16 protocol_version;
+ u8 path_id;
+ u8 target_id;
/* Note: port number is only really known on the client side */
- unsigned int port_number;
- unsigned int flags;
- unsigned int max_transfer_bytes;
+ u32 port_number;
+ u32 flags;
+ u32 max_transfer_bytes;
- /* This id is unique for each channel and will correspond with */
- /* vendor specific data in the inquirydata */
- unsigned long long unique_id;
+ /*
+ * This id is unique for each channel and will correspond with
+ * vendor specific data in the inquiry data.
+ */
+
+ u64 unique_id;
} __packed;
/* This structure is sent during the storage protocol negotiations. */
struct vmstorage_protocol_version {
/* Major (MSW) and minor (LSW) version numbers. */
- unsigned short major_minor;
+ u16 major_minor;
/*
* Revision number is auto-incremented whenever this file is changed
* (See FILL_VMSTOR_REVISION macro above). Mismatch does not
* definitely indicate incompatibility--but it does indicate mismatched
* builds.
+ * This is only used on the windows side. Just set it to 0.
*/
- unsigned short revision;
+ u16 revision;
} __packed;
/* Channel Property Flags */
@@ -190,10 +157,10 @@ struct vstor_packet {
enum vstor_packet_operation operation;
/* Flags - see below for values */
- unsigned int flags;
+ u32 flags;
/* Status of the request returned from the server side. */
- unsigned int status;
+ u32 status;
/* Data payload area */
union {
@@ -211,18 +178,47 @@ struct vstor_packet {
};
} __packed;
-/* Packet flags */
/*
+ * Packet Flags:
+ *
* This flag indicates that the server should send back a completion for this
* packet.
*/
+
#define REQUEST_COMPLETION_FLAG 0x1
-/* This is the set of flags that the vsc can set in any packets it sends */
-#define VSC_LEGAL_FLAGS (REQUEST_COMPLETION_FLAG)
+/* Matches Windows-end */
+enum storvsc_request_type {
+ WRITE_TYPE = 0,
+ READ_TYPE,
+ UNKNOWN_TYPE,
+};
+
+/*
+ * SRB status codes and masks; a subset of the codes used here.
+ */
+
+#define SRB_STATUS_AUTOSENSE_VALID 0x80
+#define SRB_STATUS_INVALID_LUN 0x20
+#define SRB_STATUS_SUCCESS 0x01
+#define SRB_STATUS_ERROR 0x04
+
+/*
+ * This is the end of Protocol specific defines.
+ */
+
+
+/*
+ * We setup a mempool to allocate request structures for this driver
+ * on a per-lun basis. The following define specifies the number of
+ * elements in the pool.
+ */
+#define STORVSC_MIN_BUF_NR 64
+static int storvsc_ringbuffer_size = (20 * PAGE_SIZE);
-/* Defines */
+module_param(storvsc_ringbuffer_size, int, S_IRUGO);
+MODULE_PARM_DESC(storvsc_ringbuffer_size, "Ring buffer size (bytes)");
#define STORVSC_MAX_IO_REQUESTS 128
@@ -235,27 +231,23 @@ struct vstor_packet {
#define STORVSC_MAX_LUNS_PER_TARGET 64
#define STORVSC_MAX_TARGETS 1
#define STORVSC_MAX_CHANNELS 1
-#define STORVSC_MAX_CMD_LEN 16
-/* Matches Windows-end */
-enum storvsc_request_type {
- WRITE_TYPE,
- READ_TYPE,
- UNKNOWN_TYPE,
-};
-struct hv_storvsc_request {
+struct storvsc_cmd_request {
+ struct list_head entry;
+ struct scsi_cmnd *cmd;
+
+ unsigned int bounce_sgl_count;
+ struct scatterlist *bounce_sgl;
+
struct hv_device *device;
/* Synchronize the request/response if needed */
struct completion wait_event;
unsigned char *sense_buffer;
- void *context;
- void (*on_io_completion)(struct hv_storvsc_request *request);
struct hv_multipage_buffer data_buffer;
-
struct vstor_packet vstor_packet;
};
@@ -281,8 +273,8 @@ struct storvsc_device {
unsigned char target_id;
/* Used for vsc/vsp channel reset process */
- struct hv_storvsc_request init_request;
- struct hv_storvsc_request reset_request;
+ struct storvsc_cmd_request init_request;
+ struct storvsc_cmd_request reset_request;
};
struct stor_mem_pools {
@@ -297,16 +289,6 @@ struct hv_host_device {
unsigned char target;
};
-struct storvsc_cmd_request {
- struct list_head entry;
- struct scsi_cmnd *cmd;
-
- unsigned int bounce_sgl_count;
- struct scatterlist *bounce_sgl;
-
- struct hv_storvsc_request request;
-};
-
struct storvsc_scan_work {
struct work_struct work;
struct Scsi_Host *host;
@@ -352,6 +334,34 @@ done:
kfree(wrk);
}
+/*
+ * Major/minor macros. Minor version is in LSB, meaning that earlier flat
+ * version numbers will be interpreted as "0.x" (i.e., 1 becomes 0.1).
+ */
+
+static inline u16 storvsc_get_version(u8 major, u8 minor)
+{
+ u16 version;
+
+ version = ((major << 8) | minor);
+ return version;
+}
+
+/*
+ * We can get incoming messages from the host that are not in response to
+ * messages that we have sent out. An example of this would be messages
+ * received by the guest to notify dynamic addition/removal of LUNs. To
+ * deal with potential race conditions where the driver may be in the
+ * midst of being unloaded when we might receive an unsolicited message
+ * from the host, we have implemented a mechanism to gurantee sequential
+ * consistency:
+ *
+ * 1) Once the device is marked as being destroyed, we will fail all
+ * outgoing messages.
+ * 2) We permit incoming messages when the device is being destroyed,
+ * only to properly account for messages already sent out.
+ */
+
static inline struct storvsc_device *get_out_stor_device(
struct hv_device *device)
{
@@ -398,116 +408,342 @@ get_in_err:
}
-static int storvsc_channel_init(struct hv_device *device)
+static void destroy_bounce_buffer(struct scatterlist *sgl,
+ unsigned int sg_count)
{
- struct storvsc_device *stor_device;
- struct hv_storvsc_request *request;
- struct vstor_packet *vstor_packet;
- int ret, t;
+ int i;
+ struct page *page_buf;
- stor_device = get_out_stor_device(device);
- if (!stor_device)
- return -ENODEV;
+ for (i = 0; i < sg_count; i++) {
+ page_buf = sg_page((&sgl[i]));
+ if (page_buf != NULL)
+ __free_page(page_buf);
+ }
- request = &stor_device->init_request;
- vstor_packet = &request->vstor_packet;
+ kfree(sgl);
+}
- /*
- * Now, initiate the vsc/vsp initialization protocol on the open
- * channel
- */
- memset(request, 0, sizeof(struct hv_storvsc_request));
- init_completion(&request->wait_event);
- vstor_packet->operation = VSTOR_OPERATION_BEGIN_INITIALIZATION;
- vstor_packet->flags = REQUEST_COMPLETION_FLAG;
+static int do_bounce_buffer(struct scatterlist *sgl, unsigned int sg_count)
+{
+ int i;
- ret = vmbus_sendpacket(device->channel, vstor_packet,
- sizeof(struct vstor_packet),
- (unsigned long)request,
- VM_PKT_DATA_INBAND,
- VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
- if (ret != 0)
- goto cleanup;
+ /* No need to check */
+ if (sg_count < 2)
+ return -1;
- t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
- if (t == 0) {
- ret = -ETIMEDOUT;
- goto cleanup;
+ /* We have at least 2 sg entries */
+ for (i = 0; i < sg_count; i++) {
+ if (i == 0) {
+ /* make sure 1st one does not have hole */
+ if (sgl[i].offset + sgl[i].length != PAGE_SIZE)
+ return i;
+ } else if (i == sg_count - 1) {
+ /* make sure last one does not have hole */
+ if (sgl[i].offset != 0)
+ return i;
+ } else {
+ /* make sure no hole in the middle */
+ if (sgl[i].length != PAGE_SIZE || sgl[i].offset != 0)
+ return i;
+ }
}
+ return -1;
+}
- if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO ||
- vstor_packet->status != 0)
- goto cleanup;
-
-
- /* reuse the packet for version range supported */
- memset(vstor_packet, 0, sizeof(struct vstor_packet));
- vstor_packet->operation = VSTOR_OPERATION_QUERY_PROTOCOL_VERSION;
- vstor_packet->flags = REQUEST_COMPLETION_FLAG;
+static struct scatterlist *create_bounce_buffer(struct scatterlist *sgl,
+ unsigned int sg_count,
+ unsigned int len,
+ int write)
+{
+ int i;
+ int num_pages;
+ struct scatterlist *bounce_sgl;
+ struct page *page_buf;
+ unsigned int buf_len = ((write == WRITE_TYPE) ? 0 : PAGE_SIZE);
- vstor_packet->version.major_minor = VMSTOR_PROTOCOL_VERSION_CURRENT;
- FILL_VMSTOR_REVISION(vstor_packet->version.revision);
+ num_pages = ALIGN(len, PAGE_SIZE) >> PAGE_SHIFT;
- ret = vmbus_sendpacket(device->channel, vstor_packet,
- sizeof(struct vstor_packet),
- (unsigned long)request,
- VM_PKT_DATA_INBAND,
- VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
- if (ret != 0)
- goto cleanup;
+ bounce_sgl = kcalloc(num_pages, sizeof(struct scatterlist), GFP_ATOMIC);
+ if (!bounce_sgl)
+ return NULL;
- t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
- if (t == 0) {
- ret = -ETIMEDOUT;
- goto cleanup;
+ for (i = 0; i < num_pages; i++) {
+ page_buf = alloc_page(GFP_ATOMIC);
+ if (!page_buf)
+ goto cleanup;
+ sg_set_page(&bounce_sgl[i], page_buf, buf_len, 0);
}
- if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO ||
- vstor_packet->status != 0)
- goto cleanup;
-
+ return bounce_sgl;
- memset(vstor_packet, 0, sizeof(struct vstor_packet));
- vstor_packet->operation = VSTOR_OPERATION_QUERY_PROPERTIES;
- vstor_packet->flags = REQUEST_COMPLETION_FLAG;
- vstor_packet->storage_channel_properties.port_number =
- stor_device->port_number;
+cleanup:
+ destroy_bounce_buffer(bounce_sgl, num_pages);
+ return NULL;
+}
- ret = vmbus_sendpacket(device->channel, vstor_packet,
- sizeof(struct vstor_packet),
- (unsigned long)request,
- VM_PKT_DATA_INBAND,
- VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
+/* Assume the original sgl has enough room */
+static unsigned int copy_from_bounce_buffer(struct scatterlist *orig_sgl,
+ struct scatterlist *bounce_sgl,
+ unsigned int orig_sgl_count,
+ unsigned int bounce_sgl_count)
+{
+ int i;
+ int j = 0;
+ unsigned long src, dest;
+ unsigned int srclen, destlen, copylen;
+ unsigned int total_copied = 0;
+ unsigned long bounce_addr = 0;
+ unsigned long dest_addr = 0;
+ unsigned long flags;
- if (ret != 0)
- goto cleanup;
+ local_irq_save(flags);
- t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
- if (t == 0) {
- ret = -ETIMEDOUT;
- goto cleanup;
- }
+ for (i = 0; i < orig_sgl_count; i++) {
+ dest_addr = (unsigned long)kmap_atomic(sg_page((&orig_sgl[i])),
+ KM_IRQ0) + orig_sgl[i].offset;
+ dest = dest_addr;
+ destlen = orig_sgl[i].length;
- if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO ||
- vstor_packet->status != 0)
- goto cleanup;
+ if (bounce_addr == 0)
+ bounce_addr =
+ (unsigned long)kmap_atomic(sg_page((&bounce_sgl[j])),
+ KM_IRQ0);
- stor_device->path_id = vstor_packet->storage_channel_properties.path_id;
- stor_device->target_id
- = vstor_packet->storage_channel_properties.target_id;
+ while (destlen) {
+ src = bounce_addr + bounce_sgl[j].offset;
+ srclen = bounce_sgl[j].length - bounce_sgl[j].offset;
- memset(vstor_packet, 0, sizeof(struct vstor_packet));
- vstor_packet->operation = VSTOR_OPERATION_END_INITIALIZATION;
- vstor_packet->flags = REQUEST_COMPLETION_FLAG;
+ copylen = min(srclen, destlen);
+ memcpy((void *)dest, (void *)src, copylen);
- ret = vmbus_sendpacket(device->channel, vstor_packet,
- sizeof(struct vstor_packet),
- (unsigned long)request,
- VM_PKT_DATA_INBAND,
- VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
+ total_copied += copylen;
+ bounce_sgl[j].offset += copylen;
+ destlen -= copylen;
+ dest += copylen;
- if (ret != 0)
- goto cleanup;
+ if (bounce_sgl[j].offset == bounce_sgl[j].length) {
+ /* full */
+ kunmap_atomic((void *)bounce_addr, KM_IRQ0);
+ j++;
+
+ /*
+ * It is possible that the number of elements
+ * in the bounce buffer may not be equal to
+ * the number of elements in the original
+ * scatter list. Handle this correctly.
+ */
+
+ if (j == bounce_sgl_count) {
+ /*
+ * We are done; cleanup and return.
+ */
+ kunmap_atomic((void *)(dest_addr -
+ orig_sgl[i].offset),
+ KM_IRQ0);
+ local_irq_restore(flags);
+ return total_copied;
+ }
+
+ /* if we need to use another bounce buffer */
+ if (destlen || i != orig_sgl_count - 1)
+ bounce_addr =
+ (unsigned long)kmap_atomic(
+ sg_page((&bounce_sgl[j])), KM_IRQ0);
+ } else if (destlen == 0 && i == orig_sgl_count - 1) {
+ /* unmap the last bounce that is < PAGE_SIZE */
+ kunmap_atomic((void *)bounce_addr, KM_IRQ0);
+ }
+ }
+
+ kunmap_atomic((void *)(dest_addr - orig_sgl[i].offset),
+ KM_IRQ0);
+ }
+
+ local_irq_restore(flags);
+
+ return total_copied;
+}
+
+/* Assume the bounce_sgl has enough room ie using the create_bounce_buffer() */
+static unsigned int copy_to_bounce_buffer(struct scatterlist *orig_sgl,
+ struct scatterlist *bounce_sgl,
+ unsigned int orig_sgl_count)
+{
+ int i;
+ int j = 0;
+ unsigned long src, dest;
+ unsigned int srclen, destlen, copylen;
+ unsigned int total_copied = 0;
+ unsigned long bounce_addr = 0;
+ unsigned long src_addr = 0;
+ unsigned long flags;
+
+ local_irq_save(flags);
+
+ for (i = 0; i < orig_sgl_count; i++) {
+ src_addr = (unsigned long)kmap_atomic(sg_page((&orig_sgl[i])),
+ KM_IRQ0) + orig_sgl[i].offset;
+ src = src_addr;
+ srclen = orig_sgl[i].length;
+
+ if (bounce_addr == 0)
+ bounce_addr =
+ (unsigned long)kmap_atomic(sg_page((&bounce_sgl[j])),
+ KM_IRQ0);
+
+ while (srclen) {
+ /* assume bounce offset always == 0 */
+ dest = bounce_addr + bounce_sgl[j].length;
+ destlen = PAGE_SIZE - bounce_sgl[j].length;
+
+ copylen = min(srclen, destlen);
+ memcpy((void *)dest, (void *)src, copylen);
+
+ total_copied += copylen;
+ bounce_sgl[j].length += copylen;
+ srclen -= copylen;
+ src += copylen;
+
+ if (bounce_sgl[j].length == PAGE_SIZE) {
+ /* full..move to next entry */
+ kunmap_atomic((void *)bounce_addr, KM_IRQ0);
+ j++;
+
+ /* if we need to use another bounce buffer */
+ if (srclen || i != orig_sgl_count - 1)
+ bounce_addr =
+ (unsigned long)kmap_atomic(
+ sg_page((&bounce_sgl[j])), KM_IRQ0);
+
+ } else if (srclen == 0 && i == orig_sgl_count - 1) {
+ /* unmap the last bounce that is < PAGE_SIZE */
+ kunmap_atomic((void *)bounce_addr, KM_IRQ0);
+ }
+ }
+
+ kunmap_atomic((void *)(src_addr - orig_sgl[i].offset), KM_IRQ0);
+ }
+
+ local_irq_restore(flags);
+
+ return total_copied;
+}
+
+static int storvsc_channel_init(struct hv_device *device)
+{
+ struct storvsc_device *stor_device;
+ struct storvsc_cmd_request *request;
+ struct vstor_packet *vstor_packet;
+ int ret, t;
+
+ stor_device = get_out_stor_device(device);
+ if (!stor_device)
+ return -ENODEV;
+
+ request = &stor_device->init_request;
+ vstor_packet = &request->vstor_packet;
+
+ /*
+ * Now, initiate the vsc/vsp initialization protocol on the open
+ * channel
+ */
+ memset(request, 0, sizeof(struct storvsc_cmd_request));
+ init_completion(&request->wait_event);
+ vstor_packet->operation = VSTOR_OPERATION_BEGIN_INITIALIZATION;
+ vstor_packet->flags = REQUEST_COMPLETION_FLAG;
+
+ ret = vmbus_sendpacket(device->channel, vstor_packet,
+ sizeof(struct vstor_packet),
+ (unsigned long)request,
+ VM_PKT_DATA_INBAND,
+ VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
+ if (ret != 0)
+ goto cleanup;
+
+ t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
+ if (t == 0) {
+ ret = -ETIMEDOUT;
+ goto cleanup;
+ }
+
+ if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO ||
+ vstor_packet->status != 0)
+ goto cleanup;
+
+
+ /* reuse the packet for version range supported */
+ memset(vstor_packet, 0, sizeof(struct vstor_packet));
+ vstor_packet->operation = VSTOR_OPERATION_QUERY_PROTOCOL_VERSION;
+ vstor_packet->flags = REQUEST_COMPLETION_FLAG;
+
+ vstor_packet->version.major_minor =
+ storvsc_get_version(VMSTOR_CURRENT_MAJOR, VMSTOR_CURRENT_MINOR);
+
+ /*
+ * The revision number is only used in Windows; set it to 0.
+ */
+ vstor_packet->version.revision = 0;
+
+ ret = vmbus_sendpacket(device->channel, vstor_packet,
+ sizeof(struct vstor_packet),
+ (unsigned long)request,
+ VM_PKT_DATA_INBAND,
+ VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
+ if (ret != 0)
+ goto cleanup;
+
+ t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
+ if (t == 0) {
+ ret = -ETIMEDOUT;
+ goto cleanup;
+ }
+
+ if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO ||
+ vstor_packet->status != 0)
+ goto cleanup;
+
+
+ memset(vstor_packet, 0, sizeof(struct vstor_packet));
+ vstor_packet->operation = VSTOR_OPERATION_QUERY_PROPERTIES;
+ vstor_packet->flags = REQUEST_COMPLETION_FLAG;
+ vstor_packet->storage_channel_properties.port_number =
+ stor_device->port_number;
+
+ ret = vmbus_sendpacket(device->channel, vstor_packet,
+ sizeof(struct vstor_packet),
+ (unsigned long)request,
+ VM_PKT_DATA_INBAND,
+ VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
+
+ if (ret != 0)
+ goto cleanup;
+
+ t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
+ if (t == 0) {
+ ret = -ETIMEDOUT;
+ goto cleanup;
+ }
+
+ if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO ||
+ vstor_packet->status != 0)
+ goto cleanup;
+
+ stor_device->path_id = vstor_packet->storage_channel_properties.path_id;
+ stor_device->target_id
+ = vstor_packet->storage_channel_properties.target_id;
+
+ memset(vstor_packet, 0, sizeof(struct vstor_packet));
+ vstor_packet->operation = VSTOR_OPERATION_END_INITIALIZATION;
+ vstor_packet->flags = REQUEST_COMPLETION_FLAG;
+
+ ret = vmbus_sendpacket(device->channel, vstor_packet,
+ sizeof(struct vstor_packet),
+ (unsigned long)request,
+ VM_PKT_DATA_INBAND,
+ VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
+
+ if (ret != 0)
+ goto cleanup;
t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
if (t == 0) {
@@ -524,9 +760,84 @@ cleanup:
return ret;
}
+
+static void storvsc_command_completion(struct storvsc_cmd_request *cmd_request)
+{
+ struct scsi_cmnd *scmnd = cmd_request->cmd;
+ struct hv_host_device *host_dev = shost_priv(scmnd->device->host);
+ void (*scsi_done_fn)(struct scsi_cmnd *);
+ struct scsi_sense_hdr sense_hdr;
+ struct vmscsi_request *vm_srb;
+ struct storvsc_scan_work *wrk;
+ struct stor_mem_pools *memp = scmnd->device->hostdata;
+
+ vm_srb = &cmd_request->vstor_packet.vm_srb;
+ if (cmd_request->bounce_sgl_count) {
+ if (vm_srb->data_in == READ_TYPE)
+ copy_from_bounce_buffer(scsi_sglist(scmnd),
+ cmd_request->bounce_sgl,
+ scsi_sg_count(scmnd),
+ cmd_request->bounce_sgl_count);
+ destroy_bounce_buffer(cmd_request->bounce_sgl,
+ cmd_request->bounce_sgl_count);
+ }
+
+ /*
+ * If there is an error; offline the device since all
+ * error recovery strategies would have already been
+ * deployed on the host side.
+ */
+ if (vm_srb->srb_status == SRB_STATUS_ERROR)
+ scmnd->result = DID_TARGET_FAILURE << 16;
+ else
+ scmnd->result = vm_srb->scsi_status;
+
+ /*
+ * If the LUN is invalid; remove the device.
+ */
+ if (vm_srb->srb_status == SRB_STATUS_INVALID_LUN) {
+ struct storvsc_device *stor_dev;
+ struct hv_device *dev = host_dev->dev;
+ struct Scsi_Host *host;
+
+ stor_dev = get_in_stor_device(dev);
+ host = stor_dev->host;
+
+ wrk = kmalloc(sizeof(struct storvsc_scan_work),
+ GFP_ATOMIC);
+ if (!wrk) {
+ scmnd->result = DID_TARGET_FAILURE << 16;
+ } else {
+ wrk->host = host;
+ wrk->lun = vm_srb->lun;
+ INIT_WORK(&wrk->work, storvsc_remove_lun);
+ schedule_work(&wrk->work);
+ }
+ }
+
+ if (scmnd->result) {
+ if (scsi_normalize_sense(scmnd->sense_buffer,
+ SCSI_SENSE_BUFFERSIZE, &sense_hdr))
+ scsi_print_sense_hdr("storvsc", &sense_hdr);
+ }
+
+ scsi_set_resid(scmnd,
+ cmd_request->data_buffer.len -
+ vm_srb->data_transfer_length);
+
+ scsi_done_fn = scmnd->scsi_done;
+
+ scmnd->host_scribble = NULL;
+ scmnd->scsi_done = NULL;
+
+ scsi_done_fn(scmnd);
+
+ mempool_free(cmd_request, memp->request_mempool);
+}
+
static void storvsc_on_io_completion(struct hv_device *device,
struct vstor_packet *vstor_packet,
- struct hv_storvsc_request *request)
+ struct storvsc_cmd_request *request)
{
struct storvsc_device *stor_device;
struct vstor_packet *stor_pkt;
@@ -546,9 +857,9 @@ static void storvsc_on_io_completion(struct hv_device *device,
*/
if ((stor_pkt->vm_srb.cdb[0] == INQUIRY) ||
- (stor_pkt->vm_srb.cdb[0] == MODE_SENSE)) {
+ (stor_pkt->vm_srb.cdb[0] == MODE_SENSE)) {
vstor_packet->vm_srb.scsi_status = 0;
- vstor_packet->vm_srb.srb_status = 0x1;
+ vstor_packet->vm_srb.srb_status = SRB_STATUS_SUCCESS;
}
@@ -559,7 +870,7 @@ static void storvsc_on_io_completion(struct hv_device *device,
vstor_packet->vm_srb.sense_info_length;
if (vstor_packet->vm_srb.scsi_status != 0 ||
- vstor_packet->vm_srb.srb_status != 1){
+ vstor_packet->vm_srb.srb_status != SRB_STATUS_SUCCESS){
dev_warn(&device->device,
"cmd 0x%x scsi status 0x%x srb status 0x%x\n",
stor_pkt->vm_srb.cdb[0],
@@ -569,7 +880,8 @@ static void storvsc_on_io_completion(struct hv_device *device,
if ((vstor_packet->vm_srb.scsi_status & 0xFF) == 0x02) {
/* CHECK_CONDITION */
- if (vstor_packet->vm_srb.srb_status & 0x80) {
+ if (vstor_packet->vm_srb.srb_status &
+ SRB_STATUS_AUTOSENSE_VALID) {
/* autosense data available */
dev_warn(&device->device,
"stor pkt %p autosense data valid - len %d\n",
@@ -586,7 +898,7 @@ static void storvsc_on_io_completion(struct hv_device *device,
stor_pkt->vm_srb.data_transfer_length =
vstor_packet->vm_srb.data_transfer_length;
- request->on_io_completion(request);
+ storvsc_command_completion(request);
if (atomic_dec_and_test(&stor_device->num_outstanding_req) &&
stor_device->drain_notify)
@@ -597,7 +909,7 @@ static void storvsc_on_io_completion(struct hv_device *device,
static void storvsc_on_receive(struct hv_device *device,
struct vstor_packet *vstor_packet,
- struct hv_storvsc_request *request)
+ struct storvsc_cmd_request *request)
{
struct storvsc_scan_work *work;
struct storvsc_device *stor_device;
@@ -631,7 +943,7 @@ static void storvsc_on_channel_callback(void *context)
u32 bytes_recvd;
u64 request_id;
unsigned char packet[ALIGN(sizeof(struct vstor_packet), 8)];
- struct hv_storvsc_request *request;
+ struct storvsc_cmd_request *request;
int ret;
@@ -645,7 +957,7 @@ static void storvsc_on_channel_callback(void *context)
&bytes_recvd, &request_id);
if (ret == 0 && bytes_recvd > 0) {
- request = (struct hv_storvsc_request *)
+ request = (struct storvsc_cmd_request *)
(unsigned long)request_id;
if ((request == &stor_device->init_request) ||
@@ -674,7 +986,6 @@ static int storvsc_connect_to_vsp(struct hv_device *device, u32 ring_size)
memset(&props, 0, sizeof(struct vmstorage_channel_properties));
- /* Open the channel */
ret = vmbus_open(device->channel,
ring_size,
ring_size,
@@ -728,7 +1039,7 @@ static int storvsc_dev_remove(struct hv_device *device)
}
static int storvsc_do_io(struct hv_device *device,
- struct hv_storvsc_request *request)
+ struct storvsc_cmd_request *request)
{
struct storvsc_device *stor_device;
struct vstor_packet *vstor_packet;
@@ -749,342 +1060,94 @@ static int storvsc_do_io(struct hv_device *device,
vstor_packet->vm_srb.length = sizeof(struct vmscsi_request);
- vstor_packet->vm_srb.sense_info_length = SENSE_BUFFER_SIZE;
-
-
- vstor_packet->vm_srb.data_transfer_length =
- request->data_buffer.len;
-
- vstor_packet->operation = VSTOR_OPERATION_EXECUTE_SRB;
-
- if (request->data_buffer.len) {
- ret = vmbus_sendpacket_multipagebuffer(device->channel,
- &request->data_buffer,
- vstor_packet,
- sizeof(struct vstor_packet),
- (unsigned long)request);
- } else {
- ret = vmbus_sendpacket(device->channel, vstor_packet,
- sizeof(struct vstor_packet),
- (unsigned long)request,
- VM_PKT_DATA_INBAND,
- VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
- }
-
- if (ret != 0)
- return ret;
-
- atomic_inc(&stor_device->num_outstanding_req);
-
- return ret;
-}
-
-static void storvsc_get_ide_info(struct hv_device *dev, int *target, int *path)
-{
- *target =
- dev->dev_instance.b[5] << 8 | dev->dev_instance.b[4];
-
- *path =
- dev->dev_instance.b[3] << 24 |
- dev->dev_instance.b[2] << 16 |
- dev->dev_instance.b[1] << 8 | dev->dev_instance.b[0];
-}
-
-
-static int storvsc_device_alloc(struct scsi_device *sdevice)
-{
- struct stor_mem_pools *memp;
- int number = STORVSC_MIN_BUF_NR;
-
- memp = kzalloc(sizeof(struct stor_mem_pools), GFP_KERNEL);
- if (!memp)
- return -ENOMEM;
-
- memp->request_pool =
- kmem_cache_create(dev_name(&sdevice->sdev_dev),
- sizeof(struct storvsc_cmd_request), 0,
- SLAB_HWCACHE_ALIGN, NULL);
-
- if (!memp->request_pool)
- goto err0;
-
- memp->request_mempool = mempool_create(number, mempool_alloc_slab,
- mempool_free_slab,
- memp->request_pool);
-
- if (!memp->request_mempool)
- goto err1;
-
- sdevice->hostdata = memp;
-
- return 0;
-
-err1:
- kmem_cache_destroy(memp->request_pool);
-
-err0:
- kfree(memp);
- return -ENOMEM;
-}
-
-static void storvsc_device_destroy(struct scsi_device *sdevice)
-{
- struct stor_mem_pools *memp = sdevice->hostdata;
-
- mempool_destroy(memp->request_mempool);
- kmem_cache_destroy(memp->request_pool);
- kfree(memp);
- sdevice->hostdata = NULL;
-}
-
-static int storvsc_device_configure(struct scsi_device *sdevice)
-{
- scsi_adjust_queue_depth(sdevice, MSG_SIMPLE_TAG,
- STORVSC_MAX_IO_REQUESTS);
-
- blk_queue_max_segment_size(sdevice->request_queue, PAGE_SIZE);
-
- blk_queue_bounce_limit(sdevice->request_queue, BLK_BOUNCE_ANY);
-
- return 0;
-}
-
-static void destroy_bounce_buffer(struct scatterlist *sgl,
- unsigned int sg_count)
-{
- int i;
- struct page *page_buf;
-
- for (i = 0; i < sg_count; i++) {
- page_buf = sg_page((&sgl[i]));
- if (page_buf != NULL)
- __free_page(page_buf);
- }
-
- kfree(sgl);
-}
-
-static int do_bounce_buffer(struct scatterlist *sgl, unsigned int sg_count)
-{
- int i;
-
- /* No need to check */
- if (sg_count < 2)
- return -1;
-
- /* We have at least 2 sg entries */
- for (i = 0; i < sg_count; i++) {
- if (i == 0) {
- /* make sure 1st one does not have hole */
- if (sgl[i].offset + sgl[i].length != PAGE_SIZE)
- return i;
- } else if (i == sg_count - 1) {
- /* make sure last one does not have hole */
- if (sgl[i].offset != 0)
- return i;
- } else {
- /* make sure no hole in the middle */
- if (sgl[i].length != PAGE_SIZE || sgl[i].offset != 0)
- return i;
- }
- }
- return -1;
-}
-
-static struct scatterlist *create_bounce_buffer(struct scatterlist *sgl,
- unsigned int sg_count,
- unsigned int len,
- int write)
-{
- int i;
- int num_pages;
- struct scatterlist *bounce_sgl;
- struct page *page_buf;
- unsigned int buf_len = ((write == WRITE_TYPE) ? 0 : PAGE_SIZE);
-
- num_pages = ALIGN(len, PAGE_SIZE) >> PAGE_SHIFT;
-
- bounce_sgl = kcalloc(num_pages, sizeof(struct scatterlist), GFP_ATOMIC);
- if (!bounce_sgl)
- return NULL;
-
- for (i = 0; i < num_pages; i++) {
- page_buf = alloc_page(GFP_ATOMIC);
- if (!page_buf)
- goto cleanup;
- sg_set_page(&bounce_sgl[i], page_buf, buf_len, 0);
- }
-
- return bounce_sgl;
-
-cleanup:
- destroy_bounce_buffer(bounce_sgl, num_pages);
- return NULL;
-}
-
-
-/* Assume the original sgl has enough room */
-static unsigned int copy_from_bounce_buffer(struct scatterlist *orig_sgl,
- struct scatterlist *bounce_sgl,
- unsigned int orig_sgl_count,
- unsigned int bounce_sgl_count)
-{
- int i;
- int j = 0;
- unsigned long src, dest;
- unsigned int srclen, destlen, copylen;
- unsigned int total_copied = 0;
- unsigned long bounce_addr = 0;
- unsigned long dest_addr = 0;
- unsigned long flags;
-
- local_irq_save(flags);
-
- for (i = 0; i < orig_sgl_count; i++) {
- dest_addr = (unsigned long)kmap_atomic(sg_page((&orig_sgl[i])))
- + orig_sgl[i].offset;
- dest = dest_addr;
- destlen = orig_sgl[i].length;
-
- if (bounce_addr == 0)
- bounce_addr =
- (unsigned long)kmap_atomic(sg_page((&bounce_sgl[j])));
-
- while (destlen) {
- src = bounce_addr + bounce_sgl[j].offset;
- srclen = bounce_sgl[j].length - bounce_sgl[j].offset;
-
- copylen = min(srclen, destlen);
- memcpy((void *)dest, (void *)src, copylen);
-
- total_copied += copylen;
- bounce_sgl[j].offset += copylen;
- destlen -= copylen;
- dest += copylen;
-
- if (bounce_sgl[j].offset == bounce_sgl[j].length) {
- /* full */
- kunmap_atomic((void *)bounce_addr);
- j++;
-
- /*
- * It is possible that the number of elements
- * in the bounce buffer may not be equal to
- * the number of elements in the original
- * scatter list. Handle this correctly.
- */
+ vstor_packet->vm_srb.sense_info_length = STORVSC_SENSE_BUFFER_SIZE;
- if (j == bounce_sgl_count) {
- /*
- * We are done; cleanup and return.
- */
- kunmap_atomic((void *)(dest_addr -
- orig_sgl[i].offset),
- KM_IRQ0);
- local_irq_restore(flags);
- return total_copied;
- }
- /* if we need to use another bounce buffer */
- if (destlen || i != orig_sgl_count - 1)
- bounce_addr =
- (unsigned long)kmap_atomic(
- sg_page((&bounce_sgl[j])));
- } else if (destlen == 0 && i == orig_sgl_count - 1) {
- /* unmap the last bounce that is < PAGE_SIZE */
- kunmap_atomic((void *)bounce_addr);
- }
- }
+ vstor_packet->vm_srb.data_transfer_length =
+ request->data_buffer.len;
- kunmap_atomic((void *)(dest_addr - orig_sgl[i].offset));
+ vstor_packet->operation = VSTOR_OPERATION_EXECUTE_SRB;
+
+ if (request->data_buffer.len) {
+ ret = vmbus_sendpacket_multipagebuffer(device->channel,
+ &request->data_buffer,
+ vstor_packet,
+ sizeof(struct vstor_packet),
+ (unsigned long)request);
+ } else {
+ ret = vmbus_sendpacket(device->channel, vstor_packet,
+ sizeof(struct vstor_packet),
+ (unsigned long)request,
+ VM_PKT_DATA_INBAND,
+ VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
}
- local_irq_restore(flags);
+ if (ret != 0)
+ return ret;
- return total_copied;
-}
+ atomic_inc(&stor_device->num_outstanding_req);
+ return ret;
+}
-/* Assume the bounce_sgl has enough room ie using the create_bounce_buffer() */
-static unsigned int copy_to_bounce_buffer(struct scatterlist *orig_sgl,
- struct scatterlist *bounce_sgl,
- unsigned int orig_sgl_count)
+static int storvsc_device_alloc(struct scsi_device *sdevice)
{
- int i;
- int j = 0;
- unsigned long src, dest;
- unsigned int srclen, destlen, copylen;
- unsigned int total_copied = 0;
- unsigned long bounce_addr = 0;
- unsigned long src_addr = 0;
- unsigned long flags;
-
- local_irq_save(flags);
+ struct stor_mem_pools *memp;
+ int number = STORVSC_MIN_BUF_NR;
- for (i = 0; i < orig_sgl_count; i++) {
- src_addr = (unsigned long)kmap_atomic(sg_page((&orig_sgl[i])))
- + orig_sgl[i].offset;
- src = src_addr;
- srclen = orig_sgl[i].length;
+ memp = kzalloc(sizeof(struct stor_mem_pools), GFP_KERNEL);
+ if (!memp)
+ return -ENOMEM;
- if (bounce_addr == 0)
- bounce_addr =
- (unsigned long)kmap_atomic(sg_page((&bounce_sgl[j])));
+ memp->request_pool =
+ kmem_cache_create(dev_name(&sdevice->sdev_dev),
+ sizeof(struct storvsc_cmd_request), 0,
+ SLAB_HWCACHE_ALIGN, NULL);
- while (srclen) {
- /* assume bounce offset always == 0 */
- dest = bounce_addr + bounce_sgl[j].length;
- destlen = PAGE_SIZE - bounce_sgl[j].length;
+ if (!memp->request_pool)
+ goto err0;
- copylen = min(srclen, destlen);
- memcpy((void *)dest, (void *)src, copylen);
+ memp->request_mempool = mempool_create(number, mempool_alloc_slab,
+ mempool_free_slab,
+ memp->request_pool);
- total_copied += copylen;
- bounce_sgl[j].length += copylen;
- srclen -= copylen;
- src += copylen;
+ if (!memp->request_mempool)
+ goto err1;
- if (bounce_sgl[j].length == PAGE_SIZE) {
- /* full..move to next entry */
- kunmap_atomic((void *)bounce_addr);
- j++;
+ sdevice->hostdata = memp;
- /* if we need to use another bounce buffer */
- if (srclen || i != orig_sgl_count - 1)
- bounce_addr =
- (unsigned long)kmap_atomic(
- sg_page((&bounce_sgl[j])));
+ return 0;
- } else if (srclen == 0 && i == orig_sgl_count - 1) {
- /* unmap the last bounce that is < PAGE_SIZE */
- kunmap_atomic((void *)bounce_addr);
- }
- }
+err1:
+ kmem_cache_destroy(memp->request_pool);
- kunmap_atomic((void *)(src_addr - orig_sgl[i].offset));
- }
+err0:
+ kfree(memp);
+ return -ENOMEM;
+}
- local_irq_restore(flags);
+static void storvsc_device_destroy(struct scsi_device *sdevice)
+{
+ struct stor_mem_pools *memp = sdevice->hostdata;
- return total_copied;
+ mempool_destroy(memp->request_mempool);
+ kmem_cache_destroy(memp->request_pool);
+ kfree(memp);
+ sdevice->hostdata = NULL;
}
-
-static int storvsc_remove(struct hv_device *dev)
+static int storvsc_device_configure(struct scsi_device *sdevice)
{
- struct storvsc_device *stor_device = hv_get_drvdata(dev);
- struct Scsi_Host *host = stor_device->host;
-
- scsi_remove_host(host);
+ scsi_adjust_queue_depth(sdevice, MSG_SIMPLE_TAG,
+ STORVSC_MAX_IO_REQUESTS);
- scsi_host_put(host);
+ blk_queue_max_segment_size(sdevice->request_queue, PAGE_SIZE);
- storvsc_dev_remove(dev);
+ blk_queue_bounce_limit(sdevice->request_queue, BLK_BOUNCE_ANY);
return 0;
}
-
static int storvsc_get_chs(struct scsi_device *sdev, struct block_device * bdev,
sector_t capacity, int *info)
{
@@ -1108,10 +1171,13 @@ static int storvsc_get_chs(struct scsi_device *sdev, struct block_device * bdev,
return 0;
}
-static int storvsc_host_reset(struct hv_device *device)
+static int storvsc_host_reset_handler(struct scsi_cmnd *scmnd)
{
+ struct hv_host_device *host_dev = shost_priv(scmnd->device->host);
+ struct hv_device *device = host_dev->dev;
+
struct storvsc_device *stor_device;
- struct hv_storvsc_request *request;
+ struct storvsc_cmd_request *request;
struct vstor_packet *vstor_packet;
int ret, t;
@@ -1150,105 +1216,16 @@ static int storvsc_host_reset(struct hv_device *device)
return SUCCESS;
}
-
-/*
- * storvsc_host_reset_handler - Reset the scsi HBA
- */
-static int storvsc_host_reset_handler(struct scsi_cmnd *scmnd)
-{
- struct hv_host_device *host_dev = shost_priv(scmnd->device->host);
- struct hv_device *dev = host_dev->dev;
-
- return storvsc_host_reset(dev);
-}
-
-
-/*
- * storvsc_command_completion - Command completion processing
- */
-static void storvsc_command_completion(struct hv_storvsc_request *request)
-{
- struct storvsc_cmd_request *cmd_request =
- (struct storvsc_cmd_request *)request->context;
- struct scsi_cmnd *scmnd = cmd_request->cmd;
- struct hv_host_device *host_dev = shost_priv(scmnd->device->host);
- void (*scsi_done_fn)(struct scsi_cmnd *);
- struct scsi_sense_hdr sense_hdr;
- struct vmscsi_request *vm_srb;
- struct storvsc_scan_work *wrk;
- struct stor_mem_pools *memp = scmnd->device->hostdata;
-
- vm_srb = &request->vstor_packet.vm_srb;
- if (cmd_request->bounce_sgl_count) {
- if (vm_srb->data_in == READ_TYPE)
- copy_from_bounce_buffer(scsi_sglist(scmnd),
- cmd_request->bounce_sgl,
- scsi_sg_count(scmnd),
- cmd_request->bounce_sgl_count);
- destroy_bounce_buffer(cmd_request->bounce_sgl,
- cmd_request->bounce_sgl_count);
- }
-
- /*
- * If there is an error; offline the device since all
- * error recovery strategies would have already been
- * deployed on the host side.
- */
- if (vm_srb->srb_status == 0x4)
- scmnd->result = DID_TARGET_FAILURE << 16;
- else
- scmnd->result = vm_srb->scsi_status;
-
- /*
- * If the LUN is invalid; remove the device.
- */
- if (vm_srb->srb_status == 0x20) {
- struct storvsc_device *stor_dev;
- struct hv_device *dev = host_dev->dev;
- struct Scsi_Host *host;
-
- stor_dev = get_in_stor_device(dev);
- host = stor_dev->host;
-
- wrk = kmalloc(sizeof(struct storvsc_scan_work),
- GFP_ATOMIC);
- if (!wrk) {
- scmnd->result = DID_TARGET_FAILURE << 16;
- } else {
- wrk->host = host;
- wrk->lun = vm_srb->lun;
- INIT_WORK(&wrk->work, storvsc_remove_lun);
- schedule_work(&wrk->work);
- }
- }
-
- if (scmnd->result) {
- if (scsi_normalize_sense(scmnd->sense_buffer,
- SCSI_SENSE_BUFFERSIZE, &sense_hdr))
- scsi_print_sense_hdr("storvsc", &sense_hdr);
- }
-
- scsi_set_resid(scmnd,
- request->data_buffer.len -
- vm_srb->data_transfer_length);
-
- scsi_done_fn = scmnd->scsi_done;
-
- scmnd->host_scribble = NULL;
- scmnd->scsi_done = NULL;
-
- scsi_done_fn(scmnd);
-
- mempool_free(cmd_request, memp->request_mempool);
-}
-
-static bool storvsc_check_scsi_cmd(struct scsi_cmnd *scmnd)
+static bool storvsc_scsi_cmd_ok(struct scsi_cmnd *scmnd)
{
bool allowed = true;
u8 scsi_op = scmnd->cmnd[0];
switch (scsi_op) {
- /* smartd sends this command, which will offline the device */
+ /*
+ * smartd sends this command and the host does not handle
+ * this. So, don't send it.
+ */
case SET_WINDOW:
scmnd->result = ILLEGAL_REQUEST << 16;
allowed = false;
@@ -1259,15 +1236,11 @@ static bool storvsc_check_scsi_cmd(struct scsi_cmnd *scmnd)
return allowed;
}
-/*
- * storvsc_queuecommand - Initiate command processing
- */
static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd)
{
int ret;
struct hv_host_device *host_dev = shost_priv(host);
struct hv_device *dev = host_dev->dev;
- struct hv_storvsc_request *request;
struct storvsc_cmd_request *cmd_request;
unsigned int request_size = 0;
int i;
@@ -1276,38 +1249,31 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd)
struct vmscsi_request *vm_srb;
struct stor_mem_pools *memp = scmnd->device->hostdata;
- if (storvsc_check_scsi_cmd(scmnd) == false) {
+ if (!storvsc_scsi_cmd_ok(scmnd)) {
scmnd->scsi_done(scmnd);
return 0;
}
- /* If retrying, no need to prep the cmd */
- if (scmnd->host_scribble) {
-
- cmd_request =
- (struct storvsc_cmd_request *)scmnd->host_scribble;
-
- goto retry_request;
- }
-
request_size = sizeof(struct storvsc_cmd_request);
cmd_request = mempool_alloc(memp->request_mempool,
GFP_ATOMIC);
+
+ /*
+ * We might be invoked in an interrupt context; hence
+ * mempool_alloc() can fail.
+ */
if (!cmd_request)
return SCSI_MLQUEUE_DEVICE_BUSY;
memset(cmd_request, 0, sizeof(struct storvsc_cmd_request));
/* Setup the cmd request */
- cmd_request->bounce_sgl_count = 0;
- cmd_request->bounce_sgl = NULL;
cmd_request->cmd = scmnd;
scmnd->host_scribble = (unsigned char *)cmd_request;
- request = &cmd_request->request;
- vm_srb = &request->vstor_packet.vm_srb;
+ vm_srb = &cmd_request->vstor_packet.vm_srb;
/* Build the SRB */
@@ -1323,8 +1289,6 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd)
break;
}
- request->on_io_completion = storvsc_command_completion;
- request->context = cmd_request;/* scmnd; */
vm_srb->port_number = host_dev->port;
vm_srb->path_id = scmnd->device->channel;
@@ -1335,10 +1299,10 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd)
memcpy(vm_srb->cdb, scmnd->cmnd, vm_srb->cdb_length);
- request->sense_buffer = scmnd->sense_buffer;
+ cmd_request->sense_buffer = scmnd->sense_buffer;
- request->data_buffer.len = scsi_bufflen(scmnd);
+ cmd_request->data_buffer.len = scsi_bufflen(scmnd);
if (scsi_sg_count(scmnd)) {
sgl = (struct scatterlist *)scsi_sglist(scmnd);
sg_count = scsi_sg_count(scmnd);
@@ -1350,11 +1314,8 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd)
scsi_bufflen(scmnd),
vm_srb->data_in);
if (!cmd_request->bounce_sgl) {
- scmnd->host_scribble = NULL;
- mempool_free(cmd_request,
- memp->request_mempool);
-
- return SCSI_MLQUEUE_HOST_BUSY;
+ ret = SCSI_MLQUEUE_HOST_BUSY;
+ goto queue_error;
}
cmd_request->bounce_sgl_count =
@@ -1370,41 +1331,42 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd)
sg_count = cmd_request->bounce_sgl_count;
}
- request->data_buffer.offset = sgl[0].offset;
+ cmd_request->data_buffer.offset = sgl[0].offset;
for (i = 0; i < sg_count; i++)
- request->data_buffer.pfn_array[i] =
+ cmd_request->data_buffer.pfn_array[i] =
page_to_pfn(sg_page((&sgl[i])));
} else if (scsi_sglist(scmnd)) {
- request->data_buffer.offset =
+ cmd_request->data_buffer.offset =
virt_to_phys(scsi_sglist(scmnd)) & (PAGE_SIZE-1);
- request->data_buffer.pfn_array[0] =
+ cmd_request->data_buffer.pfn_array[0] =
virt_to_phys(scsi_sglist(scmnd)) >> PAGE_SHIFT;
}
-retry_request:
/* Invokes the vsc to start an IO */
- ret = storvsc_do_io(dev, &cmd_request->request);
+ ret = storvsc_do_io(dev, cmd_request);
if (ret == -EAGAIN) {
/* no more space */
- if (cmd_request->bounce_sgl_count)
+ if (cmd_request->bounce_sgl_count) {
destroy_bounce_buffer(cmd_request->bounce_sgl,
cmd_request->bounce_sgl_count);
- mempool_free(cmd_request, memp->request_mempool);
-
- scmnd->host_scribble = NULL;
-
- ret = SCSI_MLQUEUE_DEVICE_BUSY;
+ ret = SCSI_MLQUEUE_DEVICE_BUSY;
+ goto queue_error;
+ }
}
+ return 0;
+
+queue_error:
+ mempool_free(cmd_request, memp->request_mempool);
+ scmnd->host_scribble = NULL;
return ret;
}
-/* Scsi driver */
static struct scsi_host_template scsi_driver = {
.module = THIS_MODULE,
.name = "storvsc_host_t",
@@ -1445,11 +1407,6 @@ static const struct hv_vmbus_device_id id_table[] = {
MODULE_DEVICE_TABLE(vmbus, id_table);
-
-/*
- * storvsc_probe - Add a new device for this driver
- */
-
static int storvsc_probe(struct hv_device *device,
const struct hv_vmbus_device_id *dev_id)
{
@@ -1457,7 +1414,6 @@ static int storvsc_probe(struct hv_device *device,
struct Scsi_Host *host;
struct hv_host_device *host_dev;
bool dev_is_ide = ((dev_id->driver_data == IDE_GUID) ? true : false);
- int path = 0;
int target = 0;
struct storvsc_device *stor_device;
@@ -1490,9 +1446,6 @@ static int storvsc_probe(struct hv_device *device,
if (ret)
goto err_out1;
- if (dev_is_ide)
- storvsc_get_ide_info(device, &target, &path);
-
host_dev->path = stor_device->path_id;
host_dev->target = stor_device->target_id;
@@ -1512,12 +1465,14 @@ static int storvsc_probe(struct hv_device *device,
if (!dev_is_ide) {
scsi_scan_host(host);
- return 0;
- }
- ret = scsi_add_device(host, 0, target, 0);
- if (ret) {
- scsi_remove_host(host);
- goto err_out2;
+ } else {
+ target = (device->dev_instance.b[5] << 8 |
+ device->dev_instance.b[4]);
+ ret = scsi_add_device(host, 0, target, 0);
+ if (ret) {
+ scsi_remove_host(host);
+ goto err_out2;
+ }
}
return 0;
@@ -1539,7 +1494,17 @@ err_out0:
return ret;
}
-/* The one and only one */
+static int storvsc_remove(struct hv_device *dev)
+{
+ struct storvsc_device *stor_device = hv_get_drvdata(dev);
+ struct Scsi_Host *host = stor_device->host;
+
+ scsi_remove_host(host);
+ storvsc_dev_remove(dev);
+ scsi_host_put(host);
+
+ return 0;
+}
static struct hv_driver storvsc_drv = {
.name = KBUILD_MODNAME,
--
1.7.4.1
^ permalink raw reply related
* [PATCH 2/2] Staging: hv: storvsc: Move the storage driver out of the staging area
From: K. Y. Srinivasan @ 2012-01-26 17:38 UTC (permalink / raw)
To: gregkh, linux-kernel, devel, virtualization, ohering, jbottomley,
hch, linux-scsi
Cc: K. Y. Srinivasan
In-Reply-To: <1327599515-12679-1-git-send-email-kys@microsoft.com>
The storage driver (storvsc_drv.c) handles all block storage devices
assigned to Linux guests hosted on Hyper-V. This driver has been in the
staging tree for a while and this patch moves it out of the staging area.
This patch is based on the storvsc patches that are already on Greg's queue
for the staging tree that addressed Christoph's review comments.
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
---
drivers/scsi/Kconfig | 7 +++++++
drivers/scsi/Makefile | 3 +++
drivers/{staging/hv => scsi}/storvsc_drv.c | 0
drivers/staging/Kconfig | 2 --
drivers/staging/hv/Kconfig | 5 -----
drivers/staging/hv/Makefile | 3 ---
drivers/staging/hv/TODO | 5 -----
7 files changed, 10 insertions(+), 15 deletions(-)
rename drivers/{staging/hv => scsi}/storvsc_drv.c (100%)
delete mode 100644 drivers/staging/hv/Kconfig
delete mode 100644 drivers/staging/hv/Makefile
delete mode 100644 drivers/staging/hv/TODO
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index 16570aa..d3d18e8 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -662,6 +662,13 @@ config VMWARE_PVSCSI
To compile this driver as a module, choose M here: the
module will be called vmw_pvscsi.
+config HYPERV_STORAGE
+ tristate "Microsoft Hyper-V virtual storage driver"
+ depends on SCSI && HYPERV
+ default HYPERV
+ help
+ Select this option to enable the Hyper-V virtual storage driver.
+
config LIBFC
tristate "LibFC module"
select SCSI_FC_ATTRS
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index 2b88749..e4c1a69 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -142,6 +142,7 @@ obj-$(CONFIG_SCSI_BNX2_ISCSI) += libiscsi.o bnx2i/
obj-$(CONFIG_BE2ISCSI) += libiscsi.o be2iscsi/
obj-$(CONFIG_SCSI_PMCRAID) += pmcraid.o
obj-$(CONFIG_VMWARE_PVSCSI) += vmw_pvscsi.o
+obj-$(CONFIG_HYPERV_STORAGE) += hv_storvsc.o
obj-$(CONFIG_ARM) += arm/
@@ -170,6 +171,8 @@ scsi_mod-$(CONFIG_SCSI_PROC_FS) += scsi_proc.o
scsi_mod-y += scsi_trace.o
scsi_mod-$(CONFIG_PM) += scsi_pm.o
+hv_storvsc-y := storvsc_drv.o
+
scsi_tgt-y += scsi_tgt_lib.o scsi_tgt_if.o
sd_mod-objs := sd.o
diff --git a/drivers/staging/hv/storvsc_drv.c b/drivers/scsi/storvsc_drv.c
similarity index 100%
rename from drivers/staging/hv/storvsc_drv.c
rename to drivers/scsi/storvsc_drv.c
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index 21e2f4b..87beded 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -78,8 +78,6 @@ source "drivers/staging/vt6655/Kconfig"
source "drivers/staging/vt6656/Kconfig"
-source "drivers/staging/hv/Kconfig"
-
source "drivers/staging/vme/Kconfig"
source "drivers/staging/sep/Kconfig"
diff --git a/drivers/staging/hv/Kconfig b/drivers/staging/hv/Kconfig
deleted file mode 100644
index 60ac479..0000000
--- a/drivers/staging/hv/Kconfig
+++ /dev/null
@@ -1,5 +0,0 @@
-config HYPERV_STORAGE
- tristate "Microsoft Hyper-V virtual storage driver"
- depends on HYPERV && SCSI
- help
- Select this option to enable the Hyper-V virtual storage driver.
diff --git a/drivers/staging/hv/Makefile b/drivers/staging/hv/Makefile
deleted file mode 100644
index af95a6b..0000000
--- a/drivers/staging/hv/Makefile
+++ /dev/null
@@ -1,3 +0,0 @@
-obj-$(CONFIG_HYPERV_STORAGE) += hv_storvsc.o
-
-hv_storvsc-y := storvsc_drv.o
diff --git a/drivers/staging/hv/TODO b/drivers/staging/hv/TODO
deleted file mode 100644
index dea7d92..0000000
--- a/drivers/staging/hv/TODO
+++ /dev/null
@@ -1,5 +0,0 @@
-TODO:
- - audit the scsi driver
-
-Please send patches for this code to Greg Kroah-Hartman <gregkh@suse.de>,
-Haiyang Zhang <haiyangz@microsoft.com>, and K. Y. Srinivasan <kys@microsoft.com>
--
1.7.4.1
^ permalink raw reply related
* RE: [PATCH 1/2] Staging: hv: Applied all the patches already in the staging queue
From: KY Srinivasan @ 2012-01-26 17:41 UTC (permalink / raw)
To: Greg KH
Cc: linux-kernel@vger.kernel.org, devel@linuxdriverproject.org,
virtualization@lists.osdl.org, ohering@suse.com,
jbottomley@parallels.com, hch@infradead.org,
linux-scsi@vger.kernel.org
In-Reply-To: <20120126173751.GA14400@suse.de>
> -----Original Message-----
> From: Greg KH [mailto:gregkh@suse.de]
> Sent: Thursday, January 26, 2012 12:38 PM
> To: KY Srinivasan
> Cc: linux-kernel@vger.kernel.org; devel@linuxdriverproject.org;
> virtualization@lists.osdl.org; ohering@suse.com; jbottomley@parallels.com;
> hch@infradead.org; linux-scsi@vger.kernel.org
> Subject: Re: [PATCH 1/2] Staging: hv: Applied all the patches already in the staging
> queue
>
> On Thu, Jan 26, 2012 at 09:38:34AM -0800, K. Y. Srinivasan wrote:
> > This patch gets the storage driver to the same level as in the staging tree.
> >
> > Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
> > ---
> > drivers/staging/hv/storvsc_drv.c | 1301 ++++++++++++++++++-------------------
> > 1 files changed, 633 insertions(+), 668 deletions(-)
>
> What? That changelog comment makes no sense at all, as you are patching
> the staging version of the driver. This isn't an acceptable patch at
> all.
>
> Yes, I have pending patches for this driver in my "to-apply" queue, but
> that is for 3.4, not now.
If you prefer; we could move the storage driver out of staging, based on the code
We have in staging. I could re-submit the patches against the new location for
3.4.
Regards,
K. Y
^ permalink raw reply
* Re: [PATCH 1/2] Staging: hv: Applied all the patches already in the staging queue
From: James Bottomley @ 2012-01-26 17:50 UTC (permalink / raw)
To: Greg KH
Cc: K. Y. Srinivasan, linux-kernel, devel, virtualization, ohering,
hch, linux-scsi
In-Reply-To: <20120126173751.GA14400@suse.de>
On Thu, 2012-01-26 at 09:37 -0800, Greg KH wrote:
> On Thu, Jan 26, 2012 at 09:38:34AM -0800, K. Y. Srinivasan wrote:
> > This patch gets the storage driver to the same level as in the staging tree.
> >
> > Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
> > ---
> > drivers/staging/hv/storvsc_drv.c | 1301 ++++++++++++++++++-------------------
> > 1 files changed, 633 insertions(+), 668 deletions(-)
>
> What? That changelog comment makes no sense at all, as you are patching
> the staging version of the driver. This isn't an acceptable patch at
> all.
Agreed
> Yes, I have pending patches for this driver in my "to-apply" queue, but
> that is for 3.4, not now.
>
> So, how about I just apply those patches, and then apply a patch that
> moves it out of staging into drivers/scsi/, and queue all of those up
> for 3.4.
>
> James, any objection to that?
Well, we were going to try to stage this driver for 3.3-rc. If everyone
agrees to push it back to 3.4, then this works for me.
James
^ permalink raw reply
* CFP: The 9th Int. Conf. on Autonomic Computing (ICAC 2012) -- San Jose CA
From: Ioan Raicu @ 2012-01-26 22:01 UTC (permalink / raw)
To: virtualization
CALL FOR PAPERS and WORKSHOP PROPOSALS
The 9th International Conference on Autonomic Computing (ICAC 2012)
September 17-21, 2012. San Jose, CA, USA
http://icac2012.cs.fiu.edu/
-----------------------------------------------------------------
IMPORTANT DATES
Paper and Poster Submission: March 9, 2012, 11:59pm PST
Notification: May 18, 2012
Camera-ready Due: June 8, 2012
Workshop Proposal Submission: February 10, 2012
-----------------------------------------------------------------
OVERVIEW
ICAC is the leading conference on autonomic computing techniques,
foundations, and applications. Autonomic computing refers to
methods and means for automated management of performance, fault,
security, and configuration with little involvement of users or
administrators. Systems introducing new autonomic features are
becoming increasingly prevalent, motivating research that spans
a variety of areas, from computer systems, networking, software
engineering, and data management to machine learning, control
theory, and bio-inspired computing. ICAC brings together
researchers and practitioners across these disciplines to
address multiple facets of adaptation and self-management in
computing systems and applications from different perspectives.
Autonomic computing solutions are sought for clouds, grids,
data centers, enterprise software, internet services, data
services, smart phones, embedded systems, and sensor networks.
In these environments, resources and applications must be managed
to maximize performance and minimize cost, while maintaining
predictable and reliable behavior in the face of varying
workloads, failures, and malicious threats. Papers are solicited
from all areas of autonomic computing, including (but not limited
to):
* End-to-end techniques for management of resources, workloads,
performance, faults, power/cooling, security, and others.
* Self-managing components, such as server, storage, network
protocols, or specific application elements, and embedded and
mobile end systems such as smart phones.
* Decision and analysis techniques and their use, such as machine
learning, control theory, predictive methods, probability and
stochastic processes, queuing theory methodologies, emergent
behavior, rule-based systems, and bio-inspired techniques.
* Monitoring systems for autonomic computing.
* Hypervisor, operating systems, hardware, or application support
for autonomic computing.
* Novel human interfaces for monitoring and controlling autonomic
systems.
* Management topics, such as specification and modeling of
service-level agreements, behavior enforcement and tie-in with
IT governance.
* Toolkits, frameworks, principles and architectures, from
software engineering practices and experimental methodologies
to agent-based techniques and virtualization.
* Fundamental science and theory of self-managing systems:
understanding, controlling or exploiting system behaviors to
enforce autonomic properties.
* Applications of autonomic computing and experiences with
prototyped or deployed systems solving real-world problems in
science, engineering, business and society.
Papers will be judged on originality, significance, interest,
correctness, clarity and relevance to the broader community.
Papers should report on experiences, measurements, user studies,
or other evaluations, as appropriate. Evaluations of a prototype
or large-scale deployment of systems and applications is expected.
PAPER AND POSTER SUBMISSIONS
Full papers (a maximum of 10 pages in the two-column ACM proceedings
format) and posters (2 pages) are invited on a wide variety of
topics relating to autonomic computing. Submitted papers must be
original work, and may not be under consideration for another
conference or journal. Complete formatting and submission
instructions can be found on the conference web site. Accepted
papers and posters will appear in proceedings distributed at the
conference and available electronically. Relevant top ICAC'12
papers will be invited for "fast-track" submissions to the
ACM Transactions on Autonomous and Adaptive Systems (TAAS).
WORKSHOPS, DEMONSTRATIONS AND EXHIBITION
ICAC'12 welcomes proposals for co-located workshops on topics of
interest to the autonomic computing community. Workshop proposals
should be submitted to the Workshop Chair, Fred Douglis
(f.douglis@computer.org) by February 10, 2012. Workshops are
expected to publish proceedings, and should cover areas that
complement the main program. ICAC'12 will also feature a
demonstration and exhibition session consisting of prototypes and
technology artifacts such as demonstrating autonomic software or
autonomic computing principles. Entries will be judged by a
separate committee led by the demo/exhibit chair.
INDUSTRY SESSION
One of ICAC's important roles is to bring together researchers
and practitioners from academia and industry. In its industry
session, ICAC helps fulfill this role by presenting an industry
viewpoint on technologies, products, and market needs. The
industry session also addresses current challenges, and
opportunities for academic and corporate research collaborations.
We encourage industry leaders, including entrepreneurs, product
developers, architects, managers, marketers and end users,
to submit their papers and posters reflecting such industry
perspectives as part of the regular submission process.
------------------------------------------------------------------
ORGANIZERS
GENERAL CHAIR
Dejan Milojicic, HP Labs
PROGRAM CHAIRS
Dongyan Xu, Purdue University
Vanish Talwar, HP Labs
INDUSTRY CHAIR
Xiaoyun Zhu, VMware
WORKSHOPS CHAIR
Fred Douglis, EMC
POSTERS/DEMO/EXHIBITS CHAIR
Eno Thereska, Microsoft Research
FINANCE CHAIR
Michael Kozuch, Intel
LOCAL ARRANGEMENT CHAIR
Jessica Blaine
PUBLICITY CHAIRS
Daniel Batista, University of São Paulo
Vartan Padaryan, ISP/Russian Academy of Sci.
Ioan Raicu, Illinois Inst. of Technology
Jianfeng Zhan, ICT/Chinese Academy of Sci.
Ming Zhao, Florida Intl. University
PROGRAM COMMITTEE
Tarek Abdelzaher, UIUC
Umesh Bellur, IIT, Bombay
Ken Birman, Cornell University
Rajkumar Buyya, Univ. of Melbourne
Rocky Chang, Hong Kong Polytechnic University
Yuan Chen, HP Labs
Alva Couch, Tufts University
Peter Dinda, Northwestern University
Fred Douglis, EMC
Renato Figueiredo, University of Florida
Mohamed Hefeeda, Qatar Computing Research Institute
Joe Hellerstein, Google
Geoff Jiang, NEC Labs
Jeff Kephart, IBM Research
Emre Kiciman, Microsoft Research
Fabio Kon, University of São Paulo
Michael Kozuch, Intel
Dejan Milojicic, HP Labs
Klara Nahrstedt, UIUC
Priya Narasimhan, CMU
Manish Parashar, Rutgers University
Ioan Raicu, Illinois Inst. of Technology
Omer Rana, Cardiff University
Masoud Sadjadi, Florida Intl. University
Rick Schlichting, AT&T Labs
Hartmut Schmeck, KIT
Karsten Schwan, Georgia Tech
Onn Shehory, IBM Research
Eno Thereska, Microsoft Research
Xiaoyun Zhu, VMware
--
=================================================================
Ioan Raicu, Ph.D.
Assistant Professor, Illinois Institute of Technology (IIT)
Guest Research Faculty, Argonne National Laboratory (ANL)
=================================================================
Data-Intensive Distributed Systems Laboratory, CS/IIT
Distributed Systems Laboratory, MCS/ANL
=================================================================
Cel: 1-847-722-0876
Office: 1-312-567-5704
Email: iraicu@cs.iit.edu
Web: http://www.cs.iit.edu/~iraicu/
Web: http://datasys.cs.iit.edu/
=================================================================
=================================================================
^ permalink raw reply
* CFP: 3rd Cloud Futures Workshop 2012: Hot Topics in Research and Education -- Berkeley CA
From: Ioan Raicu @ 2012-01-26 22:35 UTC (permalink / raw)
To: virtualization
[-- Attachment #1.1: Type: text/plain, Size: 3692 bytes --]
*3rd Cloud Futures Workshop 2012*: Hot Topics in Research and Education
May 7--8, 2012 | Berkeley, California, United States
*Website:*http://research.microsoft.com/en-US/events/cloudfutures2012/
Cloud computing is an exciting platform for research and education. It
has the potential to advance scientific and technological progress by
making data and computing resources readily available at unprecedented
economy of scale and nearly infinite scalability. To realize the full
promise of cloud computing for research and education, however, we must
think about the cloud as a holistic platform for creating new services,
new experiences, and new methods to pursue research, teaching, and
scholarly communication. This goal presents a broad range of interesting
questions.
The Cloud Futures Workshop series brings together thought leaders from
academia, industry, and government to discuss the role of cloud
computing across a variety of research and educational areas.
Presentations, posters and discussions will investigate how new
programming techniques, software platforms, software engineering and
methodology, and methods of research and teaching in the cloud may solve
distinct challenges arising in diverse areas of society.
*General Co-Chairs*
Michaael J Franklin, University of California, Berkeley
Tony Hey, Microsoft Research
*Keynote speakers*
Joseph L Hellerstein, Manager, Big Science , Google Inc.
Yousef Khalidi, Distinguished Engineer, Microsoft Corporation
*Call for Abstracts and Participation*
This year, we are looking for extended abstracts on hot topics in cloud
computing to be presented at the workshop---either as talks or posters.
Abstracts should highlight how new techniques and methods of research in
the cloud may solve distinct challenges arising in diverse areas,
including computer science, engineering, earth sciences, healthcare,
humanities, interactive games, life sciences, and social sciences. We
encourage abstracts that describe practical experiences, experimental
results, and vision papers. All papers will be peer-reviewed.
*Submission Instructions*
·Submit abstracts of five pages, including references.
·Your submission should include a bio (150 words maximum).
·Submit your abstracts through the online form
<https://mail.microsoft.com/owa/redir.aspx?C=dnvrQ6rAd065TEvukSGfg1evauXAqs4ImhoW0OYeMkWA_utxcf4W8nIiM7al3R8qGfAQiC3gS70.&URL=https%3a%2f%2fcmt.research.microsoft.com%2fcloudfutures2012%2f>.
*Important Dates*
·Abstracts due: February 29, 2012
·Results available: March 23, 2012
·Workshop: May 7--8, 2012
*About the Workshop*
The Cloud Futures 2012 workshop is a joint venture between the Microsoft
Research Connections, Azure Research Engagement, and Developer &
Platform Evangelism Academic groups, and is in association with and
co-supported by the University of California, Berkeley.
--
=================================================================
Ioan Raicu, Ph.D.
Assistant Professor, Illinois Institute of Technology (IIT)
Guest Research Faculty, Argonne National Laboratory (ANL)
=================================================================
Data-Intensive Distributed Systems Laboratory, CS/IIT
Distributed Systems Laboratory, MCS/ANL
=================================================================
Cel: 1-847-722-0876
Office: 1-312-567-5704
Email: iraicu@cs.iit.edu
Web: http://www.cs.iit.edu/~iraicu/
Web: http://datasys.cs.iit.edu/
=================================================================
=================================================================
[-- Attachment #1.2: Type: text/html, Size: 37428 bytes --]
[-- Attachment #2: Type: text/plain, Size: 183 bytes --]
_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization
^ permalink raw reply
* Re: lguest documentation
From: Rusty Russell @ 2012-01-27 1:22 UTC (permalink / raw)
To: Stephen Hemminger, Davidlohr Bueso; +Cc: virtualization
In-Reply-To: <20120125095716.78ad3f2d@nehalam.linuxnetplumber.net>
On Wed, 25 Jan 2012 09:57:16 -0800, Stephen Hemminger <shemminger@vyatta.com> wrote:
> After moving lguest to tools the documentation index was not updated.
>
> Documentation/virtual/00-INDEX still refers to lguest/ when in fact
> the documentation is now over in tools/lguest. Maybe make a symlink,
> or change the reference in the index?
Kill the reference.
From: Rusty Russell <rusty@rustcorp.com.au>
Subject: lguest: remove reference from Documentation/virtual/00-INDEX
We're in tools/lguest now.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
diff --git a/Documentation/virtual/00-INDEX b/Documentation/virtual/00-INDEX
--- a/Documentation/virtual/00-INDEX
+++ b/Documentation/virtual/00-INDEX
@@ -4,8 +4,6 @@ 00-INDEX
- this file.
kvm/
- Kernel Virtual Machine. See also http://linux-kvm.org
-lguest/
- - Extremely simple hypervisor for experimental/educational use.
uml/
- User Mode Linux, builds/runs Linux kernel as a userspace program.
virtio.txt
^ permalink raw reply
* [PATCH 0000/0006] drivers: hv
From: K. Y. Srinivasan @ 2012-01-27 23:55 UTC (permalink / raw)
To: gregkh, linux-kernel, devel, virtualization, ohering, zbr
Cc: K. Y. Srinivasan
This patch-set does some cleanup of the KVP component. Also included is a
patch that will remove artificial limitation on the number of VCPUs that
can be assigned to the Linux guest on Hyper-V.
Regards,
K. Y
^ permalink raw reply
* [PATCH 1/6] drivers: hv: kvp: Add/cleanup connector defines
From: K. Y. Srinivasan @ 2012-01-27 23:55 UTC (permalink / raw)
To: gregkh, linux-kernel, devel, virtualization, ohering, zbr
Cc: K. Y. Srinivasan, Haiyang Zhang
In-Reply-To: <1327708522-26914-1-git-send-email-kys@microsoft.com>
The current KVP code carries some private connector related defines.
Update connector.h to have all the KVP defines. As part of this patch
get rid of some unused defines.
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
---
drivers/hv/hv_kvp.h | 3 ---
include/linux/connector.h | 1 +
tools/hv/hv_kvp_daemon.c | 4 ----
3 files changed, 1 insertions(+), 7 deletions(-)
diff --git a/drivers/hv/hv_kvp.h b/drivers/hv/hv_kvp.h
index 9b765d7..c2c5bba 100644
--- a/drivers/hv/hv_kvp.h
+++ b/drivers/hv/hv_kvp.h
@@ -107,9 +107,6 @@
* the KVP user-mode component.
*/
-#define CN_KVP_VAL 0x1 /* This supports queries from the kernel */
-#define CN_KVP_USER_VAL 0x2 /* This supports queries from the user */
-
enum hv_ku_op {
KVP_REGISTER = 0, /* Register the user mode component */
KVP_KERNEL_GET, /* Kernel is requesting the value */
diff --git a/include/linux/connector.h b/include/linux/connector.h
index 3c9c54f..7638407 100644
--- a/include/linux/connector.h
+++ b/include/linux/connector.h
@@ -43,6 +43,7 @@
#define CN_IDX_DRBD 0x8
#define CN_VAL_DRBD 0x1
#define CN_KVP_IDX 0x9 /* HyperV KVP */
+#define CN_KVP_VAL 0x1 /* queries from the kernel */
#define CN_NETLINK_USERS 10 /* Highest index + 1 */
diff --git a/tools/hv/hv_kvp_daemon.c b/tools/hv/hv_kvp_daemon.c
index 11224ed..2b6a2d9 100644
--- a/tools/hv/hv_kvp_daemon.c
+++ b/tools/hv/hv_kvp_daemon.c
@@ -40,15 +40,11 @@
#include <syslog.h>
/*
- * KYS: TODO. Need to register these in the kernel.
*
* The following definitions are shared with the in-kernel component; do not
* change any of this without making the corresponding changes in
* the KVP kernel component.
*/
-#define CN_KVP_IDX 0x9 /* MSFT KVP functionality */
-#define CN_KVP_VAL 0x1 /* This supports queries from the kernel */
-#define CN_KVP_USER_VAL 0x2 /* This supports queries from the user */
/*
* KVP protocol: The user mode component first registers with the
--
1.7.4.1
^ permalink raw reply related
* [PATCH 2/6] drivers: hv: kvp: Move the contents of hv_kvp.h to hyperv.h
From: K. Y. Srinivasan @ 2012-01-27 23:55 UTC (permalink / raw)
To: gregkh, linux-kernel, devel, virtualization, ohering, zbr
Cc: K. Y. Srinivasan, Haiyang Zhang
In-Reply-To: <1327708562-26964-1-git-send-email-kys@microsoft.com>
In preparation for consolidating all KVP related defines into a single header file
that both the kernel and user level components can use, move the contents of
hv_kvp.h into hyperv.h.
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
---
drivers/hv/hv_kvp.c | 2 -
drivers/hv/hv_kvp.h | 181 ------------------------------------------------
drivers/hv/hv_util.c | 3 -
include/linux/hyperv.h | 165 +++++++++++++++++++++++++++++++++++++++++++
4 files changed, 165 insertions(+), 186 deletions(-)
delete mode 100644 drivers/hv/hv_kvp.h
diff --git a/drivers/hv/hv_kvp.c b/drivers/hv/hv_kvp.c
index 0e8343f..4a6971e 100644
--- a/drivers/hv/hv_kvp.c
+++ b/drivers/hv/hv_kvp.c
@@ -28,8 +28,6 @@
#include <linux/workqueue.h>
#include <linux/hyperv.h>
-#include "hv_kvp.h"
-
/*
diff --git a/drivers/hv/hv_kvp.h b/drivers/hv/hv_kvp.h
deleted file mode 100644
index c2c5bba..0000000
--- a/drivers/hv/hv_kvp.h
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
- * An implementation of HyperV key value pair (KVP) functionality for Linux.
- *
- *
- * Copyright (C) 2010, Novell, Inc.
- * Author : K. Y. Srinivasan <ksrinivasan@novell.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published
- * by the Free Software Foundation.
- *
- * 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, GOOD TITLE or
- * NON INFRINGEMENT. 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- */
-#ifndef _KVP_H
-#define _KVP_H_
-
-/*
- * Maximum value size - used for both key names and value data, and includes
- * any applicable NULL terminators.
- *
- * Note: This limit is somewhat arbitrary, but falls easily within what is
- * supported for all native guests (back to Win 2000) and what is reasonable
- * for the IC KVP exchange functionality. Note that Windows Me/98/95 are
- * limited to 255 character key names.
- *
- * MSDN recommends not storing data values larger than 2048 bytes in the
- * registry.
- *
- * Note: This value is used in defining the KVP exchange message - this value
- * cannot be modified without affecting the message size and compatibility.
- */
-
-/*
- * bytes, including any null terminators
- */
-#define HV_KVP_EXCHANGE_MAX_VALUE_SIZE (2048)
-
-
-/*
- * Maximum key size - the registry limit for the length of an entry name
- * is 256 characters, including the null terminator
- */
-
-#define HV_KVP_EXCHANGE_MAX_KEY_SIZE (512)
-
-/*
- * In Linux, we implement the KVP functionality in two components:
- * 1) The kernel component which is packaged as part of the hv_utils driver
- * is responsible for communicating with the host and responsible for
- * implementing the host/guest protocol. 2) A user level daemon that is
- * responsible for data gathering.
- *
- * Host/Guest Protocol: The host iterates over an index and expects the guest
- * to assign a key name to the index and also return the value corresponding to
- * the key. The host will have atmost one KVP transaction outstanding at any
- * given point in time. The host side iteration stops when the guest returns
- * an error. Microsoft has specified the following mapping of key names to
- * host specified index:
- *
- * Index Key Name
- * 0 FullyQualifiedDomainName
- * 1 IntegrationServicesVersion
- * 2 NetworkAddressIPv4
- * 3 NetworkAddressIPv6
- * 4 OSBuildNumber
- * 5 OSName
- * 6 OSMajorVersion
- * 7 OSMinorVersion
- * 8 OSVersion
- * 9 ProcessorArchitecture
- *
- * The Windows host expects the Key Name and Key Value to be encoded in utf16.
- *
- * Guest Kernel/KVP Daemon Protocol: As noted earlier, we implement all of the
- * data gathering functionality in a user mode daemon. The user level daemon
- * is also responsible for binding the key name to the index as well. The
- * kernel and user-level daemon communicate using a connector channel.
- *
- * The user mode component first registers with the
- * the kernel component. Subsequently, the kernel component requests, data
- * for the specified keys. In response to this message the user mode component
- * fills in the value corresponding to the specified key. We overload the
- * sequence field in the cn_msg header to define our KVP message types.
- *
- *
- * The kernel component simply acts as a conduit for communication between the
- * Windows host and the user-level daemon. The kernel component passes up the
- * index received from the Host to the user-level daemon. If the index is
- * valid (supported), the corresponding key as well as its
- * value (both are strings) is returned. If the index is invalid
- * (not supported), a NULL key string is returned.
- */
-
-/*
- *
- * The following definitions are shared with the user-mode component; do not
- * change any of this without making the corresponding changes in
- * the KVP user-mode component.
- */
-
-enum hv_ku_op {
- KVP_REGISTER = 0, /* Register the user mode component */
- KVP_KERNEL_GET, /* Kernel is requesting the value */
- KVP_KERNEL_SET, /* Kernel is providing the value */
- KVP_USER_GET, /* User is requesting the value */
- KVP_USER_SET /* User is providing the value */
-};
-
-struct hv_ku_msg {
- __u32 kvp_index; /* Key index */
- __u8 kvp_key[HV_KVP_EXCHANGE_MAX_KEY_SIZE]; /* Key name */
- __u8 kvp_value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE]; /* Key value */
-};
-
-
-
-
-#ifdef __KERNEL__
-
-/*
- * Registry value types.
- */
-
-#define REG_SZ 1
-
-enum hv_kvp_exchg_op {
- KVP_OP_GET = 0,
- KVP_OP_SET,
- KVP_OP_DELETE,
- KVP_OP_ENUMERATE,
- KVP_OP_COUNT /* Number of operations, must be last. */
-};
-
-enum hv_kvp_exchg_pool {
- KVP_POOL_EXTERNAL = 0,
- KVP_POOL_GUEST,
- KVP_POOL_AUTO,
- KVP_POOL_AUTO_EXTERNAL,
- KVP_POOL_AUTO_INTERNAL,
- KVP_POOL_COUNT /* Number of pools, must be last. */
-};
-
-struct hv_kvp_hdr {
- u8 operation;
- u8 pool;
-};
-
-struct hv_kvp_exchg_msg_value {
- u32 value_type;
- u32 key_size;
- u32 value_size;
- u8 key[HV_KVP_EXCHANGE_MAX_KEY_SIZE];
- u8 value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE];
-};
-
-struct hv_kvp_msg_enumerate {
- u32 index;
- struct hv_kvp_exchg_msg_value data;
-};
-
-struct hv_kvp_msg {
- struct hv_kvp_hdr kvp_hdr;
- struct hv_kvp_msg_enumerate kvp_data;
-};
-
-int hv_kvp_init(struct hv_util_service *);
-void hv_kvp_deinit(void);
-void hv_kvp_onchannelcallback(void *);
-
-#endif /* __KERNEL__ */
-#endif /* _KVP_H */
-
diff --git a/drivers/hv/hv_util.c b/drivers/hv/hv_util.c
index 55d58f2..dbb8b8e 100644
--- a/drivers/hv/hv_util.c
+++ b/drivers/hv/hv_util.c
@@ -28,9 +28,6 @@
#include <linux/reboot.h>
#include <linux/hyperv.h>
-#include "hv_kvp.h"
-
-
static void shutdown_onchannelcallback(void *context);
static struct hv_util_service util_shutdown = {
.util_cb = shutdown_onchannelcallback,
diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h
index 62b908e..7332b3f 100644
--- a/include/linux/hyperv.h
+++ b/include/linux/hyperv.h
@@ -25,6 +25,166 @@
#ifndef _HYPERV_H
#define _HYPERV_H
+#include <linux/types.h>
+
+/*
+ * An implementation of HyperV key value pair (KVP) functionality for Linux.
+ *
+ *
+ * Copyright (C) 2010, Novell, Inc.
+ * Author : K. Y. Srinivasan <ksrinivasan@novell.com>
+ *
+ */
+
+/*
+ * Maximum value size - used for both key names and value data, and includes
+ * any applicable NULL terminators.
+ *
+ * Note: This limit is somewhat arbitrary, but falls easily within what is
+ * supported for all native guests (back to Win 2000) and what is reasonable
+ * for the IC KVP exchange functionality. Note that Windows Me/98/95 are
+ * limited to 255 character key names.
+ *
+ * MSDN recommends not storing data values larger than 2048 bytes in the
+ * registry.
+ *
+ * Note: This value is used in defining the KVP exchange message - this value
+ * cannot be modified without affecting the message size and compatibility.
+ */
+
+/*
+ * bytes, including any null terminators
+ */
+#define HV_KVP_EXCHANGE_MAX_VALUE_SIZE (2048)
+
+
+/*
+ * Maximum key size - the registry limit for the length of an entry name
+ * is 256 characters, including the null terminator
+ */
+
+#define HV_KVP_EXCHANGE_MAX_KEY_SIZE (512)
+
+/*
+ * In Linux, we implement the KVP functionality in two components:
+ * 1) The kernel component which is packaged as part of the hv_utils driver
+ * is responsible for communicating with the host and responsible for
+ * implementing the host/guest protocol. 2) A user level daemon that is
+ * responsible for data gathering.
+ *
+ * Host/Guest Protocol: The host iterates over an index and expects the guest
+ * to assign a key name to the index and also return the value corresponding to
+ * the key. The host will have atmost one KVP transaction outstanding at any
+ * given point in time. The host side iteration stops when the guest returns
+ * an error. Microsoft has specified the following mapping of key names to
+ * host specified index:
+ *
+ * Index Key Name
+ * 0 FullyQualifiedDomainName
+ * 1 IntegrationServicesVersion
+ * 2 NetworkAddressIPv4
+ * 3 NetworkAddressIPv6
+ * 4 OSBuildNumber
+ * 5 OSName
+ * 6 OSMajorVersion
+ * 7 OSMinorVersion
+ * 8 OSVersion
+ * 9 ProcessorArchitecture
+ *
+ * The Windows host expects the Key Name and Key Value to be encoded in utf16.
+ *
+ * Guest Kernel/KVP Daemon Protocol: As noted earlier, we implement all of the
+ * data gathering functionality in a user mode daemon. The user level daemon
+ * is also responsible for binding the key name to the index as well. The
+ * kernel and user-level daemon communicate using a connector channel.
+ *
+ * The user mode component first registers with the
+ * the kernel component. Subsequently, the kernel component requests, data
+ * for the specified keys. In response to this message the user mode component
+ * fills in the value corresponding to the specified key. We overload the
+ * sequence field in the cn_msg header to define our KVP message types.
+ *
+ *
+ * The kernel component simply acts as a conduit for communication between the
+ * Windows host and the user-level daemon. The kernel component passes up the
+ * index received from the Host to the user-level daemon. If the index is
+ * valid (supported), the corresponding key as well as its
+ * value (both are strings) is returned. If the index is invalid
+ * (not supported), a NULL key string is returned.
+ */
+
+/*
+ *
+ * The following definitions are shared with the user-mode component; do not
+ * change any of this without making the corresponding changes in
+ * the KVP user-mode component.
+ */
+
+enum hv_ku_op {
+ KVP_REGISTER = 0, /* Register the user mode component */
+ KVP_KERNEL_GET, /* Kernel is requesting the value */
+ KVP_KERNEL_SET, /* Kernel is providing the value */
+ KVP_USER_GET, /* User is requesting the value */
+ KVP_USER_SET /* User is providing the value */
+};
+
+struct hv_ku_msg {
+ __u32 kvp_index; /* Key index */
+ __u8 kvp_key[HV_KVP_EXCHANGE_MAX_KEY_SIZE]; /* Key name */
+ __u8 kvp_value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE]; /* Key value */
+};
+
+
+
+
+#ifdef __KERNEL__
+
+/*
+ * Registry value types.
+ */
+
+#define REG_SZ 1
+
+enum hv_kvp_exchg_op {
+ KVP_OP_GET = 0,
+ KVP_OP_SET,
+ KVP_OP_DELETE,
+ KVP_OP_ENUMERATE,
+ KVP_OP_COUNT /* Number of operations, must be last. */
+};
+
+enum hv_kvp_exchg_pool {
+ KVP_POOL_EXTERNAL = 0,
+ KVP_POOL_GUEST,
+ KVP_POOL_AUTO,
+ KVP_POOL_AUTO_EXTERNAL,
+ KVP_POOL_AUTO_INTERNAL,
+ KVP_POOL_COUNT /* Number of pools, must be last. */
+};
+
+struct hv_kvp_hdr {
+ u8 operation;
+ u8 pool;
+};
+
+struct hv_kvp_exchg_msg_value {
+ u32 value_type;
+ u32 key_size;
+ u32 value_size;
+ u8 key[HV_KVP_EXCHANGE_MAX_KEY_SIZE];
+ u8 value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE];
+};
+
+struct hv_kvp_msg_enumerate {
+ u32 index;
+ struct hv_kvp_exchg_msg_value data;
+};
+
+struct hv_kvp_msg {
+ struct hv_kvp_hdr kvp_hdr;
+ struct hv_kvp_msg_enumerate kvp_data;
+};
+
#include <linux/scatterlist.h>
#include <linux/list.h>
#include <linux/uuid.h>
@@ -870,4 +1030,9 @@ struct hyperv_service_callback {
extern void vmbus_prep_negotiate_resp(struct icmsg_hdr *,
struct icmsg_negotiate *, u8 *);
+int hv_kvp_init(struct hv_util_service *);
+void hv_kvp_deinit(void);
+void hv_kvp_onchannelcallback(void *);
+
+#endif /* __KERNEL__ */
#endif /* _HYPERV_H */
--
1.7.4.1
^ permalink raw reply related
* [PATCH 3/6] drivers: hv: Cleanup the kvp related state in hyperv.h
From: K. Y. Srinivasan @ 2012-01-27 23:55 UTC (permalink / raw)
To: gregkh, linux-kernel, devel, virtualization, ohering, zbr
Cc: K. Y. Srinivasan, Haiyang Zhang
In-Reply-To: <1327708562-26964-1-git-send-email-kys@microsoft.com>
Now cleanup the hyperv.h with regards to KVP definitions.
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
include/linux/hyperv.h | 32 +++++++++++++++++++-------------
1 files changed, 19 insertions(+), 13 deletions(-)
diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h
index 7332b3f..802ece8 100644
--- a/include/linux/hyperv.h
+++ b/include/linux/hyperv.h
@@ -137,7 +137,6 @@ struct hv_ku_msg {
-#ifdef __KERNEL__
/*
* Registry value types.
@@ -162,29 +161,36 @@ enum hv_kvp_exchg_pool {
KVP_POOL_COUNT /* Number of pools, must be last. */
};
+#ifndef __packed
+#define __packed __attribute__((packed))
+#endif
+
+
struct hv_kvp_hdr {
- u8 operation;
- u8 pool;
-};
+ __u8 operation;
+ __u8 pool;
+ __u16 pad;
+} __packed;
struct hv_kvp_exchg_msg_value {
- u32 value_type;
- u32 key_size;
- u32 value_size;
- u8 key[HV_KVP_EXCHANGE_MAX_KEY_SIZE];
- u8 value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE];
-};
+ __u32 value_type;
+ __u32 key_size;
+ __u32 value_size;
+ __u8 key[HV_KVP_EXCHANGE_MAX_KEY_SIZE];
+ __u8 value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE];
+} __packed;
struct hv_kvp_msg_enumerate {
- u32 index;
+ __u32 index;
struct hv_kvp_exchg_msg_value data;
-};
+} __packed;
struct hv_kvp_msg {
struct hv_kvp_hdr kvp_hdr;
struct hv_kvp_msg_enumerate kvp_data;
-};
+} __packed;
+#ifdef __KERNEL__
#include <linux/scatterlist.h>
#include <linux/list.h>
#include <linux/uuid.h>
--
1.7.4.1
^ permalink raw reply related
* [PATCH 4/6] tools: hv: Use hyperv.h to get the KVP definitions
From: K. Y. Srinivasan @ 2012-01-27 23:56 UTC (permalink / raw)
To: gregkh, linux-kernel, devel, virtualization, ohering, zbr
Cc: K. Y. Srinivasan, Haiyang Zhang
In-Reply-To: <1327708562-26964-1-git-send-email-kys@microsoft.com>
Now use hyperv.h to get the KVP defines in the KVP user-mode code.
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
---
tools/hv/hv_kvp_daemon.c | 28 +---------------------------
1 files changed, 1 insertions(+), 27 deletions(-)
diff --git a/tools/hv/hv_kvp_daemon.c b/tools/hv/hv_kvp_daemon.c
index 2b6a2d9..b75523c 100644
--- a/tools/hv/hv_kvp_daemon.c
+++ b/tools/hv/hv_kvp_daemon.c
@@ -34,17 +34,12 @@
#include <errno.h>
#include <arpa/inet.h>
#include <linux/connector.h>
+#include <linux/hyperv.h>
#include <linux/netlink.h>
#include <ifaddrs.h>
#include <netdb.h>
#include <syslog.h>
-/*
- *
- * The following definitions are shared with the in-kernel component; do not
- * change any of this without making the corresponding changes in
- * the KVP kernel component.
- */
/*
* KVP protocol: The user mode component first registers with the
@@ -56,25 +51,8 @@
* We use this infrastructure for also supporting queries from user mode
* application for state that may be maintained in the KVP kernel component.
*
- * XXXKYS: Have a shared header file between the user and kernel (TODO)
*/
-enum kvp_op {
- KVP_REGISTER = 0, /* Register the user mode component*/
- KVP_KERNEL_GET, /*Kernel is requesting the value for the specified key*/
- KVP_KERNEL_SET, /*Kernel is providing the value for the specified key*/
- KVP_USER_GET, /*User is requesting the value for the specified key*/
- KVP_USER_SET /*User is providing the value for the specified key*/
-};
-
-#define HV_KVP_EXCHANGE_MAX_KEY_SIZE 512
-#define HV_KVP_EXCHANGE_MAX_VALUE_SIZE 2048
-
-struct hv_ku_msg {
- __u32 kvp_index;
- __u8 kvp_key[HV_KVP_EXCHANGE_MAX_KEY_SIZE]; /* Key name */
- __u8 kvp_value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE]; /* Key value */
-};
enum key_index {
FullyQualifiedDomainName = 0,
@@ -89,10 +67,6 @@ enum key_index {
ProcessorArchitecture
};
-/*
- * End of shared definitions.
- */
-
static char kvp_send_buffer[4096];
static char kvp_recv_buffer[4096];
static struct sockaddr_nl addr;
--
1.7.4.1
^ permalink raw reply related
* [PATCH 5/6] drivers: hv: kvp: Cleanup the kernel/user protocol
From: K. Y. Srinivasan @ 2012-01-27 23:56 UTC (permalink / raw)
To: gregkh, linux-kernel, devel, virtualization, ohering, zbr
Cc: K. Y. Srinivasan, Haiyang Zhang
In-Reply-To: <1327708562-26964-1-git-send-email-kys@microsoft.com>
Now, cleanup the user/kernel KVP protocol by using the same structure
definition that is used for host/guest KVP protocol. This simplifies the code.
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
---
drivers/hv/hv_kvp.c | 41 +++++++++++++++++++++++++----------------
include/linux/hyperv.h | 30 +++++-------------------------
tools/hv/hv_kvp_daemon.c | 30 +++++++++++++++---------------
3 files changed, 45 insertions(+), 56 deletions(-)
diff --git a/drivers/hv/hv_kvp.c b/drivers/hv/hv_kvp.c
index 4a6971e..0ef4c1f 100644
--- a/drivers/hv/hv_kvp.c
+++ b/drivers/hv/hv_kvp.c
@@ -71,15 +71,20 @@ kvp_register(void)
{
struct cn_msg *msg;
+ struct hv_kvp_msg *kvp_msg;
+ char *version;
- msg = kzalloc(sizeof(*msg) + strlen(HV_DRV_VERSION) + 1 , GFP_ATOMIC);
+ msg = kzalloc(sizeof(*msg) + sizeof(struct hv_kvp_msg), GFP_ATOMIC);
if (msg) {
+ kvp_msg = (struct hv_kvp_msg *)msg->data;
+ version = kvp_msg->body.kvp_version;
msg->id.idx = CN_KVP_IDX;
msg->id.val = CN_KVP_VAL;
- msg->seq = KVP_REGISTER;
- strcpy(msg->data, HV_DRV_VERSION);
- msg->len = strlen(HV_DRV_VERSION) + 1;
+
+ kvp_msg->kvp_hdr.operation = KVP_OP_REGISTER;
+ strcpy(version, HV_DRV_VERSION);
+ msg->len = sizeof(struct hv_kvp_msg);
cn_netlink_send(msg, 0, GFP_ATOMIC);
kfree(msg);
}
@@ -101,23 +106,24 @@ kvp_work_func(struct work_struct *dummy)
static void
kvp_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp)
{
- struct hv_ku_msg *message;
+ struct hv_kvp_msg *message;
+ struct hv_kvp_msg_enumerate *data;
- message = (struct hv_ku_msg *)msg->data;
- if (msg->seq == KVP_REGISTER) {
+ message = (struct hv_kvp_msg *)msg->data;
+ if (message->kvp_hdr.operation == KVP_OP_REGISTER) {
pr_info("KVP: user-mode registering done.\n");
kvp_register();
}
- if (msg->seq == KVP_USER_SET) {
+ if (message->kvp_hdr.operation == KVP_OP_ENUMERATE) {
+ data = &message->body.kvp_enum_data;
/*
* Complete the transaction by forwarding the key value
* to the host. But first, cancel the timeout.
*/
if (cancel_delayed_work_sync(&kvp_work))
- kvp_respond_to_host(message->kvp_key,
- message->kvp_value,
- !strlen(message->kvp_key));
+ kvp_respond_to_host(data->data.key, data->data.value,
+ !strlen(data->data.key));
}
}
@@ -125,6 +131,7 @@ static void
kvp_send_key(struct work_struct *dummy)
{
struct cn_msg *msg;
+ struct hv_kvp_msg *message;
int index = kvp_transaction.index;
msg = kzalloc(sizeof(*msg) + sizeof(struct hv_kvp_msg) , GFP_ATOMIC);
@@ -132,9 +139,11 @@ kvp_send_key(struct work_struct *dummy)
if (msg) {
msg->id.idx = CN_KVP_IDX;
msg->id.val = CN_KVP_VAL;
- msg->seq = KVP_KERNEL_GET;
- ((struct hv_ku_msg *)msg->data)->kvp_index = index;
- msg->len = sizeof(struct hv_ku_msg);
+
+ message = (struct hv_kvp_msg *)msg->data;
+ message->kvp_hdr.operation = KVP_OP_ENUMERATE;
+ message->body.kvp_enum_data.index = index;
+ msg->len = sizeof(struct hv_kvp_msg);
cn_netlink_send(msg, 0, GFP_ATOMIC);
kfree(msg);
}
@@ -191,7 +200,7 @@ kvp_respond_to_host(char *key, char *value, int error)
kvp_msg = (struct hv_kvp_msg *)
&recv_buffer[sizeof(struct vmbuspipe_hdr) +
sizeof(struct icmsg_hdr)];
- kvp_data = &kvp_msg->kvp_data;
+ kvp_data = &kvp_msg->body.kvp_enum_data;
key_name = key;
/*
@@ -266,7 +275,7 @@ void hv_kvp_onchannelcallback(void *context)
sizeof(struct vmbuspipe_hdr) +
sizeof(struct icmsg_hdr)];
- kvp_data = &kvp_msg->kvp_data;
+ kvp_data = &kvp_msg->body.kvp_enum_data;
/*
* We only support the "get" operation on
diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h
index 802ece8..1029515 100644
--- a/include/linux/hyperv.h
+++ b/include/linux/hyperv.h
@@ -113,30 +113,6 @@
* (not supported), a NULL key string is returned.
*/
-/*
- *
- * The following definitions are shared with the user-mode component; do not
- * change any of this without making the corresponding changes in
- * the KVP user-mode component.
- */
-
-enum hv_ku_op {
- KVP_REGISTER = 0, /* Register the user mode component */
- KVP_KERNEL_GET, /* Kernel is requesting the value */
- KVP_KERNEL_SET, /* Kernel is providing the value */
- KVP_USER_GET, /* User is requesting the value */
- KVP_USER_SET /* User is providing the value */
-};
-
-struct hv_ku_msg {
- __u32 kvp_index; /* Key index */
- __u8 kvp_key[HV_KVP_EXCHANGE_MAX_KEY_SIZE]; /* Key name */
- __u8 kvp_value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE]; /* Key value */
-};
-
-
-
-
/*
* Registry value types.
@@ -149,6 +125,7 @@ enum hv_kvp_exchg_op {
KVP_OP_SET,
KVP_OP_DELETE,
KVP_OP_ENUMERATE,
+ KVP_OP_REGISTER,
KVP_OP_COUNT /* Number of operations, must be last. */
};
@@ -187,7 +164,10 @@ struct hv_kvp_msg_enumerate {
struct hv_kvp_msg {
struct hv_kvp_hdr kvp_hdr;
- struct hv_kvp_msg_enumerate kvp_data;
+ union {
+ struct hv_kvp_msg_enumerate kvp_enum_data;
+ char kvp_version[HV_KVP_EXCHANGE_MAX_KEY_SIZE];
+ } body;
} __packed;
#ifdef __KERNEL__
diff --git a/tools/hv/hv_kvp_daemon.c b/tools/hv/hv_kvp_daemon.c
index b75523c..4ebf703 100644
--- a/tools/hv/hv_kvp_daemon.c
+++ b/tools/hv/hv_kvp_daemon.c
@@ -302,7 +302,7 @@ int main(void)
struct pollfd pfd;
struct nlmsghdr *incoming_msg;
struct cn_msg *incoming_cn_msg;
- struct hv_ku_msg *hv_msg;
+ struct hv_kvp_msg *hv_msg;
char *p;
char *key_value;
char *key_name;
@@ -340,9 +340,11 @@ int main(void)
message = (struct cn_msg *)kvp_send_buffer;
message->id.idx = CN_KVP_IDX;
message->id.val = CN_KVP_VAL;
- message->seq = KVP_REGISTER;
+
+ hv_msg = (struct hv_kvp_msg *)message->data;
+ hv_msg->kvp_hdr.operation = KVP_OP_REGISTER;
message->ack = 0;
- message->len = 0;
+ message->len = sizeof(struct hv_kvp_msg);
len = netlink_send(fd, message);
if (len < 0) {
@@ -368,14 +370,15 @@ int main(void)
incoming_msg = (struct nlmsghdr *)kvp_recv_buffer;
incoming_cn_msg = (struct cn_msg *)NLMSG_DATA(incoming_msg);
+ hv_msg = (struct hv_kvp_msg *)incoming_cn_msg->data;
- switch (incoming_cn_msg->seq) {
- case KVP_REGISTER:
+ switch (hv_msg->kvp_hdr.operation) {
+ case KVP_OP_REGISTER:
/*
* Driver is registering with us; stash away the version
* information.
*/
- p = (char *)incoming_cn_msg->data;
+ p = (char *)hv_msg->body.kvp_version;
lic_version = malloc(strlen(p) + 1);
if (lic_version) {
strcpy(lic_version, p);
@@ -386,17 +389,15 @@ int main(void)
}
continue;
- case KVP_KERNEL_GET:
- break;
default:
- continue;
+ break;
}
- hv_msg = (struct hv_ku_msg *)incoming_cn_msg->data;
- key_name = (char *)hv_msg->kvp_key;
- key_value = (char *)hv_msg->kvp_value;
+ hv_msg = (struct hv_kvp_msg *)incoming_cn_msg->data;
+ key_name = (char *)hv_msg->body.kvp_enum_data.data.key;
+ key_value = (char *)hv_msg->body.kvp_enum_data.data.value;
- switch (hv_msg->kvp_index) {
+ switch (hv_msg->body.kvp_enum_data.index) {
case FullyQualifiedDomainName:
kvp_get_domain_name(key_value,
HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
@@ -456,9 +457,8 @@ int main(void)
incoming_cn_msg->id.idx = CN_KVP_IDX;
incoming_cn_msg->id.val = CN_KVP_VAL;
- incoming_cn_msg->seq = KVP_USER_SET;
incoming_cn_msg->ack = 0;
- incoming_cn_msg->len = sizeof(struct hv_ku_msg);
+ incoming_cn_msg->len = sizeof(struct hv_kvp_msg);
len = netlink_send(fd, incoming_cn_msg);
if (len < 0) {
--
1.7.4.1
^ permalink raw reply related
* [PATCH 6/6] drivers: hv: Increase the number of VCPUs supported in the guest
From: K. Y. Srinivasan @ 2012-01-27 23:56 UTC (permalink / raw)
To: gregkh, linux-kernel, devel, virtualization, ohering, zbr
Cc: K. Y. Srinivasan, Haiyang Zhang
In-Reply-To: <1327708562-26964-1-git-send-email-kys@microsoft.com>
The current code arbirarily limited the number of CPUs the guest could have.
Change that so that we can support the maximum number of CPUs the guest can
support. While we use NR_CPUS to size the per-cpu state all we are allocating
based on NR_CPUS are the pointers to per-cpu state that will be allocatted in
the context of the initializing CPU. This patch triggers a checkpatch warning
for the usage of NR_CPU and since all we are allocating a couple of pointers
per CPU, it should be ok..
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
---
drivers/hv/hv.c | 4 ++--
drivers/hv/hyperv_vmbus.h | 5 ++---
2 files changed, 4 insertions(+), 5 deletions(-)
diff --git a/drivers/hv/hv.c b/drivers/hv/hv.c
index 12aa97f..15956bd 100644
--- a/drivers/hv/hv.c
+++ b/drivers/hv/hv.c
@@ -155,9 +155,9 @@ int hv_init(void)
union hv_x64_msr_hypercall_contents hypercall_msr;
void *virtaddr = NULL;
- memset(hv_context.synic_event_page, 0, sizeof(void *) * MAX_NUM_CPUS);
+ memset(hv_context.synic_event_page, 0, sizeof(void *) * NR_CPUS);
memset(hv_context.synic_message_page, 0,
- sizeof(void *) * MAX_NUM_CPUS);
+ sizeof(void *) * NR_CPUS);
if (!query_hypervisor_presence())
goto cleanup;
diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h
index 6d7d286..699f0d8 100644
--- a/drivers/hv/hyperv_vmbus.h
+++ b/drivers/hv/hyperv_vmbus.h
@@ -457,7 +457,6 @@ static const uuid_le VMBUS_SERVICE_ID = {
},
};
-#define MAX_NUM_CPUS 32
struct hv_input_signal_event_buffer {
@@ -483,8 +482,8 @@ struct hv_context {
/* 8-bytes aligned of the buffer above */
struct hv_input_signal_event *signal_event_param;
- void *synic_message_page[MAX_NUM_CPUS];
- void *synic_event_page[MAX_NUM_CPUS];
+ void *synic_message_page[NR_CPUS];
+ void *synic_event_page[NR_CPUS];
};
extern struct hv_context hv_context;
--
1.7.4.1
^ permalink raw reply related
* Re: [PATCH] vhost-net: Acquire device lock when releasing device
From: Sasha Levin @ 2012-01-28 0:13 UTC (permalink / raw)
To: Michael S. Tsirkin; +Cc: netdev, linux-kernel, kvm, virtualization
In-Reply-To: <20111127170558.GA31970@redhat.com>
I just noticed that it happened again, and that this patch didn't make
it's way in.
The patch below indeed fixes the problem for me. Please push it in.
On Sun, 2011-11-27 at 19:06 +0200, Michael S. Tsirkin wrote:
> On Sun, Nov 27, 2011 at 06:49:27PM +0200, Michael S. Tsirkin wrote:
> > On Fri, Nov 18, 2011 at 11:19:42AM +0200, Sasha Levin wrote:
> > > Device lock should be held when releasing a device, and specifically
> > > when calling vhost_dev_cleanup(). Otherwise, RCU complains about it:
> > >
> > > [ 2025.642835] ===============================
> > > [ 2025.643838] [ INFO: suspicious RCU usage. ]
> > > [ 2025.645182] -------------------------------
> > > [ 2025.645927] drivers/vhost/vhost.c:475 suspicious rcu_dereference_protected() usage!
> > > [ 2025.647329]
> > > [ 2025.647330] other info that might help us debug this:
> > > [ 2025.647331]
> > > [ 2025.649042]
> > > [ 2025.649043] rcu_scheduler_active = 1, debug_locks = 1
> > > [ 2025.650235] no locks held by trinity/21042.
> > > [ 2025.650971]
> > > [ 2025.650972] stack backtrace:
> > > [ 2025.651789] Pid: 21042, comm: trinity Not tainted 3.2.0-rc2-sasha-00057-ga9098b3 #5
> > > [ 2025.653342] Call Trace:
> > > [ 2025.653792] [<ffffffff810b4a6a>] lockdep_rcu_suspicious+0xaf/0xb9
> > > [ 2025.654916] [<ffffffff818d4c2c>] vhost_dev_cleanup+0x342/0x3ac
> > > [ 2025.655985] [<ffffffff818d4f18>] vhost_net_release+0x48/0x7f
> > > [ 2025.657247] [<ffffffff811416e3>] fput+0x11e/0x1dc
> > > [ 2025.658091] [<ffffffff8113f1ec>] filp_close+0x6e/0x79
> > > [ 2025.658964] [<ffffffff81089ed7>] put_files_struct+0xcc/0x196
> > > [ 2025.659971] [<ffffffff8108a034>] exit_files+0x46/0x4f
> > > [ 2025.660865] [<ffffffff8108a716>] do_exit+0x264/0x75c
> > > [ 2025.662201] [<ffffffff8113f490>] ? fsnotify_modify+0x60/0x68
> > > [ 2025.663260] [<ffffffff81bbdbca>] ? sysret_check+0x2e/0x69
> > > [ 2025.664269] [<ffffffff8108acc1>] do_group_exit+0x83/0xb1
> > > [ 2025.665448] [<ffffffff8108ad01>] sys_exit_group+0x12/0x16
> > > [ 2025.666396] [<ffffffff81bbdb92>] system_call_fastpath+0x16/0x1b
> > >
> > > Cc: "Michael S. Tsirkin" <mst@redhat.com>
> > > Cc: kvm@vger.kernel.org
> > > Cc: virtualization@lists.linux-foundation.org
> > > Cc: netdev@vger.kernel.org
> > > Signed-off-by: Sasha Levin <levinsasha928@gmail.com>
> > > ---
> > > drivers/vhost/net.c | 2 ++
> > > 1 files changed, 2 insertions(+), 0 deletions(-)
> > >
> > > diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
> > > index 882a51f..c9be601 100644
> > > --- a/drivers/vhost/net.c
> > > +++ b/drivers/vhost/net.c
> > > @@ -586,6 +586,7 @@ static int vhost_net_release(struct inode *inode, struct file *f)
> > > struct socket *tx_sock;
> > > struct socket *rx_sock;
> > >
> > > + mutex_lock(&n->dev.mutex);
> > > vhost_net_stop(n, &tx_sock, &rx_sock);
> > > vhost_net_flush(n);
> > > vhost_dev_cleanup(&n->dev);
> > > @@ -596,6 +597,7 @@ static int vhost_net_release(struct inode *inode, struct file *f)
> > > /* We do an extra flush before freeing memory,
> > > * since jobs can re-queue themselves. */
> > > vhost_net_flush(n);
> > > + mutex_unlock(&n->dev.mutex);
> > > kfree(n);
> > > return 0;
> > > }
> >
> > This calls fput fom release under lock which is generally a bad idea,
> > as locks become nested then. For example, consider what would happen if this
> > somehow triggers a release which in turn needs the same mutex.
> >
> > And, we are releasing the device, so it seems better to check
> > that no one has the lock.
> > How about the following instead? What do you think?
> >
> > -->
> >
> > vhost: fix release path lockdep checks
> >
> > We shouldn't hold any locks on release path. Pass a flag to
> > vhost_dev_cleanup to use the lockdep info correctly.
> >
> > Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
> >
> > ---
>
> Sorry, this got cut short. Here's the full patch (1st chunk was
> missing). Does this solve the problem for you?
>
>
> diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
> index 8b16d16..9bba4b3 100644
> --- a/drivers/vhost/net.c
> +++ b/drivers/vhost/net.c
> @@ -598,7 +598,7 @@ static int vhost_net_release(struct inode *inode, struct file *f)
>
> vhost_net_stop(n, &tx_sock, &rx_sock);
> vhost_net_flush(n);
> - vhost_dev_cleanup(&n->dev);
> + vhost_dev_cleanup(&n->dev, false);
> if (tx_sock)
> fput(tx_sock->file);
> if (rx_sock)
> diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
> index a8c95ef..96f9769 100644
> --- a/drivers/vhost/vhost.c
> +++ b/drivers/vhost/vhost.c
> @@ -424,7 +424,7 @@ long vhost_dev_reset_owner(struct vhost_dev *dev)
> if (!memory)
> return -ENOMEM;
>
> - vhost_dev_cleanup(dev);
> + vhost_dev_cleanup(dev, true);
>
> memory->nregions = 0;
> RCU_INIT_POINTER(dev->memory, memory);
> @@ -455,8 +455,8 @@ int vhost_zerocopy_signal_used(struct vhost_virtqueue *vq)
> return j;
> }
>
> -/* Caller should have device mutex */
> -void vhost_dev_cleanup(struct vhost_dev *dev)
> +/* Caller should have device mutex if and only if locked is set */
> +void vhost_dev_cleanup(struct vhost_dev *dev, bool locked)
> {
> int i;
>
> @@ -493,7 +493,8 @@ void vhost_dev_cleanup(struct vhost_dev *dev)
> dev->log_file = NULL;
> /* No one will access memory at this point */
> kfree(rcu_dereference_protected(dev->memory,
> - lockdep_is_held(&dev->mutex)));
> + locked ==
> + lockdep_is_held(&dev->mutex)));
> RCU_INIT_POINTER(dev->memory, NULL);
> WARN_ON(!list_empty(&dev->work_list));
> if (dev->worker) {
> diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h
> index b3e8cc3..97e18d3 100644
> --- a/drivers/vhost/vhost.h
> +++ b/drivers/vhost/vhost.h
> @@ -164,7 +164,7 @@ struct vhost_dev {
> long vhost_dev_init(struct vhost_dev *, struct vhost_virtqueue *vqs, int nvqs);
> long vhost_dev_check_owner(struct vhost_dev *);
> long vhost_dev_reset_owner(struct vhost_dev *);
> -void vhost_dev_cleanup(struct vhost_dev *);
> +void vhost_dev_cleanup(struct vhost_dev *, bool locked);
> long vhost_dev_ioctl(struct vhost_dev *, unsigned int ioctl, unsigned long arg);
> int vhost_vq_access_ok(struct vhost_virtqueue *vq);
> int vhost_log_access_ok(struct vhost_dev *);
--
Sasha.
^ permalink raw reply
* Re: [PATCH 2/2] virtio-serial: setup_port_vq when adding port
From: Amit Shah @ 2012-02-01 8:12 UTC (permalink / raw)
To: zanghongyong
Cc: aliguori, kvm, wusongwei, hanweidong, Virtualization List,
xiaowei.yang, jiangningyu
In-Reply-To: <1326331207-10339-3-git-send-email-zanghongyong@huawei.com>
Hi,
Sorry for the late reply.
On (Thu) 12 Jan 2012 [09:20:07], zanghongyong@huawei.com wrote:
> From: Hongyong Zang <zanghongyong@huawei.com>
>
> Add setup_port_vq(). Create the io ports' vqs when add_port.
Can you describe the changes in more detail, please?
> Signed-off-by: Hongyong Zang <zanghongyong@huawei.com>
> ---
> drivers/char/virtio_console.c | 65 ++++++++++++++++++++++++++++++++++++++--
> 1 files changed, 61 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
> index 8e3c46d..2e5187e 100644
> --- a/drivers/char/virtio_console.c
> +++ b/drivers/char/virtio_console.c
> @@ -1132,6 +1132,55 @@ static void send_sigio_to_port(struct port *port)
> kill_fasync(&port->async_queue, SIGIO, POLL_OUT);
> }
>
> +static void in_intr(struct virtqueue *vq);
> +static void out_intr(struct virtqueue *vq);
> +
> +static int setup_port_vq(struct ports_device *portdev, u32 id)
> +{
> + int err, vq_num;
> + vq_callback_t **io_callbacks;
> + char **io_names;
> + struct virtqueue **vqs;
> + u32 i,j,nr_ports,nr_queues;
> +
> + err = 0;
> + vq_num = (id + 1) * 2;
> + nr_ports = portdev->config.max_nr_ports;
> + nr_queues = use_multiport(portdev) ? (nr_ports + 1) * 2 : 2;
> +
> + vqs = kmalloc(nr_queues * sizeof(struct virtqueue *), GFP_KERNEL);
> + io_callbacks = kmalloc(nr_queues * sizeof(vq_callback_t *), GFP_KERNEL);
> + io_names = kmalloc(nr_queues * sizeof(char *), GFP_KERNEL);
> + if (!vqs || !io_callbacks || !io_names) {
> + err = -ENOMEM;
> + goto free;
> + }
> +
> + for (i = 0, j = 0; i <= nr_ports; i++) {
> + io_callbacks[j] = in_intr;
> + io_callbacks[j + 1] = out_intr;
> + io_names[j] = NULL;
> + io_names[j + 1] = NULL;
> + j += 2;
> + }
> + io_names[vq_num] = "serial-input";
> + io_names[vq_num + 1] = "serial-output";
> + err = portdev->vdev->config->find_vqs(portdev->vdev, nr_queues, vqs,
> + io_callbacks,
> + (const char **)io_names);
> + if (err)
> + goto free;
> + portdev->in_vqs[id] = vqs[vq_num];
> + portdev->out_vqs[id] = vqs[vq_num + 1];
I don't think this approach will work fine for port hot-plug /
hot-unplug cases at all. For example, I first start qemu with one
port, at id 1. Then I add a port at id 5, then at 2, then at 10.
Will that be fine?
> +
> +free:
> + kfree(io_names);
> + kfree(io_callbacks);
> + kfree(vqs);
> +
> + return err;
> +}
> +
> static int add_port(struct ports_device *portdev, u32 id)
> {
> char debugfs_name[16];
> @@ -1163,6 +1212,14 @@ static int add_port(struct ports_device *portdev, u32 id)
>
> port->outvq_full = false;
>
> + if (!portdev->in_vqs[port->id] && !portdev->out_vqs[port->id]) {
> + spin_lock(&portdev->ports_lock);
> + err = setup_port_vq(portdev, port->id);
> + spin_unlock(&portdev->ports_lock);
> + if (err)
> + goto free_port;
> + }
> +
> port->in_vq = portdev->in_vqs[port->id];
> port->out_vq = portdev->out_vqs[port->id];
>
> @@ -1614,8 +1671,8 @@ static int init_vqs(struct ports_device *portdev)
> j += 2;
> io_callbacks[j] = in_intr;
> io_callbacks[j + 1] = out_intr;
> - io_names[j] = "input";
> - io_names[j + 1] = "output";
> + io_names[j] = NULL;
> + io_names[j + 1] = NULL;
> }
> }
> /* Find the queues. */
> @@ -1635,8 +1692,8 @@ static int init_vqs(struct ports_device *portdev)
>
> for (i = 1; i < nr_ports; i++) {
> j += 2;
> - portdev->in_vqs[i] = vqs[j];
> - portdev->out_vqs[i] = vqs[j + 1];
> + portdev->in_vqs[i] = NULL;
> + portdev->out_vqs[i] = NULL;
> }
> }
> kfree(io_names);
So a queue once created will not be removed unless the module is
removed or the device is removed. That seems reasonable, port
hot-unplug will keep queues around, as is the case now.
Amit
^ permalink raw reply
* Re: [PATCH 1/2] virtio-pci: add setup_vqs flag in vp_try_to_find_vqs
From: Amit Shah @ 2012-02-01 8:14 UTC (permalink / raw)
To: zanghongyong
Cc: aliguori, kvm, wusongwei, hanweidong, Virtualization List,
xiaowei.yang, Michael S. Tsirkin, jiangningyu
In-Reply-To: <1326331207-10339-2-git-send-email-zanghongyong@huawei.com>
Michael, Rusty, any comments?
On (Thu) 12 Jan 2012 [09:20:06], zanghongyong@huawei.com wrote:
> From: Hongyong Zang <zanghongyong@huawei.com>
>
> changes in vp_try_to_find_vqs:
> Virtio-serial's probe() calls it to request irqs and setup vqs of port0 and
> controls; add_port() calls it to set up vqs of io_port.
> it will not create virtqueue if the name is null.
>
> Signed-off-by: Hongyong Zang <zanghongyong@huawei.com>
> ---
> drivers/virtio/virtio_pci.c | 17 +++++++++++++----
> 1 files changed, 13 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/virtio/virtio_pci.c b/drivers/virtio/virtio_pci.c
> index baabb79..1f98c36 100644
> --- a/drivers/virtio/virtio_pci.c
> +++ b/drivers/virtio/virtio_pci.c
> @@ -492,9 +492,11 @@ static void vp_del_vqs(struct virtio_device *vdev)
> list_for_each_entry_safe(vq, n, &vdev->vqs, list) {
> info = vq->priv;
> if (vp_dev->per_vq_vectors &&
> - info->msix_vector != VIRTIO_MSI_NO_VECTOR)
> + info->msix_vector != VIRTIO_MSI_NO_VECTOR) {
> free_irq(vp_dev->msix_entries[info->msix_vector].vector,
> vq);
> + vp_dev->msix_used_vectors--;
> + }
> vp_del_vq(vq);
> }
> vp_dev->per_vq_vectors = false;
> @@ -511,7 +513,10 @@ static int vp_try_to_find_vqs(struct virtio_device *vdev, unsigned nvqs,
> {
> struct virtio_pci_device *vp_dev = to_vp_device(vdev);
> u16 msix_vec;
> - int i, err, nvectors, allocated_vectors;
> + int i, err, nvectors;
> +
> + if (vp_dev->msix_used_vectors)
> + goto setup_vqs;
>
> if (!use_msix) {
> /* Old style: one normal interrupt for change and all vqs. */
> @@ -536,12 +541,16 @@ static int vp_try_to_find_vqs(struct virtio_device *vdev, unsigned nvqs,
> }
>
> vp_dev->per_vq_vectors = per_vq_vectors;
> - allocated_vectors = vp_dev->msix_used_vectors;
> +
> +setup_vqs:
> for (i = 0; i < nvqs; ++i) {
> + if (names[i] == NULL)
> + continue;
> +
> if (!callbacks[i] || !vp_dev->msix_enabled)
> msix_vec = VIRTIO_MSI_NO_VECTOR;
> else if (vp_dev->per_vq_vectors)
> - msix_vec = allocated_vectors++;
> + msix_vec = vp_dev->msix_used_vectors++;
> else
> msix_vec = VP_MSIX_VQ_VECTOR;
> vqs[i] = setup_vq(vdev, i, callbacks[i], names[i], msix_vec);
> --
> 1.7.1
>
Amit
^ permalink raw reply
* Re: [PATCH 2/2] virtio-serial: setup_port_vq when adding port
From: Zang Hongyong @ 2012-02-01 9:32 UTC (permalink / raw)
To: Amit Shah
Cc: aliguori, kvm, wusongwei, hanweidong, Virtualization List,
xiaowei.yang, jiangningyu
In-Reply-To: <20120201081257.GD24943@amit.redhat.com>
On 2012/2/1,星期三 16:12, Amit Shah wrote:
> Hi,
>
> Sorry for the late reply.
>
> On (Thu) 12 Jan 2012 [09:20:07], zanghongyong@huawei.com wrote:
>> From: Hongyong Zang<zanghongyong@huawei.com>
>>
>> Add setup_port_vq(). Create the io ports' vqs when add_port.
> Can you describe the changes in more detail, please?
The motivation of this patch is as follows. When we use virtio-serial
for communication between guest and host, we usually use only a few
ports (for example 1 or 2 ports), so there's no need to create max ports
when build a virtio-serial. The patch does the port hot-plug thing without
port hot-unplug.
>
>> Signed-off-by: Hongyong Zang<zanghongyong@huawei.com>
>> ---
>> drivers/char/virtio_console.c | 65 ++++++++++++++++++++++++++++++++++++++--
>> 1 files changed, 61 insertions(+), 4 deletions(-)
>>
>> diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
>> index 8e3c46d..2e5187e 100644
>> --- a/drivers/char/virtio_console.c
>> +++ b/drivers/char/virtio_console.c
>> @@ -1132,6 +1132,55 @@ static void send_sigio_to_port(struct port *port)
>> kill_fasync(&port->async_queue, SIGIO, POLL_OUT);
>> }
>>
>> +static void in_intr(struct virtqueue *vq);
>> +static void out_intr(struct virtqueue *vq);
>> +
>> +static int setup_port_vq(struct ports_device *portdev, u32 id)
>> +{
>> + int err, vq_num;
>> + vq_callback_t **io_callbacks;
>> + char **io_names;
>> + struct virtqueue **vqs;
>> + u32 i,j,nr_ports,nr_queues;
>> +
>> + err = 0;
>> + vq_num = (id + 1) * 2;
>> + nr_ports = portdev->config.max_nr_ports;
>> + nr_queues = use_multiport(portdev) ? (nr_ports + 1) * 2 : 2;
>> +
>> + vqs = kmalloc(nr_queues * sizeof(struct virtqueue *), GFP_KERNEL);
>> + io_callbacks = kmalloc(nr_queues * sizeof(vq_callback_t *), GFP_KERNEL);
>> + io_names = kmalloc(nr_queues * sizeof(char *), GFP_KERNEL);
>> + if (!vqs || !io_callbacks || !io_names) {
>> + err = -ENOMEM;
>> + goto free;
>> + }
>> +
>> + for (i = 0, j = 0; i<= nr_ports; i++) {
>> + io_callbacks[j] = in_intr;
>> + io_callbacks[j + 1] = out_intr;
>> + io_names[j] = NULL;
>> + io_names[j + 1] = NULL;
>> + j += 2;
>> + }
>> + io_names[vq_num] = "serial-input";
>> + io_names[vq_num + 1] = "serial-output";
>> + err = portdev->vdev->config->find_vqs(portdev->vdev, nr_queues, vqs,
>> + io_callbacks,
>> + (const char **)io_names);
>> + if (err)
>> + goto free;
>> + portdev->in_vqs[id] = vqs[vq_num];
>> + portdev->out_vqs[id] = vqs[vq_num + 1];
> I don't think this approach will work fine for port hot-plug /
> hot-unplug cases at all. For example, I first start qemu with one
> port, at id 1. Then I add a port at id 5, then at 2, then at 10.
> Will that be fine?
yes.
In this case, the virtio-serial will create id 1's queue when probe the
device. Then, add port id 5, it will create the id 5's queue and the queues
of id 2-4 still be null.
we find the right ioport by vq_num, and only the io_name[vq_num] and
io_name[vq_num+1] are not null. So after portdev->vdev->config->find_vqs(),
the id 5's queues are created(see the changes in virtio-pci), the others
are
still null.
>
>> +
>> +free:
>> + kfree(io_names);
>> + kfree(io_callbacks);
>> + kfree(vqs);
>> +
>> + return err;
>> +}
>> +
>> static int add_port(struct ports_device *portdev, u32 id)
>> {
>> char debugfs_name[16];
>> @@ -1163,6 +1212,14 @@ static int add_port(struct ports_device *portdev, u32 id)
>>
>> port->outvq_full = false;
>>
>> + if (!portdev->in_vqs[port->id]&& !portdev->out_vqs[port->id]) {
>> + spin_lock(&portdev->ports_lock);
>> + err = setup_port_vq(portdev, port->id);
>> + spin_unlock(&portdev->ports_lock);
>> + if (err)
>> + goto free_port;
>> + }
>> +
>> port->in_vq = portdev->in_vqs[port->id];
>> port->out_vq = portdev->out_vqs[port->id];
>>
>> @@ -1614,8 +1671,8 @@ static int init_vqs(struct ports_device *portdev)
>> j += 2;
>> io_callbacks[j] = in_intr;
>> io_callbacks[j + 1] = out_intr;
>> - io_names[j] = "input";
>> - io_names[j + 1] = "output";
>> + io_names[j] = NULL;
>> + io_names[j + 1] = NULL;
>> }
>> }
>> /* Find the queues. */
>> @@ -1635,8 +1692,8 @@ static int init_vqs(struct ports_device *portdev)
>>
>> for (i = 1; i< nr_ports; i++) {
>> j += 2;
>> - portdev->in_vqs[i] = vqs[j];
>> - portdev->out_vqs[i] = vqs[j + 1];
>> + portdev->in_vqs[i] = NULL;
>> + portdev->out_vqs[i] = NULL;
>> }
>> }
>> kfree(io_names);
> So a queue once created will not be removed unless the module is
> removed or the device is removed. That seems reasonable, port
> hot-unplug will keep queues around, as is the case now.
As we use the virtio-serial with only a few io-ports, the maxport queues
may
waste more memory. So we try to create queues when port hot-plug, as for
port hot-unplug there's no change.
>
> Amit
>
> .
>
_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization
^ permalink raw reply
* Call for Workshops: The 9th Int. Conf. on Autonomic Computing (ICAC 2012)
From: Ioan Raicu @ 2012-02-01 23:43 UTC (permalink / raw)
To: virtualization
CALL FOR WORKSHOP PROPOSALS
The 9th International Conference on Autonomic Computing (ICAC 2012)
September 17-21, 2012. San Jose, CA, USA
http://icac2012.cs.fiu.edu/
-----------------------------------------------------------------
IMPORTANT DATES
Workshop Proposal Submission: February 10, 2012
-----------------------------------------------------------------
OVERVIEW
ICAC is the leading conference on autonomic computing techniques,
foundations, and applications. Autonomic computing refers to
methods and means for automated management of performance, fault,
security, and configuration with little involvement of users or
administrators. Systems introducing new autonomic features are
becoming increasingly prevalent, motivating research that spans
a variety of areas, from computer systems, networking, software
engineering, and data management to machine learning, control
theory, and bio-inspired computing. ICAC brings together
researchers and practitioners across these disciplines to
address multiple facets of adaptation and self-management in
computing systems and applications from different perspectives.
Autonomic computing solutions are sought for clouds, grids,
data centers, enterprise software, internet services, data
services, smart phones, embedded systems, and sensor networks.
In these environments, resources and applications must be managed
to maximize performance and minimize cost, while maintaining
predictable and reliable behavior in the face of varying
workloads, failures, and malicious threats.
ICAC'12 welcomes proposals for co-located workshops on topics of
interest to the autonomic computing community. Workshop proposals
should be submitted to the Workshop Chair, Fred Douglis
(f.douglis@computer.org) by February 10, 2012. Workshops are
expected to publish proceedings, and should cover areas that
complement the main program.
------------------------------------------------------------------
ORGANIZERS
GENERAL CHAIR: Dejan Milojicic, HP Labs
WORKSHOPS CHAIR: Fred Douglis, EMC
--
=================================================================
Ioan Raicu, Ph.D.
Assistant Professor, Illinois Institute of Technology (IIT)
Guest Research Faculty, Argonne National Laboratory (ANL)
=================================================================
Data-Intensive Distributed Systems Laboratory, CS/IIT
Distributed Systems Laboratory, MCS/ANL
=================================================================
Cel: 1-847-722-0876
Office: 1-312-567-5704
Email: iraicu@cs.iit.edu
Web: http://www.cs.iit.edu/~iraicu/
Web: http://datasys.cs.iit.edu/
=================================================================
=================================================================
^ permalink raw reply
* drivres/hv
From: y @ 2012-02-02 2:48 UTC (permalink / raw)
To: gregkh, devel, virtualization, ohering
Greg,
I recently saw on the mailing list that your suse.com address was no
longer valid. I had sent some patches late last month for the hv_utils
driver; I think it was sent around the 27th of Jan. Should I resend these
patches to your greg@kroah.com or greg@linuxfoundation.org address.
Regards,
K. Y
^ permalink raw reply
* Re: drivres/hv
From: Greg KH @ 2012-02-02 2:55 UTC (permalink / raw)
To: y; +Cc: devel, ohering, virtualization
In-Reply-To: <1328150891-29752-1-git-send-email-y>
On Wed, Feb 01, 2012 at 06:48:11PM -0800, y@linuxonhyperv.com wrote:
>
> Greg,
>
> I recently saw on the mailing list that your suse.com address was no
> longer valid. I had sent some patches late last month for the hv_utils
> driver; I think it was sent around the 27th of Jan. Should I resend these
> patches to your greg@kroah.com or greg@linuxfoundation.org address.
Nope, I still have them in my to-apply queue, they are not lost.
thanks,
greg k-h
^ permalink raw reply
* Re: [PATCH 1/1] drivers: hid: hid-hyperv: Properly disconnect the input device
From: Jiri Kosina @ 2012-02-02 9:56 UTC (permalink / raw)
To: K. Y. Srinivasan
Cc: gregkh, linux-kernel, devel, virtualization, ohering, joe,
dmitry.torokhov, Haiyang Zhang, stable
In-Reply-To: <1326905834-7624-1-git-send-email-kys@microsoft.com>
On Wed, 18 Jan 2012, K. Y. Srinivasan wrote:
> When we unload the mouse driver, properly disconnect the input device.
>
> Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
> Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
> Reported-by: Fuzhou Chen <fuzhouch@microsoft.com>
> Cc: stable <stable@vger.kernel.org>
> ---
> drivers/hid/hid-hyperv.c | 1 +
> 1 files changed, 1 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/hid/hid-hyperv.c b/drivers/hid/hid-hyperv.c
> index 0c33ae9..4066324 100644
> --- a/drivers/hid/hid-hyperv.c
> +++ b/drivers/hid/hid-hyperv.c
> @@ -548,6 +548,7 @@ static int mousevsc_remove(struct hv_device *dev)
> struct mousevsc_dev *input_dev = hv_get_drvdata(dev);
>
> vmbus_close(dev->channel);
> + hid_hw_stop(input_dev->hid_device);
> hid_destroy_device(input_dev->hid_device);
> mousevsc_free_device(input_dev);
Applied, thanks.
--
Jiri Kosina
SUSE Labs
^ permalink raw reply
* Re: [PATCH 3/6] drivers: hv: Cleanup the kvp related state in hyperv.h
From: Greg KH @ 2012-02-02 23:29 UTC (permalink / raw)
To: K. Y. Srinivasan
Cc: gregkh, linux-kernel, devel, virtualization, ohering, zbr,
Haiyang Zhang
In-Reply-To: <1327708562-26964-3-git-send-email-kys@microsoft.com>
On Fri, Jan 27, 2012 at 03:55:59PM -0800, K. Y. Srinivasan wrote:
> Now cleanup the hyperv.h with regards to KVP definitions.
>
> Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
> Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
> include/linux/hyperv.h | 32 +++++++++++++++++++-------------
> 1 files changed, 19 insertions(+), 13 deletions(-)
>
> diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h
> index 7332b3f..802ece8 100644
> --- a/include/linux/hyperv.h
> +++ b/include/linux/hyperv.h
> @@ -137,7 +137,6 @@ struct hv_ku_msg {
>
>
>
> -#ifdef __KERNEL__
>
> /*
> * Registry value types.
> @@ -162,29 +161,36 @@ enum hv_kvp_exchg_pool {
> KVP_POOL_COUNT /* Number of pools, must be last. */
> };
>
> +#ifndef __packed
> +#define __packed __attribute__((packed))
> +#endif
Why do this?
If you are so worried about this in userspace, then just change the
values below to __attribute__((packed)), like all of the other public .h
files do.
thanks,
greg k-h
^ permalink raw reply
* Re: [PATCH 0000/0006] drivers: hv
From: Greg KH @ 2012-02-02 23:31 UTC (permalink / raw)
To: K. Y. Srinivasan
Cc: gregkh, linux-kernel, devel, virtualization, ohering, zbr
In-Reply-To: <1327708522-26914-1-git-send-email-kys@microsoft.com>
On Fri, Jan 27, 2012 at 03:55:22PM -0800, K. Y. Srinivasan wrote:
>
> This patch-set does some cleanup of the KVP component. Also included is a
> patch that will remove artificial limitation on the number of VCPUs that
> can be assigned to the Linux guest on Hyper-V.
I have applied the first 2, please fix patch 3, and resend the rest.
thanks,
greg k-h
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox