-
Notifications
You must be signed in to change notification settings - Fork 61
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow multiple device arguments to dasdfmt, and allow them to be formatted in parallel. #115
base: master
Are you sure you want to change the base?
Conversation
Signed-off-by: Hannes Reinecke <[email protected]> Signed-off-by: Mark Post <[email protected]>
Signed-off-by: Hannes Reinecke <[email protected]> Signed-off-by: Mark Post <[email protected]>
…be entered via the 'vi vmsg' CP command. Signed-off-by: Mark Post <[email protected]>
That's a great enhancement! |
Hmm. I did not intend for the boot menu message commit to be part of this pull request. I guess I need to learn how to use github better. :( |
On 8/3/21 11:27 AM, Marc Hartmayer wrote:
This change seems to be unrelated.
That's because it is unrelated. As I commented after creating the pull
request.
Mark Post
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add a more descriptive commit message as well.
} | ||
if (!numdev) | ||
error("%s: No device specified!\n", | ||
prog_name); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could be written in one line.
Also, there is a check in get_device_name()
Lines 518 to 519 in 895dc80
if (optind >= argc) | |
error("No device specified!"); |
that checks for "No device" already. You're calling get_device_name() in line 1721 in the loop. The check could be moved out before entering the loop and then removed here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not quite sure what you mean. If you're referring to the "while (optind < argc)" as the loop, then are you saying move the call to get_device_name on line 1735 to just before "while (optind < argc)", or something else.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, within the while (optind < argc)
loop your first call is get_device_name()
. Within that function the first check
is the one I referenced above (optind >= argc
). You are essentially doing the exact same check after the loop
with if (!numdev)
. That check however, is pretty much a dead code path as get_device_name() would fail first.
With moving the check out of the loop, I mean that the check could be done right before while (optind < argc)
and can then be removed from get_device_name()
.
I also just figured, that the check for the label if (numdev > 1 && g.labelspec)
could also be moved before
the loop.
It would look like this:
if (optind >= argc)
error("No device specified!");
if ((argc - optind) > 1 && g.labelspec)
error("Specifying a volser to be written doesn't make sense when formatting multiple DASD volumes.");
while (optind < argc) {
get_device_name(optind, argc, argv);
strncpy(g.dev_path_array[numdev], g.dev_path, strlen(g.dev_path));
strncpy(g.dev_node_array[numdev], g.dev_node, strlen(g.dev_node));
optind++;
numdev++;
}
@@ -1644,6 +1696,9 @@ int main(int argc, char *argv[]) | |||
break; /* exit loop if finished */ | |||
} | |||
|
|||
/* Reset the value of rc since we're going to use it again later. */ | |||
rc = 0; | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change should go into the second patch. It's not relevant here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll double check that to be sure I didn't get something else wrong.
dasdfmt/dasdfmt.c
Outdated
for (i = 0; i < numdev; i++) | ||
{ | ||
strncpy(g.dev_path, g.dev_path_array[i], strlen(g.dev_path_array[i])+1); | ||
strncpy(g.dev_node, g.dev_node_array[i], strlen(g.dev_node_array[i])+1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These two lines produce some warnings and I think the string operations can be avoided.
See below for a different approach.
In function ‘strncpy’,
inlined from ‘main’ at dasdfmt.c:1742:3:
/usr/include/s390x-linux-gnu/bits/string_fortified.h:106:10: warning: ‘__builtin_strncpy’ specified bound depends on the length of the source argument [-Wstringop-overflow=]
106 | return __builtin___strncpy_chk (__dest, __src, __len, __bos (__dest));
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
dasdfmt.c: In function ‘main’:
dasdfmt.c:1742:44: note: length computed here
1742 | strncpy(g.dev_path, g.dev_path_array[i], strlen(g.dev_path_array[i])+1);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~
char *tmp_path = g.dev_path;
char *tmp_node = g.dev_node;
for (i = 0; i < numdev; i++)
{
g.dev_path = g.dev_path_array[i];
g.dev_node = g.dev_node_array[i];
process_dasd(&vlabel, format_params);
}
free(tmp_path);
free(tmp_node);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm. I don't get that warning, or I would have worked to eliminate it. What version of gcc are you using?
Not being particularly strong in C, I don't understand what you're doing here. How do the *tmp_ variables come into play here?
while (optind < argc) { | ||
get_device_name(optind, argc, argv); | ||
strncpy(g.dev_path_array[numdev], g.dev_path, strlen(g.dev_path)); | ||
strncpy(g.dev_node_array[numdev], g.dev_node, strlen(g.dev_node)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
strncpy() is tricky here. As it is, the following warning is produced:
In function ‘strncpy’,
inlined from ‘main’ at dasdfmt.c:1722:3:
/usr/include/s390x-linux-gnu/bits/string_fortified.h:106:10: warning: ‘__builtin_strncpy’ output truncated before terminating nul copying as many bytes from a string as its length [-Wstringop-truncation]
106 | return __builtin___strncpy_chk (__dest, __src, __len, __bos (__dest));
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
dasdfmt.c: In function ‘main’:
dasdfmt.c:1722:3: note: length computed here
1722 | strncpy(g.dev_path_array[numdev], g.dev_path, strlen(g.dev_path));
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Adding +1 to make sure the terminating nul is copied as well will produce another warning:
In function ‘strncpy’,
inlined from ‘main’ at dasdfmt.c:1722:3:
/usr/include/s390x-linux-gnu/bits/string_fortified.h:106:10: warning: ‘__builtin_strncpy’ specified bound depends on the length of the source argument [-Wstringop-overflow=]
106 | return __builtin___strncpy_chk (__dest, __src, __len, __bos (__dest));
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
dasdfmt.c: In function ‘main’:
dasdfmt.c:1722:49: note: length computed here
1722 | strncpy(g.dev_path_array[numdev], g.dev_path, strlen(g.dev_path) + 1);
| ^~~~~~~~~~~~~~~~~~
In this scenario I think strcpy() should suffice. However, we have util_strlcpy() which is probably the even better solution to provide some safety. It would look like this and the warnings would be gone:
util_strlcpy(g.dev_path_array[numdev], g.dev_path, MAX_LENGTH);
util_strlcpy(g.dev_node_array[numdev], g.dev_node, MAX_LENGTH);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll take a look at your util function.
{ | ||
volume_label_t vlabel; | ||
char old_volser[7]; | ||
|
||
char str[ERR_LENGTH]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While you're touching this area anyway, would be nice to format it in reverse xmas tree here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand what you mean by that. Format what? and what is "reverse xmas tree?"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a format style that we try to follow where the order of the variable declarations is determined by the
length starting with the longest line at the top. In this example it would look like this:
volume_label_t vlabel;
char str[ERR_LENGTH];
char old_volser[7];
@@ -25,6 +25,8 @@ | |||
|
|||
#include "dasdfmt.h" | |||
|
|||
#define MAX_DEVICES 512 | |||
#define MAX_LENGTH 256 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a check in get_device_name() that should probably now check against that value:
Lines 521 to 522 in 895dc80
if (strlen(argv[optind]) >= PATH_MAX) | |
error("device name too long!"); |
eval_format_mode(); | ||
|
||
/* Not sure this next line is needed in the new version of the code. */ | ||
memcpy(&vlabel, orig_vlabel, sizeof(vlabel)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think is line is relevant here. Just use orig_vlabel (and call it vlabel)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll give it a try.
@@ -96,7 +96,7 @@ Do not use this option if you are using a 3270 console, | |||
running in background or redirecting the output to a file. | |||
|
|||
.TP | |||
\fB-P\fR or \fB--percentage\fR | |||
\fB-Q\fR or \fB--percentage\fR |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know it's sad that both p and P are taken, but please don't change the behaviour of an established command line option.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I already warned you about this, so no surprise here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, but still wanted to mentioned that we shouldn't change it.
strncpy(g.dev_node, g.dev_node_array[i], strlen(g.dev_node_array[i])+1); | ||
process_dasd(&vlabel, format_params); | ||
for (numproc = 0; numproc < numdev; numproc++) { | ||
chpid = fork(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have one major issue with the fork() approach. The output is very clutttered:
[root@m83lp46 ~]# ./dasdfmt -y -p -b 4096 -P 4 /dev/dasdb /dev/dasdc /dev/dasdd /dev/dasde
WARNING:
Disk /dev/dasdd is online on operating system instances in 58 different LPARs.
Ensure that the disk is not being used by a system outside your LPAR.
Note: Your installation might include z/VM systems that are configured to
automatically vary on disks, regardless of whether they are subsequently used.
WARNING:
Disk /dev/dasdb is online on operating system instances in 58 different LPARs.
Ensure that the disk is not being used by a system outside your LPAR.
Note: Your installation might include z/VM systems that are configured to
automatically vary on disks, regardless of whether they are subsequently used.
WARNING:
Disk /dev/dasde is online on operating system instances in 58 different LPARs.
Ensure that the disk is not being used by a system outside your LPAR.
Note: Your installation might include z/VM systems that are configured to
automatically vary on disks, regardless of whether they are subsequently used.
WARNING:
Disk /dev/dasdc is online on operating system instances in 58 different LPARs.
Ensure that the disk is not being used by a system outside your LPAR.
Note: Your installation might include z/VM systems that are configured to
automatically vary on disks, regardless of whether they are subsequently used.
cyl 1113 of 1113 |#################################|100% [5s]
cyl 1113 of 1113 |#################################|100% [5s]
Finished formatting the /dev/dasdb device.
Finished formatting the /dev/dasdd device.
cyl 1113 of 1113 |#################################|100% [5s]
Rereading the partition table for /dev/dasdb... ok
Rereading the partition table for /dev/dasdd... ok
Finished formatting the /dev/dasdc device.
Rereading the partition table for /dev/dasdc... ok
cyl 1113 of 1113 |#################################|100% [5s]
Finished formatting the /dev/dasde device.
Rereading the partition table for /dev/dasde... ok
This is hard to consume and very confusing (and this is for only 4 devices).
This lies in the nature of fork() as the process is just cloned and all the output
is directed to the same terminal as it comes in.
I'd rather appreciate an approach using pthreads, which allows to track the progress of each
formatting run. Also, it should allow for more fine grained control over each formatting process
and outputs could then be displayed as required.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would not be capable of writing anything with pthreads. Sorry. I wouldn't be opposed to someone else who knows that they're doing in that regard taking on that task.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We would still need a solution to aggregate the output. If pthreads are to complicated at this point, one solution
that came to mind whilst discussing this with my team was pipe() (See man 2 pipe). Which seems rather
easy to implement and you could collect the status of each forked process and work with that in the main
process. That way, output could be reduced to a meaningful and easy to consume minimum.
Specify the number of disks to be formatted in parallel. | ||
\fInumdisks\fR specifies the number of formatting processed, | ||
independent on the overall number of disks to be formatted. | ||
The maximum value for \fInumdisks\fR is 512. Default is 1. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the default value should be numdev and the number the user can set should
be an optional parameter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll have to think about that. I think that might be an unexpected change for some people.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have in mind that at one point we could allow the user to specify ranges of devices. Just like for other tools
like zdev. So, one could just do dasdfmt -b 4096 -y -p -n 0.0.9300-0.9330
and all devices would
automatically be formatted in parallel.
The number to specify the amount of devices that should be formatted in parallel would be optional.
That way the user doesn't need to bother with counting the amount of devices but still has the option to limit
it if resources are a constraint.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add a more descriptive commit message as well.
Just what are you looking for here?
dasdfmt/dasdfmt.c
Outdated
for (i = 0; i < numdev; i++) | ||
{ | ||
strncpy(g.dev_path, g.dev_path_array[i], strlen(g.dev_path_array[i])+1); | ||
strncpy(g.dev_node, g.dev_node_array[i], strlen(g.dev_node_array[i])+1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm. I don't get that warning, or I would have worked to eliminate it. What version of gcc are you using?
Not being particularly strong in C, I don't understand what you're doing here. How do the *tmp_ variables come into play here?
while (optind < argc) { | ||
get_device_name(optind, argc, argv); | ||
strncpy(g.dev_path_array[numdev], g.dev_path, strlen(g.dev_path)); | ||
strncpy(g.dev_node_array[numdev], g.dev_node, strlen(g.dev_node)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll take a look at your util function.
@@ -1644,6 +1696,9 @@ int main(int argc, char *argv[]) | |||
break; /* exit loop if finished */ | |||
} | |||
|
|||
/* Reset the value of rc since we're going to use it again later. */ | |||
rc = 0; | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll double check that to be sure I didn't get something else wrong.
Specify the number of disks to be formatted in parallel. | ||
\fInumdisks\fR specifies the number of formatting processed, | ||
independent on the overall number of disks to be formatted. | ||
The maximum value for \fInumdisks\fR is 512. Default is 1. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll have to think about that. I think that might be an unexpected change for some people.
No description provided.