Subject: [PATCH] [FEAT LS1501] dasdfmt: Add new formatting modes From: Jan Höppner Summary: dasdfmt: Add new formatting modes Description: Introduce new formatting modes 'quick' and 'expand' to either format an earlier formatted DASD that could potentially be re-initialized very easily or format unformatted tracks at the end of a device that was previously extended. Also add the command line argument --check to provide a function that checks a DASD volume for correct formatting. Upstream-ID: - Problem-ID: LS1501 Upstream-Description: dasdfmt: Add expand format mode If a DASD was extended, the format of the first part of the disk can be assumed to be correct. Usually, a full format would be necessary to ensure a fully functional disk. However, this would also format the already formatted part resulting in the loss of the data stored in that part. Add an expand mode which will search for the start of the unformatted area and begin formatting from there. The mode is being specified by --mode=expand (or -M expand for short). Furthermore: - Add string array for the individual modes for output purposes - Avoid writing labels when EXPAND mode is active since they can be assumed to be correct - Add man page description Signed-off-by: Jan Höppner --- dasdfmt/dasdfmt.8 | 7 +++ dasdfmt/dasdfmt.c | 120 +++++++++++++++++++++++++++++++++++++++++++++++++----- dasdfmt/dasdfmt.h | 5 ++ 3 files changed, 123 insertions(+), 9 deletions(-) --- a/dasdfmt/dasdfmt.8 +++ b/dasdfmt/dasdfmt.8 @@ -118,6 +118,13 @@ Format the first two tracks and write la 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). +.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 +formatted, while a consecutive set of tracks at the end are unformatted. You can +use this mode to make added space available for Linux use after dynamically +increasing the size of a DASD volume. A blocksize can optionally be specified +using \fB-b\fR (\fB--blocksize\fR). .RE .TP --- a/dasdfmt/dasdfmt.c +++ b/dasdfmt/dasdfmt.c @@ -88,7 +88,9 @@ static void exit_usage(int exitcode) " device node of the device to format\n" " is either\n" " 'full' to fully format the device (default)\n" - " 'quick' to format only the first two tracks\n"); + " 'quick' to format only the first two tracks\n" + " 'expand' to format only the unformatted end" + " of a device\n"); exit(exitcode); } @@ -791,8 +793,11 @@ static format_check_t check_track_format if (errno == ENOTTY) { ERRMSG("%s: Missing kernel support for format checking", prog_name); - if (!info->check) + if (mode == EXPAND) { + ERRMSG(". Mode 'expand' cannot be used"); + } else if (!info->check) { ERRMSG(" (--force to override)"); + } ERRMSG_EXIT(EXIT_FAILURE, ".\n"); } ERRMSG_EXIT(EXIT_FAILURE, "%s: Could no check format: %s\n", @@ -957,8 +962,7 @@ static void dasdfmt_print_info(dasdfmt_i printf(" Compatible Disk Layout : %s\n", (p->intensity & DASD_FMT_INT_COMPAT) ? "yes" : "no"); printf(" Blocksize : %d\n", p->blksize); - printf(" Mode : %s\n", - (mode == FULL) ? "Full" : "Quick"); + printf(" Mode : %s\n", mode_str[mode]); if (info->testmode) printf("Test mode active, omitting ioctl.\n"); @@ -1169,6 +1173,60 @@ static void dasdfmt_write_labels(dasdfmt } /* + * This function will search for the beginning of an unformatted area + * on the device. It checks selected tracks beforehand and makes sure + * that the device is formatted to a certain extent. Otherwise the + * process is terminated. + */ +static void dasdfmt_find_start(dasdfmt_info_t *info, unsigned int cylinders, + unsigned heads, format_data_t *format_params) +{ + format_check_t cdata; + unsigned int middle; + unsigned int left = 2; + unsigned int right = (cylinders * heads) - 1; + unsigned int first = left; + + check_blocksize(info, format_params->blksize); + + format_params->start_unit = 0; + format_params->stop_unit = 4; + cdata = check_track_format(info, format_params); + + if (cdata.result) { + evaluate_format_error(info, &cdata, heads); + ERRMSG_EXIT(EXIT_FAILURE, "Use --mode=full to perform a " + "clean format.\n"); + } + + printf("Expansion mode active. Searching for starting position...\n"); + + while (left <= right) { + /* new track number to look at */ + middle = left + ((right - left) / 2); + + format_params->start_unit = middle; + format_params->stop_unit = middle; + cdata = check_track_format(info, format_params); + if (cdata.blksize != format_params->blksize) { + first = middle; + right = middle - 1; + } else { + left = middle + 1; + } + } + + if (first == 2 && cdata.blksize == format_params->blksize) + ERRMSG_EXIT(EXIT_FAILURE, + "No unformatted part found, aborting.\n"); + + printf("Done. Unformatted part starts at track %d.\n", first); + + /* return format_params with start_unit set to the correct value */ + format_params->start_unit = first; +} + +/* * formats the disk cylinderwise */ static void dasdfmt_format(dasdfmt_info_t *info, unsigned int cylinders, @@ -1239,6 +1297,40 @@ static void dasdfmt_prepare_and_format(d } /* + * This function will start the expand format process. + */ +static void dasdfmt_expand_format(dasdfmt_info_t *info, unsigned int cylinders, + unsigned int heads, format_data_t *p) +{ + if (!((info->withoutprompt) && (info->verbosity < 1))) + printf("Formatting the device. This may take a while " + "(get yourself a coffee).\n"); + + if (info->verbosity > 0) + printf("Detaching the device...\n"); + + if (ioctl(filedes, BIODASDDISABLE, p) != 0) + ERRMSG_EXIT(EXIT_FAILURE, "%s: (prepare device) IOCTL " + "BIODASDDISABLE failed. (%s)\n", prog_name, + strerror(errno)); + disk_disabled = 1; + + dasdfmt_format(info, cylinders, heads, p); + + if (info->verbosity > 0) + printf("Formatting tracks complete...\n"); + + if (info->verbosity > 0) + printf("Re-accessing the device...\n"); + + if (ioctl(filedes, BIODASDENABLE, p) != 0) + ERRMSG_EXIT(EXIT_FAILURE, "%s: (prepare device) IOCTL " + "BIODASDENABLE failed. (%s)\n", prog_name, + strerror(errno)); + disk_disabled = 0; +} + +/* * This function will only format the first two tracks of a DASD. * The rest of the DASD is untouched and left as is. */ @@ -1310,6 +1402,10 @@ static void do_format_dasd(dasdfmt_info_ case QUICK: /* just the first two */ p->stop_unit = 1; break; + case EXPAND: /* only the end of the disk */ + dasdfmt_find_start(info, cylinders, heads, p); + p->stop_unit = (cylinders * heads) - 1; + break; } if ((info->verbosity > 0) || !info->withoutprompt || info->testmode) @@ -1338,10 +1434,12 @@ static void do_format_dasd(dasdfmt_info_ if (!info->testmode) { if (!info->withoutprompt) { - printf("\n--->> ATTENTION! <<---\n"); - printf("All data of that device will be lost.\nType " - "\"yes\" to continue, no will leave the disk " - "untouched: "); + printf("\n"); + if (mode != EXPAND) + printf("--->> ATTENTION! <<---\nAll data of " + "that device will be lost.\n"); + printf("Type \"yes\" to continue, no will leave the " + "disk untouched: "); if (fgets(inp_buffer, sizeof(inp_buffer), stdin) == NULL) return; if (strcasecmp(inp_buffer, "yes") && @@ -1359,12 +1457,14 @@ static void do_format_dasd(dasdfmt_info_ case QUICK: dasdfmt_quick_format(info, cylinders, heads, p); break; + case EXPAND: + dasdfmt_expand_format(info, cylinders, heads, p); } if (!info->yast_mode) printf("Finished formatting the device.\n"); - if (!info->writenolabel) + if (!(info->writenolabel || mode == EXPAND)) dasdfmt_write_labels(info, vlabel, cylinders, heads); if (!info->yast_mode) @@ -1526,6 +1626,8 @@ int main(int argc, char *argv[]) mode = FULL; else if (strcasecmp(optarg, "quick") == 0) mode = QUICK; + else if (strcasecmp(optarg, "expand") == 0) + mode = EXPAND; else ERRMSG_EXIT(EXIT_FAILURE, "%s: The specified mode '%s' is " --- a/dasdfmt/dasdfmt.h +++ b/dasdfmt/dasdfmt.h @@ -150,8 +150,13 @@ struct dasd_eckd_characteristics { typedef enum format_mode_t { FULL, /* default mode */ QUICK, /* format only the first 2 tracks */ + EXPAND, /* search for unformatted area and format only that part*/ } format_mode_t; +static const char mode_str[3][10] = { + "Full", "Quick", "Expand" +}; + /* * struct format_data_t * represents all data necessary to format a dasd