aboutsummaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorAlexander Motin <mav@FreeBSD.org>2011-06-02 20:56:42 +0000
committerAlexander Motin <mav@FreeBSD.org>2011-06-02 20:56:42 +0000
commit37ddbd16a5a8978fd77f4a468ac913ada9299680 (patch)
treeea59f9b46988e872e566c935b25982386ddde21e /sys
parent6924e68e11d31cd378f101ebfa7d0a8f3784d3e6 (diff)
When possible, join ranges of subsequest BIO_DELETE requests to handle more
(up to 2048 instead of 256 or even 64) of them with single TRIM request. OCZ Vertex2/Vertex3 SSDs can handle no more then 64 ranges per TRIM request. Due to lack of BIO_DELETE clustering now, it means that we could delete no more then 2MB per request (on FS with 32K block) with limited request rate. This change increases delete rate on Vertex2 from 250MB/s to 950MB/s.
Notes
Notes: svn path=/head/; revision=222628
Diffstat (limited to 'sys')
-rw-r--r--sys/cam/ata/ata_da.c34
1 files changed, 25 insertions, 9 deletions
diff --git a/sys/cam/ata/ata_da.c b/sys/cam/ata/ata_da.c
index 7418e1e9a228..f918956b0425 100644
--- a/sys/cam/ata/ata_da.c
+++ b/sys/cam/ata/ata_da.c
@@ -115,10 +115,11 @@ struct disk_params {
};
#define TRIM_MAX_BLOCKS 4
-#define TRIM_MAX_RANGES TRIM_MAX_BLOCKS * 64
+#define TRIM_MAX_RANGES (TRIM_MAX_BLOCKS * 64)
+#define TRIM_MAX_BIOS (TRIM_MAX_RANGES * 8)
struct trim_request {
uint8_t data[TRIM_MAX_RANGES * 8];
- struct bio *bps[TRIM_MAX_RANGES];
+ struct bio *bps[TRIM_MAX_BIOS];
};
struct ada_softc {
@@ -1067,7 +1068,8 @@ adastart(struct cam_periph *periph, union ccb *start_ccb)
(bp = bioq_first(&softc->trim_queue)) != 0) {
struct trim_request *req = &softc->trim_req;
struct bio *bp1;
- int bps = 0, ranges = 0;
+ uint64_t lastlba = (uint64_t)-1;
+ int bps = 0, c, lastcount = 0, off, ranges = 0;
softc->trim_running = 1;
bzero(req, sizeof(*req));
@@ -1078,10 +1080,22 @@ adastart(struct cam_periph *periph, union ccb *start_ccb)
softc->params.secsize;
bioq_remove(&softc->trim_queue, bp1);
- while (count > 0) {
- int c = min(count, 0xffff);
- int off = ranges * 8;
+ /* Try to extend the previous range. */
+ if (lba == lastlba) {
+ c = min(count, 0xffff - lastcount);
+ lastcount += c;
+ off = (ranges - 1) * 8;
+ req->data[off + 6] = lastcount & 0xff;
+ req->data[off + 7] =
+ (lastcount >> 8) & 0xff;
+ count -= c;
+ lba += c;
+ }
+
+ while (count > 0) {
+ c = min(count, 0xffff);
+ off = ranges * 8;
req->data[off + 0] = lba & 0xff;
req->data[off + 1] = (lba >> 8) & 0xff;
req->data[off + 2] = (lba >> 16) & 0xff;
@@ -1092,11 +1106,14 @@ adastart(struct cam_periph *periph, union ccb *start_ccb)
req->data[off + 7] = (c >> 8) & 0xff;
lba += c;
count -= c;
+ lastcount = c;
ranges++;
}
+ lastlba = lba;
req->bps[bps++] = bp1;
bp1 = bioq_first(&softc->trim_queue);
- if (bp1 == NULL ||
+ if (bps >= TRIM_MAX_BIOS ||
+ bp1 == NULL ||
bp1->bio_bcount / softc->params.secsize >
(softc->trim_max_ranges - ranges) * 0xffff)
break;
@@ -1370,8 +1387,7 @@ adadone(struct cam_periph *periph, union ccb *done_ccb)
(struct trim_request *)ataio->data_ptr;
int i;
- for (i = 1; i < softc->trim_max_ranges &&
- req->bps[i]; i++) {
+ for (i = 1; i < TRIM_MAX_BIOS && req->bps[i]; i++) {
struct bio *bp1 = req->bps[i];
bp1->bio_resid = bp->bio_resid;