Commit 7e64db15 authored by Jan Höppner's avatar Jan Höppner Committed by Vasily Gorbik

s390/dasd: Add discard support for ESE volumes

ESE (Extent Space Efficient) volumes are thin-provisioned and therefore
space is only occupied with real data. In order to make previously used
space available for re-allocation again, discard support is enabled for
ESE volumes allowing the DASD driver to release said space.
Signed-off-by: default avatarJan Höppner <hoeppner@linux.ibm.com>
Reviewed-by: default avatarStefan Haberland <sth@linux.ibm.com>
Signed-off-by: default avatarVasily Gorbik <gor@linux.ibm.com>
parent b5444153
...@@ -1987,6 +1987,9 @@ dasd_eckd_check_characteristics(struct dasd_device *device) ...@@ -1987,6 +1987,9 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
if (readonly) if (readonly)
set_bit(DASD_FLAG_DEVICE_RO, &device->flags); set_bit(DASD_FLAG_DEVICE_RO, &device->flags);
if (dasd_eckd_is_ese(device))
dasd_set_feature(device->cdev, DASD_FEATURE_DISCARD, 1);
dev_info(&device->cdev->dev, "New DASD %04X/%02X (CU %04X/%02X) " dev_info(&device->cdev->dev, "New DASD %04X/%02X (CU %04X/%02X) "
"with %d cylinders, %d heads, %d sectors%s\n", "with %d cylinders, %d heads, %d sectors%s\n",
private->rdc_data.dev_type, private->rdc_data.dev_type,
...@@ -3617,6 +3620,14 @@ static int dasd_eckd_release_space(struct dasd_device *device, ...@@ -3617,6 +3620,14 @@ static int dasd_eckd_release_space(struct dasd_device *device,
return -EINVAL; return -EINVAL;
} }
static struct dasd_ccw_req *
dasd_eckd_build_cp_discard(struct dasd_device *device, struct dasd_block *block,
struct request *req, sector_t first_trk,
sector_t last_trk)
{
return dasd_eckd_dso_ras(device, block, req, first_trk, last_trk, 1);
}
static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_single( static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_single(
struct dasd_device *startdev, struct dasd_device *startdev,
struct dasd_block *block, struct dasd_block *block,
...@@ -4361,6 +4372,10 @@ static struct dasd_ccw_req *dasd_eckd_build_cp(struct dasd_device *startdev, ...@@ -4361,6 +4372,10 @@ static struct dasd_ccw_req *dasd_eckd_build_cp(struct dasd_device *startdev,
cmdwtd = private->features.feature[12] & 0x40; cmdwtd = private->features.feature[12] & 0x40;
use_prefix = private->features.feature[8] & 0x01; use_prefix = private->features.feature[8] & 0x01;
if (req_op(req) == REQ_OP_DISCARD)
return dasd_eckd_build_cp_discard(startdev, block, req,
first_trk, last_trk);
cqr = NULL; cqr = NULL;
if (cdlspecial || dasd_page_cache) { if (cdlspecial || dasd_page_cache) {
/* do nothing, just fall through to the cmd mode single case */ /* do nothing, just fall through to the cmd mode single case */
...@@ -4639,11 +4654,13 @@ static struct dasd_ccw_req *dasd_eckd_build_alias_cp(struct dasd_device *base, ...@@ -4639,11 +4654,13 @@ static struct dasd_ccw_req *dasd_eckd_build_alias_cp(struct dasd_device *base,
struct dasd_block *block, struct dasd_block *block,
struct request *req) struct request *req)
{ {
struct dasd_device *startdev = NULL;
struct dasd_eckd_private *private; struct dasd_eckd_private *private;
struct dasd_device *startdev;
unsigned long flags;
struct dasd_ccw_req *cqr; struct dasd_ccw_req *cqr;
unsigned long flags;
/* Discard requests can only be processed on base devices */
if (req_op(req) != REQ_OP_DISCARD)
startdev = dasd_alias_get_start_dev(base); startdev = dasd_alias_get_start_dev(base);
if (!startdev) if (!startdev)
startdev = base; startdev = base;
...@@ -6357,8 +6374,20 @@ static void dasd_eckd_setup_blk_queue(struct dasd_block *block) ...@@ -6357,8 +6374,20 @@ static void dasd_eckd_setup_blk_queue(struct dasd_block *block)
unsigned int logical_block_size = block->bp_block; unsigned int logical_block_size = block->bp_block;
struct request_queue *q = block->request_queue; struct request_queue *q = block->request_queue;
struct dasd_device *device = block->base; struct dasd_device *device = block->base;
struct dasd_eckd_private *private;
unsigned int max_discard_sectors;
unsigned int max_bytes;
unsigned int ext_bytes; /* Extent Size in Bytes */
int recs_per_trk;
int trks_per_cyl;
int ext_limit;
int ext_size; /* Extent Size in Cylinders */
int max; int max;
private = device->private;
trks_per_cyl = private->rdc_data.trk_per_cyl;
recs_per_trk = recs_per_track(&private->rdc_data, 0, logical_block_size);
if (device->features & DASD_FEATURE_USERAW) { if (device->features & DASD_FEATURE_USERAW) {
/* /*
* the max_blocks value for raw_track access is 256 * the max_blocks value for raw_track access is 256
...@@ -6379,6 +6408,28 @@ static void dasd_eckd_setup_blk_queue(struct dasd_block *block) ...@@ -6379,6 +6408,28 @@ static void dasd_eckd_setup_blk_queue(struct dasd_block *block)
/* With page sized segments each segment can be translated into one idaw/tidaw */ /* With page sized segments each segment can be translated into one idaw/tidaw */
blk_queue_max_segment_size(q, PAGE_SIZE); blk_queue_max_segment_size(q, PAGE_SIZE);
blk_queue_segment_boundary(q, PAGE_SIZE - 1); blk_queue_segment_boundary(q, PAGE_SIZE - 1);
if (dasd_eckd_is_ese(device)) {
/*
* Depending on the extent size, up to UINT_MAX bytes can be
* accepted. However, neither DASD_ECKD_RAS_EXTS_MAX nor the
* device limits should be exceeded.
*/
ext_size = dasd_eckd_ext_size(device);
ext_limit = min(private->real_cyl / ext_size, DASD_ECKD_RAS_EXTS_MAX);
ext_bytes = ext_size * trks_per_cyl * recs_per_trk *
logical_block_size;
max_bytes = UINT_MAX - (UINT_MAX % ext_bytes);
if (max_bytes / ext_bytes > ext_limit)
max_bytes = ext_bytes * ext_limit;
max_discard_sectors = max_bytes / 512;
blk_queue_max_discard_sectors(q, max_discard_sectors);
blk_queue_flag_set(QUEUE_FLAG_DISCARD, q);
q->limits.discard_granularity = ext_bytes;
q->limits.discard_alignment = ext_bytes;
}
} }
static struct ccw_driver dasd_eckd_driver = { static struct ccw_driver dasd_eckd_driver = {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment