From f29a76bc19c35aeb92cbfd47c779ff8215e2e1dc Mon Sep 17 00:00:00 2001 From: Alexandre Ratchov Date: Fri, 12 Jun 2020 17:21:02 +0200 Subject: [PATCH] On error, drop clients and close the device only if it's still open Fixes crashes when USB devices are disconnected, caused by an attempt to close the already closed device: it was closed once when its ref counter drops to zero (after the last client is disconnected) and once with an explicit call to dev_close() on the error code-path. The same pattern was used for MIDI ports, it's fixed as well. --- sndiod/dev.c | 9 +++++---- sndiod/dev.h | 2 +- sndiod/midi.c | 7 ++++--- sndiod/midi.h | 1 + sndiod/miofile.c | 2 +- sndiod/siofile.c | 4 ++-- 6 files changed, 14 insertions(+), 11 deletions(-) diff --git a/sndiod/dev.c b/sndiod/dev.c index 9dc37a9..9beb8e7 100644 --- a/sndiod/dev.c +++ b/sndiod/dev.c @@ -60,7 +60,6 @@ struct dev *dev_new(char *, struct aparams *, unsigned int, unsigned int, void dev_adjpar(struct dev *, int, int, int); int dev_allocbufs(struct dev *); int dev_open(struct dev *); -void dev_exitall(struct dev *); void dev_freebufs(struct dev *); void dev_close(struct dev *); int dev_ref(struct dev *); @@ -1194,10 +1193,10 @@ dev_open(struct dev *d) } /* - * Force all slots to exit + * Force all slots to exit and close device, called after an error */ void -dev_exitall(struct dev *d) +dev_abort(struct dev *d) { int i; struct slot *s; @@ -1215,6 +1214,9 @@ dev_exitall(struct dev *d) c->ops->exit(c->arg); c->ops = NULL; } + + if (d->pstate != DEV_CFG) + dev_close(d); } /* @@ -1250,7 +1252,6 @@ dev_close(struct dev *d) { struct ctl *c; - dev_exitall(d); d->pstate = DEV_CFG; dev_sio_close(d); dev_freebufs(d); diff --git a/sndiod/dev.h b/sndiod/dev.h index fad647c..416fd27 100644 --- a/sndiod/dev.h +++ b/sndiod/dev.h @@ -260,7 +260,7 @@ struct dev { extern struct dev *dev_list; void dev_log(struct dev *); -void dev_close(struct dev *); +void dev_abort(struct dev *); int dev_reopen(struct dev *); struct dev *dev_new(char *, struct aparams *, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int); diff --git a/sndiod/midi.c b/sndiod/midi.c index 643d888..4410d43 100644 --- a/sndiod/midi.c +++ b/sndiod/midi.c @@ -564,7 +564,7 @@ port_open(struct port *c) } void -port_exitall(struct port *c) +port_abort(struct port *c) { int i; struct midi *ep; @@ -575,6 +575,9 @@ port_exitall(struct port *c) (c->midi->txmask & ep->self)) ep->ops->exit(ep->arg); } + + if (c->state != PORT_CFG) + port_close(c); } int @@ -589,8 +592,6 @@ port_close(struct port *c) #endif c->state = PORT_CFG; port_mio_close(c); - - port_exitall(c); return 1; } diff --git a/sndiod/midi.h b/sndiod/midi.h index cff3576..29dfd5c 100644 --- a/sndiod/midi.h +++ b/sndiod/midi.h @@ -124,5 +124,6 @@ void port_done(struct port *); void port_drain(struct port *); int port_close(struct port *); int port_reopen(struct port *); +void port_abort(struct port *); #endif /* !defined(MIDI_H) */ diff --git a/sndiod/miofile.c b/sndiod/miofile.c index ed3a205..5cf9bf9 100644 --- a/sndiod/miofile.c +++ b/sndiod/miofile.c @@ -187,5 +187,5 @@ port_mio_hup(void *arg) struct port *p = arg; if (!port_reopen(p)) - port_close(p); + port_abort(p); } diff --git a/sndiod/siofile.c b/sndiod/siofile.c index ae1dbf4..0297ba9 100644 --- a/sndiod/siofile.c +++ b/sndiod/siofile.c @@ -83,7 +83,7 @@ dev_sio_timeout(void *arg) dev_log(d); log_puts(": watchdog timeout\n"); - dev_close(d); + dev_abort(d); } /* @@ -640,5 +640,5 @@ dev_sio_hup(void *arg) } #endif if (!dev_reopen(d)) - dev_close(d); + dev_abort(d); }