On Sun, Oct 16, 2016 at 10:19:53AM +0200, Stefan Fritsch wrote: > On Sun, 16 Oct 2016, Stefan Fritsch wrote: > > * When a R/W mount is updated to R/O. I will send patches for this in a > > separate mail. > > Part 1: Add an ioctl: > > > add DIOCCACHESYNC > > Add an ioctl to tell storage devices to flush their internal caches. > Ported from netbsd by pedro@ > > OK?
Some remarks inline > @@ -848,6 +848,10 @@ wdioctl(dev_t dev, u_long xfer, caddr_t addr, int flag, > struct proc *p) > } > #endif > > + /* XXX pedro: should set AT_WAIT according to force flag */ Does this comment help? Either do (*(int *)addr ? AT_WAIT : 0) or just pass AT_WAIT. But don't force all people reading the code to think about it. I think the AT_WAIT code is correct and the comment is wrong. In sdioctl() the force flag overrides the SDF_DIRTY flag. This is different from setting AT_WAIT. Just remove the pedro comment. Then we have the NetBSD code. > + case DIOCCACHESYNC: > + return wd_flushcache(wd, AT_WAIT); > + All other cases have a "goto exit". With the return we miss a device_unref(). > default: > error = wdc_ioctl(wd->drvp, xfer, addr, flag, p); > goto exit; > @@ -1067,13 +1071,13 @@ wd_get_params(struct wd_softc *wd, u_int8_t flags, > struct ataparams *params) > } > } > > -void > +int > wd_flushcache(struct wd_softc *wd, int flags) > { > struct wdc_command wdc_c; > > if (wd->drvp->ata_vers < 4) /* WDCC_FLUSHCACHE is here since ATA-4 */ > - return; > + return EIO; > bzero(&wdc_c, sizeof(struct wdc_command)); > wdc_c.r_command = (wd->sc_flags & WDF_LBA48 ? WDCC_FLUSHCACHE_EXT : > WDCC_FLUSHCACHE); > @@ -1088,20 +1092,18 @@ wd_flushcache(struct wd_softc *wd, int flags) > if (wdc_exec_command(wd->drvp, &wdc_c) != WDC_COMPLETE) { > printf("%s: flush cache command didn't complete\n", > wd->sc_dev.dv_xname); > + return EIO; > } > - if (wdc_c.flags & AT_TIMEOU) { > - printf("%s: flush cache command timeout\n", > - wd->sc_dev.dv_xname); > + if (wdc_c.flags & AT_ERROR) { > + if (wdc_c.r_error == WDCE_ABRT) /* command not supported */ > + return ENODEV; > } > - if (wdc_c.flags & AT_DF) { > - printf("%s: flush cache command: drive fault\n", > + if (wdc_c.flags & (AT_ERROR | AT_TIMEOU | AT_DF)) { > + printf("%s: flush cache command timeout\n", > wd->sc_dev.dv_xname); NetBSD prints the flags here. If we merge the cases, debugging will be harder if don't print the relevant bits. > + return EIO; > } > - /* > - * Ignore error register, it shouldn't report anything else > - * than COMMAND ABORTED, which means the device doesn't support > - * flush cache > - */ > + return 0; > } Instead of merging the cases, which was done independently in NetBSD, I would perfer to take their original commit. http://cvsweb.netbsd.org/bsdweb.cgi/src/sys/dev/ata/wd.c.diff?r1=1.275&r2=1.276&only_with_tag=MAIN&f=h Also I think their EIO/ENODEV choices are better. > @@ -999,6 +999,15 @@ sdioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, > struct proc *p) > error = sd_ioctl_cache(sc, cmd, (struct dk_cache *)addr); > goto exit; > > + case DIOCCACHESYNC: > + if (!ISSET(flag, FWRITE)) { > + error = EBADF; > + goto exit; > + } > + if ((sc->flags & SDF_DIRTY) != 0 || *(int *)addr != 0) > + error = sd_flush(sc, 0); > + return (error); You need a goto exit to call device_unref(). > + > default: > if (part != RAW_PART) { > error = ENOTTY; bluhm