summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/cam/ata/ata_da.c3
-rw-r--r--sys/cam/scsi/scsi_da.c21
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_geom.c1
-rw-r--r--sys/geom/geom_io.c1
-rw-r--r--sys/geom/sched/subr_disk.c37
-rw-r--r--sys/kern/subr_disk.c37
-rw-r--r--sys/sys/bio.h1
7 files changed, 74 insertions, 27 deletions
diff --git a/sys/cam/ata/ata_da.c b/sys/cam/ata/ata_da.c
index 3968026..8a27931 100644
--- a/sys/cam/ata/ata_da.c
+++ b/sys/cam/ata/ata_da.c
@@ -874,7 +874,8 @@ adastart(struct cam_periph *periph, union ccb *start_ccb)
}
bioq_remove(&softc->bio_queue, bp);
- if ((softc->flags & ADA_FLAG_NEED_OTAG) != 0) {
+ if ((bp->bio_flags & BIO_ORDERED) != 0
+ || (softc->flags & ADA_FLAG_NEED_OTAG) != 0) {
softc->flags &= ~ADA_FLAG_NEED_OTAG;
softc->ordered_tag_count++;
tag_code = 0;
diff --git a/sys/cam/scsi/scsi_da.c b/sys/cam/scsi/scsi_da.c
index 8f64361..7729ecc 100644
--- a/sys/cam/scsi/scsi_da.c
+++ b/sys/cam/scsi/scsi_da.c
@@ -1354,7 +1354,8 @@ dastart(struct cam_periph *periph, union ccb *start_ccb)
bioq_remove(&softc->bio_queue, bp);
- if ((softc->flags & DA_FLAG_NEED_OTAG) != 0) {
+ if ((bp->bio_flags & BIO_ORDERED) != 0
+ || (softc->flags & DA_FLAG_NEED_OTAG) != 0) {
softc->flags &= ~DA_FLAG_NEED_OTAG;
softc->ordered_tag_count++;
tag_code = MSG_ORDERED_Q_TAG;
@@ -1368,7 +1369,8 @@ dastart(struct cam_periph *periph, union ccb *start_ccb)
/*retries*/da_retry_count,
/*cbfcnp*/dadone,
/*tag_action*/tag_code,
- /*read_op*/bp->bio_cmd == BIO_READ,
+ /*read_op*/bp->bio_cmd
+ == BIO_READ,
/*byte2*/0,
softc->minimum_cmd_size,
/*lba*/bp->bio_pblkno,
@@ -1377,17 +1379,24 @@ dastart(struct cam_periph *periph, union ccb *start_ccb)
/*data_ptr*/ bp->bio_data,
/*dxfer_len*/ bp->bio_bcount,
/*sense_len*/SSD_FULL_SIZE,
- /*timeout*/da_default_timeout*1000);
+ da_default_timeout * 1000);
break;
case BIO_FLUSH:
+ /*
+ * BIO_FLUSH doesn't currently communicate
+ * range data, so we synchronize the cache
+ * over the whole disk. We also force
+ * ordered tag semantics the flush applies
+ * to all previously queued I/O.
+ */
scsi_synchronize_cache(&start_ccb->csio,
/*retries*/1,
/*cbfcnp*/dadone,
- MSG_SIMPLE_Q_TAG,
- /*begin_lba*/0,/* Cover the whole disk */
+ MSG_ORDERED_Q_TAG,
+ /*begin_lba*/0,
/*lb_count*/0,
SSD_FULL_SIZE,
- /*timeout*/da_default_timeout*1000);
+ da_default_timeout*1000);
break;
}
start_ccb->ccb_h.ccb_state = DA_CCB_BUFFER_IO;
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_geom.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_geom.c
index 00817bf..d0d5137 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_geom.c
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_geom.c
@@ -598,6 +598,7 @@ sendreq:
break;
case ZIO_TYPE_IOCTL:
bp->bio_cmd = BIO_FLUSH;
+ bp->bio_flags |= BIO_ORDERED;
bp->bio_data = NULL;
bp->bio_offset = cp->provider->mediasize;
bp->bio_length = 0;
diff --git a/sys/geom/geom_io.c b/sys/geom/geom_io.c
index b145441..b4044a7 100644
--- a/sys/geom/geom_io.c
+++ b/sys/geom/geom_io.c
@@ -265,6 +265,7 @@ g_io_flush(struct g_consumer *cp)
g_trace(G_T_BIO, "bio_flush(%s)", cp->provider->name);
bp = g_alloc_bio();
bp->bio_cmd = BIO_FLUSH;
+ bp->bio_flags |= BIO_ORDERED;
bp->bio_done = NULL;
bp->bio_attribute = NULL;
bp->bio_offset = cp->provider->mediasize;
diff --git a/sys/geom/sched/subr_disk.c b/sys/geom/sched/subr_disk.c
index 008eaab..db2a9ef 100644
--- a/sys/geom/sched/subr_disk.c
+++ b/sys/geom/sched/subr_disk.c
@@ -86,7 +86,7 @@ __FBSDID("$FreeBSD$");
* bioq_remove() remove a generic element from the queue, act as
* bioq_takefirst() if invoked on the head of the queue.
*
- * The semantic of these methods is the same of the operations
+ * The semantic of these methods is the same as the operations
* on the underlying TAILQ, but with additional guarantees on
* subsequent bioq_disksort() calls. E.g. bioq_insert_tail()
* can be useful for making sure that all previous ops are flushed
@@ -115,10 +115,10 @@ void
gs_bioq_remove(struct bio_queue_head *head, struct bio *bp)
{
- if (bp == TAILQ_FIRST(&head->queue))
- head->last_offset = bp->bio_offset + bp->bio_length;
-
- if (bp == head->insert_point)
+ if (head->insert_point == NULL) {
+ if (bp == TAILQ_FIRST(&head->queue))
+ head->last_offset = bp->bio_offset + bp->bio_length;
+ } else if (bp == head->insert_point)
head->insert_point = NULL;
TAILQ_REMOVE(&head->queue, bp, bio_queue);
@@ -137,7 +137,8 @@ void
gs_bioq_insert_head(struct bio_queue_head *head, struct bio *bp)
{
- head->last_offset = bp->bio_offset;
+ if (head->insert_point == NULL)
+ head->last_offset = bp->bio_offset;
TAILQ_INSERT_HEAD(&head->queue, bp, bio_queue);
}
@@ -147,6 +148,7 @@ gs_bioq_insert_tail(struct bio_queue_head *head, struct bio *bp)
TAILQ_INSERT_TAIL(&head->queue, bp, bio_queue);
head->insert_point = bp;
+ head->last_offset = bp->bio_offset;
}
struct bio *
@@ -189,13 +191,28 @@ gs_bioq_bio_key(struct bio_queue_head *head, struct bio *bp)
void
gs_bioq_disksort(struct bio_queue_head *head, struct bio *bp)
{
- struct bio *cur, *prev = NULL;
- uoff_t key = gs_bioq_bio_key(head, bp);
+ struct bio *cur, *prev;
+ uoff_t key;
+
+ if ((bp->bio_flags & BIO_ORDERED) != 0) {
+ /*
+ * Ordered transactions can only be dispatched
+ * after any currently queued transactions. They
+ * also have barrier semantics - no transactions
+ * queued in the future can pass them.
+ */
+ gs_bioq_insert_tail(head, bp);
+ return;
+ }
+ prev = NULL;
+ key = gs_bioq_bio_key(head, bp);
cur = TAILQ_FIRST(&head->queue);
- if (head->insert_point)
- cur = head->insert_point;
+ if (head->insert_point) {
+ prev = head->insert_point;
+ cur = TAILQ_NEXT(head->insert_point, bio_queue);
+ }
while (cur != NULL && key >= gs_bioq_bio_key(head, cur)) {
prev = cur;
diff --git a/sys/kern/subr_disk.c b/sys/kern/subr_disk.c
index 12b0159..2391540 100644
--- a/sys/kern/subr_disk.c
+++ b/sys/kern/subr_disk.c
@@ -127,7 +127,7 @@ disk_err(struct bio *bp, const char *what, int blkdone, int nl)
* bioq_remove() remove a generic element from the queue, act as
* bioq_takefirst() if invoked on the head of the queue.
*
- * The semantic of these methods is the same of the operations
+ * The semantic of these methods is the same as the operations
* on the underlying TAILQ, but with additional guarantees on
* subsequent bioq_disksort() calls. E.g. bioq_insert_tail()
* can be useful for making sure that all previous ops are flushed
@@ -156,10 +156,10 @@ void
bioq_remove(struct bio_queue_head *head, struct bio *bp)
{
- if (bp == TAILQ_FIRST(&head->queue))
- head->last_offset = bp->bio_offset + bp->bio_length;
-
- if (bp == head->insert_point)
+ if (head->insert_point == NULL) {
+ if (bp == TAILQ_FIRST(&head->queue))
+ head->last_offset = bp->bio_offset + bp->bio_length;
+ } else if (bp == head->insert_point)
head->insert_point = NULL;
TAILQ_REMOVE(&head->queue, bp, bio_queue);
@@ -178,7 +178,8 @@ void
bioq_insert_head(struct bio_queue_head *head, struct bio *bp)
{
- head->last_offset = bp->bio_offset;
+ if (head->insert_point == NULL)
+ head->last_offset = bp->bio_offset;
TAILQ_INSERT_HEAD(&head->queue, bp, bio_queue);
}
@@ -188,6 +189,7 @@ bioq_insert_tail(struct bio_queue_head *head, struct bio *bp)
TAILQ_INSERT_TAIL(&head->queue, bp, bio_queue);
head->insert_point = bp;
+ head->last_offset = bp->bio_offset;
}
struct bio *
@@ -230,13 +232,28 @@ bioq_bio_key(struct bio_queue_head *head, struct bio *bp)
void
bioq_disksort(struct bio_queue_head *head, struct bio *bp)
{
- struct bio *cur, *prev = NULL;
- uoff_t key = bioq_bio_key(head, bp);
+ struct bio *cur, *prev;
+ uoff_t key;
+ if ((bp->bio_flags & BIO_ORDERED) != 0) {
+ /*
+ * Ordered transactions can only be dispatched
+ * after any currently queued transactions. They
+ * also have barrier semantics - no transactions
+ * queued in the future can pass them.
+ */
+ bioq_insert_tail(head, bp);
+ return;
+ }
+
+ prev = NULL;
+ key = bioq_bio_key(head, bp);
cur = TAILQ_FIRST(&head->queue);
- if (head->insert_point)
- cur = head->insert_point;
+ if (head->insert_point) {
+ prev = head->insert_point;
+ cur = TAILQ_NEXT(head->insert_point, bio_queue);
+ }
while (cur != NULL && key >= bioq_bio_key(head, cur)) {
prev = cur;
diff --git a/sys/sys/bio.h b/sys/sys/bio.h
index 8b6ff0e..c016ee6 100644
--- a/sys/sys/bio.h
+++ b/sys/sys/bio.h
@@ -54,6 +54,7 @@
#define BIO_ERROR 0x01
#define BIO_DONE 0x02
#define BIO_ONQUEUE 0x04
+#define BIO_ORDERED 0x08
#ifdef _KERNEL
struct disk;
OpenPOWER on IntegriCloud