From e2c1243f427b7dd387efd42669cc199cbb9b514c Mon Sep 17 00:00:00 2001 From: Warner Losh Date: Wed, 29 Sep 2021 20:18:28 -0600 Subject: [PATCH] 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 --- sys/dev/fdc/fdc.c | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/sys/dev/fdc/fdc.c b/sys/dev/fdc/fdc.c index 11262231c3b2..6f035e9689f1 100644 --- a/sys/dev/fdc/fdc.c +++ b/sys/dev/fdc/fdc.c @@ -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);