fd: Move from using device_busy to a refcount
Use refcounting to delay the detach rather than device_busy and/or device_unbusy. fd/fdc is one of the few consumers of device_busy in the tree for that, and it's not a good fit. Also, nothing is waking 'fd' and other drivers don't loop like this. Return EBUSY if we still have active users. Sponsored by: Netflix Reviewed by: mav Differential Revision: https://reviews.freebsd.org/D31830
This commit is contained in:
parent
8ea95b2fba
commit
e2c1243f42
@ -261,6 +261,7 @@ struct fd_data {
|
||||
struct g_provider *fd_provider;
|
||||
device_t dev;
|
||||
struct bio_queue_head fd_bq;
|
||||
bool gone;
|
||||
};
|
||||
|
||||
#define FD_NOT_VALID -2
|
||||
@ -1398,6 +1399,7 @@ fdautoselect(struct fd_data *fd)
|
||||
static g_access_t fd_access;
|
||||
static g_start_t fd_start;
|
||||
static g_ioctl_t fd_ioctl;
|
||||
static g_provgone_t fd_providergone;
|
||||
|
||||
struct g_class g_fd_class = {
|
||||
.name = "FD",
|
||||
@ -1405,6 +1407,7 @@ struct g_class g_fd_class = {
|
||||
.start = fd_start,
|
||||
.access = fd_access,
|
||||
.ioctl = fd_ioctl,
|
||||
.providergone = fd_providergone,
|
||||
};
|
||||
|
||||
static int
|
||||
@ -1413,7 +1416,6 @@ fd_access(struct g_provider *pp, int r, int w, int e)
|
||||
struct fd_data *fd;
|
||||
struct fdc_data *fdc;
|
||||
int ar, aw, ae;
|
||||
int busy;
|
||||
|
||||
fd = pp->geom->softc;
|
||||
fdc = fd->fdc;
|
||||
@ -1431,11 +1433,9 @@ fd_access(struct g_provider *pp, int r, int w, int e)
|
||||
|
||||
if (ar == 0 && aw == 0 && ae == 0) {
|
||||
fd->options &= ~(FDOPT_NORETRY | FDOPT_NOERRLOG | FDOPT_NOERROR);
|
||||
device_unbusy(fd->dev);
|
||||
return (0);
|
||||
}
|
||||
|
||||
busy = 0;
|
||||
if (pp->acr == 0 && pp->acw == 0 && pp->ace == 0) {
|
||||
if (fdmisccmd(fd, BIO_PROBE, NULL))
|
||||
return (ENXIO);
|
||||
@ -1453,13 +1453,9 @@ fd_access(struct g_provider *pp, int r, int w, int e)
|
||||
fd->flags &= ~FD_NEWDISK;
|
||||
mtx_unlock(&fdc->fdc_mtx);
|
||||
}
|
||||
device_busy(fd->dev);
|
||||
busy = 1;
|
||||
}
|
||||
|
||||
if (w > 0 && (fd->flags & FD_WP)) {
|
||||
if (busy)
|
||||
device_unbusy(fd->dev);
|
||||
return (EROFS);
|
||||
}
|
||||
|
||||
@ -1588,8 +1584,6 @@ fd_ioctl(struct g_provider *pp, u_long cmd, void *data, int fflag, struct thread
|
||||
return (error);
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Configuration/initialization stuff, per controller.
|
||||
*/
|
||||
@ -2055,6 +2049,16 @@ fd_attach(device_t dev)
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
fd_providergone(struct g_provider *pp)
|
||||
{
|
||||
struct fd_data *fd;
|
||||
|
||||
fd = pp->geom->softc;
|
||||
fd->gone = true;
|
||||
wakeup(fd);
|
||||
}
|
||||
|
||||
static void
|
||||
fd_detach_geom(void *arg, int flag)
|
||||
{
|
||||
@ -2070,9 +2074,17 @@ fd_detach(device_t dev)
|
||||
struct fd_data *fd;
|
||||
|
||||
fd = device_get_softc(dev);
|
||||
|
||||
g_waitfor_event(fd_detach_geom, fd, M_WAITOK, NULL);
|
||||
while (device_get_state(dev) == DS_BUSY)
|
||||
tsleep(fd, PZERO, "fdd", hz/10);
|
||||
while (!fd->gone) {
|
||||
tsleep(fd, PZERO, "fdgone", hz/10);
|
||||
}
|
||||
|
||||
/*
|
||||
* There may be accesses to the floppy while we're waitng, so drain the
|
||||
* motor callback here. fdc_detach turns off motor if it's still on when
|
||||
* we get to this point.
|
||||
*/
|
||||
callout_drain(&fd->toffhandle);
|
||||
|
||||
return (0);
|
||||
|
Loading…
Reference in New Issue
Block a user