Re: [PATCH v2 1/2 RESEND] staging: dgnc: remove dead code in dgnc_tty_write()

2015-04-11 Thread Giedrius Statkevičius
On Sat, 11 Apr 2015, Sudip Mukherjee wrote:

> On Fri, Apr 10, 2015 at 05:48:54PM +0300, Giedrius Statkevičius wrote:
> > Remove the dead code protected by in_user in dgnc_tty_write() because it is 
> > set
> > to 0 and never changed to 1 thus the code in ifs never gets executed.
> dgnc_tty_write() is being called by dgnc_tty_put_char() and it is also
> the write callback function of struct tty_operations, so I think the
> correct fix will be to use from_user and make it 0 when
> dgnc_tty_put_char() calls this function else make it 1 to inform the
> function that the data wil be coming from the userspace. Maybe some
> thing like this:
Well, I think this is wrong because:
* parameter of write member of struct tty_operations buf is not tagged with
  "__user" so it should be safe to just memcpy() from it
* Looked through some other write operations in other tty drivers and I've never
  seen copy_from_user() used on buf argument of write operation - always
  memcpy() or some other similar function
* Ldd3 (and the comments in tty_driver.h) says that write could be called from
  interrupt context too so it can't sleep and thus use copy_from_user()

While looking through I've caught that dgnc_TmpWriteBuf could be also deleted
because it will be unused if this patch goes through. If it does then I'll send
another one (or should I send a v3?)

Su pagarba / Regards,
Giedrius___
devel mailing list
de...@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel


Re: [PATCH v2 1/2 RESEND] staging: dgnc: remove dead code in dgnc_tty_write()

2015-04-11 Thread Sudip Mukherjee
On Sat, Apr 11, 2015 at 03:20:43PM +0300, Giedrius Statkevičius wrote:
> On Sat, 11 Apr 2015, Sudip Mukherjee wrote:
> 
> > On Fri, Apr 10, 2015 at 05:48:54PM +0300, Giedrius Statkevičius wrote:
> Well, I think this is wrong because:

yes. I looked at many of the tty drivers and all of them have used
memcpy(). Sorry for my last mail, i should have written that after
seeing all other similar drivers and maybe once in a while i should
go back to LDD3. :)

regards
sudip

> 
> Su pagarba / Regards,
> Giedrius

___
devel mailing list
de...@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel


[PATCH 10/21] Drivers: hv: vss: switch to using the hvutil_device_state state machine

2015-04-11 Thread K. Y. Srinivasan
From: Vitaly Kuznetsov 

Switch to using the hvutil_device_state state machine from using 
kvp_transaction.active.

State transitions are:
-> HVUTIL_DEVICE_INIT when driver loads or on device release
-> HVUTIL_READY if the handshake was successful
-> HVUTIL_HOSTMSG_RECEIVED when there is a non-negotiation message from the host
-> HVUTIL_USERSPACE_REQ after we sent the message to the userspace daemon
   -> HVUTIL_USERSPACE_RECV after/if the userspace daemon has replied
-> HVUTIL_READY after we respond to the host
-> HVUTIL_DEVICE_DYING on driver unload

In hv_vss_onchannelcallback() process ICMSGTYPE_NEGOTIATE messages even when
the userspace daemon is disconnected, otherwise we can make the host think
we don't support VSS and disable the service completely.

Unfortunately there is no good way we can figure out that the userspace daemon
has died (unless we start treating all timeouts as such), add a protection
against processing new VSS_OP_REGISTER messages while being in the middle of a
transaction (HVUTIL_USERSPACE_REQ or HVUTIL_USERSPACE_RECV state).

Signed-off-by: Vitaly Kuznetsov 
Tested-by: Alex Ng 
Signed-off-by: K. Y. Srinivasan 
---
 drivers/hv/hv_snapshot.c |   87 ++---
 1 files changed, 58 insertions(+), 29 deletions(-)

diff --git a/drivers/hv/hv_snapshot.c b/drivers/hv/hv_snapshot.c
index 4bb9b1c..ddb1cda 100644
--- a/drivers/hv/hv_snapshot.c
+++ b/drivers/hv/hv_snapshot.c
@@ -33,16 +33,21 @@
 #define VSS_USERSPACE_TIMEOUT (msecs_to_jiffies(10 * 1000))
 
 /*
- * Global state maintained for transaction that is being processed.
- * Note that only one transaction can be active at any point in time.
+ * Global state maintained for transaction that is being processed. For a class
+ * of integration services, including the "VSS service", the specified protocol
+ * is a "request/response" protocol which means that there can only be single
+ * outstanding transaction from the host at any given point in time. We use
+ * this to simplify memory management in this driver - we cache and process
+ * only one message at a time.
  *
- * This state is set when we receive a request from the host; we
- * cleanup this state when the transaction is completed - when we respond
- * to the host with the key value.
+ * While the request/response protocol is guaranteed by the host, we further
+ * ensure this by serializing packet processing in this driver - we do not
+ * read additional packets from the VMBUs until the current packet is fully
+ * handled.
  */
 
 static struct {
-   bool active; /* transaction status - active or not */
+   int state;   /* hvutil_device_state */
int recv_len; /* number of bytes received. */
struct vmbus_channel *recv_channel; /* chn we got the request */
u64 recv_req_id; /* request ID. */
@@ -75,6 +80,10 @@ static void vss_timeout_func(struct work_struct *dummy)
pr_warn("VSS: timeout waiting for daemon to reply\n");
vss_respond_to_host(HV_E_FAIL);
 
+   /* Transaction is finished, reset the state. */
+   if (vss_transaction.state > HVUTIL_READY)
+   vss_transaction.state = HVUTIL_READY;
+
hv_poll_channel(vss_transaction.vss_context,
hv_vss_onchannelcallback);
 }
@@ -86,15 +95,32 @@ vss_cn_callback(struct cn_msg *msg, struct 
netlink_skb_parms *nsp)
 
vss_msg = (struct hv_vss_msg *)msg->data;
 
-   if (vss_msg->vss_hdr.operation == VSS_OP_REGISTER) {
+   /*
+* Don't process registration messages if we're in the middle of
+* a transaction processing.
+*/
+   if (vss_transaction.state > HVUTIL_READY &&
+   vss_msg->vss_hdr.operation == VSS_OP_REGISTER)
+   return;
+
+   if (vss_transaction.state == HVUTIL_DEVICE_INIT &&
+   vss_msg->vss_hdr.operation == VSS_OP_REGISTER) {
pr_info("VSS daemon registered\n");
-   vss_transaction.active = false;
+   vss_transaction.state = HVUTIL_READY;
+   } else if (vss_transaction.state == HVUTIL_USERSPACE_REQ) {
+   vss_transaction.state = HVUTIL_USERSPACE_RECV;
+   if (cancel_delayed_work_sync(&vss_timeout_work)) {
+   vss_respond_to_host(vss_msg->error);
+   /* Transaction is finished, reset the state. */
+   vss_transaction.state = HVUTIL_READY;
+   hv_poll_channel(vss_transaction.vss_context,
+   hv_vss_onchannelcallback);
+   }
+   } else {
+   /* This is a spurious call! */
+   pr_warn("VSS: Transaction not active\n");
+   return;
}
-   if (cancel_delayed_work_sync(&vss_timeout_work))
-   vss_respond_to_host(vss_msg->error);
-
-   hv_poll_channel(vss_transaction.vss_context,
-   hv_vss_onchannelcallback);
 }
 
 
@@ -105,6 +131,10 @@ static void vss_send_op(s

[PATCH 21/21] Drivers: hv: utils: unify driver registration reporting

2015-04-11 Thread K. Y. Srinivasan
From: Vitaly Kuznetsov 

Unify driver registration reporting and move it to debug level as normally 
daemons write to syslog themselves
and these kernel messages are useless.

Signed-off-by: Vitaly Kuznetsov 
Tested-by: Alex Ng 
Signed-off-by: K. Y. Srinivasan 
---
 drivers/hv/hv_fcopy.c|3 +--
 drivers/hv/hv_kvp.c  |3 ++-
 drivers/hv/hv_snapshot.c |2 +-
 3 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/hv/hv_fcopy.c b/drivers/hv/hv_fcopy.c
index b7b528c..b50dd33 100644
--- a/drivers/hv/hv_fcopy.c
+++ b/drivers/hv/hv_fcopy.c
@@ -107,8 +107,7 @@ static int fcopy_handle_handshake(u32 version)
 */
return -EINVAL;
}
-   pr_info("FCP: user-mode registering done. Daemon version: %d\n",
-   version);
+   pr_debug("FCP: userspace daemon ver. %d registered\n", version);
fcopy_transaction.state = HVUTIL_READY;
hv_poll_channel(fcopy_transaction.fcopy_context,
hv_fcopy_onchannelcallback);
diff --git a/drivers/hv/hv_kvp.c b/drivers/hv/hv_kvp.c
index baa1208..d85798d 100644
--- a/drivers/hv/hv_kvp.c
+++ b/drivers/hv/hv_kvp.c
@@ -150,7 +150,8 @@ static int kvp_handle_handshake(struct hv_kvp_msg *msg)
/*
 * We have a compatible daemon; complete the handshake.
 */
-   pr_info("KVP: user-mode registering done.\n");
+   pr_debug("KVP: userspace daemon ver. %d registered\n",
+KVP_OP_REGISTER);
kvp_register(dm_reg_value);
kvp_transaction.state = HVUTIL_READY;
 
diff --git a/drivers/hv/hv_snapshot.c b/drivers/hv/hv_snapshot.c
index ee1762b..815405f 100644
--- a/drivers/hv/hv_snapshot.c
+++ b/drivers/hv/hv_snapshot.c
@@ -113,7 +113,7 @@ static int vss_handle_handshake(struct hv_vss_msg *vss_msg)
return -EINVAL;
}
vss_transaction.state = HVUTIL_READY;
-   pr_info("VSS daemon registered\n");
+   pr_debug("VSS: userspace daemon ver. %d registered\n", dm_reg_value);
return 0;
 }
 
-- 
1.7.4.1

___
devel mailing list
de...@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel


[PATCH 00/21] Drivers: hv: utils: re-implement the kernel/userspace communication layer

2015-04-11 Thread K. Y. Srinivasan
Changes in v3:
- Removed RFC from subject, rebased on top of current char-misc-next tree.

RFCv2: 
http://driverdev.linuxdriverproject.org/pipermail/driverdev-devel/2015-March/066629.html

Anatomy of the series:
Patches 01 - 07 are cleanup with minor functional change.
Patch 08 defines the state machine.
Patches 09-11 convert all 3 drivers to using the state machine.
Patch 12 fixes a bug in fcopy. This change is going away in Patch 15,
 I just want to highlight the fix.
Patch 13 introduces a transport abstraction.
Patch 14-16 convert all drivers to using the transport abstraction.
Patches 17-18 switch KVP and VSS daemon to using char devices.
Patches 19-20 convert FCOPY and VSS to hull handshake (the same we have in
 KVP). These two can be postponed till we really need to distinguish between
 different kernels in the daemon code.
Patch 21 unifies log messages on daemons connect across all drivers and moves
 these messages to debug level.

I smoke-tested this series with both old (netlink) and new (char devices)
daemons and tested the daemon upgrade procedure.

Original description:
This series converts kvp/vss daemons to use misc char devices instead of
netlink for userspace/kernel communication and then updates fcopy to be
consistent with kvp/vss.

Userspace/kernel communication via netlink has a number of issues:
- It is hard for userspace to figure out if the kernel part was loaded or not
  and this fact can change as there is a way to enable/disable the service from
  host side. Racy daemon startup is also a problem.
