[PATCH makedumpfile] Add -L option to limit output file size

HAGIO KAZUHITO(萩尾 一仁) k-hagio-ab at nec.com
Thu Jun 17 01:32:01 PDT 2021


-----Original Message-----
> This option can be used to ensure that a certain amount of free space is
> preserved. It is useful when the output of makedumpfile is on the root
> filesystem and some services fail to start at boot if there is no space
> left.

Thanks for the patch, the option seems nice!
Some comments inline.

> 
> Signed-off-by: Benjamin Poirier <bpoirier at nvidia.com>
> ---
>  makedumpfile.8 | 12 +++++++++---
>  makedumpfile.c | 50 ++++++++++++++++++++++++++++++++++++++++++++------
>  makedumpfile.h |  2 ++
>  print_info.c   |  3 +++
>  4 files changed, 58 insertions(+), 9 deletions(-)
> 
> diff --git a/makedumpfile.8 b/makedumpfile.8
> index 313a41c..9a90f0e 100644
> --- a/makedumpfile.8
> +++ b/makedumpfile.8
> @@ -157,9 +157,10 @@ will be effective if you specify domain-0's \fIvmlinux\fR with \-x option.
>  Then the pages are excluded only from domain-0.
>  .br
>  If specifying multiple dump_levels with the delimiter ',', makedumpfile retries
> -to create a \fIDUMPFILE\fR by other dump_level when "No space on device" error
> -happens. For example, if dump_level is "11,31" and makedumpfile fails
> -by dump_level 11, makedumpfile retries it by dump_level 31.
> +to create \fIDUMPFILE\fR using the next dump_level when the size of a dumpfile
> +exceeds the limit specified with '-L' or when when a "No space on device" error
> +happens. For example, if dump_level is "11,31" and makedumpfile fails with
> +dump_level 11, makedumpfile retries with dump_level 31.
>  .br
>  .B Example:
>  .br
> @@ -221,6 +222,11 @@ Here is the all combinations of the bits.
>      30 |      |   X   |   X   |  X   |  X
>      31 |  X   |   X   |   X   |  X   |  X
> 
> +.TP
> +\fB\-L\fR \fISIZE\fR
> +Limit the size of the output file to \fISIZE\fR bytes. An incomplete
> +\fIDUMPFILE\fR or \fILOGFILE\fR is written if the size would otherwise exceed
> +\fISIZE\fR.
> 
>  .TP
>  \fB\-E\fR
> diff --git a/makedumpfile.c b/makedumpfile.c
> index 894c88e..8a443c6 100644
> --- a/makedumpfile.c
> +++ b/makedumpfile.c
> @@ -22,6 +22,8 @@
>  #include "cache.h"
>  #include <stddef.h>
>  #include <ctype.h>
> +#include <signal.h>
> +#include <sys/resource.h>
>  #include <sys/time.h>
>  #include <limits.h>
>  #include <assert.h>
> @@ -1383,6 +1385,28 @@ open_dump_file(void)
>  		return FALSE;
>  	}
>  	info->fd_dumpfile = fd;
> +
> +	if (info->size_limit != -1) {
> +		struct sigaction act = {
> +			.sa_handler = SIG_IGN,
> +		};
> +		struct rlimit rlim = {
> +			.rlim_cur = info->size_limit,
> +			.rlim_max = info->size_limit,
> +		};
> +
> +		if (sigaction(SIGXFSZ, &act, NULL)) {
> +			ERRMSG("Can't ignore SIGXFSZ. %s\n", strerror(errno));
> +			return FALSE;
> +		}
> +
> +		if (setrlimit(RLIMIT_FSIZE, &rlim)) {
> +			ERRMSG("Can't set file size limit(%lld). %s\n",
> +			       (long long) info->size_limit, strerror(errno));
> +			return FALSE;
> +		}
> +	}
> +
>  	return TRUE;
>  }
> 
> @@ -4729,7 +4753,7 @@ write_and_check_space(int fd, void *buf, size_t buf_size, char *file_name)
>  			written_size += status;
>  			continue;
>  		}
> -		if (errno == ENOSPC)
> +		if (errno == ENOSPC || errno == EFBIG)
>  			info->flag_nospace = TRUE;
>  		MSG("\nCan't write the dump file(%s). %s\n",
>  		    file_name, strerror(errno));
> @@ -5308,7 +5332,7 @@ dump_log_entry(char *logptr, int fp)
>  	for (i = 0, p = msg; i < text_len; i++, p++) {
>  		if (bufp - buf >= sizeof(buf) - buf_need) {
>  			if (write(info->fd_dumpfile, buf, bufp - buf) < 0)
> -				return FALSE;
> +				goto out_fail;
>  			bufp = buf;
>  		}
> 
> @@ -5322,10 +5346,13 @@ dump_log_entry(char *logptr, int fp)
> 
>  	*bufp++ = '\n';
> 
> -	if (write(info->fd_dumpfile, buf, bufp - buf) < 0)
> -		return FALSE;
> -	else
> +	if (write(info->fd_dumpfile, buf, bufp - buf) >= 0)
>  		return TRUE;
> +
> +out_fail:
> +	ERRMSG("\nCan't write the log file(%s). %s\n", info->name_dumpfile,
> +	       strerror(errno));
> +	return FALSE;
>  }

