diff options
author | smh <smh@FreeBSD.org> | 2013-04-26 16:22:54 +0000 |
---|---|---|
committer | smh <smh@FreeBSD.org> | 2013-04-26 16:22:54 +0000 |
commit | 04187593784330ee90171da3112f318e802f5341 (patch) | |
tree | 97998d55ef77c21ba6d178437ffc1aa53be9be90 /sys/geom/geom_disk.c | |
parent | 1ea74503ffd8a99053489e54715f57cb34bb9880 (diff) | |
download | FreeBSD-src-04187593784330ee90171da3112f318e802f5341.zip FreeBSD-src-04187593784330ee90171da3112f318e802f5341.tar.gz |
Teach GEOM and CAM about the difference between the max "size" of r/w and delete
requests.
sys/geom/geom_disk.h:
- Added d_delmaxsize which represents the maximum size of individual
device delete requests in bytes. This can be used by devices to
inform geom of their size limitations regarding delete operations
which are generally different from the read / write limits as data
is not usually transferred from the host to physical device.
sys/geom/geom_disk.c:
- Use new d_delmaxsize to calculate the size of chunks passed through to
the underlying strategy during deletes instead of using read / write
optimised values. This defaults to d_maxsize if unset (0).
- Moved d_maxsize default up so it can be used to default d_delmaxsize
sys/cam/ata/ata_da.c:
- Added d_delmaxsize calculations for TRIM and CFA
sys/cam/scsi/scsi_da.c:
- Added re-calculation of d_delmaxsize whenever delete_method is set.
- Added kern.cam.da.X.delete_max sysctl which allows the max size for
delete requests to be limited. This is useful in preventing timeouts
on devices who's delete methods are slow. It should be noted that
this limit is reset then the device delete method is changed and
that it can only be lowered not increased from the device max.
Reviewed by: mav
Approved by: pjd (mentor)
Diffstat (limited to 'sys/geom/geom_disk.c')
-rw-r--r-- | sys/geom/geom_disk.c | 29 |
1 files changed, 22 insertions, 7 deletions
diff --git a/sys/geom/geom_disk.c b/sys/geom/geom_disk.c index 7292ae3..bb7b4ce 100644 --- a/sys/geom/geom_disk.c +++ b/sys/geom/geom_disk.c @@ -141,14 +141,23 @@ g_disk_access(struct g_provider *pp, int r, int w, int e) } pp->mediasize = dp->d_mediasize; pp->sectorsize = dp->d_sectorsize; - pp->stripeoffset = dp->d_stripeoffset; - pp->stripesize = dp->d_stripesize; - dp->d_flags |= DISKFLAG_OPEN; if (dp->d_maxsize == 0) { printf("WARNING: Disk drive %s%d has no d_maxsize\n", dp->d_name, dp->d_unit); dp->d_maxsize = DFLTPHYS; } + if (dp->d_flags & DISKFLAG_CANDELETE) { + if (bootverbose && dp->d_delmaxsize == 0) { + printf("WARNING: Disk drive %s%d has no d_delmaxsize\n", + dp->d_name, dp->d_unit); + dp->d_delmaxsize = dp->d_maxsize; + } + } else { + dp->d_delmaxsize = 0; + } + pp->stripeoffset = dp->d_stripeoffset; + pp->stripesize = dp->d_stripesize; + dp->d_flags |= DISKFLAG_OPEN; } else if ((pp->acr + pp->acw + pp->ace) > 0 && (r + w + e) == 0) { if (dp->d_close != NULL) { g_disk_lock_giant(dp); @@ -293,6 +302,10 @@ g_disk_start(struct bio *bp) break; } do { + off_t d_maxsize; + + d_maxsize = (bp->bio_cmd == BIO_DELETE) ? + dp->d_delmaxsize : dp->d_maxsize; bp2->bio_offset += off; bp2->bio_length -= off; if ((bp->bio_flags & BIO_UNMAPPED) == 0) { @@ -307,18 +320,20 @@ g_disk_start(struct bio *bp) bp2->bio_ma_offset %= PAGE_SIZE; bp2->bio_ma_n -= off / PAGE_SIZE; } - if (bp2->bio_length > dp->d_maxsize) { + if (bp2->bio_length > d_maxsize) { /* * XXX: If we have a stripesize we should really - * use it here. + * use it here. Care should be taken in the delete + * case if this is done as deletes can be very + * sensitive to size given how they are processed. */ - bp2->bio_length = dp->d_maxsize; + bp2->bio_length = d_maxsize; if ((bp->bio_flags & BIO_UNMAPPED) != 0) { bp2->bio_ma_n = howmany( bp2->bio_ma_offset + bp2->bio_length, PAGE_SIZE); } - off += dp->d_maxsize; + off += d_maxsize; /* * To avoid a race, we need to grab the next bio * before we schedule this one. See "notes". |