- When the userspace daemon restarts/dies kernel part doesn't receive a
  notification.
- Netlink communication is not stable under heavy load.
- ...


Vitaly Kuznetsov (21):
  Drivers: hv: util: move kvp/vss function declarations to
hyperv_vmbus.h
  Drivers: hv: kvp: reset kvp_context
  Drivers: hv: kvp: move poll_channel() to hyperv_vmbus.h
  Drivers: hv: fcopy: process deferred messages when we complete the
transaction
  Drivers: hv: vss: process deferred messages when we complete the
transaction
  Drivers: hv: kvp: rename kvp_work -> kvp_timeout_work
  Drivers: hv: fcopy: rename fcopy_work -> fcopy_timeout_work
  Drivers: hv: util: introduce state machine for util drivers
  Drivers: hv: kvp: switch to using the hvutil_device_state state
machine
  Drivers: hv: vss: switch to using the hvutil_device_state state
machine
  Drivers: hv: fcopy: switch to using the hvutil_device_state state
machine
  Drivers: hv: fcopy: set .owner reference for file operations
  Drivers: hv: util: introduce hv_utils_transport abstraction
  Drivers: hv: vss: convert to hv_utils_transport
  Drivers: hv: fcopy: convert to hv_utils_transport
  Drivers: hv: kvp: convert to hv_utils_transport
  Tools: hv: kvp: use misc char device to communicate with kernel
  Tools: hv: vss: use misc char device to communicate with kernel
  Drivers: hv: vss: full handshake support
  Drivers: hv: fcopy: full handshake support
  Drivers: hv: utils: unify driver registration reporting

 drivers/hv/Makefile |2 +-
 drivers/hv/hv_fcopy.c   |  287 +--
 drivers/hv/hv_kvp.c |  192 +-
 drivers/hv/hv_snapshot.c|  168 ---
 drivers/hv/hv_utils_transport.c |  276 +
 drivers/hv/hv_utils_transport.h |   51 +++
 drivers/hv/hyperv_vmbus.h   |   29 
 include/linux/hyperv.h  |7 -
 include/uapi/linux/hyperv.h |8 +-
 tools/hv/hv_fcopy_daemon.c  |   15 ++
 tools/hv/hv_kvp_daemon.c|  166 --
 tools/hv/hv_vss_daemon.c|  149 +---
 12 files changed, 752 insertions(+), 598 deletions(-)
 create mode 100644 drivers/hv/hv_utils_transport.c
 create mode 100644 drivers/hv/hv_utils_transport.h

-- 
1.7.4.1

___
devel mailing list
de...@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel


[PATCH 04/21] Drivers: hv: fcopy: process deferred messages when we complete the transaction

2015-04-11 Thread K. Y. Srinivasan
From: Vitaly Kuznetsov 

In theory, the host is not supposed to issue any requests before be reply to
the previous one. In KVP we, however, support the following scenarios:
1) A message was received before userspace daemon registered;
2) A message was received while the previous one is still being processed.
In FCOPY we support only the former. Add support for the later, use
hv_poll_channel() to do the job.

Signed-off-by: Vitaly Kuznetsov 
Tested-by: Alex Ng 
Signed-off-by: K. Y. Srinivasan 
---
 drivers/hv/hv_fcopy.c |   12 +---
 1 files changed, 9 insertions(+), 3 deletions(-)

diff --git a/drivers/hv/hv_fcopy.c b/drivers/hv/hv_fcopy.c
index cd453e4..8bdf752 100644
--- a/drivers/hv/hv_fcopy.c
+++ b/drivers/hv/hv_fcopy.c
@@ -98,6 +98,8 @@ static void fcopy_work_func(struct work_struct *dummy)
if (down_trylock(&fcopy_transaction.read_sema))
;
 
+   hv_poll_channel(fcopy_transaction.fcopy_context,
+   hv_fcopy_onchannelcallback);
 }
 
 static int fcopy_handle_handshake(u32 version)
@@ -117,8 +119,8 @@ static int fcopy_handle_handshake(u32 version)
pr_info("FCP: user-mode registering done. Daemon version: %d\n",
version);
fcopy_transaction.active = false;
-   if (fcopy_transaction.fcopy_context)
-   hv_fcopy_onchannelcallback(fcopy_transaction.fcopy_context);
+   hv_poll_channel(fcopy_transaction.fcopy_context,
+   hv_fcopy_onchannelcallback);
in_hand_shake = false;
return 0;
 }
@@ -226,6 +228,7 @@ void hv_fcopy_onchannelcallback(void *context)
fcopy_transaction.fcopy_context = context;
return;
}
+   fcopy_transaction.fcopy_context = NULL;
 
vmbus_recvpacket(channel, recv_buffer, PAGE_SIZE * 2, &recvlen,
 &requestid);
@@ -333,8 +336,11 @@ static ssize_t fcopy_write(struct file *file, const char 
__user *buf,
 * Complete the transaction by forwarding the result
 * to the host. But first, cancel the timeout.
 */
-   if (cancel_delayed_work_sync(&fcopy_work))
+   if (cancel_delayed_work_sync(&fcopy_work)) {
fcopy_respond_to_host(response);
+   hv_poll_channel(fcopy_transaction.fcopy_context,
+   hv_fcopy_onchannelcallback);
+   }
 
return sizeof(int);
 }
-- 
1.7.4.1

___
devel mailing list
de...@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel


[PATCH 20/21] Drivers: hv: fcopy: full handshake support

2015-04-11 Thread K. Y. Srinivasan
From: Vitaly Kuznetsov 

Introduce FCOPY_VERSION_1 to support kernel replying to the negotiation
message with its own version.

Signed-off-by: Vitaly Kuznetsov 
Tested-by: Alex Ng 
Signed-off-by: K. Y. Srinivasan 
---
 drivers/hv/hv_fcopy.c   |   16 +++-
 include/uapi/linux/hyperv.h |3 ++-
 tools/hv/hv_fcopy_daemon.c  |   15 +++
 3 files changed, 32 insertions(+), 2 deletions(-)

diff --git a/drivers/hv/hv_fcopy.c b/drivers/hv/hv_fcopy.c
index 6a8ec9f..b7b528c 100644
--- a/drivers/hv/hv_fcopy.c
+++ b/drivers/hv/hv_fcopy.c
@@ -62,6 +62,10 @@ static DECLARE_WORK(fcopy_send_work, fcopy_send_data);
 static const char fcopy_devname[] = "vmbus/hv_fcopy";
 static u8 *recv_buffer;
 static struct hvutil_transport *hvt;
