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.
This commit is contained in:
Alexandre Ratchov 2020-06-12 17:21:02 +02:00
parent c531dda0ad
commit f29a76bc19
6 changed files with 14 additions and 11 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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;
}

View File

@ -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) */

View File

@ -187,5 +187,5 @@ port_mio_hup(void *arg)
struct port *p = arg;
if (!port_reopen(p))
port_close(p);
port_abort(p);
}

View File

@ -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);
}