From 214580a70428222cd850c17e8778820d33a3ba76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20H=C3=B6ppner?= Date: Tue, 5 Mar 2019 15:37:33 +0100 Subject: [PATCH] dasdfmt: Add support for thin-provisioned volumes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make dasdfmt aware of thinly provisioned (Extent Space Efficient (ESE)) DASD volumes. If an ESE volume is recognised a QUICK format is performed, formatting only the first two tracks. The mode can always be overwritten by --mode. Previously allocated space is always released before formatting, if not specified otherwise. The option --no-discard (-D) is provided to omit the space release. Reviewed-by: Stefan Haberland Signed-off-by: Jan Höppner --- dasdfmt/dasdfmt.8 | 6 +++++ dasdfmt/dasdfmt.c | 58 ++++++++++++++++++++++++++++++++++++++++++++--- dasdfmt/dasdfmt.h | 3 +++ 3 files changed, 64 insertions(+), 3 deletions(-) diff --git a/dasdfmt/dasdfmt.8 b/dasdfmt/dasdfmt.8 index 99da9ed0..c3e98faa 100644 --- a/dasdfmt/dasdfmt.8 +++ b/dasdfmt/dasdfmt.8 @@ -122,6 +122,8 @@ Format the first two tracks and write label and partition information. Only use this option if you are sure that the target DASD already contains a regular format with the specified blocksize. A blocksize can optionally be specified using \fB-b\fR (\fB--blocksize\fR). +.br +For thin-provisioned DASD ESE volumes this is the default mode. .IP expand Format all unformatted tracks at the end of the target DASD. This mode assumes that tracks at the beginning of the DASD volume have already been correctly @@ -136,6 +138,10 @@ using \fB-b\fR (\fB--blocksize\fR). Perform a complete format check on a DASD volume. A blocksize can be specified with \fB-b\fR (\fB--blocksize\fR). +.TP +\fB--no-discard\fR +Omit a full space release when formatting a thin-provisioned DASD ESE volume. + .TP \fB-r\fR \fIcylindercount\fR or \fB--requestsize\fR=\fIcylindercount\fR Number of cylinders to be processed in one formatting step. diff --git a/dasdfmt/dasdfmt.c b/dasdfmt/dasdfmt.c index 944376d9..c78080c9 100644 --- a/dasdfmt/dasdfmt.c +++ b/dasdfmt/dasdfmt.c @@ -53,6 +53,7 @@ static const struct util_prg prg = { /* Defines for options with no short command */ #define OPT_CHECK 128 #define OPT_NOZERO 129 +#define OPT_NODISCARD 130 static struct util_opt opt_vec[] = { UTIL_OPT_SECTION("FORMAT ACTIONS"), @@ -105,6 +106,11 @@ static struct util_opt opt_vec[] = { .desc = "Prevent storage server from modifying record 0", .flags = UTIL_OPT_FLAG_NOSHORT, }, + { + .option = { "no-discard", no_argument, NULL, OPT_NODISCARD }, + .desc = "Do not discard space before formatting", + .flags = UTIL_OPT_FLAG_NOSHORT, + }, { .option = { NULL, no_argument, NULL, 'y' }, .desc = "Start formatting without further user-confirmation", @@ -921,6 +927,8 @@ static void dasdfmt_print_info(dasdfmt_info_t *info, char *devname, printf("Drive Geometry: %d Cylinders * %d Heads = %d Tracks\n", cylinders, heads, (cylinders * heads)); + printf("Device Type: %s Provisioned\n", + info->ese ? "Thinly" : "Fully"); printf("\nI am going to format the device "); printf("%s in the following way:\n", devname); printf(" Device number of device : 0x%x\n", info->dasd_info.devno); @@ -939,7 +947,10 @@ static void dasdfmt_print_info(dasdfmt_info_t *info, char *devname, (p->intensity & DASD_FMT_INT_COMPAT) ? "yes" : "no"); printf(" Blocksize : %d\n", p->blksize); printf(" Mode : %s\n", mode_str[mode]); - + if (info->ese) { + printf(" Full Space Release : %s\n", + (info->no_discard || mode == FULL) ? "no" : "yes"); + } if (info->testmode) printf("Test mode active, omitting ioctl.\n"); } @@ -1234,6 +1245,26 @@ static void dasdfmt_format(dasdfmt_info_t *info, unsigned int cylinders, process_tracks(info, cylinders, heads, format_params); } +static void dasdfmt_release_space(dasdfmt_info_t *info) +{ + format_data_t r = { + .start_unit = 0, + .stop_unit = 0, + .intensity = DASD_FMT_INT_ESE_FULL, + }; + int err = 0; + + if (!info->ese || info->no_discard) + return; + + printf("Releasing space for the entire device...\n"); + err = dasd_release_space(dev_filename, &r); + if (err) { + ERRMSG_EXIT(EXIT_FAILURE, "%s: Could not release space (%s)\n", + prog_name, strerror(err)); + } +} + static void dasdfmt_prepare_and_format(dasdfmt_info_t *info, unsigned int cylinders, unsigned int heads, format_data_t *p) @@ -1329,6 +1360,8 @@ static void dasdfmt_quick_format(dasdfmt_info_t *info, unsigned int cylinders, if (info->force) { printf("Skipping format check due to --force.\n"); + } else if (info->ese) { + printf("Skipping format check due to thin-provisioned device.\n"); } else { check_blocksize(info, p->blksize); @@ -1438,6 +1471,7 @@ static void do_format_dasd(dasdfmt_info_t *info, char *devname, dasdfmt_prepare_and_format(info, cylinders, heads, p); break; case QUICK: + dasdfmt_release_space(info); dasdfmt_quick_format(info, cylinders, heads, p); break; case EXPAND: @@ -1461,6 +1495,19 @@ static void do_format_dasd(dasdfmt_info_t *info, char *devname, } } +static void eval_format_mode(dasdfmt_info_t *info) +{ + if (!info->force && info->mode_specified && info->ese && mode == EXPAND) { + ERRMSG_EXIT(EXIT_FAILURE, + "WARNING: The specified device is thin-provisioned\n" + "Format mode 'expand' is not feasible.\n" + "Use --mode=full or --mode=quick to perform a clean format\n"); + } + + if (!info->mode_specified) + mode = info->ese ? QUICK : FULL; +} + int main(int argc, char *argv[]) { dasdfmt_info_t info = { @@ -1496,8 +1543,6 @@ int main(int argc, char *argv[]) format_params.blksize = DEFAULT_BLOCKSIZE; format_params.intensity = DASD_FMT_INT_COMPAT; - mode = FULL; - /*************** parse parameters **********************/ while (1) { @@ -1601,6 +1646,10 @@ int main(int argc, char *argv[]) "invalid. Consult the man page for " "more information.\n", prog_name, optarg); + info.mode_specified = 1; + break; + case OPT_NODISCARD: + info.no_discard = 1; break; case OPT_CHECK: info.check = 1; @@ -1645,6 +1694,9 @@ int main(int argc, char *argv[]) "device information failed (%s).\n", prog_name, strerror(rc)); + info.ese = dasd_sys_ese(dev_filename); + eval_format_mode(&info); + /* Either let the user specify the blksize or get it from the kernel */ if (!info.blksize_specified) { if (!(mode == FULL || diff --git a/dasdfmt/dasdfmt.h b/dasdfmt/dasdfmt.h index 3dc9aecc..2f53a0df 100644 --- a/dasdfmt/dasdfmt.h +++ b/dasdfmt/dasdfmt.h @@ -92,6 +92,9 @@ typedef struct dasdfmt_info { int force_host; int layout_specified; int check; + int mode_specified; + int ese; + int no_discard; } dasdfmt_info_t;