This change in dump_log_entry() looks ok, but the function supports only
Linux 3.5 to 5.9 kernels.  The other kernels are supported by the other
function or path:

dump_dmesg()
...
        if ((SYMBOL(prb) != NOT_FOUND_SYMBOL))
                return dump_lockless_dmesg();  <<-- 5.10 and newer
...
        if (info->kernel_version < KERNEL_VERSION(3, 5, 0)) {
...
                if (write(info->fd_dumpfile, log_buffer, length_log) < 0) <<-- 3.4 and older
                        goto out;

Could you add support for those kernels? if you need the -L option for
the --dump-dmesg option.

But it seems that write() with RLIMIT_FSIZE returns the rest size to
the limit first, and returns -1 with EFBIG next time.  So a change
might be needed for the write() above.

> 
>  /*
> @@ -11585,6 +11612,7 @@ main(int argc, char *argv[])
>  	}
>  	info->file_vmcoreinfo = NULL;
>  	info->fd_vmlinux = -1;
> +	info->size_limit = -1;
>  	info->fd_xen_syms = -1;
>  	info->fd_memory = -1;
>  	info->fd_dumpfile = -1;
> @@ -11605,9 +11633,11 @@ main(int argc, char *argv[])
> 
>  	info->block_order = DEFAULT_ORDER;
>  	message_level = DEFAULT_MSG_LEVEL;
> -	while ((opt = getopt_long(argc, argv, "b:cDd:eEFfg:hi:lpRvXx:", longopts,
> +	while ((opt = getopt_long(argc, argv, "b:cDd:eEFfg:hi:lL:pRvXx:", longopts,
>  	    NULL)) != -1) {
>  		switch (opt) {
> +			long long val;
> +
>  		case OPT_BLOCK_ORDER:
>  			info->block_order = atoi(optarg);
>  			break;
> @@ -11624,6 +11654,14 @@ main(int argc, char *argv[])
>  			if (!parse_dump_level(optarg))
>  				goto out;
>  			break;
> +		case OPT_SIZE_LIMIT:
> +			val = atoll(optarg);
> +			if (val < 0) {

The atoll() returns 0 if the optarg is an invalid string and "-L 0" is
also meaningless, so I'd prefer (val <= 0) here.

Thanks,
Kazu

> +				MSG("Limit size(%lld) is invalid.\n", val);
> +				goto out;
> +			}
> +			info->size_limit = val;
> +			break;
>  		case OPT_ELF_DUMPFILE:
>  			info->flag_elf_dumpfile = 1;
>  			break;
> diff --git a/makedumpfile.h b/makedumpfile.h
> index 79046f2..7357ee7 100644
> --- a/makedumpfile.h
> +++ b/makedumpfile.h
> @@ -1344,6 +1344,7 @@ struct DumpInfo {
>  	int		max_dump_level;      /* maximum dump level */
>  	int		num_dump_level;      /* number of dump level */
>  	int		array_dump_level[NUM_ARRAY_DUMP_LEVEL];
> +	off_t		size_limit;          /* dump file size limit */
>  	int		flag_compress;       /* flag of compression */
>  	int		flag_lzo_support;    /* flag of LZO compression support */
>  	int		flag_elf_dumpfile;   /* flag of creating ELF dumpfile */
> @@ -2458,6 +2459,7 @@ struct elf_prstatus {
>  #define OPT_HELP                'h'
>  #define OPT_READ_VMCOREINFO     'i'
>  #define OPT_COMPRESS_LZO        'l'
> +#define OPT_SIZE_LIMIT          'L'
>  #define OPT_COMPRESS_SNAPPY     'p'
>  #define OPT_REARRANGE           'R'
>  #define OPT_VERSION             'v'
> diff --git a/print_info.c b/print_info.c
> index ad4184e..8b28554 100644
> --- a/print_info.c
> +++ b/print_info.c
> @@ -144,6 +144,9 @@ print_usage(void)
>  	MSG("        16  |                                    X\n");
>  	MSG("        31  |   X       X        X       X       X\n");
>  	MSG("\n");
> +	MSG("  [-L SIZE]:\n");
> +	MSG("      Limit the size of the output file to SIZE bytes.\n");
> +	MSG("\n");
>  	MSG("  [-E]:\n");
>  	MSG("      Create DUMPFILE in the ELF format.\n");
>  	MSG("      This option cannot be specified with the -c, -l or -p options,\n");
> --
> 2.32.0.rc0
> 
> 
> _______________________________________________
> kexec mailing list
> kexec at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/kexec



More information about the kexec mailing list