From c36e0129267befe90a4116f1d9c5d92fac0128fa Mon Sep 17 00:00:00 2001 From: Peter Rajnoha Date: Mon, 23 Oct 2023 13:56:55 +0200 Subject: [PATCH] libdm: report: fix invalid JSON if using DM_REPORT_OUTPUT_MULTIPLE_TIMES and selection When reporting in JSON format, we need to be able to find the 'last displayed row', not just 'last row' as we did before. This is used to decide whether to put the JSON_SEPARATOR (the ',' character) between the lines when reporting in JSON format. This is mainly important in case we use a combination of JSON format and a report marked with DM_REPORT_OUTPUT_MULTIPLE_TIMES flag. Such report may be reused several times with different selection criteria each time. In that case, the report always contains all lines in memory, even though some of them do not need to pass the selection criteria that are currently used. Without DM_REPORT_OUTPUT_MULTIPLE_TIMES flag, the report only contains the lines that have passed the selection criteria, so the this wasn't an issue in this case. Fix suggested by Lars Ellenberg and reported here: https://github.com/lvmteam/lvm2/issues/130 --- WHATS_NEW_DM | 1 + device_mapper/libdm-report.c | 30 +++++++++++++++++++++++++++--- libdm/libdm-report.c | 30 +++++++++++++++++++++++++++--- 3 files changed, 55 insertions(+), 6 deletions(-) diff --git a/WHATS_NEW_DM b/WHATS_NEW_DM index b279756ed..9b6bd08e6 100644 --- a/WHATS_NEW_DM +++ b/WHATS_NEW_DM @@ -1,5 +1,6 @@ Version 1.02.197 - =================================== + Fix invalid JSON report if using DM_REPORT_OUTPUT_MULTIPLE_TIMES and selection. Propagate ioctl errno from dm_task_run when creating new table line. Add support for group aliases in dmstats. Add support for exit-on file for dmeventd to reduce shutdown delays. diff --git a/device_mapper/libdm-report.c b/device_mapper/libdm-report.c index c3bab4906..602ba51a7 100644 --- a/device_mapper/libdm-report.c +++ b/device_mapper/libdm-report.c @@ -4811,12 +4811,36 @@ static int _output_as_rows(struct dm_report *rh) return 0; } +static struct dm_list *_get_last_displayed_rowh(struct dm_report *rh) +{ + struct dm_list *rowh; + struct row *row; + + /* + * We need to find 'last displayed row', not just 'last row'. + * + * This is because the report may be marked with + * DM_REPORT_OUTPUT_MULTIPLE_TIMES flag. In that case, the report + * may be used more than once and with different selection + * criteria each time. Therefore, such report may also contain + * rows which we do not display on output with current selection + * criteria. + */ + for (rowh = dm_list_last(&rh->rows); rowh; rowh = dm_list_prev(&rh->rows, rowh)) { + row = dm_list_item(rowh, struct row); + if (_should_display_row(row)) + return rowh; + } + + return NULL; +} + static int _output_as_columns(struct dm_report *rh) { struct dm_list *fh, *rowh, *ftmp, *rtmp; struct row *row = NULL; struct dm_report_field *field; - struct dm_list *last_row; + struct dm_list *last_rowh; int do_field_delim; char *line; @@ -4825,7 +4849,7 @@ static int _output_as_columns(struct dm_report *rh) _report_headings(rh); /* Print and clear buffer */ - last_row = dm_list_last(&rh->rows); + last_rowh = _get_last_displayed_rowh(rh); dm_list_iterate_safe(rowh, rtmp, &rh->rows) { row = dm_list_item(rowh, struct row); @@ -4879,7 +4903,7 @@ static int _output_as_columns(struct dm_report *rh) log_error(UNABLE_TO_EXTEND_OUTPUT_LINE_MSG); goto bad; } - if (rowh != last_row && + if (rowh != last_rowh && !dm_pool_grow_object(rh->mem, JSON_SEPARATOR, 0)) { log_error(UNABLE_TO_EXTEND_OUTPUT_LINE_MSG); goto bad; diff --git a/libdm/libdm-report.c b/libdm/libdm-report.c index 5f5f0a773..18cad454f 100644 --- a/libdm/libdm-report.c +++ b/libdm/libdm-report.c @@ -4810,12 +4810,36 @@ static int _output_as_rows(struct dm_report *rh) return 0; } +static struct dm_list *_get_last_displayed_rowh(struct dm_report *rh) +{ + struct dm_list *rowh; + struct row *row; + + /* + * We need to find 'last displayed row', not just 'last row'. + * + * This is because the report may be marked with + * DM_REPORT_OUTPUT_MULTIPLE_TIMES flag. In that case, the report + * may be used more than once and with different selection + * criteria each time. Therefore, such report may also contain + * rows which we do not display on output with current selection + * criteria. + */ + for (rowh = dm_list_last(&rh->rows); rowh; rowh = dm_list_prev(&rh->rows, rowh)) { + row = dm_list_item(rowh, struct row); + if (_should_display_row(row)) + return rowh; + } + + return NULL; +} + static int _output_as_columns(struct dm_report *rh) { struct dm_list *fh, *rowh, *ftmp, *rtmp; struct row *row = NULL; struct dm_report_field *field; - struct dm_list *last_row; + struct dm_list *last_rowh; int do_field_delim; char *line; @@ -4824,7 +4848,7 @@ static int _output_as_columns(struct dm_report *rh) _report_headings(rh); /* Print and clear buffer */ - last_row = dm_list_last(&rh->rows); + last_rowh = _get_last_displayed_rowh(rh); dm_list_iterate_safe(rowh, rtmp, &rh->rows) { row = dm_list_item(rowh, struct row); @@ -4878,7 +4902,7 @@ static int _output_as_columns(struct dm_report *rh) log_error(UNABLE_TO_EXTEND_OUTPUT_LINE_MSG); goto bad; } - if (rowh != last_row && + if (rowh != last_rowh && !dm_pool_grow_object(rh->mem, JSON_SEPARATOR, 0)) { log_error(UNABLE_TO_EXTEND_OUTPUT_LINE_MSG); goto bad; -- 2.43.5