mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
zipl/src: Implement '--dry-run' option for ngdumps
Use the directory specified by the shell environment variable TMPDIR for temporary objects creation and ngdump job simulation. If TMPDIR is not set, then use "/tmp" for the mentioned purposes; While running ngdump job in 'dry-run' mode: . Don't format/mount the target dump device. Instead, create the bootmap file and the meta-file at the temporary mount point without mounting anything to it. Thus, the mentioned files to be acrually created in the "proxy" file system owning the temporary mount point; . Retrieve base disk info from the read-only dump device and complete that info with the block size of the proxy file system; Separate the steps on retrieving/setting file system block size into a dedicated procedure; Use definitions instead of hardcoded file names; Fix a bug in an error path (accessing freed memory); Make misc_open_simulate() and misc_open_exclusive() static; Update man pages with the requirements on the system environment (resources) for ngdump job being executed in dry-run mode; Provide hints for user (in stderr) in case when ngdump job in dry-run mode failed due to inappropriate system environment. Tested-by: Mikhail Zaslonko <zaslonko@linux.ibm.com> Reviewed-by: Mikhail Zaslonko <zaslonko@linux.ibm.com> Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com> Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
This commit is contained in:
committed by
Jan Höppner
parent
1e8edb6524
commit
c39722aff2
@@ -19,6 +19,8 @@
|
||||
#include "zipl.h"
|
||||
#include "lib/vtoc.h"
|
||||
|
||||
#define FS_MAP_ERROR "Could not get file mapping"
|
||||
|
||||
|
||||
/* Type for representing disk block numbers */
|
||||
typedef uint64_t blocknum_t;
|
||||
@@ -102,6 +104,7 @@ int disk_type_is_eckd_ldl(struct disk_ext_type *ext_type);
|
||||
int disk_type_is_nvme(struct disk_ext_type *ext_type);
|
||||
int disk_type_is_eckd(disk_type_t type);
|
||||
|
||||
int disk_info_set_fs_block(const char *filename, struct disk_info *info);
|
||||
int disk_get_info_from_file(const char* filename,
|
||||
struct job_target_data* target,
|
||||
struct disk_info** info);
|
||||
|
||||
@@ -20,5 +20,6 @@ void error_text(const char* fmt, ...);
|
||||
void error_clear_reason(void);
|
||||
void error_clear_text(void);
|
||||
void error_print(void);
|
||||
int is_error(const char *this);
|
||||
|
||||
#endif /* not ERROR_H */
|
||||
|
||||
@@ -261,5 +261,6 @@ int check_job_images_ngdump(struct job_dump_data* dump, char* name);
|
||||
void job_dump_check_set_ngdump(struct job_data *job,
|
||||
struct disk_ext_type *ext_type);
|
||||
bool job_dump_is_ngdump(struct job_data *job);
|
||||
void ngdump_delete_meta(const char *path);
|
||||
|
||||
#endif /* not JOB_H */
|
||||
|
||||
+1
-3
@@ -33,8 +33,6 @@ void* misc_malloc(size_t size);
|
||||
int misc_asprintf(char **out, const char *fmt, ...);
|
||||
void* misc_calloc(size_t n, size_t size);
|
||||
char* misc_strdup(const char* s);
|
||||
int misc_open_exclusive(const char* filename);
|
||||
int misc_open_simulate(const char *filename, struct misc_fd *mfd);
|
||||
int misc_open_device(const char *filename, struct misc_fd *mfd, int simulate);
|
||||
int misc_read(int fd, void* buffer, size_t count);
|
||||
int misc_read_file(const char* filename, char** buffer, size_t* size,
|
||||
@@ -49,7 +47,7 @@ int misc_get_file_buffer(const char* filename,
|
||||
struct misc_file_buffer* buffer);
|
||||
void misc_free_file_buffer(struct misc_file_buffer* file);
|
||||
int misc_get_char(struct misc_file_buffer* file, off_t readahead);
|
||||
char* misc_make_path(char* dirname, char* filename);
|
||||
char *misc_make_path(const char *dirname, char *filename);
|
||||
int misc_temp_dev(dev_t dev, int blockdev, char** devno);
|
||||
int misc_temp_dev_from_file(char* file, char** devno);
|
||||
void misc_free_temp_dev(char* device);
|
||||
|
||||
@@ -25,7 +25,9 @@
|
||||
|
||||
#define BOOTMAP_FILENAME "bootmap"
|
||||
#define BOOTMAP_TEMPLATE_FILENAME "bootmap_temp.XXXXXX"
|
||||
#define DUMP_TEMP_MOUNT_POINT_DIR "/tmp"
|
||||
#define DUMP_TEMP_MOUNT_POINT_NAME "zipl-dump-mount-point-XXXXXX"
|
||||
#define DUMP_META_FILE_NAME "ngdump.meta"
|
||||
|
||||
#define DEFAULTBOOT_SECTION "defaultboot"
|
||||
|
||||
|
||||
@@ -366,6 +366,13 @@ error-checking is still done.
|
||||
Note that when working with tapes, the current device position will be changed
|
||||
even when specifying this option.
|
||||
|
||||
When working with ngdumps, the directory specified by the shell environment
|
||||
variable TMPDIR is used for simulating the dump job. This directory should
|
||||
belong to a "real" file system managing disk space addresses (like ext4, or
|
||||
xfs), and have enough free space (matching the size of the specified dump
|
||||
device). If TMPDIR is not set, then "/tmp" is used, which can lead to errors,
|
||||
e.g. in case when it belongs to tmpfs.
|
||||
|
||||
.TP
|
||||
.BR "\-f" " or " "\-\-force"
|
||||
Omit validity checking while producing a multi-volume dump.
|
||||
|
||||
+87
-22
@@ -1542,11 +1542,39 @@ static int prepare_build_program_table_file(struct job_data *job,
|
||||
return -1;
|
||||
}
|
||||
bis->tmp_filename_created = 1;
|
||||
/* Retrieve target device information. Note that we have to
|
||||
* call disk_get_info_from_file() to also get the file system
|
||||
* block size. */
|
||||
if (disk_get_info_from_file(bis->filename, &job->target, &bis->info))
|
||||
return -1;
|
||||
/*
|
||||
* Retrieve target device information and
|
||||
* complete the info with the file system block size
|
||||
*/
|
||||
if (job->id == job_dump_partition && dry_run) {
|
||||
/*
|
||||
* ngdump job in dry-run mode.
|
||||
*
|
||||
* The dump device has read-only status.
|
||||
* The bootmap and the meta-file to be created
|
||||
* directly at the temporary mount point wthout
|
||||
* mounting anything to it (thus, the mentioned
|
||||
* files to be actually created in the "proxy"
|
||||
* file system.
|
||||
*
|
||||
* Retrieve info from the dump device
|
||||
* Retrieve file system block size from the proxy
|
||||
* file system
|
||||
*/
|
||||
if (disk_get_info(job->data.dump.device,
|
||||
&job->target, &bis->info))
|
||||
return -1;
|
||||
if (disk_info_set_fs_block(bis->filename, bis->info))
|
||||
return -1;
|
||||
} else {
|
||||
/*
|
||||
* ngdump or ipl job.
|
||||
*/
|
||||
if (disk_get_info_from_file(bis->filename,
|
||||
&job->target,
|
||||
&bis->info))
|
||||
return -1;
|
||||
}
|
||||
if (!disk_is_appropriate(job, bis->info))
|
||||
return -1;
|
||||
if (verbose) {
|
||||
@@ -1627,8 +1655,17 @@ static int bootmap_create_file(struct job_data *job, struct install_set *bis,
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ngdump_delete_meta(const char *dir)
|
||||
{
|
||||
char *filename = NULL;
|
||||
|
||||
filename = misc_make_path(dir, DUMP_META_FILE_NAME);
|
||||
unlink(filename);
|
||||
free(filename);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a file with the short name "ngdump.meta" in the directory PATH.
|
||||
* Create a file with the short name DUMP_META_FILE_NAME in the directory PATH.
|
||||
* This file is required for NGDump stand-alone dumper, it's read/written
|
||||
* by the dumper when it starts.
|
||||
*/
|
||||
@@ -1638,13 +1675,13 @@ static int ngdump_create_meta(const char *path)
|
||||
FILE *fp;
|
||||
int rc;
|
||||
|
||||
util_asprintf(&filename, "%s/ngdump.meta", path);
|
||||
filename = misc_make_path(path, DUMP_META_FILE_NAME);
|
||||
|
||||
fp = fopen(filename, "w");
|
||||
if (!fp) {
|
||||
free(filename);
|
||||
error_reason(strerror(errno));
|
||||
error_text("Could not create file '%s'", filename);
|
||||
free(filename);
|
||||
return -1;
|
||||
}
|
||||
free(filename);
|
||||
@@ -1665,6 +1702,40 @@ static int ngdump_create_meta(const char *path)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ngdump_mount_device(struct job_data *job)
|
||||
{
|
||||
if (dry_run)
|
||||
/*
|
||||
* the bootmap and the meta-file to be stored
|
||||
* directly at the temporary mount point without
|
||||
* mounting any partition
|
||||
*/
|
||||
return 0;
|
||||
/*
|
||||
* the bootmap and the meta-file to be stored on the
|
||||
* formatted and mounted dump partition
|
||||
*/
|
||||
if (mount(job->data.dump.device, job->target.bootmap_dir,
|
||||
NGDUMP_FSTYPE, 0, NULL)) {
|
||||
error_reason(strerror(errno));
|
||||
error_text("Could not mount partition '%s':",
|
||||
job->data.dump.device);
|
||||
return -1;
|
||||
}
|
||||
job->dump_mounted = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *ngdump_dir(void)
|
||||
{
|
||||
return getenv("TMPDIR") ? : DUMP_TEMP_MOUNT_POINT_DIR;
|
||||
}
|
||||
|
||||
static char *build_mount_point_pathname(void)
|
||||
{
|
||||
return misc_make_path(ngdump_dir(), DUMP_TEMP_MOUNT_POINT_NAME);
|
||||
}
|
||||
|
||||
static int prepare_bootloader_ngdump(struct job_data *job,
|
||||
struct install_set *bis)
|
||||
{
|
||||
@@ -1679,8 +1750,7 @@ static int prepare_bootloader_ngdump(struct job_data *job,
|
||||
return -1;
|
||||
|
||||
assert(!job->target.bootmap_dir);
|
||||
job->target.bootmap_dir = misc_make_path("/tmp",
|
||||
DUMP_TEMP_MOUNT_POINT_NAME);
|
||||
job->target.bootmap_dir = build_mount_point_pathname();
|
||||
if (!job->target.bootmap_dir) {
|
||||
error_reason(strerror(errno));
|
||||
error_text("Could not make path for '%s'",
|
||||
@@ -1695,25 +1765,20 @@ static int prepare_bootloader_ngdump(struct job_data *job,
|
||||
return -1;
|
||||
}
|
||||
job->bootmap_dir_created = 1;
|
||||
/*
|
||||
* Mount partition where bootmap file and also a dump file will
|
||||
* be stored.
|
||||
*/
|
||||
if (mount(job->data.dump.device, job->target.bootmap_dir,
|
||||
NGDUMP_FSTYPE, 0, NULL)) {
|
||||
error_reason(strerror(errno));
|
||||
error_text("Could not mount partition '%s':",
|
||||
job->data.dump.device);
|
||||
if (ngdump_mount_device(job))
|
||||
return -1;
|
||||
}
|
||||
job->dump_mounted = 1;
|
||||
/*
|
||||
* Build a single program table for List-Directed IPL
|
||||
* See comments before install_bootloader() for details
|
||||
*/
|
||||
bis->print_details = 1;
|
||||
if (bootmap_create_file(job, bis, BLKPTR_FORMAT_ID))
|
||||
if (bootmap_create_file(job, bis, BLKPTR_FORMAT_ID)) {
|
||||
if (dry_run && is_error(FS_MAP_ERROR))
|
||||
fprintf(stderr,
|
||||
"'%s' doesn't satisfy the requirements. Set TMPDIR properly\n",
|
||||
ngdump_dir());
|
||||
return -1;
|
||||
}
|
||||
return ngdump_create_meta(job->target.bootmap_dir);
|
||||
}
|
||||
|
||||
|
||||
+29
-18
@@ -811,20 +811,15 @@ int disk_type_is_eckd(disk_type_t type)
|
||||
type == disk_type_eckd_cdl);
|
||||
}
|
||||
|
||||
int
|
||||
disk_get_info_from_file(const char* filename, struct job_target_data* target,
|
||||
struct disk_info** info)
|
||||
/**
|
||||
* Retrieve and set block size of the file system which contains FILENAME
|
||||
*/
|
||||
int disk_info_set_fs_block(const char *filename, struct disk_info *info)
|
||||
{
|
||||
struct stat stats;
|
||||
char* device;
|
||||
int blocksize;
|
||||
int fd;
|
||||
int rc;
|
||||
|
||||
if (stat(filename, &stats)) {
|
||||
error_reason(strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
/* Retrieve file system block size */
|
||||
fd = open(filename, O_RDONLY);
|
||||
if (fd == -1) {
|
||||
@@ -838,17 +833,33 @@ disk_get_info_from_file(const char* filename, struct job_target_data* target,
|
||||
filename);
|
||||
return -1;
|
||||
}
|
||||
/* Create temporary device file */
|
||||
rc = misc_temp_dev(stats.st_dev, 1, &device);
|
||||
if (rc)
|
||||
info->fs_block_size = blocksize;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve disk info of the device which contains FILENAME
|
||||
* and set the filesystem block size
|
||||
*/
|
||||
int disk_get_info_from_file(const char *filename,
|
||||
struct job_target_data *target,
|
||||
struct disk_info **info)
|
||||
{
|
||||
struct stat stats;
|
||||
char *device;
|
||||
|
||||
if (stat(filename, &stats)) {
|
||||
error_reason(strerror(errno));
|
||||
return -1;
|
||||
/* Get device info */
|
||||
rc = disk_get_info(device, target, info);
|
||||
if (rc == 0)
|
||||
(*info)->fs_block_size = blocksize;
|
||||
/* Clean up */
|
||||
}
|
||||
if (misc_temp_dev(stats.st_dev, 1, &device))
|
||||
return -1;
|
||||
if (disk_get_info(device, target, info)) {
|
||||
misc_free_temp_dev(device);
|
||||
return -1;
|
||||
}
|
||||
misc_free_temp_dev(device);
|
||||
return rc;
|
||||
return disk_info_set_fs_block(filename, *info);
|
||||
}
|
||||
|
||||
void disk_free_info(struct disk_info *info)
|
||||
|
||||
@@ -82,3 +82,8 @@ error_print(void)
|
||||
else
|
||||
fprintf(stderr, "Error: An unspecified error occurred\n");
|
||||
}
|
||||
|
||||
int is_error(const char *this)
|
||||
{
|
||||
return strcmp(error_reason_string, this) == 0;
|
||||
}
|
||||
|
||||
+1
-1
@@ -96,7 +96,7 @@ int fs_map(int fd, uint64_t offset, blocknum_t *mapped,
|
||||
/* FIEMAP failed, fall back to FIBMAP */
|
||||
block = offset / fs_block_size;
|
||||
if (ioctl(fd, FIBMAP, &block)) {
|
||||
error_reason("Could not get file mapping");
|
||||
error_reason(FS_MAP_ERROR);
|
||||
free(fiemap);
|
||||
return -1;
|
||||
}
|
||||
|
||||
+3
-2
@@ -1119,8 +1119,9 @@ install_dump(const char *device, struct job_target_data *target, uint64_t mem,
|
||||
|
||||
stage2dump_parms.mem_upper_limit = mem;
|
||||
stage2dump_parms.no_compress = no_compress;
|
||||
mfd.fd = misc_open_exclusive(device);
|
||||
if (mfd.fd == -1) {
|
||||
|
||||
/* Check if @device is a tape device */
|
||||
if (misc_open_device(device, &mfd, 0) == -1) {
|
||||
error_text("Could not open dump device '%s'", device);
|
||||
return -1;
|
||||
}
|
||||
|
||||
+17
-10
@@ -459,17 +459,24 @@ free_mvdump_data(struct job_mvdump_data* data)
|
||||
free(data->device[i]);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
job_free(struct job_data* job)
|
||||
void job_free(struct job_data *job)
|
||||
{
|
||||
|
||||
if (job->dump_mounted && umount(job->target.bootmap_dir))
|
||||
fprintf(stderr, "Could not umount dump device at %s",
|
||||
job->target.bootmap_dir);
|
||||
if (job->bootmap_dir_created && rmdir(job->target.bootmap_dir))
|
||||
fprintf(stderr, "Could not remove directory %s",
|
||||
job->target.bootmap_dir);
|
||||
if (job->dump_mounted && umount(job->target.bootmap_dir)) {
|
||||
fprintf(stderr,
|
||||
"Could not umount dump device at %s(%s)\n",
|
||||
job->target.bootmap_dir,
|
||||
strerror(errno));
|
||||
}
|
||||
if (job->bootmap_dir_created) {
|
||||
/* remove the meta-file created in dry-run mode */
|
||||
ngdump_delete_meta(job->target.bootmap_dir);
|
||||
if (rmdir(job->target.bootmap_dir)) {
|
||||
fprintf(stderr,
|
||||
"Could not remove directory %s(%s)\n",
|
||||
job->target.bootmap_dir,
|
||||
strerror(errno));
|
||||
}
|
||||
}
|
||||
free_target_data(&job->target);
|
||||
free_envblk_data(&job->envblk);
|
||||
free(job->name);
|
||||
|
||||
+3
-4
@@ -88,8 +88,7 @@ misc_strdup(const char* s)
|
||||
|
||||
|
||||
/* Open file exclusive */
|
||||
int
|
||||
misc_open_exclusive(const char* filename)
|
||||
static int misc_open_exclusive(const char *filename)
|
||||
{
|
||||
int fd;
|
||||
|
||||
@@ -104,7 +103,7 @@ misc_open_exclusive(const char* filename)
|
||||
/**
|
||||
* Open file FILENAME for write simulation
|
||||
*/
|
||||
int misc_open_simulate(const char *filename, struct misc_fd *mfd)
|
||||
static int misc_open_simulate(const char *filename, struct misc_fd *mfd)
|
||||
{
|
||||
/*
|
||||
* In write simulation mode actual data are not written to the file,
|
||||
@@ -301,7 +300,7 @@ misc_get_char(struct misc_file_buffer* file, off_t readahead)
|
||||
|
||||
|
||||
char*
|
||||
misc_make_path(char* dirname, char* filename)
|
||||
misc_make_path(const char *dirname, char *filename)
|
||||
{
|
||||
char* result;
|
||||
size_t len;
|
||||
|
||||
Reference in New Issue
Block a user