From: "K. Y. Srinivasan" <kys@microsoft.com> Date: 2012-03-10 23:25:16
This patch-set further enhances the KVP functionality for Linux
guests:
1. Supports most of the Win8 KVP protocol.
2. Supports operations on all the pools.
Regards,
K. Y
From: "K. Y. Srinivasan" <kys@microsoft.com> Date: 2012-03-10 23:25:46
Now fully support the new KVP messages in the user level daemon. Hyper-V defines
multiple persistent pools to which the host can write/read/modify KVP tuples.
In this patch we implement a file for each specified pool, where the KVP tuples
will stored in the guest.
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Reviewed-by: Haiyang Zhang <haiyangz@microsoft.com>
---
tools/hv/hv_kvp_daemon.c | 281 +++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 280 insertions(+), 1 deletions(-)
@@ -79,6 +80,250 @@ static char *os_build;staticchar*lic_version;staticstructutsnameuts_buf;++#define MAX_FILE_NAME 100+#define ENTRIES_PER_BLOCK 50++structkvp_record{+__u8key[HV_KVP_EXCHANGE_MAX_KEY_SIZE];+__u8value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE];+};++structkvp_file_state{+intfd;+intnum_blocks;+structkvp_record*records;+intnum_records;+__u8fname[MAX_FILE_NAME];+};++staticstructkvp_file_statekvp_file_info[KVP_POOL_COUNT];++staticvoidkvp_acquire_lock(intpool)+{+structflockfl={F_WRLCK,SEEK_SET,0,0,0};+fl.l_pid=getpid();++if(fcntl(kvp_file_info[pool].fd,F_SETLKW,&fl)==-1){+syslog(LOG_ERR,"Failed to acquire the lock pool: %d",pool);+exit(-1);+}+}++staticvoidkvp_release_lock(intpool)+{+structflockfl={F_UNLCK,SEEK_SET,0,0,0};+fl.l_pid=getpid();++if(fcntl(kvp_file_info[pool].fd,F_SETLK,&fl)==-1){+perror("fcntl");+syslog(LOG_ERR,"Failed to release the lock pool: %d",pool);+exit(-1);+}+}++staticvoidkvp_update_file(intpool)+{+FILE*filep;+size_tbytes_written;++/*+*Wearegoingtowriteourin-memoryregistryoutto+*disk;acquirethelockfirst.+*/+kvp_acquire_lock(pool);++filep=fopen(kvp_file_info[pool].fname,"w");+if(!filep){+kvp_release_lock(pool);+syslog(LOG_ERR,"Failed to open file, pool: %d",pool);+exit(-1);+}++bytes_written=fwrite(kvp_file_info[pool].records,+sizeof(structkvp_record),+kvp_file_info[pool].num_records,filep);++fflush(filep);+kvp_release_lock(pool);+}++staticintkvp_file_init(void)+{+intret,fd;+FILE*filep;+size_trecords_read;+__u8*fname;+structkvp_record*record;+structkvp_record*readp;+intnum_blocks;+inti;+intalloc_unit=sizeof(structkvp_record)*ENTRIES_PER_BLOCK;++if(access("/var/opt/hyperv",F_OK)){+if(mkdir("/var/opt/hyperv",S_IRUSR|S_IWUSR|S_IROTH)){+syslog(LOG_ERR," Failed to create /var/opt/hyperv");+exit(-1);+}+}++for(i=0;i<KVP_POOL_COUNT;i++){+fname=kvp_file_info[i].fname;+records_read=0;+num_blocks=1;+sprintf(fname,"/var/opt/hyperv/.kvp_pool_%d",i);+fd=open(fname,O_RDWR|O_CREAT,S_IRUSR|S_IWUSR|S_IROTH);++if(fd==-1)+return1;+++filep=fopen(fname,"r");+if(!filep)+return1;++record=malloc(alloc_unit*num_blocks);+if(record==NULL){+fclose(filep);+return1;+}+while(!feof(filep)){+readp=&record[records_read];+records_read+=fread(readp,sizeof(structkvp_record),+ENTRIES_PER_BLOCK,+filep);++if(!feof(filep)){+/*+*Wehavemoredatatoread.+*/+num_blocks++;+record=realloc(record,alloc_unit*+num_blocks);+if(record==NULL){+fclose(filep);+return1;+}+continue;+}+break;+}+kvp_file_info[i].fd=fd;+kvp_file_info[i].num_blocks=num_blocks;+kvp_file_info[i].records=record;+kvp_file_info[i].num_records=records_read;+fclose(filep);++}++return0;+}++staticintkvp_key_delete(intpool,__u8*key,intkey_size)+{+inti;+intj,k;+intnum_records=kvp_file_info[pool].num_records;+structkvp_record*record=kvp_file_info[pool].records;++for(i=0;i<num_records;i++){+if(memcmp(key,record[i].key,key_size))+continue;+/*+*Foundamatch;justmovetheremaining+*entriesup.+*/+if(i==num_records){+kvp_file_info[pool].num_records--;+kvp_update_file(pool);+return0;+}++j=i;+k=j+1;+for(;k<num_records;k++){+strcpy(record[j].key,record[k].key);+strcpy(record[j].value,record[k].value);+j++;+}++kvp_file_info[pool].num_records--;+kvp_update_file(pool);+return0;+}+return1;+}++staticintkvp_key_add_or_modify(intpool,__u8*key,intkey_size,__u8*value,+intvalue_size)+{+inti;+intj,k;+intnum_records=kvp_file_info[pool].num_records;+structkvp_record*record=kvp_file_info[pool].records;+intnum_blocks=kvp_file_info[pool].num_blocks;++if((key_size>HV_KVP_EXCHANGE_MAX_KEY_SIZE)||+(value_size>HV_KVP_EXCHANGE_MAX_VALUE_SIZE))+return1;++for(i=0;i<num_records;i++){+if(memcmp(key,record[i].key,key_size))+continue;+/*+*Foundamatch;justupdatethevalue-+*thisisthemodifycase.+*/+memcpy(record[i].value,value,value_size);+kvp_update_file(pool);+return0;+}++/*+*Needtoaddanewentry;+*/+if(num_records==(ENTRIES_PER_BLOCK*num_blocks)){+/* Need to allocate a larger array for reg entries. */+record=realloc(record,sizeof(structkvp_record)*+ENTRIES_PER_BLOCK*(num_blocks+1));++if(record==NULL)+return1;+kvp_file_info[pool].num_blocks++;++}+memcpy(record[i].value,value,value_size);+memcpy(record[i].key,key,key_size);+kvp_file_info[pool].records=record;+kvp_file_info[pool].num_records++;+kvp_update_file(pool);+return0;+}++staticintkvp_get_value(intpool,__u8*key,intkey_size,__u8*value,+intvalue_size)+{+inti;+intnum_records=kvp_file_info[pool].num_records;+structkvp_record*record=kvp_file_info[pool].records;++if((key_size>HV_KVP_EXCHANGE_MAX_KEY_SIZE)||+(value_size>HV_KVP_EXCHANGE_MAX_VALUE_SIZE))+return1;++for(i=0;i<num_records;i++){+if(memcmp(key,record[i].key,key_size))+continue;+/*+*Foundamatch;justcopythevalueout.+*/+memcpy(value,record[i].value,value_size);+return0;+}++return1;+}+voidkvp_get_os_info(void){FILE*file;
@@ -315,6 +560,11 @@ int main(void)*/kvp_get_os_info();+if(kvp_file_init()){+syslog(LOG_ERR,"Failed to initialize the pools");+exit(-1);+}+fd=socket(AF_NETLINK,SOCK_DGRAM,NETLINK_CONNECTOR);if(fd<0){syslog(LOG_ERR,"netlink socket creation failed; error:%d",fd);
@@ -389,9 +639,38 @@ int main(void)}continue;+/*+*Thecurrentprotocolwiththekernelcomponentusesa+*NULLkeynametopassanerrorcondition.+*FortheSET,GETandDELETEoperations,+*usetheexistingprotocoltopassbackerror.+*/+caseKVP_OP_SET:+if(kvp_key_add_or_modify(hv_msg->kvp_hdr.pool,+hv_msg->body.kvp_set.data.key,+hv_msg->body.kvp_set.data.key_size,+hv_msg->body.kvp_set.data.value,+hv_msg->body.kvp_set.data.value_size))+strcpy(hv_msg->body.kvp_set.data.key,"");+break;+caseKVP_OP_GET:+if(kvp_get_value(hv_msg->kvp_hdr.pool,+hv_msg->body.kvp_set.data.key,+hv_msg->body.kvp_set.data.key_size,+hv_msg->body.kvp_set.data.value,+hv_msg->body.kvp_set.data.value_size))+strcpy(hv_msg->body.kvp_set.data.key,"");+break;+caseKVP_OP_DELETE:+if(kvp_key_delete(hv_msg->kvp_hdr.pool,+hv_msg->body.kvp_delete.key,+hv_msg->body.kvp_delete.key_size))+strcpy(hv_msg->body.kvp_delete.key,"");+break;+default:break;}
From: "K. Y. Srinivasan" <kys@microsoft.com> Date: 2012-03-10 23:25:48
Add additional KVP (Key Value Pair) protocol messages to
enhance KVP functionality for Linux guests on Hyper-V. As part of this,
patch define an explicit version negoitiation message.
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Reviewed-by: Haiyang Zhang <haiyangz@microsoft.com>
---
drivers/hv/hv_kvp.c | 5 +++--
include/linux/hyperv.h | 30 +++++++++++++++++++++++++++---
tools/hv/hv_kvp_daemon.c | 2 +-
3 files changed, 31 insertions(+), 6 deletions(-)
From: "K. Y. Srinivasan" <kys@microsoft.com> Date: 2012-03-10 23:25:49
Now support the newly defined KVP message types. It turns out that the host
pushes a set of stand key value pairs as soon as the guest opens the KVP channel.
Since we cannot handle these tuples until the user level daemon loads up, defer
reading the KVP channel until the user level daemon is launched.
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Reviewed-by: Haiyang Zhang <haiyangz@microsoft.com>
---
drivers/hv/hv_kvp.c | 184 ++++++++++++++++++++++++++++++++++++----------
include/linux/hyperv.h | 2 +
tools/hv/hv_kvp_daemon.c | 7 ++
3 files changed, 153 insertions(+), 40 deletions(-)
@@ -42,9 +42,10 @@staticstruct{boolactive;/* transaction status - active or not */intrecv_len;/* number of bytes received. */-intindex;/* current index */+structhv_kvp_msg*kvp_msg;/* current message */structvmbus_channel*recv_channel;/* chn we got the request */u64recv_req_id;/* request ID. */+void*kvp_context;/* for the channel callback */}kvp_transaction;staticvoidkvp_send_key(structwork_struct*dummy);
From: "K. Y. Srinivasan" <kys@microsoft.com> Date: 2012-03-10 23:26:33
We have supported enumeration only from the AUTO pool. Now support
enumeration from all the available pools.
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Reviewed-by: Haiyang Zhang <haiyangz@microsoft.com>
---
drivers/hv/hv_kvp.c | 7 ++-
include/linux/hyperv.h | 1 +
tools/hv/hv_kvp_daemon.c | 124 +++++++++++++++++++++++++++++++++++++++++++---
3 files changed, 122 insertions(+), 10 deletions(-)
@@ -148,6 +148,51 @@ static void kvp_update_file(int pool)kvp_release_lock(pool);}+staticvoidkvp_update_mem_state(intpool)+{+FILE*filep;+size_trecords_read=0;+structkvp_record*record=kvp_file_info[pool].records;+structkvp_record*readp;+intnum_blocks=kvp_file_info[pool].num_blocks;+intalloc_unit=sizeof(structkvp_record)*ENTRIES_PER_BLOCK;++kvp_acquire_lock(pool);++filep=fopen(kvp_file_info[pool].fname,"r");+if(!filep){+kvp_release_lock(pool);+syslog(LOG_ERR,"Failed to open file, pool: %d",pool);+exit(-1);+}+while(!feof(filep)){+readp=&record[records_read];+records_read+=fread(readp,sizeof(structkvp_record),+ENTRIES_PER_BLOCK*num_blocks,+filep);++if(!feof(filep)){+/*+*Wehavemoredatatoread.+*/+num_blocks++;+record=realloc(record,alloc_unit*num_blocks);++if(record==NULL){+syslog(LOG_ERR,"malloc failed");+exit(-1);+}+continue;+}+break;+}++kvp_file_info[pool].num_blocks=num_blocks;+kvp_file_info[pool].records=record;+kvp_file_info[pool].num_records=records_read;++kvp_release_lock(pool);+}staticintkvp_file_init(void){intret,fd;
@@ -223,8 +268,16 @@ static int kvp_key_delete(int pool, __u8 *key, int key_size){inti;intj,k;-intnum_records=kvp_file_info[pool].num_records;-structkvp_record*record=kvp_file_info[pool].records;+intnum_records;+structkvp_record*record;++/*+*Firstupdatethein-memorystate.+*/+kvp_update_mem_state(pool);++num_records=kvp_file_info[pool].num_records;+record=kvp_file_info[pool].records;for(i=0;i<num_records;i++){if(memcmp(key,record[i].key,key_size))
@@ -259,14 +312,23 @@ static int kvp_key_add_or_modify(int pool, __u8 *key, int key_size, __u8 *value,{inti;intj,k;-intnum_records=kvp_file_info[pool].num_records;-structkvp_record*record=kvp_file_info[pool].records;-intnum_blocks=kvp_file_info[pool].num_blocks;+intnum_records;+structkvp_record*record;+intnum_blocks;if((key_size>HV_KVP_EXCHANGE_MAX_KEY_SIZE)||(value_size>HV_KVP_EXCHANGE_MAX_VALUE_SIZE))return1;+/*+*Firstupdatethein-memorystate.+*/+kvp_update_mem_state(pool);++num_records=kvp_file_info[pool].num_records;+record=kvp_file_info[pool].records;+num_blocks=kvp_file_info[pool].num_blocks;+for(i=0;i<num_records;i++){if(memcmp(key,record[i].key,key_size))continue;
@@ -304,13 +366,21 @@ static int kvp_get_value(int pool, __u8 *key, int key_size, __u8 *value,intvalue_size){inti;-intnum_records=kvp_file_info[pool].num_records;-structkvp_record*record=kvp_file_info[pool].records;+intnum_records;+structkvp_record*record;if((key_size>HV_KVP_EXCHANGE_MAX_KEY_SIZE)||(value_size>HV_KVP_EXCHANGE_MAX_VALUE_SIZE))return1;+/*+*Firstupdatethein-memorystate.+*/+kvp_update_mem_state(pool);++num_records=kvp_file_info[pool].num_records;+record=kvp_file_info[pool].records;+for(i=0;i<num_records;i++){if(memcmp(key,record[i].key,key_size))continue;
@@ -324,6 +394,31 @@ static int kvp_get_value(int pool, __u8 *key, int key_size, __u8 *value,return1;}+staticvoidkvp_pool_enumerate(intpool,intindex,__u8*key,intkey_size,+__u8*value,intvalue_size)+{+structkvp_record*record;++/*+*Firstupdateourin-memorydatabase.+*/+kvp_update_mem_state(pool);+record=kvp_file_info[pool].records;++if(index>=kvp_file_info[pool].num_records){+/*+*Thisisaninvalidindex;terminateenumeration;+*-aNULLvaluewilldothetrick.+*/+strcpy(value,"");+return;+}++memcpy(key,record[index].key,key_size);+memcpy(value,record[index].value,value_size);+}++voidkvp_get_os_info(void){FILE*file;
@@ -678,6 +773,21 @@ int main(void)if(hv_msg->kvp_hdr.operation!=KVP_OP_ENUMERATE)gotokvp_done;+/*+*IfthepoolisKVP_POOL_AUTO,dynamicallygenerate+*boththekeyandthevalue;ifnotreadfromthe+*appropriatepool.+*/+if(hv_msg->kvp_hdr.pool!=KVP_POOL_AUTO){+kvp_pool_enumerate(hv_msg->kvp_hdr.pool,+hv_msg->body.kvp_enum_data.index,+hv_msg->body.kvp_enum_data.data.key,+HV_KVP_EXCHANGE_MAX_KEY_SIZE,+hv_msg->body.kvp_enum_data.data.value,+HV_KVP_EXCHANGE_MAX_VALUE_SIZE);+gotokvp_done;+}+hv_msg=(structhv_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;
From: Dan Carpenter <hidden> Date: 2012-03-11 10:40:22
On Sat, Mar 10, 2012 at 03:32:09PM -0800, K. Y. Srinivasan wrote:
quoted hunk
+ switch (message->kvp_hdr.operation) {+ case KVP_OP_SET:+ switch (in_msg->body.kvp_set.data.value_type) {+ case REG_SZ:+ /*+ * The value is a string - utf16 encoding.+ */+ message->body.kvp_set.data.value_size =+ utf16s_to_utf8s(+ (wchar_t *)+ in_msg->body.kvp_set.data.value,+ in_msg->body.kvp_set.data.value_size,+ UTF16_LITTLE_ENDIAN,+ message->body.kvp_set.data.value,+ HV_KVP_EXCHANGE_MAX_VALUE_SIZE) + 1;+ break;+
This block of unreadable text is so nasty.
You could return directly if the msg = kmalloc() fails and pull
everything in one indent level. It's normally more readable to
handle errors as soon as possible anyway.
Probably that's not enough to make a difference and we'd need to
introduce a new function.
Btw I don't know if utf16s_to_utf8s() counts the NUL char or not.
It feels like maybe we could end up with ->value_size equal to
HV_KVP_EXCHANGE_MAX_VALUE_SIZE + 1.
regards,
dan carpenter
From: Alan Stern <stern@rowland.harvard.edu> Date: 2012-03-11 16:01:29
On Sun, 11 Mar 2012, Dan Carpenter wrote:
Btw I don't know if utf16s_to_utf8s() counts the NUL char or not.
It feels like maybe we could end up with ->value_size equal to
HV_KVP_EXCHANGE_MAX_VALUE_SIZE + 1.
It does not count NUL characters. If it encounters a NUL character in
the input, it stops right away without copying that character to the
output. If it reaches the end of the input, it does not add a
terminating NUL character to the output.
Alan Stern
From: KY Srinivasan <kys@microsoft.com> Date: 2012-03-11 16:56:57
-----Original Message-----
From: Dan Carpenter [mailto:dan.carpenter@oracle.com]
Sent: Sunday, March 11, 2012 6:43 AM
To: KY Srinivasan
Cc: gregkh@linuxfoundation.org; linux-kernel@vger.kernel.org;
devel@linuxdriverproject.org; virtualization@lists.osdl.org; ohering@suse.com;
Alan Stern
Subject: Re: [PATCH 2/4] Drivers: hv: Support the newly introduced KVP
messages in the driver
On Sat, Mar 10, 2012 at 03:32:09PM -0800, K. Y. Srinivasan wrote:
quoted
+ switch (message->kvp_hdr.operation) {+ case KVP_OP_SET:+ switch (in_msg->body.kvp_set.data.value_type) {+ case REG_SZ:+ /*+ * The value is a string - utf16 encoding.+ */+ message->body.kvp_set.data.value_size =+ utf16s_to_utf8s(+ (wchar_t *)+ in_msg->body.kvp_set.data.value,+ in_msg->body.kvp_set.data.value_size,+ UTF16_LITTLE_ENDIAN,+ message->body.kvp_set.data.value,+ HV_KVP_EXCHANGE_MAX_VALUE_SIZE) + 1;+ break;+
This block of unreadable text is so nasty.
You could return directly if the msg = kmalloc() fails and pull
everything in one indent level. It's normally more readable to
handle errors as soon as possible anyway.
True.
Probably that's not enough to make a difference and we'd need to
introduce a new function.
Btw I don't know if utf16s_to_utf8s() counts the NUL char or not.
It feels like maybe we could end up with ->value_size equal to
HV_KVP_EXCHANGE_MAX_VALUE_SIZE + 1.
The MAX value is set to accommodate the maximum string that will ever
be handled including the string terminator. The function utf16s_to_utf8s()
returns the converted string length but the returned length does not
include the string terminator (like strlen), hence the "+1".
Dan, I will see if there are other comments on these patches and will
accommodate your suggestion then. If there are no other comments,
would you mind if I addressed your comments here in a separate patch.
Regards,
K. Y
From: Dan Carpenter <hidden> Date: 2012-03-11 18:47:11
On Sun, Mar 11, 2012 at 04:56:06PM +0000, KY Srinivasan wrote:
quoted
Probably that's not enough to make a difference and we'd need to
introduce a new function.
Btw I don't know if utf16s_to_utf8s() counts the NUL char or not.
It feels like maybe we could end up with ->value_size equal to
HV_KVP_EXCHANGE_MAX_VALUE_SIZE + 1.
The MAX value is set to accommodate the maximum string that will ever
be handled including the string terminator. The function utf16s_to_utf8s()
returns the converted string length but the returned length does not
include the string terminator (like strlen), hence the "+1".
sprintf() and friends copy the NUL terminator but utf16s_to_utf8s()
doesn't so the code isn't right and it does seem like maybe we could
end up with a ->value_size equal to HV_KVP_EXCHANGE_MAX_VALUE_SIZE +
1.
regards,
dan carpenter
From: KY Srinivasan <kys@microsoft.com> Date: 2012-03-11 20:54:14
-----Original Message-----
From: Dan Carpenter [mailto:dan.carpenter@oracle.com]
Sent: Sunday, March 11, 2012 2:49 PM
To: KY Srinivasan
Cc: gregkh@linuxfoundation.org; linux-kernel@vger.kernel.org;
devel@linuxdriverproject.org; virtualization@lists.osdl.org; ohering@suse.com;
Alan Stern
Subject: Re: [PATCH 2/4] Drivers: hv: Support the newly introduced KVP
messages in the driver
On Sun, Mar 11, 2012 at 04:56:06PM +0000, KY Srinivasan wrote:
quoted
quoted
Probably that's not enough to make a difference and we'd need to
introduce a new function.
Btw I don't know if utf16s_to_utf8s() counts the NUL char or not.
It feels like maybe we could end up with ->value_size equal to
HV_KVP_EXCHANGE_MAX_VALUE_SIZE + 1.
The MAX value is set to accommodate the maximum string that will ever
be handled including the string terminator. The function utf16s_to_utf8s()
returns the converted string length but the returned length does not
include the string terminator (like strlen), hence the "+1".
sprintf() and friends copy the NUL terminator but utf16s_to_utf8s()
doesn't so the code isn't right and it does seem like maybe we could
end up with a ->value_size equal to HV_KVP_EXCHANGE_MAX_VALUE_SIZE +
1.
You are right in that utf16s_to_utf8s() does not copy the string terminator. This
is not an issue in this case since the buffer for the utf8 string is zeroed out to begin
with (this memory was allocated using kzalloc()). The return value of the utf16s_to_utf8s()
is the length of the utf8s string as what would be returned by strlen. I add one to take into account
the string terminator character for further processing. As I said before the MAX value takes into
account the terminating character for all the strings handled.
Regards,
K. Y
From: Dan Carpenter <hidden> Date: 2012-03-12 05:20:15
On Sun, Mar 11, 2012 at 08:53:57PM +0000, KY Srinivasan wrote:
quoted
-----Original Message-----
From: Dan Carpenter [mailto:dan.carpenter@oracle.com]
Sent: Sunday, March 11, 2012 2:49 PM
To: KY Srinivasan
Cc: gregkh@linuxfoundation.org; linux-kernel@vger.kernel.org;
devel@linuxdriverproject.org; virtualization@lists.osdl.org; ohering@suse.com;
Alan Stern
Subject: Re: [PATCH 2/4] Drivers: hv: Support the newly introduced KVP
messages in the driver
On Sun, Mar 11, 2012 at 04:56:06PM +0000, KY Srinivasan wrote:
quoted
quoted
Probably that's not enough to make a difference and we'd need to
introduce a new function.
Btw I don't know if utf16s_to_utf8s() counts the NUL char or not.
It feels like maybe we could end up with ->value_size equal to
HV_KVP_EXCHANGE_MAX_VALUE_SIZE + 1.
The MAX value is set to accommodate the maximum string that will ever
be handled including the string terminator. The function utf16s_to_utf8s()
returns the converted string length but the returned length does not
include the string terminator (like strlen), hence the "+1".
sprintf() and friends copy the NUL terminator but utf16s_to_utf8s()
doesn't so the code isn't right and it does seem like maybe we could
end up with a ->value_size equal to HV_KVP_EXCHANGE_MAX_VALUE_SIZE +
1.
You are right in that utf16s_to_utf8s() does not copy the string
terminator. This is not an issue in this case since the buffer for
the utf8 string is zeroed out to begin with (this memory was
allocated using kzalloc()). The return value of the
utf16s_to_utf8s() is the length of the utf8s string as what would
be returned by strlen.
There is no strlen() involved... It returns the number of bytes
copied to the output string. It doesn't copy a NUL. We pass
HV_KVP_EXCHANGE_MAX_VALUE_SIZE bytes as the limit. So it fills up
the buffer with non-null characters and we have an off-by-one.
I add one to take into account the string
terminator character for further processing. As I said before the
MAX value takes into account the terminating character for all the
strings handled.
So you're saying that since we control the input string, we'll never
hit the max? Still, why not pass HV_KVP_EXCHANGE_MAX_VALUE_SIZE - 1
to leave room for the NUL just for correctness? We'd still add one
to the return value but we wouldn't go over the size of the buffer.
Again, I don't really know how utf16s_to_utf8s() works so I might
have misunderstood.
regards,
dan carpenter
From: KY Srinivasan <kys@microsoft.com> Date: 2012-03-12 12:37:14
-----Original Message-----
From: Dan Carpenter [mailto:dan.carpenter@oracle.com]
Sent: Monday, March 12, 2012 1:22 AM
To: KY Srinivasan
Cc: gregkh@linuxfoundation.org; ohering@suse.com; linux-
kernel@vger.kernel.org; virtualization@lists.osdl.org; Alan Stern;
devel@linuxdriverproject.org
Subject: Re: [PATCH 2/4] Drivers: hv: Support the newly introduced KVP
messages in the driver
On Sun, Mar 11, 2012 at 08:53:57PM +0000, KY Srinivasan wrote:
quoted
quoted
-----Original Message-----
From: Dan Carpenter [mailto:dan.carpenter@oracle.com]
Sent: Sunday, March 11, 2012 2:49 PM
To: KY Srinivasan
Cc: gregkh@linuxfoundation.org; linux-kernel@vger.kernel.org;
devel@linuxdriverproject.org; virtualization@lists.osdl.org;
ohering@suse.com;
quoted
quoted
Alan Stern
Subject: Re: [PATCH 2/4] Drivers: hv: Support the newly introduced KVP
messages in the driver
On Sun, Mar 11, 2012 at 04:56:06PM +0000, KY Srinivasan wrote:
quoted
quoted
Probably that's not enough to make a difference and we'd need to
introduce a new function.
Btw I don't know if utf16s_to_utf8s() counts the NUL char or not.
It feels like maybe we could end up with ->value_size equal to
HV_KVP_EXCHANGE_MAX_VALUE_SIZE + 1.
The MAX value is set to accommodate the maximum string that will ever
be handled including the string terminator. The function utf16s_to_utf8s()
returns the converted string length but the returned length does not
include the string terminator (like strlen), hence the "+1".
sprintf() and friends copy the NUL terminator but utf16s_to_utf8s()
doesn't so the code isn't right and it does seem like maybe we could
end up with a ->value_size equal to HV_KVP_EXCHANGE_MAX_VALUE_SIZE
+
quoted
quoted
1.
You are right in that utf16s_to_utf8s() does not copy the string
terminator. This is not an issue in this case since the buffer for
the utf8 string is zeroed out to begin with (this memory was
allocated using kzalloc()). The return value of the
utf16s_to_utf8s() is the length of the utf8s string as what would
be returned by strlen.
There is no strlen() involved... It returns the number of bytes
copied to the output string. It doesn't copy a NUL. We pass
HV_KVP_EXCHANGE_MAX_VALUE_SIZE bytes as the limit. So it fills up
the buffer with non-null characters and we have an off-by-one.
Dan,
I am sorry for not being as precise as I should be:
utf16s_to_utf8s() takes two length parameters - the length of the utf16 string
that is to be converted and the second the length of the utf8 output string.
The windows host manipulates all string in utf16 encoding and the string we get
from the host is guaranteed to be less than or equal to MAX value that we have
including the terminating character. In my code, I simply pass the length of the
utf16 string as received from the host.
The parameter that I am currently passing MAX length value is the "maxout"
parameter of the utf16s_utf8s() function. This by definition is the size of the
output buffer and in this case it happens to be MAX characters big.
quoted
I add one to take into account the string
terminator character for further processing. As I said before the
MAX value takes into account the terminating character for all the
strings handled.
So you're saying that since we control the input string, we'll never
hit the max? Still, why not pass HV_KVP_EXCHANGE_MAX_VALUE_SIZE - 1
to leave room for the NUL just for correctness? We'd still add one
to the return value but we wouldn't go over the size of the buffer.
As I described earlier, with the host side guarantee that the string we get from
the host is always guaranteed to be less than or equal to MAX length
(including the terminating character), there is no question of going over the
size of the output buffer which is sized based on the host specification.
Regards,
K. Y
From: Dan Carpenter <hidden> Date: 2012-03-12 13:01:34
On Mon, Mar 12, 2012 at 12:36:53PM +0000, KY Srinivasan wrote:
Dan,
I am sorry for not being as precise as I should be:
utf16s_to_utf8s() takes two length parameters - the length of the utf16 string
that is to be converted and the second the length of the utf8 output string.
The windows host manipulates all string in utf16 encoding and the string we get
from the host is guaranteed to be less than or equal to MAX value that we have
including the terminating character. In my code, I simply pass the length of the
utf16 string as received from the host.
The parameter that I am currently passing MAX length value is the "maxout"
parameter of the utf16s_utf8s() function. This by definition is the size of the
output buffer and in this case it happens to be MAX characters big.
I also think I'm not being as clear as I should... I understand
that you trust the input; I'm say that for correctness sake you
should specify a output size which leaves room for the NUL char.
I can't say I know this code very well so I could be wrong, but it's
what we do inside usb_string() for example. Can someone who knows
the code check if we should do something like this:
On Sat, Mar 10, 2012 at 03:31:40PM -0800, K. Y. Srinivasan wrote:
This patch-set further enhances the KVP functionality for Linux
guests:
1. Supports most of the Win8 KVP protocol.
2. Supports operations on all the pools.
I've only applied the first patch, due to the issues with the second.
Feel free to resend the rest when you have them worked out.
greg k-h
From: KY Srinivasan <kys@microsoft.com> Date: 2012-03-15 23:27:10
-----Original Message-----
From: Greg KH [mailto:gregkh@linuxfoundation.org]
Sent: Tuesday, March 13, 2012 5:51 PM
To: KY Srinivasan
Cc: linux-kernel@vger.kernel.org; devel@linuxdriverproject.org;
virtualization@lists.osdl.org; ohering@suse.com
Subject: Re: [PATCH 0000/0004] drivers: hv
On Sat, Mar 10, 2012 at 03:31:40PM -0800, K. Y. Srinivasan wrote:
quoted
This patch-set further enhances the KVP functionality for Linux
guests:
1. Supports most of the Win8 KVP protocol.
2. Supports operations on all the pools.
I've only applied the first patch, due to the issues with the second.
Feel free to resend the rest when you have them worked out.
Thanks Greg. I don't think there are any substantive issues with the remaining
patches. I will fix them up and re-send them soon.
K. Y
From: KY Srinivasan <kys@microsoft.com> Date: 2012-03-15 23:36:25
-----Original Message-----
From: Dan Carpenter [mailto:dan.carpenter@oracle.com]
Sent: Monday, March 12, 2012 9:04 AM
To: KY Srinivasan
Cc: gregkh@linuxfoundation.org; ohering@suse.com; linux-
kernel@vger.kernel.org; virtualization@lists.osdl.org; Alan Stern;
devel@linuxdriverproject.org
Subject: Re: [PATCH 2/4] Drivers: hv: Support the newly introduced KVP
messages in the driver
On Mon, Mar 12, 2012 at 12:36:53PM +0000, KY Srinivasan wrote:
quoted
Dan,
I am sorry for not being as precise as I should be:
utf16s_to_utf8s() takes two length parameters - the length of the utf16 string
that is to be converted and the second the length of the utf8 output string.
The windows host manipulates all string in utf16 encoding and the string we get
from the host is guaranteed to be less than or equal to MAX value that we have
including the terminating character. In my code, I simply pass the length of the
utf16 string as received from the host.
The parameter that I am currently passing MAX length value is the "maxout"
parameter of the utf16s_utf8s() function. This by definition is the size of the
output buffer and in this case it happens to be MAX characters big.
I also think I'm not being as clear as I should... I understand
that you trust the input; I'm say that for correctness sake you
should specify a output size which leaves room for the NUL char.
I can't say I know this code very well so I could be wrong, but it's
what we do inside usb_string() for example. Can someone who knows
the code check if we should do something like this:
Dan,
Sorry I could not get back to you earlier. You are right, in that I am trusting
the host! I am of the firm belief that in a virtualized environment, if you don't trust
the host, there is not a whole lot you can do in a guest! I have had this arguments
with other on this mailing list in the past. Having said that, I think we have spent more
time debating this than we should; your proposal is reasonable and I will go ahead and
re-spin those patches based on your comments. I should be posting them shortly.
Regards,
K. Y
From: Dan Carpenter <hidden> Date: 2012-03-16 05:36:23
On Thu, Mar 15, 2012 at 11:36:16PM +0000, KY Srinivasan wrote:
Dan,
Sorry I could not get back to you earlier. You are right, in that I am trusting
the host! I am of the firm belief that in a virtualized environment, if you don't trust
the host, there is not a whole lot you can do in a guest! I have had this arguments
with other on this mailing list in the past. Having said that, I think we have spent more
time debating this than we should; your proposal is reasonable and I will go ahead and
re-spin those patches based on your comments. I should be posting them shortly.
Regards,
It's not about trusting the host or not trusting the host. It's
about "if you're going to specify a limitter, it can't be off by one
even if you don't expect to hit the limit".
But thanks for redoing these.
regards,
dan carpenter
From: KY Srinivasan <kys@microsoft.com> Date: 2012-03-16 05:43:22
-----Original Message-----
From: Dan Carpenter [mailto:dan.carpenter@oracle.com]
Sent: Friday, March 16, 2012 1:38 AM
To: KY Srinivasan
Cc: gregkh@linuxfoundation.org; ohering@suse.com; linux-
kernel@vger.kernel.org; virtualization@lists.osdl.org; Alan Stern;
devel@linuxdriverproject.org
Subject: Re: [PATCH 2/4] Drivers: hv: Support the newly introduced KVP
messages in the driver
On Thu, Mar 15, 2012 at 11:36:16PM +0000, KY Srinivasan wrote:
quoted
Dan,
Sorry I could not get back to you earlier. You are right, in that I am trusting
the host! I am of the firm belief that in a virtualized environment, if you don't
trust
quoted
the host, there is not a whole lot you can do in a guest! I have had this
arguments
quoted
with other on this mailing list in the past. Having said that, I think we have spent
more
quoted
time debating this than we should; your proposal is reasonable and I will go
ahead and
quoted
re-spin those patches based on your comments. I should be posting them
shortly.
quoted
Regards,
It's not about trusting the host or not trusting the host. It's
about "if you're going to specify a limitter, it can't be off by one
even if you don't expect to hit the limit".
But thanks for redoing these.
Thank you, for taking the time to review.
Regards,
K. Y