Hi,
could you test this? It ought to give you more
throughput through asynchronousity.
Regards
Oliver
From b32c2f840c1ff0d0e93b627eb07b2fdc11f37bb5 Mon Sep 17 00:00:00 2001
From: Oliver Neukum <[email protected]>
Date: Thu, 25 Feb 2016 12:20:12 +0100
Subject: [PATCH 1/4] chaoskey: O_NONBLOCK in concurrent reads
This changes the locking in chaoskey_read() to correctly
handle O_NONBLOCK in the case of concurrent readers.
Signed-off-by: Oliver Neukum <[email protected]>
---
drivers/usb/misc/chaoskey.c | 16 +++++++++++++---
1 file changed, 13 insertions(+), 3 deletions(-)
diff --git a/drivers/usb/misc/chaoskey.c b/drivers/usb/misc/chaoskey.c
index 76350e4..f7e76a3 100644
--- a/drivers/usb/misc/chaoskey.c
+++ b/drivers/usb/misc/chaoskey.c
@@ -438,9 +438,19 @@ static ssize_t chaoskey_read(struct file *file,
goto bail;
mutex_unlock(&dev->rng_lock);
- result = mutex_lock_interruptible(&dev->lock);
- if (result)
- goto bail;
+ if (file->f_flags & O_NONBLOCK) {
+ result = mutex_trylock(&dev->lock);
+ if (result == 0) {
+ result = -EAGAIN;
+ goto bail;
+ } else {
+ result = 0;
+ }
+ } else {
+ result = mutex_lock_interruptible(&dev->lock);
+ if (result)
+ goto bail;
+ }
if (dev->valid == dev->used) {
result = _chaoskey_fill(dev);
if (result < 0) {
--
2.1.4
From 8d6c9c8ce3adf192a2fe19fa247208d91ee5e900 Mon Sep 17 00:00:00 2001
From: Oliver Neukum <[email protected]>
Date: Thu, 25 Feb 2016 14:20:22 +0100
Subject: [PATCH 2/4] chaoskey: introduce asynchronous reads
This divides requesting IO and waiting for IO from each other.
Signed-off-by: Oliver Neukum <[email protected]>
---
drivers/usb/misc/chaoskey.c | 37 ++++++++++++++++++++++++++++++-------
1 file changed, 30 insertions(+), 7 deletions(-)
diff --git a/drivers/usb/misc/chaoskey.c b/drivers/usb/misc/chaoskey.c
index f7e76a3..f47e5a7 100644
--- a/drivers/usb/misc/chaoskey.c
+++ b/drivers/usb/misc/chaoskey.c
@@ -351,14 +351,12 @@ static void chaos_read_callback(struct urb *urb)
wake_up(&dev->wait_q);
}
-/* Fill the buffer. Called with dev->lock held
- */
-static int _chaoskey_fill(struct chaoskey *dev)
+static int chaoskey_request_fill(struct chaoskey *dev)
{
DEFINE_WAIT(wait);
int result;
- usb_dbg(dev->interface, "fill");
+ usb_dbg(dev->interface, "request fill");
/* Return immediately if someone called before the buffer was
* empty */
@@ -389,6 +387,22 @@ static int _chaoskey_fill(struct chaoskey *dev)
goto out;
}
+ /*
+ * powering down while a read is under way
+ * is blocked in suspend()
+ */
+ usb_autopm_put_interface(dev->interface);
+ return 0;
+out:
+ usb_autopm_put_interface(dev->interface);
+ return result;
+}
+
+static int chaoskey_wait_fill(struct chaoskey *dev)
+{
+ DEFINE_WAIT(wait);
+ int result;
+
result = wait_event_interruptible_timeout(
dev->wait_q,
!dev->reading,
@@ -403,7 +417,6 @@ static int _chaoskey_fill(struct chaoskey *dev)
result = dev->valid;
out:
/* Let the device go back to sleep eventually */
- usb_autopm_put_interface(dev->interface);
usb_dbg(dev->interface, "read %d bytes", dev->valid);
@@ -452,7 +465,12 @@ static ssize_t chaoskey_read(struct file *file,
goto bail;
}
if (dev->valid == dev->used) {
- result = _chaoskey_fill(dev);
+ result = chaoskey_request_fill(dev);
+ if (result < 0) {
+ mutex_unlock(&dev->lock);
+ goto bail;
+ }
+ result = chaoskey_wait_fill(dev);
if (result < 0) {
mutex_unlock(&dev->lock);
goto bail;
@@ -520,7 +538,7 @@ static int chaoskey_rng_read(struct hwrng *rng, void *data,
* the buffer will still be empty
*/
if (dev->valid == dev->used)
- (void) _chaoskey_fill(dev);
+ (void) chaoskey_request_fill(dev);
this_time = dev->valid - dev->used;
if (this_time > max)
@@ -540,6 +558,11 @@ static int chaoskey_rng_read(struct hwrng *rng, void *data,
static int chaoskey_suspend(struct usb_interface *interface,
pm_message_t message)
{
+ struct chaoskey *dev = usb_get_intfdata(interface);
+
+ if (dev->reading && PMSG_IS_AUTO(message))
+ return -EBUSY;
+
usb_dbg(interface, "suspend");
return 0;
}
--
2.1.4
From 877a5c63bf1b8b379971016f9537063557dda81a Mon Sep 17 00:00:00 2001
From: Oliver Neukum <[email protected]>
Date: Thu, 25 Feb 2016 14:42:04 +0100
Subject: [PATCH 3/4] chaoskey: make read() obey O_NONBLOCK
This skips waiting for a read if O_NONBLOCK is set.
Signed-off-by: Oliver Neukum <[email protected]>
---
drivers/usb/misc/chaoskey.c | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/drivers/usb/misc/chaoskey.c b/drivers/usb/misc/chaoskey.c
index f47e5a7..19dfbb7 100644
--- a/drivers/usb/misc/chaoskey.c
+++ b/drivers/usb/misc/chaoskey.c
@@ -470,10 +470,14 @@ static ssize_t chaoskey_read(struct file *file,
mutex_unlock(&dev->lock);
goto bail;
}
- result = chaoskey_wait_fill(dev);
- if (result < 0) {
- mutex_unlock(&dev->lock);
- goto bail;
+ if (!(file->f_flags & O_NONBLOCK)) {
+ result = chaoskey_wait_fill(dev);
+ if (result < 0) {
+ mutex_unlock(&dev->lock);
+ goto bail;
+ }
+ } else {
+ result = -EAGAIN;
}
}
--
2.1.4
From 4c27eb2e5cd463176f9c962e05924db83b3a1d3c Mon Sep 17 00:00:00 2001
From: Oliver Neukum <[email protected]>
Date: Thu, 25 Feb 2016 20:23:46 +0100
Subject: [PATCH 4/4] chaoskey: request data asynchronously
This requests more data if a read has exhausted the buffer
just to have it ready sooner.
Signed-off-by: Oliver Neukum <[email protected]>
---
drivers/usb/misc/chaoskey.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/drivers/usb/misc/chaoskey.c b/drivers/usb/misc/chaoskey.c
index 19dfbb7..8477587 100644
--- a/drivers/usb/misc/chaoskey.c
+++ b/drivers/usb/misc/chaoskey.c
@@ -372,6 +372,9 @@ static int chaoskey_request_fill(struct chaoskey *dev)
return -ENODEV;
}
+ if (dev->reading)
+ return -EBUSY;
+
/* Make sure the device is awake */
result = usb_autopm_get_interface(dev->interface);
if (result) {
@@ -503,13 +506,16 @@ static ssize_t chaoskey_read(struct file *file,
dev->used += this_time;
mutex_unlock(&dev->lock);
}
+ /* request data on suspicion that it will eventually be used */
+ if (dev->valid == dev->used)
+ (void)chaoskey_request_fill(dev);
bail:
if (read_count) {
usb_dbg(dev->interface, "read %zu bytes", read_count);
return read_count;
}
usb_dbg(dev->interface, "empty read, result %d", result);
- if (result == -ETIMEDOUT)
+ if (result == -ETIMEDOUT || result == -EBUSY)
result = -EAGAIN;
return result;
}
--
2.1.4