+/*
+ * This state maintains the version number registered by the daemon.
+ */
+static int dm_reg_value;
 
 static void fcopy_timeout_func(struct work_struct *dummy)
 {
@@ -81,8 +85,18 @@ static void fcopy_timeout_func(struct work_struct *dummy)
 
 static int fcopy_handle_handshake(u32 version)
 {
+   u32 our_ver = FCOPY_CURRENT_VERSION;
+
switch (version) {
-   case FCOPY_CURRENT_VERSION:
+   case FCOPY_VERSION_0:
+   /* Daemon doesn't expect us to reply */
+   dm_reg_value = version;
+   break;
+   case FCOPY_VERSION_1:
+   /* Daemon expects us to reply with our own version */
+   if (hvutil_transport_send(hvt, &our_ver, sizeof(our_ver)))
+   return -EFAULT;
+   dm_reg_value = version;
break;
default:
/*
diff --git a/include/uapi/linux/hyperv.h b/include/uapi/linux/hyperv.h
index 66c76df..e4c0a35 100644
--- a/include/uapi/linux/hyperv.h
+++ b/include/uapi/linux/hyperv.h
@@ -105,7 +105,8 @@ struct hv_vss_msg {
  */
 
 #define FCOPY_VERSION_0 0
-#define FCOPY_CURRENT_VERSION FCOPY_VERSION_0
+#define FCOPY_VERSION_1 1
+#define FCOPY_CURRENT_VERSION FCOPY_VERSION_1
 #define W_MAX_PATH 260
 
 enum hv_fcopy_op {
diff --git a/tools/hv/hv_fcopy_daemon.c b/tools/hv/hv_fcopy_daemon.c
index 9445d8f..5480e4e 100644
--- a/tools/hv/hv_fcopy_daemon.c
+++ b/tools/hv/hv_fcopy_daemon.c
@@ -137,6 +137,8 @@ int main(int argc, char *argv[])
int version = FCOPY_CURRENT_VERSION;
char *buffer[4096 * 2];
struct hv_fcopy_hdr *in_msg;
+   int in_handshake = 1;
+   __u32 kernel_modver;
 
static struct option long_options[] = {
{"help",no_argument,   0,  'h' },
@@ -191,6 +193,19 @@ int main(int argc, char *argv[])
syslog(LOG_ERR, "pread failed: %s", strerror(errno));
exit(EXIT_FAILURE);
}
+
+   if (in_handshake) {
+   if (len != sizeof(kernel_modver)) {
+   syslog(LOG_ERR, "invalid version negotiation");
+   exit(EXIT_FAILURE);
+   }
+   kernel_modver = *(__u32 *)buffer;
+   in_handshake = 0;
+   syslog(LOG_INFO, "HV_FCOPY: kernel module version: %d",
+  kernel_modver);
+   continue;
+   }
+
in_msg = (struct hv_fcopy_hdr *)buffer;
 
switch (in_msg->operation) {
-- 
1.7.4.1

___
devel mailing list
de...@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel


[PATCH 02/21] Drivers: hv: kvp: reset kvp_context

2015-04-11 Thread K. Y. Srinivasan
From: Vitaly Kuznetsov 

We set kvp_context when we want to postpone receiving a packet from vmbus due
to the previous transaction being unfinished. We, however, never reset this
state, all consequent kvp_respond_to_host() calls will result in poll_channel()
calling hv_kvp_onchannelcallback(). This doesn't cause real issues as:
1) Host is supposed to serialize transactions as well
2) If no message is pending vmbus_recvpacket() will return 0 recvlen.
This is just a cleanup.

Signed-off-by: Vitaly Kuznetsov 
Tested-by: Alex Ng 
Signed-off-by: K. Y. Srinivasan 
---
 drivers/hv/hv_kvp.c |1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/drivers/hv/hv_kvp.c b/drivers/hv/hv_kvp.c
index a414c83..caa467d 100644
--- a/drivers/hv/hv_kvp.c
+++ b/drivers/hv/hv_kvp.c
@@ -621,6 +621,7 @@ void hv_kvp_onchannelcallback(void *context)
kvp_transaction.kvp_context = context;
return;
}
+   kvp_transaction.kvp_context = NULL;
 
vmbus_recvpacket(channel, recv_buffer, PAGE_SIZE * 4, &recvlen,
 &requestid);
-- 
1.7.4.1

___
devel mailing list
de...@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel


[PATCH 01/21] Drivers: hv: util: move kvp/vss function declarations to hyperv_vmbus.h

2015-04-11 Thread K. Y. Srinivasan
From: Vitaly Kuznetsov 

These declarations are internal to hv_util module and hv_fcopy_* declarations
already reside there.

Signed-off-by: Vitaly Kuznetsov 
Tested-by: Alex Ng 
Signed-off-by: K. Y. Srinivasan 
---
 drivers/hv/hv_kvp.c   |1 +
 drivers/hv/hv_snapshot.c  |2 ++
 drivers/hv/hyperv_vmbus.h |8 
 include/linux/hyperv.h|7 ---
 4 files changed, 11 insertions(+), 7 deletions(-)

diff --git a/drivers/hv/hv_kvp.c b/drivers/hv/hv_kvp.c
index beb8105..a414c83 100644
--- a/drivers/hv/hv_kvp.c
+++ b/drivers/hv/hv_kvp.c
@@ -28,6 +28,7 @@
 #include 
 #include 
 
+#include "hyperv_vmbus.h"
 
 /*
  * Pre win8 version numbers used in ws2008 and ws 2008 r2 (win7)
diff --git a/drivers/hv/hv_snapshot.c b/drivers/hv/hv_snapshot.c
index 9d5e0d1..c1a3604 100644
--- a/drivers/hv/hv_snapshot.c
+++ b/drivers/hv/hv_snapshot.c
@@ -24,6 +24,8 @@
 #include 
 #include 
 
+#include "hyperv_vmbus.h"
+
 #define VSS_MAJOR  5
 #define VSS_MINOR  0
 #define VSS_VERSION(VSS_MAJOR << 16 | VSS_MINOR)
diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h
index 887287a..ddcf6c4 100644
--- a/drivers/hv/hyperv_vmbus.h
+++ b/drivers/hv/hyperv_vmbus.h
@@ -730,6 +730,14 @@ int vmbus_set_event(struct vmbus_channel *channel);
 
 void vmbus_on_event(unsigned long data);
 
+int hv_kvp_init(struct hv_util_service *);
+void hv_kvp_deinit(void);
+void hv_kvp_onchannelcallback(void *);
+
+int hv_vss_init(struct hv_util_service *);
+void hv_vss_deinit(void);
+void hv_vss_onchannelcallback(void *);
+
 int hv_fcopy_init(struct hv_util_service *);
 void hv_fcopy_deinit(void);
 void hv_fcopy_onchannelcallback(void *);
diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h
index 902c37a..1744148 100644
--- a/include/linux/hyperv.h
+++ b/include/linux/hyperv.h
@@ -1236,13 +1236,6 @@ extern bool vmbus_prep_negotiate_resp(struct icmsg_hdr *,
struct icmsg_negotiate *, u8 *, int,
int);
 
-int hv_kvp_init(struct hv_util_service *);
-void hv_kvp_deinit(void);
-void hv_kvp_onchannelcallback(void *);
-
-int hv_vss_init(struct hv_util_service *);
-void hv_vss_deinit(void);
-void hv_vss_onchannelcallback(void *);
 void hv_process_channel_removal(struct vmbus_channel *channel, u32 relid);
 
 extern struct resource hyperv_mmio;
-- 
1.7.4.1

___
devel mailing list
de...@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel


[PATCH 03/21] Drivers: hv: kvp: move poll_channel() to hyperv_vmbus.h

2015-04-11 Thread K. Y. Srinivasan
From: Vitaly Kuznetsov 

Move poll_channel() to hyperv_vmbus.h and make it inline and rename it to 
hv_poll_channel() so it can be reused
in other hv_util modules.

Signed-off-by: Vitaly Kuznetsov 
Tested-by: Alex Ng 
Signed-off-by: K. Y. Srinivasan 
---
 drivers/hv/hv_kvp.c   |   17 +++--
 drivers/hv/hyperv_vmbus.h |   12 
 2 files changed, 15 insertions(+), 14 deletions(-)

diff --git a/drivers/hv/hv_kvp.c b/drivers/hv/hv_kvp.c
index caa467d..939c3e7 100644
--- a/drivers/hv/hv_kvp.c
+++ b/drivers/hv/hv_kvp.c
@@ -128,17 +128,6 @@ kvp_work_func(struct work_struct *dummy)
kvp_respond_to_host(NULL, HV_E_FAIL);
 }
 
-static void poll_channel(struct vmbus_channel *channel)
-{
-   if (channel->target_cpu != smp_processor_id())
-   smp_call_function_single(channel->target_cpu,
-hv_kvp_onchannelcallback,
-channel, true);
-   else
-   hv_kvp_onchannelcallback(channel);
-}
-
-
 static int kvp_handle_handshake(struct hv_kvp_msg *msg)
 {
int ret = 1;
@@ -166,8 +155,8 @@ static int kvp_handle_handshake(struct hv_kvp_msg *msg)
pr_info("KVP: user-mode registering done.\n");
kvp_register(dm_reg_value);
kvp_transaction.active = false;
-   if (kvp_transaction.kvp_context)
-   poll_channel(kvp_transaction.kvp_context);
+   hv_poll_channel(kvp_transaction.kvp_context,
+   hv_kvp_onchannelcallback);
}
return ret;
 }
@@ -587,7 +576,7 @@ response_done:
 
vmbus_sendpacket(channel, recv_buffer, buf_len, req_id,
VM_PKT_DATA_INBAND, 0);
-   poll_channel(channel);
+   hv_poll_channel(channel, hv_kvp_onchannelcallback);
 }
 
 /*
diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h
index ddcf6c4..2f30456 100644
--- a/drivers/hv/hyperv_vmbus.h
+++ b/drivers/hv/hyperv_vmbus.h
@@ -742,5 +742,17 @@ int hv_fcopy_init(struct hv_util_service *);
 void hv_fcopy_deinit(void);
 void hv_fcopy_onchannelcallback(void *);
 
+static inline void hv_poll_channel(struct vmbus_channel *channel,
+  void (*cb)(void *))
+{
+   if (!channel)
+   return;
+
+   if (channel->target_cpu != smp_processor_id())
+   smp_call_function_single(channel->target_cpu,
+cb, channel, true);
+   else
+   cb(channel);
+}
 
 #endif /* _HYPERV_VMBUS_H */
-- 
1.7.4.1

___
devel mailing list
de...@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel


[PATCH 18/21] Tools: hv: vss: use misc char device to communicate with kernel

2015-04-11 Thread K. Y. Srinivasan
From: Vitaly Kuznetsov 

Use /dev/vmbus/hv_vss instead of netlink.

Signed-off-by: Vitaly Kuznetsov 
Tested-by: Alex Ng 
Signed-off-by: K. Y. Srinivasan 
---
 tools/hv/hv_vss_daemon.c |  139 -
 1 files changed, 25 insertions(+), 114 deletions(-)

diff --git a/tools/hv/hv_vss_daemon.c b/tools/hv/hv_vss_daemon.c
index 506dd01..36f1821 100644
--- a/tools/hv/hv_vss_daemon.c
+++ b/tools/hv/hv_vss_daemon.c
@@ -19,7 +19,6 @@
 
 
 #include 
-#include 
 #include 
 #include 
 #include 
@@ -30,21 +29,11 @@
 #include 
 #include 
 #include 
-#include 
 #include 
-#include 
 #include 
-#include 
 #include 
 #include 
 
-static struct sockaddr_nl addr;
-
-#ifndef SOL_NETLINK
-#define SOL_NETLINK 270
-#endif
-
-
 /* Don't use syslog() in the function since that can cause write to disk */
 static int vss_do_freeze(char *dir, unsigned int cmd)
 {
@@ -143,33 +132,6 @@ out:
return error;
 }
 
-static int netlink_send(int fd, struct cn_msg *msg)
-{
-   struct nlmsghdr nlh = { .nlmsg_type = NLMSG_DONE };
-   unsigned int size;
-   struct msghdr message;
-   struct iovec iov[2];
-
-   size = sizeof(struct cn_msg) + msg->len;
-
-   nlh.nlmsg_pid = getpid();
-   nlh.nlmsg_len = NLMSG_LENGTH(size);
-
-   iov[0].iov_base = &nlh;
-   iov[0].iov_len = sizeof(nlh);
-
-   iov[1].iov_base = msg;
-   iov[1].iov_len = size;
-
-   memset(&message, 0, sizeof(message));
-   message.msg_name = &addr;
-   message.msg_namelen = sizeof(addr);
-   message.msg_iov = iov;
-   message.msg_iovlen = 2;
-
-   return sendmsg(fd, &message, 0);
-}
-
 void print_usage(char *argv[])
 {
fprintf(stderr, "Usage: %s [options]\n"
@@ -180,16 +142,11 @@ void print_usage(char *argv[])
 
 int main(int argc, char *argv[])
 {
-   int fd, len, nl_group;
+   int vss_fd, len;
int error;
-   struct cn_msg *message;
struct pollfd pfd;
-   struct nlmsghdr *incoming_msg;
-   struct cn_msg   *incoming_cn_msg;
int op;
-   struct hv_vss_msg *vss_msg;
-   char *vss_recv_buffer;
-   size_t vss_recv_buffer_len;
+   struct hv_vss_msg vss_msg[1];
int daemonize = 1, long_index = 0, opt;
 
static struct option long_options[] = {
@@ -217,98 +174,50 @@ int main(int argc, char *argv[])
openlog("Hyper-V VSS", 0, LOG_USER);
syslog(LOG_INFO, "VSS starting; pid is:%d", getpid());
 
-   vss_recv_buffer_len = NLMSG_LENGTH(0) + sizeof(struct cn_msg) + 
sizeof(struct hv_vss_msg);
-   vss_recv_buffer = calloc(1, vss_recv_buffer_len);
-   if (!vss_recv_buffer) {
-   syslog(LOG_ERR, "Failed to allocate netlink buffers");
-   exit(EXIT_FAILURE);
-   }
-
-   fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
-   if (fd < 0) {
-   syslog(LOG_ERR, "netlink socket creation failed; error:%d %s",
-   errno, strerror(errno));
-   exit(EXIT_FAILURE);
-   }
-   addr.nl_family = AF_NETLINK;
-   addr.nl_pad = 0;
-   addr.nl_pid = 0;
-   addr.nl_groups = 0;
-
-
-   error = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
-   if (error < 0) {
-   syslog(LOG_ERR, "bind failed; error:%d %s", errno, 
strerror(errno));
-   close(fd);
-   exit(EXIT_FAILURE);
-   }
-   nl_group = CN_VSS_IDX;
-   if (setsockopt(fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &nl_group, 
sizeof(nl_group)) < 0) {
-   syslog(LOG_ERR, "setsockopt failed; error:%d %s", errno, 
strerror(errno));
-   close(fd);
+   vss_fd = open("/dev/vmbus/hv_vss", O_RDWR);
+   if (vss_fd < 0) {
+   syslog(LOG_ERR, "open /dev/vmbus/hv_vss failed; error: %d %s",
+  errno, strerror(errno));
exit(EXIT_FAILURE);
}
/*
 * Register ourselves with the kernel.
 */
-   message = (struct cn_msg *)vss_recv_buffer;
-   message->id.idx = CN_VSS_IDX;
-   message->id.val = CN_VSS_VAL;
-   message->ack = 0;
-   vss_msg = (struct hv_vss_msg *)message->data;
-   vss_msg->vss_hdr.operation = VSS_OP_REGISTER;
-
-   message->len = sizeof(struct hv_vss_msg);
+   vss_msg->vss_hdr.operation = VSS_OP_REGISTER1;
 
-   len = netlink_send(fd, message);
+   len = write(vss_fd, vss_msg, sizeof(struct hv_vss_msg));
if (len < 0) {
-   syslog(LOG_ERR, "netlink_send failed; error:%d %s", errno, 
strerror(errno));
-   close(fd);
+   syslog(LOG_ERR, "registration to kernel failed; error: %d %s",
+  errno, strerror(errno));
+   close(vss_fd);
exit(EXIT_FAILURE);
}
 
-   pfd.fd = fd;
+   pfd.fd = vss_fd;
 
while (1) {
-   struct sockaddr *addr_p = (struct sockaddr *) &addr;
-   socklen_t addr_l = sizeof(addr);
 

[PATCH 09/21] Drivers: hv: kvp: switch to using the hvutil_device_state state machine

2015-04-11 Thread K. Y. Srinivasan
From: Vitaly Kuznetsov 

Switch to using the hvutil_device_state state machine from using 2 different 
state variables: kvp_transaction.active and
in_hand_shake.

State transitions are:
-> HVUTIL_DEVICE_INIT when driver loads or on device release
-> HVUTIL_READY if the handshake was successful
-> HVUTIL_HOSTMSG_RECEIVED when there is a non-negotiation message from the host
-> HVUTIL_USERSPACE_REQ after we sent the message to the userspace daemon
   -> HVUTIL_USERSPACE_RECV after/if the userspace daemon has replied
-> HVUTIL_READY after we respond to the host
-> HVUTIL_DEVICE_DYING on driver unload

In hv_kvp_onchannelcallback() process ICMSGTYPE_NEGOTIATE messages even when
the userspace daemon is disconnected, otherwise we can make the host think
we don't support KVP and disable the service completely.

Unfortunately there is no good way we can figure out that the userspace daemon
has died (unless we start treating all timeouts as such). In case the daemon
restarts we skip the negotiation procedure (so the daemon is supposed to has
the same version). This behavior is unchanged from in_handshake approach.

Signed-off-by: Vitaly Kuznetsov 
Tested-by: Alex Ng 
Signed-off-by: K. Y. Srinivasan 
---
 drivers/hv/hv_kvp.c |   87 --
 1 files changed, 49 insertions(+), 38 deletions(-)

diff --git a/drivers/hv/hv_kvp.c b/drivers/hv/hv_kvp.c
index 14c62e2..a70d202 100644
--- a/drivers/hv/hv_kvp.c
+++ b/drivers/hv/hv_kvp.c
@@ -46,16 +46,21 @@
 #define WIN8_SRV_VERSION (WIN8_SRV_MAJOR << 16 | WIN8_SRV_MINOR)
 
 /*
- * Global state maintained for transaction that is being processed.
- * Note that only one transaction can be active at any point in time.
+ * Global state maintained for transaction that is being processed. For a class
+ * of integration services, including the "KVP service", the specified protocol
+ * is a "request/response" protocol which means that there can only be single
+ * outstanding transaction from the host at any given point in time. We use
+ * this to simplify memory management in this driver - we cache and process
+ * only one message at a time.
  *
- * This state is set when we receive a request from the host; we
- * cleanup this state when the transaction is completed - when we respond
- * to the host with the key value.
+ * While the request/response protocol is guaranteed by the host, we further
+ * ensure this by serializing packet processing in this driver - we do not
+ * read additional packets from the VMBUs until the current packet is fully
+ * handled.
  */
 
 static struct {
-   bool active; /* transaction status - active or not */
+   int state;   /* hvutil_device_state */
int recv_len; /* number of bytes received. */
struct hv_kvp_msg  *kvp_msg; /* current message */
struct vmbus_channel *recv_channel; /* chn we got the request */
@@ -64,13 +69,6 @@ static struct {
 } kvp_transaction;
 
 /*
- * Before we can accept KVP messages from the host, we need
- * to handshake with the user level daemon. This state tracks
- * if we are in the handshake phase.
- */
-static bool in_hand_shake = true;
-
-/*
  * This state maintains the version number registered by the daemon.
  */
 static int dm_reg_value;
@@ -126,6 +124,13 @@ static void kvp_timeout_func(struct work_struct *dummy)
 * process the pending transaction.
 */
kvp_respond_to_host(NULL, HV_E_FAIL);
+
+   /* Transaction is finished, reset the state. */
+   if (kvp_transaction.state > HVUTIL_READY)
+   kvp_transaction.state = HVUTIL_READY;
+
+   hv_poll_channel(kvp_transaction.kvp_context,
+   hv_kvp_onchannelcallback);
 }
 
 static int kvp_handle_handshake(struct hv_kvp_msg *msg)
@@ -154,9 +159,7 @@ static int kvp_handle_handshake(struct hv_kvp_msg *msg)
 */
pr_info("KVP: user-mode registering done.\n");
kvp_register(dm_reg_value);
-   kvp_transaction.active = false;
-   hv_poll_channel(kvp_transaction.kvp_context,
-   hv_kvp_onchannelcallback);
+   kvp_transaction.state = HVUTIL_READY;
}
return ret;
 }
@@ -180,12 +183,16 @@ kvp_cn_callback(struct cn_msg *msg, struct 
netlink_skb_parms *nsp)
 * with the daemon; handle that first.
 */
 
-   if (in_hand_shake) {
-   if (kvp_handle_handshake(message))
-   in_hand_shake = false;
+   if (kvp_transaction.state < HVUTIL_READY) {
+   kvp_handle_handshake(message);
return;
}
 
+   /* We didn't send anything to userspace so the reply is spurious */
+   if (kvp_transaction.state < HVUTIL_USERSPACE_REQ)
+   return;
+   kvp_transaction.state = HVUTIL_USERSPACE_RECV;
+
/*
 * Based on the version of the daemon, we propagate errors from the
 * daemon differently.
@@ -215,8 +222,12 @@ kvp_c

[PATCH 07/21] Drivers: hv: fcopy: rename fcopy_work -> fcopy_timeout_work

2015-04-11 Thread K. Y. Srinivasan
From: Vitaly Kuznetsov 

'fcopy_work' (and fcopy_work_func) is a misnomer as it sounds like we expect
this useful work to happen and in reality it is just an emergency escape when
timeout happens.

Signed-off-by: Vitaly Kuznetsov 
Tested-by: Alex Ng 
Signed-off-by: K. Y. Srinivasan 
---
 drivers/hv/hv_fcopy.c |   14 +++---
 1 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/drivers/hv/hv_fcopy.c b/drivers/hv/hv_fcopy.c
index 8bdf752..c14f0f4 100644
--- a/drivers/hv/hv_fcopy.c
+++ b/drivers/hv/hv_fcopy.c
@@ -75,11 +75,11 @@ static bool opened; /* currently device opened */
 static bool in_hand_shake = true;
 static void fcopy_send_data(void);
 static void fcopy_respond_to_host(int error);
-static void fcopy_work_func(struct work_struct *dummy);
-static DECLARE_DELAYED_WORK(fcopy_work, fcopy_work_func);
+static void fcopy_timeout_func(struct work_struct *dummy);
+static DECLARE_DELAYED_WORK(fcopy_timeout_work, fcopy_timeout_func);
 static u8 *recv_buffer;
 
-static void fcopy_work_func(struct work_struct *dummy)
+static void fcopy_timeout_func(struct work_struct *dummy)
 {
/*
 * If the timer fires, the user-mode component has not responded;
@@ -261,7 +261,7 @@ void hv_fcopy_onchannelcallback(void *context)
/*
 * Send the information to the user-level daemon.
 */
-   schedule_delayed_work(&fcopy_work, 5*HZ);
+   schedule_delayed_work(&fcopy_timeout_work, 5*HZ);
fcopy_send_data();
return;
}
@@ -336,7 +336,7 @@ static ssize_t fcopy_write(struct file *file, const char 
__user *buf,
 * Complete the transaction by forwarding the result
 * to the host. But first, cancel the timeout.
 */
-   if (cancel_delayed_work_sync(&fcopy_work)) {
+   if (cancel_delayed_work_sync(&fcopy_timeout_work))
fcopy_respond_to_host(response);
hv_poll_channel(fcopy_transaction.fcopy_context,
hv_fcopy_onchannelcallback);
@@ -378,7 +378,7 @@ static int fcopy_release(struct inode *inode, struct file 
*f)
in_hand_shake = true;
opened = false;
 
-   if (cancel_delayed_work_sync(&fcopy_work)) {
+   if (cancel_delayed_work_sync(&fcopy_timeout_work)) {
/* We haven't up()-ed the semaphore(very rare)? */
if (down_trylock(&fcopy_transaction.read_sema))
;
@@ -442,6 +442,6 @@ int hv_fcopy_init(struct hv_util_service *srv)
 
 void hv_fcopy_deinit(void)
 {
-   cancel_delayed_work_sync(&fcopy_work);
+   cancel_delayed_work_sync(&fcopy_timeout_work);
fcopy_dev_deinit();
 }
-- 
1.7.4.1

___
devel mailing list
de...@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel


[PATCH 12/21] Drivers: hv: fcopy: set .owner reference for file operations

2015-04-11 Thread K. Y. Srinivasan
From: Vitaly Kuznetsov 

Get an additional reference otherwise a crash is observed when hv_utils module 
is being unloaded while
fcopy daemon is still running. .owner gives us an additional reference when
someone holds a descriptor for the device.

Signed-off-by: Vitaly Kuznetsov 
Tested-by: Alex Ng 
Signed-off-by: K. Y. Srinivasan 
---
 drivers/hv/hv_fcopy.c |6 ++
 1 files changed, 2 insertions(+), 4 deletions(-)

diff --git a/drivers/hv/hv_fcopy.c b/drivers/hv/hv_fcopy.c
index a501301..d1475e6 100644
--- a/drivers/hv/hv_fcopy.c
+++ b/drivers/hv/hv_fcopy.c
@@ -360,12 +360,9 @@ static int fcopy_open(struct inode *inode, struct file *f)
 }
 
 /* XXX: there are still some tricky corner cases, e.g.,
- * 1) In a SMP guest, when fcopy_release() runs between
+ * In an SMP guest, when fcopy_release() runs between
  * schedule_delayed_work() and fcopy_send_data(), there is
  * still a chance an obsolete message will be queued.
- *
- * 2) When the fcopy daemon is running, if we unload the driver,
- * we'll notice a kernel oops when we kill the daemon later.
  */
 static int fcopy_release(struct inode *inode, struct file *f)
 {
@@ -385,6 +382,7 @@ static int fcopy_release(struct inode *inode, struct file 
*f)
 
 
 static const struct file_operations fcopy_fops = {
+   .owner  = THIS_MODULE,
.read   = fcopy_read,
.write  = fcopy_write,
.release= fcopy_release,
-- 
1.7.4.1

___
devel mailing list
de...@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel


[PATCH 13/21] Drivers: hv: util: introduce hv_utils_transport abstraction

2015-04-11 Thread K. Y. Srinivasan
From: Vitaly Kuznetsov 

The intention is to make KVP/VSS drivers work through misc char devices.
Introduce an abstraction for kernel/userspace communication to make the
migration smoother. Transport operational mode (netlink or char device)
is determined by the first received message. To support driver upgrades
the switch from netlink to chardev operational mode is supported.

Every hv_util daemon is supposed to register 2 callbacks:
1) on_msg() to get notified when the userspace daemon sent a message;
2) on_reset() to get notified when the userspace daemon drops the connection.

Signed-off-by: Vitaly Kuznetsov 
Tested-by: Alex Ng 
Signed-off-by: K. Y. Srinivasan 
---
 drivers/hv/Makefile |2 +-
 drivers/hv/hv_utils_transport.c |  276 +++
 drivers/hv/hv_utils_transport.h |   51 +++
 3 files changed, 328 insertions(+), 1 deletions(-)
 create mode 100644 drivers/hv/hv_utils_transport.c
 create mode 100644 drivers/hv/hv_utils_transport.h

diff --git a/drivers/hv/Makefile b/drivers/hv/Makefile
index 5e4dfa4..39c9b2c 100644
--- a/drivers/hv/Makefile
+++ b/drivers/hv/Makefile
@@ -5,4 +5,4 @@ obj-$(CONFIG_HYPERV_BALLOON)+= hv_balloon.o
 hv_vmbus-y := vmbus_drv.o \
 hv.o connection.o channel.o \
 channel_mgmt.o ring_buffer.o
-hv_utils-y := hv_util.o hv_kvp.o hv_snapshot.o hv_fcopy.o
+hv_utils-y := hv_util.o hv_kvp.o hv_snapshot.o hv_fcopy.o hv_utils_transport.o
diff --git a/drivers/hv/hv_utils_transport.c b/drivers/hv/hv_utils_transport.c
new file mode 100644
index 000..ea7ba5e
--- /dev/null
+++ b/drivers/hv/hv_utils_transport.c
@@ -0,0 +1,276 @@
+/*
+ * Kernel/userspace transport abstraction for Hyper-V util driver.
+ *
+ * Copyright (C) 2015, Vitaly Kuznetsov 
+ *
+ * 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.
+ *
+ */
+
+#include 
+#include 
+#include 
+
+#include "hyperv_vmbus.h"
+#include "hv_utils_transport.h"
+
+static DEFINE_SPINLOCK(hvt_list_lock);
+static struct list_head hvt_list = LIST_HEAD_INIT(hvt_list);
+
+static void hvt_reset(struct hvutil_transport *hvt)
+{
+   mutex_lock(&hvt->outmsg_lock);
+   kfree(hvt->outmsg);
+   hvt->outmsg = NULL;
+   hvt->outmsg_len = 0;
+   mutex_unlock(&hvt->outmsg_lock);
+   if (hvt->on_reset)
+   hvt->on_reset();
+}
+
+static ssize_t hvt_op_read(struct file *file, char __user *buf,
+  size_t count, loff_t *ppos)
+{
+   struct hvutil_transport *hvt;
+   int ret;
+
+   hvt = container_of(file->f_op, struct hvutil_transport, fops);
+
+   if (wait_event_interruptible(hvt->outmsg_q, hvt->outmsg_len > 0))
+   return -EINTR;
+
+   mutex_lock(&hvt->outmsg_lock);
+   if (!hvt->outmsg) {
+   ret = -EAGAIN;
+   goto out_unlock;
+   }
+
+   if (count < hvt->outmsg_len) {
+   ret = -EINVAL;
+   goto out_unlock;
+   }
+
+   if (!copy_to_user(buf, hvt->outmsg, hvt->outmsg_len))
+   ret = hvt->outmsg_len;
+   else
+   ret = -EFAULT;
+
+   kfree(hvt->outmsg);
+   hvt->outmsg = NULL;
+   hvt->outmsg_len = 0;
+
+out_unlock:
+   mutex_unlock(&hvt->outmsg_lock);
+   return ret;
+}
+
+static ssize_t hvt_op_write(struct file *file, const char __user *buf,
+   size_t count, loff_t *ppos)
+{
+   struct hvutil_transport *hvt;
+   u8 *inmsg;
+
+   hvt = container_of(file->f_op, struct hvutil_transport, fops);
+
+   inmsg = kzalloc(count, GFP_KERNEL);
+   if (copy_from_user(inmsg, buf, count)) {
+   kfree(inmsg);
+   return -EFAULT;
+   }
+   if (hvt->on_msg(inmsg, count))
+   return -EFAULT;
+   kfree(inmsg);
+
+   return count;
+}
+
+static unsigned int hvt_op_poll(struct file *file, poll_table *wait)
+{
+   struct hvutil_transport *hvt;
+
+   hvt = container_of(file->f_op, struct hvutil_transport, fops);
+
+   poll_wait(file, &hvt->outmsg_q, wait);
+   if (hvt->outmsg_len > 0)
+   return POLLIN | POLLRDNORM;
+
+   return 0;
+}
+
+static int hvt_op_open(struct inode *inode, struct file *file)
+{
+   struct hvutil_transport *hvt;
+
+   hvt = container_of(file->f_op, struct hvutil_transport, fops);
+
+   /*
+* Switching to CHARDEV mode. We switch bach to INIT when device
+* gets released.
+*/
+   if (hvt->mode == HVUTIL_TRANSPORT_INIT)
+   hvt->mode = HVUTIL_TRANSPORT_CHARDEV;
+   else if (h

[PATCH 14/21] Drivers: hv: vss: convert to hv_utils_transport

2015-04-11 Thread K. Y. Srinivasan
From: Vitaly Kuznetsov 

Convert to hv_utils_transport to support both netlink and /dev/vmbus/hv_vss 
communication methods.

Signed-off-by: Vitaly Kuznetsov 
Tested-by: Alex Ng 
Signed-off-by: K. Y. Srinivasan 
---
 drivers/hv/hv_snapshot.c |   52 +++--
 1 files changed, 27 insertions(+), 25 deletions(-)

diff --git a/drivers/hv/hv_snapshot.c b/drivers/hv/hv_snapshot.c
index ddb1cda..2c8c246 100644
--- a/drivers/hv/hv_snapshot.c
+++ b/drivers/hv/hv_snapshot.c
@@ -25,6 +25,7 @@
 #include 
 
 #include "hyperv_vmbus.h"
+#include "hv_utils_transport.h"
 
 #define VSS_MAJOR  5
 #define VSS_MINOR  0
@@ -58,9 +59,9 @@ static struct {
 
 static void vss_respond_to_host(int error);
 
-static struct cb_id vss_id = { CN_VSS_IDX, CN_VSS_VAL };
-static const char vss_name[] = "vss_kernel_module";
+static const char vss_devname[] = "vmbus/hv_vss";
 static __u8 *recv_buffer;
+static struct hvutil_transport *hvt;
 
 static void vss_send_op(struct work_struct *dummy);
 static void vss_timeout_func(struct work_struct *dummy);
@@ -88,12 +89,12 @@ static void vss_timeout_func(struct work_struct *dummy)
hv_vss_onchannelcallback);
 }
 
-static void
-vss_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp)
+static int vss_on_msg(void *msg, int len)
 {
-   struct hv_vss_msg *vss_msg;
+   struct hv_vss_msg *vss_msg = (struct hv_vss_msg *)msg;
 
-   vss_msg = (struct hv_vss_msg *)msg->data;
+   if (len != sizeof(*vss_msg))
+   return -EINVAL;
 
/*
 * Don't process registration messages if we're in the middle of
@@ -101,7 +102,7 @@ vss_cn_callback(struct cn_msg *msg, struct 
netlink_skb_parms *nsp)
 */
if (vss_transaction.state > HVUTIL_READY &&
vss_msg->vss_hdr.operation == VSS_OP_REGISTER)
-   return;
+   return -EINVAL;
 
if (vss_transaction.state == HVUTIL_DEVICE_INIT &&
vss_msg->vss_hdr.operation == VSS_OP_REGISTER) {
@@ -119,8 +120,9 @@ vss_cn_callback(struct cn_msg *msg, struct 
netlink_skb_parms *nsp)
} else {
/* This is a spurious call! */
pr_warn("VSS: Transaction not active\n");
-   return;
+   return -EINVAL;
}
+   return 0;
 }
 
 
@@ -128,27 +130,20 @@ static void vss_send_op(struct work_struct *dummy)
 {
int op = vss_transaction.msg->vss_hdr.operation;
int rc;
-   struct cn_msg *msg;
struct hv_vss_msg *vss_msg;
 
/* The transaction state is wrong. */
if (vss_transaction.state != HVUTIL_HOSTMSG_RECEIVED)
return;
 
-   msg = kzalloc(sizeof(*msg) + sizeof(*vss_msg), GFP_ATOMIC);
-   if (!msg)
+   vss_msg = kzalloc(sizeof(*vss_msg), GFP_KERNEL);
+   if (!vss_msg)
return;
 
-   vss_msg = (struct hv_vss_msg *)msg->data;
-
-   msg->id.idx =  CN_VSS_IDX;
-   msg->id.val = CN_VSS_VAL;
-
vss_msg->vss_hdr.operation = op;
-   msg->len = sizeof(struct hv_vss_msg);
 
vss_transaction.state = HVUTIL_USERSPACE_REQ;
-   rc = cn_netlink_send(msg, 0, 0, GFP_ATOMIC);
+   rc = hvutil_transport_send(hvt, vss_msg, sizeof(*vss_msg));
if (rc) {
pr_warn("VSS: failed to communicate to the daemon: %d\n", rc);
if (cancel_delayed_work_sync(&vss_timeout_work)) {
@@ -157,7 +152,7 @@ static void vss_send_op(struct work_struct *dummy)
}
}
 
-   kfree(msg);
+   kfree(vss_msg);
 
return;
 }
@@ -308,14 +303,16 @@ void hv_vss_onchannelcallback(void *context)
 
 }
 
+static void vss_on_reset(void)
+{
+   if (cancel_delayed_work_sync(&vss_timeout_work))
+   vss_respond_to_host(HV_E_FAIL);
+   vss_transaction.state = HVUTIL_DEVICE_INIT;
+}
+
 int
 hv_vss_init(struct hv_util_service *srv)
 {
-   int err;
-
-   err = cn_add_callback(&vss_id, vss_name, vss_cn_callback);
-   if (err)
-   return err;
recv_buffer = srv->recv_buffer;
 
/*
@@ -326,13 +323,18 @@ hv_vss_init(struct hv_util_service *srv)
 */
vss_transaction.state = HVUTIL_DEVICE_INIT;
 
+   hvt = hvutil_transport_init(vss_devname, CN_VSS_IDX, CN_VSS_VAL,
+   vss_on_msg, vss_on_reset);
+   if (!hvt)
+   return -EFAULT;
+
return 0;
 }
 
 void hv_vss_deinit(void)
 {
vss_transaction.state = HVUTIL_DEVICE_DYING;
-   cn_del_callback(&vss_id);
cancel_delayed_work_sync(&vss_timeout_work);
cancel_work_sync(&vss_send_op_work);
+   hvutil_transport_destroy(hvt);
 }
-- 
1.7.4.1

___
devel mailing list
de...@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel


[PATCH 11/21] Drivers: hv: fcopy: switch to using the hvutil_device_state state machine

2015-04-11 Thread K. Y. Srinivasan
From: Vitaly Kuznetsov 

Switch to using the hvutil_device_state state machine from using 3 different 
state variables:
fcopy_transaction.active, opened, and in_hand_shake.

State transitions are:
-> HVUTIL_DEVICE_INIT when driver loads or on device release
-> HVUTIL_READY if the handshake was successful
-> HVUTIL_HOSTMSG_RECEIVED when there is a non-negotiation message from the host
-> HVUTIL_USERSPACE_REQ after userspace daemon read the message
   -> HVUTIL_USERSPACE_RECV after/if userspace has replied
-> HVUTIL_READY after we respond to the host
-> HVUTIL_DEVICE_DYING on driver unload

In hv_fcopy_onchannelcallback() process ICMSGTYPE_NEGOTIATE messages even when
the userspace daemon is disconnected, otherwise we can make the host think
we don't support FCOPY and disable the service completely.

Signed-off-by: Vitaly Kuznetsov 
Tested-by: Alex Ng 
Signed-off-by: K. Y. Srinivasan 
---
 drivers/hv/hv_fcopy.c |   70 +
 1 files changed, 30 insertions(+), 40 deletions(-)

diff --git a/drivers/hv/hv_fcopy.c b/drivers/hv/hv_fcopy.c
index c14f0f4..a501301 100644
--- a/drivers/hv/hv_fcopy.c
+++ b/drivers/hv/hv_fcopy.c
@@ -47,15 +47,10 @@
  * ensure this by serializing packet processing in this driver - we do not
  * read additional packets from the VMBUs until the current packet is fully
  * handled.
- *
- * The transaction "active" state is set when we receive a request from the
- * host and we cleanup this state when the transaction is completed - when we
- * respond to the host with our response. When the transaction active state is
- * set, we defer handling incoming packets.
  */
 
 static struct {
-   bool active; /* transaction status - active or not */
+   int state;   /* hvutil_device_state */
int recv_len; /* number of bytes received. */
struct hv_fcopy_hdr  *fcopy_msg; /* current message */
struct hv_start_fcopy  message; /*  sent to daemon */
@@ -65,14 +60,6 @@ static struct {
struct semaphore read_sema;
 } fcopy_transaction;
 
-static bool opened; /* currently device opened */
-
-/*
- * Before we can accept copy messages from the host, we need
- * to handshake with the user level daemon. This state tracks
- * if we are in the handshake phase.
- */
-static bool in_hand_shake = true;
 static void fcopy_send_data(void);
 static void fcopy_respond_to_host(int error);
 static void fcopy_timeout_func(struct work_struct *dummy);
@@ -87,6 +74,10 @@ static void fcopy_timeout_func(struct work_struct *dummy)
 */
fcopy_respond_to_host(HV_E_FAIL);
 
+   /* Transaction is finished, reset the state. */
+   if (fcopy_transaction.state > HVUTIL_READY)
+   fcopy_transaction.state = HVUTIL_READY;
+
/* In the case the user-space daemon crashes, hangs or is killed, we
 * need to down the semaphore, otherwise, after the daemon starts next
 * time, the obsolete data in fcopy_transaction.message or
@@ -118,10 +109,9 @@ static int fcopy_handle_handshake(u32 version)
}
pr_info("FCP: user-mode registering done. Daemon version: %d\n",
version);
-   fcopy_transaction.active = false;
+   fcopy_transaction.state = HVUTIL_READY;
hv_poll_channel(fcopy_transaction.fcopy_context,
hv_fcopy_onchannelcallback);
-   in_hand_shake = false;
return 0;
 }
 
@@ -191,8 +181,6 @@ fcopy_respond_to_host(int error)
channel = fcopy_transaction.recv_channel;
req_id = fcopy_transaction.recv_req_id;
 
-   fcopy_transaction.active = false;
-
icmsghdr = (struct icmsg_hdr *)
&recv_buffer[sizeof(struct vmbuspipe_hdr)];
 
@@ -220,7 +208,7 @@ void hv_fcopy_onchannelcallback(void *context)
int util_fw_version;
int fcopy_srv_version;
 
-   if (fcopy_transaction.active) {
+   if (fcopy_transaction.state > HVUTIL_READY) {
/*
 * We will defer processing this callback once
 * the current transaction is complete.
@@ -252,12 +240,18 @@ void hv_fcopy_onchannelcallback(void *context)
 * transaction; note transactions are serialized.
 */
 
-   fcopy_transaction.active = true;
fcopy_transaction.recv_len = recvlen;
fcopy_transaction.recv_channel = channel;
fcopy_transaction.recv_req_id = requestid;
fcopy_transaction.fcopy_msg = fcopy_msg;
 
+   if (fcopy_transaction.state < HVUTIL_READY) {
+   /* Userspace is not registered yet */
+   fcopy_respond_to_host(HV_E_FAIL);
+   return;
+   }
+   fcopy_transaction.state = HVUTIL_HOSTMSG_RECEIVED;
+
/*
 * Send the information to the user-level daemon.
 */
@@ -290,10 +284,10 @@ static ssize_t fcopy_read(struct file *file, char __use

[PATCH 17/21] Tools: hv: kvp: use misc char device to communicate with kernel

2015-04-11 Thread K. Y. Srinivasan
From: Vitaly Kuznetsov 

Use /dev/vmbus/hv_kvp instead of netlink.

Signed-off-by: Vitaly Kuznetsov 
Tested-by: Alex Ng 
Signed-off-by: K. Y. Srinivasan 
---
 tools/hv/hv_kvp_daemon.c |  166 +-
 1 files changed, 31 insertions(+), 135 deletions(-)

diff --git a/tools/hv/hv_kvp_daemon.c b/tools/hv/hv_kvp_daemon.c
index 408bb07..0d9f48e 100644
--- a/tools/hv/hv_kvp_daemon.c
+++ b/tools/hv/hv_kvp_daemon.c
@@ -33,7 +33,6 @@
 #include 
 #include 
 #include 
-#include 
 #include 
 #include 
 #include 
@@ -79,7 +78,6 @@ enum {
DNS
 };
 
-static struct sockaddr_nl addr;
 static int in_hand_shake = 1;
 
 static char *os_name = "";
@@ -1387,34 +1385,6 @@ kvp_get_domain_name(char *buffer, int length)
freeaddrinfo(info);
 }
 
-static int
-netlink_send(int fd, struct cn_msg *msg)
-{
-   struct nlmsghdr nlh = { .nlmsg_type = NLMSG_DONE };
-   unsigned int size;
-   struct msghdr message;
-   struct iovec iov[2];
-
-   size = sizeof(struct cn_msg) + msg->len;
-
-   nlh.nlmsg_pid = getpid();
-   nlh.nlmsg_len = NLMSG_LENGTH(size);
-
-   iov[0].iov_base = &nlh;
-   iov[0].iov_len = sizeof(nlh);
-
-   iov[1].iov_base = msg;
-   iov[1].iov_len = size;
-
-   memset(&message, 0, sizeof(message));
-   message.msg_name = &addr;
-   message.msg_namelen = sizeof(addr);
-   message.msg_iov = iov;
-   message.msg_iovlen = 2;
-
-   return sendmsg(fd, &message, 0);
-}
-
 void print_usage(char *argv[])
 {
fprintf(stderr, "Usage: %s [options]\n"
@@ -1425,22 +1395,17 @@ void print_usage(char *argv[])
 
 int main(int argc, char *argv[])
 {
-   int fd, len, nl_group;
+   int kvp_fd, len;
int error;
-   struct cn_msg *message;
struct pollfd pfd;
-   struct nlmsghdr *incoming_msg;
-   struct cn_msg   *incoming_cn_msg;
-   struct hv_kvp_msg *hv_msg;
-   char*p;
+   char*p;
+   struct hv_kvp_msg hv_msg[1];
char*key_value;
char*key_name;
int op;
int pool;
char*if_name;
struct hv_kvp_ipaddr_value *kvp_ip_val;
-   char *kvp_recv_buffer;
-   size_t kvp_recv_buffer_len;
int daemonize = 1, long_index = 0, opt;
 
static struct option long_options[] = {
@@ -1468,12 +1433,14 @@ int main(int argc, char *argv[])
openlog("KVP", 0, LOG_USER);
syslog(LOG_INFO, "KVP starting; pid is:%d", getpid());
 
-   kvp_recv_buffer_len = NLMSG_LENGTH(0) + sizeof(struct cn_msg) + 
sizeof(struct hv_kvp_msg);
-   kvp_recv_buffer = calloc(1, kvp_recv_buffer_len);
-   if (!kvp_recv_buffer) {
-   syslog(LOG_ERR, "Failed to allocate netlink buffer");
+   kvp_fd = open("/dev/vmbus/hv_kvp", O_RDWR);
+
+   if (kvp_fd < 0) {
+   syslog(LOG_ERR, "open /dev/vmbus/hv_kvp failed; error: %d %s",
+   errno, strerror(errno));
exit(EXIT_FAILURE);
}
+
/*
 * Retrieve OS release information.
 */
@@ -1489,100 +1456,44 @@ int main(int argc, char *argv[])
exit(EXIT_FAILURE);
}
 
-   fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
-   if (fd < 0) {
-   syslog(LOG_ERR, "netlink socket creation failed; error: %d %s", 
errno,
-   strerror(errno));
-   exit(EXIT_FAILURE);
-   }
-   addr.nl_family = AF_NETLINK;
-   addr.nl_pad = 0;
-   addr.nl_pid = 0;
-   addr.nl_groups = 0;
-
-
-   error = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
-   if (error < 0) {
-   syslog(LOG_ERR, "bind failed; error: %d %s", errno, 
strerror(errno));
-   close(fd);
-   exit(EXIT_FAILURE);
-   }
-   nl_group = CN_KVP_IDX;
-
-   if (setsockopt(fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &nl_group, 
sizeof(nl_group)) < 0) {
-   syslog(LOG_ERR, "setsockopt failed; error: %d %s", errno, 
strerror(errno));
-   close(fd);
-   exit(EXIT_FAILURE);
-   }
-
/*
 * Register ourselves with the kernel.
 */
-   message = (struct cn_msg *)kvp_recv_buffer;
-   message->id.idx = CN_KVP_IDX;
-   message->id.val = CN_KVP_VAL;
-
-   hv_msg = (struct hv_kvp_msg *)message->data;
hv_msg->kvp_hdr.operation = KVP_OP_REGISTER1;
-   message->ack = 0;
-   message->len = sizeof(struct hv_kvp_msg);
-
-   len = netlink_send(fd, message);
-   if (len < 0) {
-   syslog(LOG_ERR, "netlink_send failed; error: %d %s", errno, 
strerror(errno));
-   close(fd);
+   len = write(kvp_fd, hv_msg, sizeof(struct hv_kvp_msg));
+   if (len != sizeof(struct hv_kvp_msg)) {
+   syslog(LOG_ERR, "registration to kernel failed; error: %d %s",
+  errno, strerror(errno));
+   close(kvp_fd);
exit(EXIT_FAILURE);
 

[PATCH 16/21] Drivers: hv: kvp: convert to hv_utils_transport

2015-04-11 Thread K. Y. Srinivasan
From: Vitaly Kuznetsov 

Convert to hv_utils_transport to support both netlink and /dev/vmbus/hv_kvp 
communication methods.

Signed-off-by: Vitaly Kuznetsov 
Tested-by: Alex Ng 
Signed-off-by: K. Y. Srinivasan 
---
 drivers/hv/hv_kvp.c |   91 +++---
 1 files changed, 42 insertions(+), 49 deletions(-)

diff --git a/drivers/hv/hv_kvp.c b/drivers/hv/hv_kvp.c
index a70d202..baa1208 100644
--- a/drivers/hv/hv_kvp.c
+++ b/drivers/hv/hv_kvp.c
@@ -29,6 +29,7 @@
 #include 
 
 #include "hyperv_vmbus.h"
+#include "hv_utils_transport.h"
 
 /*
  * Pre win8 version numbers used in ws2008 and ws 2008 r2 (win7)
@@ -83,9 +84,9 @@ static void kvp_register(int);
 static DECLARE_DELAYED_WORK(kvp_timeout_work, kvp_timeout_func);
 static DECLARE_WORK(kvp_sendkey_work, kvp_send_key);
 
-static struct cb_id kvp_id = { CN_KVP_IDX, CN_KVP_VAL };
-static const char kvp_name[] = "kvp_kernel_module";
+static const char kvp_devname[] = "vmbus/hv_kvp";
 static u8 *recv_buffer;
+static struct hvutil_transport *hvt;
 /*
  * Register the kernel component with the user-level daemon.
  * As part of this registration, pass the LIC version number.
@@ -97,23 +98,18 @@ static void
 kvp_register(int reg_value)
 {
 
-   struct cn_msg *msg;
struct hv_kvp_msg *kvp_msg;
char *version;
 
-   msg = kzalloc(sizeof(*msg) + sizeof(struct hv_kvp_msg), GFP_ATOMIC);
+   kvp_msg = kzalloc(sizeof(*kvp_msg), GFP_KERNEL);
 
-   if (msg) {
-   kvp_msg = (struct hv_kvp_msg *)msg->data;
+   if (kvp_msg) {
version = kvp_msg->body.kvp_register.version;
-   msg->id.idx =  CN_KVP_IDX;
-   msg->id.val = CN_KVP_VAL;
-
kvp_msg->kvp_hdr.operation = reg_value;
strcpy(version, HV_DRV_VERSION);
-   msg->len = sizeof(struct hv_kvp_msg);
-   cn_netlink_send(msg, 0, 0, GFP_ATOMIC);
-   kfree(msg);
+
+   hvutil_transport_send(hvt, kvp_msg, sizeof(*kvp_msg));
+   kfree(kvp_msg);
}
 }
 
@@ -135,8 +131,6 @@ static void kvp_timeout_func(struct work_struct *dummy)
 
 static int kvp_handle_handshake(struct hv_kvp_msg *msg)
 {
-   int ret = 1;
-
switch (msg->kvp_hdr.operation) {
case KVP_OP_REGISTER:
dm_reg_value = KVP_OP_REGISTER;
@@ -150,18 +144,17 @@ static int kvp_handle_handshake(struct hv_kvp_msg *msg)
pr_info("KVP: incompatible daemon\n");
pr_info("KVP: KVP version: %d, Daemon version: %d\n",
KVP_OP_REGISTER1, msg->kvp_hdr.operation);
-   ret = 0;
+   return -EINVAL;
}
 
-   if (ret) {
-   /*
-* We have a compatible daemon; complete the handshake.
-*/
-   pr_info("KVP: user-mode registering done.\n");
-   kvp_register(dm_reg_value);
-   kvp_transaction.state = HVUTIL_READY;
-   }
-   return ret;
+   /*
+* We have a compatible daemon; complete the handshake.
+*/
+   pr_info("KVP: user-mode registering done.\n");
+   kvp_register(dm_reg_value);
+   kvp_transaction.state = HVUTIL_READY;
+
+   return 0;
 }
 
 
@@ -169,14 +162,14 @@ static int kvp_handle_handshake(struct hv_kvp_msg *msg)
  * Callback when data is received from user mode.
  */
 
-static void
-kvp_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp)
+static int kvp_on_msg(void *msg, int len)
 {
-   struct hv_kvp_msg *message;
+   struct hv_kvp_msg *message = (struct hv_kvp_msg *)msg;
struct hv_kvp_msg_enumerate *data;
int error = 0;
 
-   message = (struct hv_kvp_msg *)msg->data;
+   if (len < sizeof(*message))
+   return -EINVAL;
 
/*
 * If we are negotiating the version information
@@ -184,13 +177,13 @@ kvp_cn_callback(struct cn_msg *msg, struct 
netlink_skb_parms *nsp)
 */
 
if (kvp_transaction.state < HVUTIL_READY) {
-   kvp_handle_handshake(message);
-   return;
+   return kvp_handle_handshake(message);
}
 
/* We didn't send anything to userspace so the reply is spurious */
if (kvp_transaction.state < HVUTIL_USERSPACE_REQ)
-   return;
+   return -EINVAL;
+
kvp_transaction.state = HVUTIL_USERSPACE_RECV;
 
/*
@@ -228,6 +221,8 @@ kvp_cn_callback(struct cn_msg *msg, struct 
netlink_skb_parms *nsp)
hv_poll_channel(kvp_transaction.kvp_context,
hv_kvp_onchannelcallback);
}
+
+   return 0;
 }
 
 
@@ -344,7 +339,6 @@ static void process_ib_ipinfo(void *in_msg, void *out_msg, 
int op)
 static void
 kvp_send_key(struct work_struct *dummy)
 {
-   struct cn_msg *msg;
struct hv_kvp_msg *message;
struct hv_kvp_msg *in_msg;
__u8 operation = kvp_transaction.kvp_msg->kvp_hdr.operation

[PATCH 05/21] Drivers: hv: vss: process deferred messages when we complete the transaction

2015-04-11 Thread K. Y. Srinivasan
From: Vitaly Kuznetsov 

In theory, the host is not supposed to issue any requests before be reply to
the previous one. In KVP we, however, support the following scenarios:
1) A message was received before userspace daemon registered;
2) A message was received while the previous one is still being processed.
In VSS we support only the former. Add support for the later, use
hv_poll_channel() to do the job.

Signed-off-by: Vitaly Kuznetsov 
Tested-by: Alex Ng 
Signed-off-by: K. Y. Srinivasan 
---
 drivers/hv/hv_snapshot.c |   14 +-
 1 files changed, 9 insertions(+), 5 deletions(-)

diff --git a/drivers/hv/hv_snapshot.c b/drivers/hv/hv_snapshot.c
index c1a3604..4bb9b1c 100644
--- a/drivers/hv/hv_snapshot.c
+++ b/drivers/hv/hv_snapshot.c
@@ -47,6 +47,7 @@ static struct {
struct vmbus_channel *recv_channel; /* chn we got the request */
u64 recv_req_id; /* request ID. */
struct hv_vss_msg  *msg; /* current message */
+   void *vss_context; /* for the channel callback */
 } vss_transaction;
 
 
@@ -73,6 +74,9 @@ static void vss_timeout_func(struct work_struct *dummy)
 */
pr_warn("VSS: timeout waiting for daemon to reply\n");
vss_respond_to_host(HV_E_FAIL);
+
+   hv_poll_channel(vss_transaction.vss_context,
+   hv_vss_onchannelcallback);
 }
 
 static void
@@ -85,13 +89,12 @@ vss_cn_callback(struct cn_msg *msg, struct 
netlink_skb_parms *nsp)
if (vss_msg->vss_hdr.operation == VSS_OP_REGISTER) {
pr_info("VSS daemon registered\n");
vss_transaction.active = false;
-   if (vss_transaction.recv_channel != NULL)
-   hv_vss_onchannelcallback(vss_transaction.recv_channel);
-   return;
-
}
if (cancel_delayed_work_sync(&vss_timeout_work))
vss_respond_to_host(vss_msg->error);
+
+   hv_poll_channel(vss_transaction.vss_context,
+   hv_vss_onchannelcallback);
 }
 
 
@@ -198,9 +201,10 @@ void hv_vss_onchannelcallback(void *context)
 * We will defer processing this callback once
 * the current transaction is complete.
 */
-   vss_transaction.recv_channel = channel;
+   vss_transaction.vss_context = context;
return;
}
+   vss_transaction.vss_context = NULL;
 
vmbus_recvpacket(channel, recv_buffer, PAGE_SIZE * 2, &recvlen,
 &requestid);
-- 
1.7.4.1

___
devel mailing list
de...@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel


[PATCH 06/21] Drivers: hv: kvp: rename kvp_work -> kvp_timeout_work

2015-04-11 Thread K. Y. Srinivasan
From: Vitaly Kuznetsov 

'kvp_work' (and kvp_work_func) is a misnomer as it sounds like we expect
this useful work to happen and in reality it is just an emergency escape when
timeout happens.

Signed-off-by: Vitaly Kuznetsov 
Tested-by: Alex Ng 
Signed-off-by: K. Y. Srinivasan 
---
 drivers/hv/hv_kvp.c |   16 
 1 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/drivers/hv/hv_kvp.c b/drivers/hv/hv_kvp.c
index 939c3e7..14c62e2 100644
--- a/drivers/hv/hv_kvp.c
+++ b/drivers/hv/hv_kvp.c
@@ -79,10 +79,10 @@ static void kvp_send_key(struct work_struct *dummy);
 
 
 static void kvp_respond_to_host(struct hv_kvp_msg *msg, int error);
-static void kvp_work_func(struct work_struct *dummy);
+static void kvp_timeout_func(struct work_struct *dummy);
 static void kvp_register(int);
 
-static DECLARE_DELAYED_WORK(kvp_work, kvp_work_func);
+static DECLARE_DELAYED_WORK(kvp_timeout_work, kvp_timeout_func);
 static DECLARE_WORK(kvp_sendkey_work, kvp_send_key);
 
 static struct cb_id kvp_id = { CN_KVP_IDX, CN_KVP_VAL };
@@ -118,8 +118,8 @@ kvp_register(int reg_value)
kfree(msg);
}
 }
-static void
-kvp_work_func(struct work_struct *dummy)
+
+static void kvp_timeout_func(struct work_struct *dummy)
 {
/*
 * If the timer fires, the user-mode component has not responded;
@@ -215,7 +215,7 @@ kvp_cn_callback(struct cn_msg *msg, struct 
netlink_skb_parms *nsp)
 * Complete the transaction by forwarding the key value
 * to the host. But first, cancel the timeout.
 */
-   if (cancel_delayed_work_sync(&kvp_work))
+   if (cancel_delayed_work_sync(&kvp_timeout_work))
kvp_respond_to_host(message, error);
 }
 
@@ -440,7 +440,7 @@ kvp_send_key(struct work_struct *dummy)
rc = cn_netlink_send(msg, 0, 0, GFP_ATOMIC);
if (rc) {
pr_debug("KVP: failed to communicate to the daemon: %d\n", rc);
-   if (cancel_delayed_work_sync(&kvp_work))
+   if (cancel_delayed_work_sync(&kvp_timeout_work))
kvp_respond_to_host(message, HV_E_FAIL);
}
 
@@ -668,7 +668,7 @@ void hv_kvp_onchannelcallback(void *context)
 * user-mode not responding.
 */
schedule_work(&kvp_sendkey_work);
-   schedule_delayed_work(&kvp_work, 5*HZ);
+   schedule_delayed_work(&kvp_timeout_work, 5*HZ);
 
return;
 
@@ -708,6 +708,6 @@ hv_kvp_init(struct hv_util_service *srv)
 void hv_kvp_deinit(void)
 {
cn_del_callback(&kvp_id);
-   cancel_delayed_work_sync(&kvp_work);
+   cancel_delayed_work_sync(&kvp_timeout_work);
cancel_work_sync(&kvp_sendkey_work);
 }
-- 
1.7.4.1

___
devel mailing list
de...@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel


[PATCH 19/21] Drivers: hv: vss: full handshake support

2015-04-11 Thread K. Y. Srinivasan
From: Vitaly Kuznetsov 

Introduce VSS_OP_REGISTER1 to support kernel replying to the negotiation
message with its own version.

Signed-off-by: Vitaly Kuznetsov 
Tested-by: Alex Ng 
Signed-off-by: K. Y. Srinivasan 
---
 drivers/hv/hv_snapshot.c|   49 --
 include/uapi/linux/hyperv.h |5 
 tools/hv/hv_vss_daemon.c|   14 
 3 files changed, 56 insertions(+), 12 deletions(-)

diff --git a/drivers/hv/hv_snapshot.c b/drivers/hv/hv_snapshot.c
index 2c8c246..ee1762b 100644
--- a/drivers/hv/hv_snapshot.c
+++ b/drivers/hv/hv_snapshot.c
@@ -59,6 +59,11 @@ static struct {
 
 static void vss_respond_to_host(int error);
 
+/*
+ * This state maintains the version number registered by the daemon.
+ */
+static int dm_reg_value;
+
 static const char vss_devname[] = "vmbus/hv_vss";
 static __u8 *recv_buffer;
 static struct hvutil_transport *hvt;
@@ -89,6 +94,29 @@ static void vss_timeout_func(struct work_struct *dummy)
hv_vss_onchannelcallback);
 }
 
+static int vss_handle_handshake(struct hv_vss_msg *vss_msg)
+{
+   u32 our_ver = VSS_OP_REGISTER1;
+
+   switch (vss_msg->vss_hdr.operation) {
+   case VSS_OP_REGISTER:
+   /* Daemon doesn't expect us to reply */
+   dm_reg_value = VSS_OP_REGISTER;
+   break;
+   case VSS_OP_REGISTER1:
+   /* Daemon expects us to reply with our own version*/
+   if (hvutil_transport_send(hvt, &our_ver, sizeof(our_ver)))
+   return -EFAULT;
+   dm_reg_value = VSS_OP_REGISTER1;
+   break;
+   default:
+   return -EINVAL;
+   }
+   vss_transaction.state = HVUTIL_READY;
+   pr_info("VSS daemon registered\n");
+   return 0;
+}
+
 static int vss_on_msg(void *msg, int len)
 {
struct hv_vss_msg *vss_msg = (struct hv_vss_msg *)msg;
@@ -96,18 +124,15 @@ static int vss_on_msg(void *msg, int len)
if (len != sizeof(*vss_msg))
return -EINVAL;
 
-   /*
-* Don't process registration messages if we're in the middle of
-* a transaction processing.
-*/
-   if (vss_transaction.state > HVUTIL_READY &&
-   vss_msg->vss_hdr.operation == VSS_OP_REGISTER)
-   return -EINVAL;
-
-   if (vss_transaction.state == HVUTIL_DEVICE_INIT &&
-   vss_msg->vss_hdr.operation == VSS_OP_REGISTER) {
-   pr_info("VSS daemon registered\n");
-   vss_transaction.state = HVUTIL_READY;
+   if (vss_msg->vss_hdr.operation == VSS_OP_REGISTER ||
+   vss_msg->vss_hdr.operation == VSS_OP_REGISTER1) {
+   /*
+* Don't process registration messages if we're in the middle
+* of a transaction processing.
+*/
+   if (vss_transaction.state > HVUTIL_READY)
+   return -EINVAL;
+   return vss_handle_handshake(vss_msg);
} else if (vss_transaction.state == HVUTIL_USERSPACE_REQ) {
vss_transaction.state = HVUTIL_USERSPACE_RECV;
if (cancel_delayed_work_sync(&vss_timeout_work)) {
diff --git a/include/uapi/linux/hyperv.h b/include/uapi/linux/hyperv.h
index bb1cb73..66c76df 100644
--- a/include/uapi/linux/hyperv.h
+++ b/include/uapi/linux/hyperv.h
@@ -45,6 +45,11 @@
 
 #define VSS_OP_REGISTER 128
 
+/*
+  Daemon code with full handshake support.
+ */
+#define VSS_OP_REGISTER1 129
+
 enum hv_vss_op {
VSS_OP_CREATE = 0,
VSS_OP_DELETE,
diff --git a/tools/hv/hv_vss_daemon.c b/tools/hv/hv_vss_daemon.c
index 36f1821..96234b6 100644
--- a/tools/hv/hv_vss_daemon.c
+++ b/tools/hv/hv_vss_daemon.c
@@ -148,6 +148,8 @@ int main(int argc, char *argv[])
int op;
struct hv_vss_msg vss_msg[1];
int daemonize = 1, long_index = 0, opt;
+   int in_handshake = 1;
+   __u32 kernel_modver;
 
static struct option long_options[] = {
{"help",no_argument,   0,  'h' },
@@ -211,6 +213,18 @@ int main(int argc, char *argv[])
 
len = read(vss_fd, vss_msg, sizeof(struct hv_vss_msg));
 
+   if (in_handshake) {
+   if (len != sizeof(kernel_modver)) {
+   syslog(LOG_ERR, "invalid version negotiation");
+   exit(EXIT_FAILURE);
+   }
+   kernel_modver = *(__u32 *)vss_msg;
+   in_handshake = 0;
+   syslog(LOG_INFO, "VSS: kernel module version: %d",
+  kernel_modver);
+   continue;
+   }
+
if (len != sizeof(struct hv_vss_msg)) {
syslog(LOG_ERR, "read failed; error:%d %s",
   errno, strerror(errno));
-- 
1.7.4.1

___
devel mailing list
de...@linuxdriverproject.org

[PATCH 08/21] Drivers: hv: util: introduce state machine for util drivers

2015-04-11 Thread K. Y. Srinivasan
From: Vitaly Kuznetsov 

KVP/VSS/FCOPY drivers work in fully serialized mode: we wait till userspace
daemon registers, wait for a message from the host, send this message to the
daemon, get the reply, send it back to host, wait for another message.
Introduce enum hvutil_device_state to represend this state in all 3 drivers.

Signed-off-by: Vitaly Kuznetsov 
Tested-by: Alex Ng 
Signed-off-by: K. Y. Srinivasan 
---
 drivers/hv/hyperv_vmbus.h |9 +
 1 files changed, 9 insertions(+), 0 deletions(-)

diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h
index 2f30456..138d663 100644
--- a/drivers/hv/hyperv_vmbus.h
+++ b/drivers/hv/hyperv_vmbus.h
@@ -755,4 +755,13 @@ static inline void hv_poll_channel(struct vmbus_channel 
*channel,
cb(channel);
 }
 
+enum hvutil_device_state {
+   HVUTIL_DEVICE_INIT = 0,  /* driver is loaded, waiting for userspace */
+   HVUTIL_READY,/* userspace is registered */
+   HVUTIL_HOSTMSG_RECEIVED, /* message from the host was received */
+   HVUTIL_USERSPACE_REQ,/* request to userspace was sent */
+   HVUTIL_USERSPACE_RECV,   /* reply from userspace was received */
+   HVUTIL_DEVICE_DYING, /* driver unload is in progress */
+};
+
 #endif /* _HYPERV_VMBUS_H */
-- 
1.7.4.1

___
devel mailing list
de...@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel


[PATCH 15/21] Drivers: hv: fcopy: convert to hv_utils_transport

2015-04-11 Thread K. Y. Srinivasan
From: Vitaly Kuznetsov 

Unify the code with the recently introduced hv_utils_transport. Netlink
communication is disabled for fcopy.

Signed-off-by: Vitaly Kuznetsov 
Tested-by: Alex Ng 
Signed-off-by: K. Y. Srinivasan 
---
 drivers/hv/hv_fcopy.c |  194 -
 1 files changed, 46 insertions(+), 148 deletions(-)

diff --git a/drivers/hv/hv_fcopy.c b/drivers/hv/hv_fcopy.c
index d1475e6..6a8ec9f 100644
--- a/drivers/hv/hv_fcopy.c
+++ b/drivers/hv/hv_fcopy.c
@@ -19,17 +19,13 @@
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
-#include 
-#include 
 #include 
 #include 
-#include 
 #include 
 #include 
-#include 
-#include 
 
 #include "hyperv_vmbus.h"
+#include "hv_utils_transport.h"
 
 #define WIN8_SRV_MAJOR 1
 #define WIN8_SRV_MINOR 1
@@ -53,18 +49,19 @@ static struct {
int state;   /* hvutil_device_state */
int recv_len; /* number of bytes received. */
struct hv_fcopy_hdr  *fcopy_msg; /* current message */
-   struct hv_start_fcopy  message; /*  sent to daemon */
struct vmbus_channel *recv_channel; /* chn we got the request */
u64 recv_req_id; /* request ID. */
void *fcopy_context; /* for the channel callback */
-   struct semaphore read_sema;
 } fcopy_transaction;
 
-static void fcopy_send_data(void);
 static void fcopy_respond_to_host(int error);
+static void fcopy_send_data(struct work_struct *dummy);
 static void fcopy_timeout_func(struct work_struct *dummy);
 static DECLARE_DELAYED_WORK(fcopy_timeout_work, fcopy_timeout_func);
+static DECLARE_WORK(fcopy_send_work, fcopy_send_data);
+static const char fcopy_devname[] = "vmbus/hv_fcopy";
 static u8 *recv_buffer;
+static struct hvutil_transport *hvt;
 
 static void fcopy_timeout_func(struct work_struct *dummy)
 {
@@ -78,17 +75,6 @@ static void fcopy_timeout_func(struct work_struct *dummy)
if (fcopy_transaction.state > HVUTIL_READY)
fcopy_transaction.state = HVUTIL_READY;
 
-   /* In the case the user-space daemon crashes, hangs or is killed, we
-* need to down the semaphore, otherwise, after the daemon starts next
-* time, the obsolete data in fcopy_transaction.message or
-* fcopy_transaction.fcopy_msg will be used immediately.
-*
-* NOTE: fcopy_read() happens to get the semaphore (very rare)? We're
-* still OK, because we've reported the failure to the host.
-*/
-   if (down_trylock(&fcopy_transaction.read_sema))
-   ;
-
hv_poll_channel(fcopy_transaction.fcopy_context,
hv_fcopy_onchannelcallback);
 }
@@ -115,11 +101,13 @@ static int fcopy_handle_handshake(u32 version)
return 0;
 }
 
-static void fcopy_send_data(void)
+static void fcopy_send_data(struct work_struct *dummy)
 {
-   struct hv_start_fcopy *smsg_out = &fcopy_transaction.message;
+   struct hv_start_fcopy smsg_out;
int operation = fcopy_transaction.fcopy_msg->operation;
struct hv_start_fcopy *smsg_in;
+   void *out_src;
+   int rc, out_len;
 
/*
 * The  strings sent from the host are encoded in
@@ -134,26 +122,39 @@ static void fcopy_send_data(void)
 
switch (operation) {
case START_FILE_COPY:
-   memset(smsg_out, 0, sizeof(struct hv_start_fcopy));
-   smsg_out->hdr.operation = operation;
+   out_len = sizeof(struct hv_start_fcopy);
+   memset(&smsg_out, 0, out_len);
+   smsg_out.hdr.operation = operation;
smsg_in = (struct hv_start_fcopy *)fcopy_transaction.fcopy_msg;
 
utf16s_to_utf8s((wchar_t *)smsg_in->file_name, W_MAX_PATH,
UTF16_LITTLE_ENDIAN,
-   (__u8 *)smsg_out->file_name, W_MAX_PATH - 1);
+   (__u8 *)&smsg_out.file_name, W_MAX_PATH - 1);
 
utf16s_to_utf8s((wchar_t *)smsg_in->path_name, W_MAX_PATH,
UTF16_LITTLE_ENDIAN,
-   (__u8 *)smsg_out->path_name, W_MAX_PATH - 1);
+   (__u8 *)&smsg_out.path_name, W_MAX_PATH - 1);
 
-   smsg_out->copy_flags = smsg_in->copy_flags;
-   smsg_out->file_size = smsg_in->file_size;
+   smsg_out.copy_flags = smsg_in->copy_flags;
+   smsg_out.file_size = smsg_in->file_size;
+   out_src = &smsg_out;
break;
 
default:
+   out_src = fcopy_transaction.fcopy_msg;
+   out_len = fcopy_transaction.recv_len;
break;
}
-   up(&fcopy_transaction.read_sema);
+
+   fcopy_transaction.state = HVUTIL_USERSPACE_REQ;
+   rc = hvutil_transport_send(hvt, out_src, out_len);
+   if (rc) {
+   pr_debug("FCP: failed to communicate to the daemon: %d\n", rc);
+   if (cancel_delayed_work_sync(&fcopy_timeout_work)) {
+