geom write cache handling
Richard Kojedzinszky
krichy at cflinux.hu
Thu Feb 6 14:37:08 UTC 2014
Dear fs team,
I own an STEC SSD, which I use for ZFS SLOG. The device is broken in that
if it gets a SCSI synchronize cache, it does something which is very slow.
Actually with it in FreeBSD the reachable sync IOPS is around 100. When
the device has write cache disabled, there is no need to send the SCSI
synchronize cache commands to it, and without them I can reach 1400 IOPS.
The device itself have power-loss-protection, so I risk no data corruption
at all.
By the way, linux behave the same, if either ata or scsi disks have their
write cache turned off, it even does not send the command to the drive.
Also, I have an Intel S3700, which is much faster, but have similar
symptons. The drive handles synchronize cache commands much faster than
STEC, maybe it is implemented in the drive as a simple NOP, but as for 4K
sync writes a sync cache follows, it effectively halves the IOPS. I have
it attached to a SATA2 controller only, and with WCE disabled, and sending
the sync cache to it I can reach around 4500 IOPS, while disabling the
sync cache it can reach >9000 IOPS.
I've attached a very simple patch for the ata layer, but I dont know how
to implement it for the scsi subsystem also.
Regards,
Kojedzinszky Richard
-------------- next part --------------
diff --git a/sys/cam/ata/ata_da.c b/sys/cam/ata/ata_da.c
index cc28311..10e4f9b 100644
--- a/sys/cam/ata/ata_da.c
+++ b/sys/cam/ata/ata_da.c
@@ -1242,7 +1242,7 @@ adaregister(struct cam_periph *periph, void *arg)
maxio = min(maxio, 256 * softc->params.secsize);
softc->disk->d_maxsize = maxio;
softc->disk->d_unit = periph->unit_number;
- softc->disk->d_flags = 0;
+ softc->disk->d_flags = DISKFLAG_WRITE_THROUGH;
if (softc->flags & ADA_FLAG_CAN_FLUSHCACHE)
softc->disk->d_flags |= DISKFLAG_CANFLUSHCACHE;
if (softc->flags & ADA_FLAG_CAN_TRIM) {
@@ -1835,6 +1835,12 @@ adadone(struct cam_periph *periph, union ccb *done_ccb)
}
}
+ if (ataio->cmd.features == ATA_SF_ENAB_WCACHE) {
+ softc->disk->d_flags &= ~DISKFLAG_WRITE_THROUGH;
+ } else {
+ softc->disk->d_flags |= DISKFLAG_WRITE_THROUGH;
+ }
+
softc->state = ADA_STATE_NORMAL;
/*
* Since our peripheral may be invalidated by an error
diff --git a/sys/geom/geom_disk.c b/sys/geom/geom_disk.c
index 16f6c44..2cb4cef 100644
--- a/sys/geom/geom_disk.c
+++ b/sys/geom/geom_disk.c
@@ -404,6 +404,10 @@ g_disk_start(struct bio *bp)
case BIO_FLUSH:
g_trace(G_T_BIO, "g_disk_flushcache(%s)",
bp->bio_to->name);
+ if (dp->d_flags & DISKFLAG_WRITE_THROUGH) {
+ error = 0;
+ break;
+ }
if (!(dp->d_flags & DISKFLAG_CANFLUSHCACHE)) {
error = EOPNOTSUPP;
break;
diff --git a/sys/geom/geom_disk.h b/sys/geom/geom_disk.h
index 5e081c8..a53aa38 100644
--- a/sys/geom/geom_disk.h
+++ b/sys/geom/geom_disk.h
@@ -111,6 +111,7 @@ struct disk {
#define DISKFLAG_LACKS_GONE 0x10
#define DISKFLAG_UNMAPPED_BIO 0x20
#define DISKFLAG_LACKS_DELMAX 0x40
+#define DISKFLAG_WRITE_THROUGH 0x80
struct disk *disk_alloc(void);
void disk_create(struct disk *disk, int version);
More information about the freebsd-fs
mailing list