forked from pool/s390-tools
Marcus Meissner
9b729e2acc
New package per "Factory first" policy. Please list me as bug owner and maintainer, if possible. OBS-URL: https://build.opensuse.org/request/show/459343 OBS-URL: https://build.opensuse.org/package/show/Base:System/s390-tools?expand=0&rev=1
454 lines
14 KiB
Diff
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;
|