SHA256
1
0
forked from pool/s390-tools
s390-tools/s390-tools-sles12sp3-dasdfmt-09-Add-command-line-argument-check.patch
2017-02-21 11:14:26 +00:00

454 lines
14 KiB
Diff

Subject: [PATCH] [FEAT LS1501] dasdfmt: Add new formatting modes
From: Jan Höppner <hoeppner@linux.vnet.ibm.com>
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 command line argument --check
Provide a function to check a DASD volume for correct formatting. This
can be useful in cases where only a few tracks of a volume are
incorrectly formatted.
All tracks on the device are checked. In an error case, the check
process is stopped and appropriate messages are displayed.
The --check command line argument can be combined with either -P,
-p or -m to display progress on the console.
Signed-off-by: Jan Höppner <hoeppner@linux.vnet.ibm.com>
Signed-off-by: Stefan Haberland <sth@linux.vnet.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.vnet.ibm.com>
---
dasdfmt/dasdfmt.8 | 5 +
dasdfmt/dasdfmt.c | 244 ++++++++++++++++++++++++++++++++++++++++--------------
dasdfmt/dasdfmt.h | 4
3 files changed, 190 insertions(+), 63 deletions(-)
--- a/dasdfmt/dasdfmt.8
+++ b/dasdfmt/dasdfmt.8
@@ -121,6 +121,11 @@ using \fB-b\fR (\fB--blocksize\fR).
.RE
.TP
+\fB--check\fR
+Perform a complete format check on a DASD volume. A blocksize can be specified
+with \fB-b\fR (\fB--blocksize\fR).
+
+.TP
\fB-r\fR \fIcylindercount\fR or \fB--requestsize\fR=\fIcylindercount\fR
Number of cylinders to be processed in one formatting step.
The value must be an integer in the range 1 - 255.
--- a/dasdfmt/dasdfmt.c
+++ b/dasdfmt/dasdfmt.c
@@ -76,7 +76,8 @@ static void exit_usage(int exitcode)
" the host access open count to ensure the device\n"
" is not online on another operating system instance\n"
" --norecordzero prevent storage server from modifying"
- " record 0\n\n"
+ " record 0\n"
+ " --check perform complete format check on device\n\n"
" <volser> is the volume identifier, which is converted\n"
" to EBCDIC and written to disk.\n"
" (6 characters, e.g. LNX001\n"
@@ -163,7 +164,8 @@ static void print_etr(int p_new, int sta
* Draw the progress indicator depending on what command line argument is set.
* This can either be a progressbar, hashmarks, or percentage.
*/
-static void draw_progress(dasdfmt_info_t *info, int cyl, unsigned int cylinders)
+static void draw_progress(dasdfmt_info_t *info, int cyl, unsigned int cylinders,
+ int aborted)
{
static int hashcount;
static int started;
@@ -175,7 +177,7 @@ static void draw_progress(dasdfmt_info_t
if (info->print_progressbar) {
printf("cyl %7d of %7d |", cyl, cylinders);
p_new = cyl * 100 / cylinders;
- if (p_new != p_old || !started) {
+ if (p_new != p_old || !started || aborted) {
/* percent value has changed */
p_old = p_new;
barlength = cyl * 33 / cylinders;
@@ -184,6 +186,8 @@ static void draw_progress(dasdfmt_info_t
for (i = barlength + 1; i <= 33; i++)
printf("-");
printf("|%3d%%", p_new);
+ if (aborted)
+ p_new = 100;
print_etr(p_new, started);
started = 1;
}
@@ -284,11 +288,17 @@ static void evaluate_format_error(dasdfm
unsigned int kl = 0;
int blksize = cdata->expect.blksize;
+ if (info->print_progressbar || info->print_hashmarks)
+ printf("\n");
+
/*
- * Reading record zero will never happen. If the record in error is 0
- * nonetheless, the device is not formatted at all!
+ * If mode is not QUICK and a device format couldn't be determined, the
+ * device is considered not formatted.
+ * Also, reading record zero will never happen. If the record in error
+ * is 0 nonetheless, the device is not formatted at all as well!
*/
- if (cdata->rec == 0) {
+ if ((info->dasd_info.format == DASD_FORMAT_NONE && mode != QUICK) ||
+ cdata->rec == 0) {
ERRMSG("WARNING: The specified device is not "
"formatted at all.\n");
return;
@@ -529,6 +539,35 @@ static void check_blocksize(dasdfmt_info
}
/*
+ * Check whether a specified layout matches the layout
+ * a device is formatted with.
+ */
+static void check_layout(dasdfmt_info_t *info, unsigned int intensity)
+{
+ char layout[4];
+
+ if (!info->layout_specified ||
+ info->dasd_info.format == DASD_FORMAT_NONE)
+ return;
+
+ if ((intensity & DASD_FMT_INT_COMPAT) &&
+ info->dasd_info.format == DASD_FORMAT_CDL)
+ return;
+
+ if (!(intensity & DASD_FMT_INT_COMPAT) &&
+ info->dasd_info.format == DASD_FORMAT_LDL)
+ return;
+
+ if (info->dasd_info.format == DASD_FORMAT_CDL)
+ sprintf(layout, "CDL");
+ if (info->dasd_info.format == DASD_FORMAT_LDL)
+ sprintf(layout, "LDL");
+
+ ERRMSG_EXIT(EXIT_FAILURE, "WARNING: Device is formatted with a "
+ "different layout (%s).\n", layout);
+}
+
+/*
* check for disk type and set some variables (e.g. usage count)
*/
static void check_disk(dasdfmt_info_t *info)
@@ -715,10 +754,29 @@ static void set_label(dasdfmt_info_t *in
}
/*
+ * Check whether hashsteps are within the correct interval.
+ */
+static void check_hashmarks(dasdfmt_info_t *info)
+{
+ if (info->print_hashmarks) {
+ if (info->hashstep < reqsize)
+ info->hashstep = reqsize;
+ if ((info->hashstep < 1) || (info->hashstep > 1000)) {
+ printf("Hashmark increment is not in range <1,1000>, "
+ "using the default.\n");
+ info->hashstep = 10;
+ }
+
+ printf("Printing hashmark every %d cylinders.\n",
+ info->hashstep);
+ }
+}
+
+/*
* This function checks whether a range of tracks is in regular format
* with the specified block size.
*/
-static format_check_t check_track_format(format_data_t *p)
+static format_check_t check_track_format(dasdfmt_info_t *info, format_data_t *p)
{
format_check_t cdata = {
.expect = {
@@ -731,9 +789,11 @@ static format_check_t check_track_format
if (ioctl(filedes, BIODASDCHECKFMT, &cdata)) {
if (errno == ENOTTY) {
- ERRMSG_EXIT(EXIT_FAILURE, "%s: Missing kernel support "
- "for format checking (--force to "
- "override)\n", prog_name);
+ ERRMSG("%s: Missing kernel support for format checking",
+ prog_name);
+ if (!info->check)
+ ERRMSG(" (--force to override)");
+ ERRMSG_EXIT(EXIT_FAILURE, ".\n");
}
ERRMSG_EXIT(EXIT_FAILURE, "%s: Could no check format: %s\n",
prog_name, strerror(errno));
@@ -742,6 +802,97 @@ static format_check_t check_track_format
return cdata;
}
+/*
+ * Either do the actual format or check depending on the check-value.
+ */
+static int process_tracks(dasdfmt_info_t *info, unsigned int cylinders,
+ unsigned int heads, format_data_t *format_params)
+{
+ format_check_t cdata = { .expect = {0}, 0};
+ format_data_t step = *format_params;
+ unsigned long step_value;
+ unsigned long cur_trk;
+ int cyl = 0;
+
+ check_hashmarks(info);
+
+ cur_trk = format_params->start_unit;
+
+ while (cur_trk < format_params->stop_unit) {
+ step_value = reqsize * heads - (cur_trk % heads);
+ step.start_unit = cur_trk;
+ if (cur_trk + heads * reqsize >= format_params->stop_unit)
+ step.stop_unit = format_params->stop_unit;
+ else
+ step.stop_unit = cur_trk + step_value - 1;
+
+ if (info->check) {
+ cdata = check_track_format(info, &step);
+ if (cdata.result) {
+ cyl = cur_trk / heads + 1;
+ draw_progress(info, cyl, cylinders, 1);
+ evaluate_format_error(info, &cdata, heads);
+ break;
+ }
+ } else {
+ if (ioctl(filedes, BIODASDFMT, &step) != 0)
+ ERRMSG_EXIT(EXIT_FAILURE, "%s: the ioctl call "
+ "to format tracks failed. (%s)\n",
+ prog_name, strerror(errno));
+ }
+
+ cyl = cur_trk / heads + 1;
+ draw_progress(info, cyl, cylinders, 0);
+
+ cur_trk += step_value;
+ }
+ /* We're done, draw the 100% mark */
+ if (!cdata.result) {
+ cyl = step.stop_unit / heads + 1;
+ draw_progress(info, cyl, cylinders, 0);
+ printf("\n");
+ }
+
+ return cdata.result;
+}
+
+/*
+ * This function checks the format of the entire disk.
+ */
+static void check_disk_format(dasdfmt_info_t *info, unsigned int cylinders,
+ unsigned int heads, format_data_t *check_params)
+{
+ check_params->start_unit = 0;
+ check_params->stop_unit = (cylinders * heads) - 1;
+
+ printf("Checking format of the entire disk...\n");
+
+ if (info->testmode) {
+ printf("Test mode active, omitting ioctl.\n");
+ return;
+ }
+
+ check_blocksize(info, check_params->blksize);
+ check_layout(info, check_params->intensity);
+
+ /*
+ * If no layout was specified, set the intensity
+ * according to what the layout seems to be.
+ */
+ if (!info->layout_specified) {
+ if (info->dasd_info.format == DASD_FORMAT_CDL)
+ check_params->intensity |= DASD_FMT_INT_COMPAT;
+ else if (info->dasd_info.format == DASD_FORMAT_LDL)
+ check_params->intensity &= ~DASD_FMT_INT_COMPAT;
+ }
+
+ if (process_tracks(info, cylinders, heads, check_params)) {
+ ERRMSG_EXIT(EXIT_FAILURE, "Use --mode=full to perform a "
+ "clean format.\n");
+ }
+
+ printf("Done. Disk is fine.\n");
+}
/*
* ask the user to specify a blocksize
@@ -1023,51 +1174,7 @@ static void dasdfmt_write_labels(dasdfmt
static void dasdfmt_format(dasdfmt_info_t *info, unsigned int cylinders,
unsigned int heads, format_data_t *format_params)
{
- unsigned int step_value;
- unsigned long cur_trk;
- format_data_t step;
- int cyl = 0;
-
- if (info->print_hashmarks) {
- if (info->hashstep < reqsize)
- info->hashstep = reqsize;
- if ((info->hashstep < 1) || (info->hashstep > 1000)) {
- printf("Hashmark increment is not in range <1,1000>, "
- "using the default.\n");
- info->hashstep = 10;
- }
-
- if(!info->yast_mode) printf("Printing hashmark every %d cylinders.\n",
- info->hashstep);
- }
-
- step = *format_params;
- cur_trk = format_params->start_unit;
-
- while (cur_trk < format_params->stop_unit) {
- step_value = reqsize * heads - (cur_trk % heads);
- step.start_unit = cur_trk;
- if (cur_trk + reqsize * heads >= format_params->stop_unit)
- step.stop_unit = format_params->stop_unit;
- else
- step.stop_unit = cur_trk + step_value - 1;
-
- if (ioctl(filedes, BIODASDFMT, &step) != 0)
- ERRMSG_EXIT(EXIT_FAILURE, "%s: (format cylinder) IOCTL "
- "BIODASDFMT failed. (%s)\n",
- prog_name, strerror(errno));
-
- cyl = cur_trk / heads + 1;
- draw_progress(info, cyl, cylinders);
-
- cur_trk += step_value;
- }
- /* We're done, draw the 100% mark */
- cyl = step.stop_unit / heads + 1;
- draw_progress(info, cyl, cylinders);
-
- if ((info->print_progressbar || info->print_hashmarks) && !info->yast_mode)
- printf("\n");
+ process_tracks(info, cylinders, heads, format_params);
}
static void dasdfmt_prepare_and_format(dasdfmt_info_t *info,
@@ -1082,6 +1189,10 @@ static void dasdfmt_prepare_and_format(d
| DASD_FMT_INT_INVAL)
};
+ 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");
@@ -1147,11 +1258,11 @@ static void dasdfmt_quick_format(dasdfmt
/* Check device format on the first and last 3 regular tracks */
tmp.start_unit = 2;
tmp.stop_unit = 4;
- cdata = check_track_format(&tmp);
+ cdata = check_track_format(info, &tmp);
if (!cdata.result) {
tmp.start_unit = (cylinders * heads) - 3;
tmp.stop_unit = (cylinders * heads) - 1;
- cdata = check_track_format(&tmp);
+ cdata = check_track_format(info, &tmp);
}
if (cdata.result) {
evaluate_format_error(info, &cdata, heads);
@@ -1243,9 +1354,6 @@ static void do_format_dasd(dasdfmt_info_
switch (mode) {
case FULL:
- if (!((info->withoutprompt) && (info->verbosity < 1)))
- printf("Formatting the device. This may take a "
- "while (get yourself a coffee).\n");
dasdfmt_prepare_and_format(info, cylinders, heads, p);
break;
case QUICK:
@@ -1337,6 +1445,7 @@ int main(int argc, char *argv[])
printf("%s is not a valid option!\n", optarg);
exit(1);
}
+ info.layout_specified = 1;
break;
case 'y':
info.withoutprompt = 1;
@@ -1424,6 +1533,9 @@ int main(int argc, char *argv[])
"more information.\n",
prog_name, optarg);
break;
+ case OPT_CHECK:
+ info.check = 1;
+ break;
case -1:
/* End of options string - start of devices list */
info.device_id = optind;
@@ -1539,7 +1651,7 @@ int main(int argc, char *argv[])
/* Either let the user specify the blksize or get it from the kernel */
if (!info.blksize_specified) {
if (!(mode == FULL ||
- info.dasd_info.format == DASD_FORMAT_NONE))
+ info.dasd_info.format == DASD_FORMAT_NONE) || info.check)
get_blocksize(&format_params.blksize);
else
format_params = ask_user_for_blksize(format_params);
@@ -1568,8 +1680,14 @@ int main(int argc, char *argv[])
set_geo(&info, &cylinders, &heads);
set_label(&info, &vlabel, &format_params, cylinders);
- do_format_dasd(&info, &vlabel, &format_params,
- cylinders, heads);
+
+ if (info.check) {
+ check_disk_format(&info, cylinders, heads,
+ &format_params);
+ } else {
+ do_format_dasd(&info, &vlabel, &format_params,
+ cylinders, heads);
+ }
if (close(filedes) != 0)
ERRMSG("%s: error during close: %s\ncontinuing...\n",
--- a/dasdfmt/dasdfmt.h
+++ b/dasdfmt/dasdfmt.h
@@ -273,6 +273,7 @@ typedef struct format_check_t {
if (*endptr) ERRMSG_EXIT(EXIT_MISUSE,"%s: " str " " \
"is in invalid format\n",prog_name);}
+#define OPT_CHECK 128
#define dasdfmt_getopt_string "b:n:l:f:d:m:M:r:hpQLtyvVFkCYP:"
static struct option dasdfmt_getopt_long_options[]=
@@ -296,6 +297,7 @@ static struct option dasdfmt_getopt_long
{ "norecordzero", 0, 0, 'z'},
{ "check_host_count", 0, 0, 'C'},
{ "mode", 1, 0, 'M'},
+ { "check", 0, 0, OPT_CHECK},
{0, 0, 0, 0}
};
@@ -328,6 +330,8 @@ typedef struct dasdfmt_info {
int device_id;
int keep_volser;
int force_host;
+ int layout_specified;
+ int check;
int yast_mode;
int procnum;
} dasdfmt_info_t;