summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorhselasky <hselasky@FreeBSD.org>2015-01-13 13:32:18 +0000
committerhselasky <hselasky@FreeBSD.org>2015-01-13 13:32:18 +0000
commit4d7a9f7cc13d3e44121d38d2b286dfaf84f1d560 (patch)
treed07ffcc7910ee3deca545e61c37187c4c2f89317
parent66ccb206af59cd3676c7ad46ab76f1b9f2b1187d (diff)
downloadFreeBSD-src-4d7a9f7cc13d3e44121d38d2b286dfaf84f1d560.zip
FreeBSD-src-4d7a9f7cc13d3e44121d38d2b286dfaf84f1d560.tar.gz
Don't use POLLNVAL as a return value from the client side poll
function. Many existing clients don't understand POLLNVAL and instead relies on an error code from the read(), write() or ioctl() system call. Also make sure we wakeup any client pollers before the cuse server is closing, so they don't wait forever for an event.
-rw-r--r--sys/fs/cuse/cuse.c38
1 files changed, 28 insertions, 10 deletions
diff --git a/sys/fs/cuse/cuse.c b/sys/fs/cuse/cuse.c
index 37765d4..7284b81 100644
--- a/sys/fs/cuse/cuse.c
+++ b/sys/fs/cuse/cuse.c
@@ -142,6 +142,7 @@ static struct cuse_server *cuse_alloc_unit[CUSE_DEVICES_MAX];
static int cuse_alloc_unit_id[CUSE_DEVICES_MAX];
static struct cuse_memory cuse_mem[CUSE_ALLOC_UNIT_MAX];
+static void cuse_server_wakeup_all_client_locked(struct cuse_server *pcs);
static void cuse_client_kqfilter_read_detach(struct knote *kn);
static void cuse_client_kqfilter_write_detach(struct knote *kn);
static int cuse_client_kqfilter_read_event(struct knote *kn, long hint);
@@ -648,6 +649,8 @@ cuse_server_free(void *arg)
return;
}
cuse_server_is_closing(pcs);
+ /* final client wakeup, if any */
+ cuse_server_wakeup_all_client_locked(pcs);
TAILQ_REMOVE(&cuse_server_head, pcs, entry);
@@ -716,6 +719,9 @@ cuse_server_close(struct cdev *dev, int fflag, int devtype, struct thread *td)
cuse_lock();
cuse_server_is_closing(pcs);
+ /* final client wakeup, if any */
+ cuse_server_wakeup_all_client_locked(pcs);
+
knlist_clear(&pcs->selinfo.si_note, 1);
cuse_unlock();
@@ -920,6 +926,18 @@ cuse_server_wakeup_locked(struct cuse_server *pcs)
KNOTE_LOCKED(&pcs->selinfo.si_note, 0);
}
+static void
+cuse_server_wakeup_all_client_locked(struct cuse_server *pcs)
+{
+ struct cuse_client *pcc;
+
+ TAILQ_FOREACH(pcc, &pcs->hcli, entry) {
+ pcc->cflags |= (CUSE_CLI_KNOTE_NEED_READ |
+ CUSE_CLI_KNOTE_NEED_WRITE);
+ }
+ cuse_server_wakeup_locked(pcs);
+}
+
static int
cuse_free_unit_by_id_locked(struct cuse_server *pcs, int id)
{
@@ -1226,11 +1244,7 @@ cuse_server_ioctl(struct cdev *dev, unsigned long cmd,
* We don't know which direction caused the event.
* Wakeup both!
*/
- TAILQ_FOREACH(pcc, &pcs->hcli, entry) {
- pcc->cflags |= (CUSE_CLI_KNOTE_NEED_READ |
- CUSE_CLI_KNOTE_NEED_WRITE);
- }
- cuse_server_wakeup_locked(pcs);
+ cuse_server_wakeup_all_client_locked(pcs);
cuse_unlock();
break;
@@ -1677,7 +1691,7 @@ cuse_client_poll(struct cdev *dev, int events, struct thread *td)
error = cuse_client_get(&pcc);
if (error != 0)
- return (POLLNVAL);
+ goto pollnval;
temp = 0;
@@ -1705,8 +1719,10 @@ cuse_client_poll(struct cdev *dev, int events, struct thread *td)
error = cuse_client_receive_command_locked(pccmd, 0, 0);
cuse_unlock();
+ cuse_cmd_unlock(pccmd);
+
if (error < 0) {
- revents = POLLNVAL;
+ goto pollnval;
} else {
revents = 0;
if (error & CUSE_POLL_READ)
@@ -1716,10 +1732,12 @@ cuse_client_poll(struct cdev *dev, int events, struct thread *td)
if (error & CUSE_POLL_ERROR)
revents |= (events & POLLHUP);
}
-
- cuse_cmd_unlock(pccmd);
-
return (revents);
+
+ pollnval:
+ /* XXX many clients don't understand POLLNVAL */
+ return (events & (POLLHUP | POLLPRI | POLLIN |
+ POLLRDNORM | POLLOUT | POLLWRNORM));
}
static int
OpenPOWER on IntegriCloud