Compare commits

...

7 commits

Author SHA1 Message Date
David Sterba c8d23eec67 btrfs-progs: inspect: add compsize-like command
Copied from  https://github.com/kilobyte/compsize

Print table with compression statistics.

This is a work in progress.

- refactor and use existing helpers
- refine use of rb_tree for extent tracking, it could be more efficient
- add options to do per-file and summary stats, similar to 'fi du'
- rename command (possibly with alias)

Issue: #553
Signed-off-by: David Sterba <dsterba@suse.com>
2022-12-01 16:10:20 +01:00
David Sterba ce31dc1c08 btrfs-progs: inspect: new command map-swapfile
Verify if a given file is suitable for a swapfile and print the physical
offset (ie. the ultimate on-device physical offset), and the resume
offset value (physical / page size).

This can be the kernel parameter or written to /sys/power/resume_offset
before hibernation.  Option -r or --resume-offset prints just the value.

This is under experimental build in case the command name changes.

Copied and simplified from Omar Sandoval's tool to print extents:

https://github.com/osandov/osandov-linux/blob/master/scripts/btrfs_map_physical.c

Issue: #544
Issue: #533
Signed-off-by: David Sterba <dsterba@suse.com>
2022-11-30 21:09:43 +01:00
David Sterba 84b49246a4 btrfs-progs: tests: add string-table test framework
Signed-off-by: David Sterba <dsterba@suse.com>
2022-11-30 19:14:30 +01:00
David Sterba 2aead46fac btrfs-progs: string-table: add ranged API for printing and clearing
Track how many rows belong to a header (names and separators) so they
can be printed or cleared separately. The rest is body that could be
cleared and filled repeatedly. The ranged API allows to print any number
of rows if the table is filled partially.

Signed-off-by: David Sterba <dsterba@suse.com>
2022-11-30 19:14:30 +01:00
David Sterba 2222d18dae btrfs-progs: string-table: check bounds before writing to a cell
Signed-off-by: David Sterba <dsterba@suse.com>
2022-11-30 19:14:30 +01:00
David Sterba 614ea40d2f btrfs-progs: string-table: cleanup and enhance formatting capabilities
Cleanups are for integer types, prototypes and comments.

New functionality: spacing can be set after table allocation as
->spacing, now able to print 1 or 2 spaces between columns.

Signed-off-by: David Sterba <dsterba@suse.com>
2022-11-30 19:14:29 +01:00
David Sterba 7fd2e51c72 btrfs-progs: inspect: new subcommand to list chunks
New command 'btrfs inspect-internal list-chunks' will list layout of
chunks as stored on the devices. This corresponds to the physical
layout, sorted by the physical offset. The block group usage can be
shown as well, but the search is too slow so it's off by default.

If the physical offset sorting is selected, the empty space between
chunks is also shown.

Signed-off-by: David Sterba <dsterba@suse.com>
2022-11-30 19:14:29 +01:00
5 changed files with 1454 additions and 30 deletions

View file

@ -499,6 +499,16 @@ test-json: json-formatter-test
done \
}
test-string-table: string-table-test
@echo " [TEST] string-table formatting"
@{ \
max=`./string-table-test`; \
for testno in `seq 1 $$max`; do \
echo " [TEST/s-t] $$testno"; \
./string-table-test $$testno ; \
done \
}
test: test-check test-check-lowmem test-mkfs test-misc test-cli test-convert test-fuzz
testsuite: btrfs-corrupt-block btrfs-find-root btrfs-select-super fssum fsstress
@ -748,6 +758,10 @@ json-formatter-test: tests/json-formatter-test.c $(objects) libbtrfsutil.a
@echo " [LD] $@"
$(Q)$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) $(LIBS)
string-table-test: tests/string-table-test.c $(objects) libbtrfsutil.a
@echo " [LD] $@"
$(Q)$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) $(LIBS)
test-build: test-build-pre test-build-real
test-build-pre:

File diff suppressed because it is too large Load diff

View file

@ -18,15 +18,17 @@
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include "common/messages.h"
#include "common/string-table.h"
#include "common/internal.h"
/*
* This function create an array of char * which will represent a table
* Create an array of char* which will point to table cell strings
*/
struct string_table *table_create(int columns, int rows)
struct string_table *table_create(unsigned int columns, unsigned int rows)
{
struct string_table *tab;
int size;
size_t size;
size = sizeof(struct string_table) + rows * columns * sizeof(char*);
tab = calloc(1, size);
@ -36,27 +38,30 @@ struct string_table *table_create(int columns, int rows)
tab->ncols = columns;
tab->nrows = rows;
tab->spacing = STRING_TABLE_SPACING_1;
return tab;
}
/*
* This function is like a vprintf, but store the results in a cell of
* the table.
* If fmt starts with '<', the text is left aligned; if fmt starts with
* '>' the text is right aligned. If fmt is equal to '=' the text will
* be replaced by a '=====' dimensioned on the basis of the column width
* This is like a vprintf, but stores the results in a cell of the table.
*/
__attribute__ ((format (printf, 4, 0)))
char *table_vprintf(struct string_table *tab, int column, int row,
char *table_vprintf(struct string_table *tab, unsigned int column, unsigned int row,
const char *fmt, va_list ap)
{
int idx = tab->ncols * row + column;
unsigned int idx = tab->ncols * row + column;
char *msg = calloc(100, 1);
if (!msg)
return NULL;
if (column >= tab->ncols || row >= tab->nrows) {
error("attempt to write outside of table: col %u row %u fmt %s",
column, row, fmt);
return NULL;
}
if (tab->cells[idx])
free(tab->cells[idx]);
tab->cells[idx] = msg;
@ -66,12 +71,11 @@ char *table_vprintf(struct string_table *tab, int column, int row,
}
/*
* This function is like a printf, but store the results in a cell of
* the table.
* This is like a printf, but stores the results in a cell of the table.
*/
__attribute__ ((format (printf, 4, 5)))
char *table_printf(struct string_table *tab, int column, int row,
const char *fmt, ...)
char *table_printf(struct string_table *tab, unsigned int column, unsigned int row,
const char *fmt, ...)
{
va_list ap;
char *ret;
@ -84,17 +88,36 @@ char *table_printf(struct string_table *tab, int column, int row,
}
/*
* This function dumps the table. Every "=" string will be replaced by
* a "=======" length as the column
* Print the table to stdout, interpret the alignment and expand specifiers.
* @from: row from which to start
* @to: upper row limit (not inclusive), 0 for the whole table
*
* Formatting:
* <TEXT - the TEXT is left aligned
* >TEXT - the TEXT is right aligned
* = - the cell text will be filled by ===== (column width)
* *C - the cell text will be filled by character C (column width)
*/
void table_dump(struct string_table *tab)
void table_dump_range(struct string_table *tab, unsigned int from, unsigned int to)
{
int sizes[tab->ncols];
int i, j;
unsigned int sizes[tab->ncols];
unsigned int i, j;
unsigned int prescan;
if (to == 0)
to = tab->nrows;
if (from > to) {
error("invalid range for table dump %u > %u", from, to);
return;
}
prescan = max_t(unsigned int, 100, to);
prescan = min_t(unsigned int, tab->nrows, prescan);
for (i = 0; i < tab->ncols; i++) {
sizes[i] = 0;
for (j = 0; j < tab->nrows; j++) {
for (j = 0; j < prescan; j++) {
int idx = i + j * tab->ncols;
int len;
@ -110,7 +133,7 @@ void table_dump(struct string_table *tab)
}
}
for (j = 0; j < tab->nrows; j++) {
for (j = from; j < to; j++) {
for (i = 0; i < tab->ncols; i++) {
int idx = i + j * tab->ncols;
char *cell = tab->cells[idx];
@ -127,8 +150,11 @@ void table_dump(struct string_table *tab)
cell[0] == '<' ? -sizes[i] : sizes[i],
cell + 1);
}
if (i != (tab->ncols - 1))
if (i != (tab->ncols - 1)) {
putchar(' ');
if (tab->spacing == STRING_TABLE_SPACING_2)
putchar(' ');
}
}
putchar('\n');
}
@ -139,7 +165,7 @@ void table_dump(struct string_table *tab)
*/
void table_free(struct string_table *tab)
{
int i, count;
unsigned int i, count;
count = tab->ncols * tab->nrows;
@ -149,3 +175,20 @@ void table_free(struct string_table *tab)
free(tab);
}
void table_clear_range(struct string_table *tab, unsigned int from, unsigned int to)
{
unsigned int row, col;
if (to == 0)
to = tab->nrows;
for (row = from; row < to; row++) {
char **rowstart = &tab->cells[row * tab->ncols];
for (col = 0; col < tab->ncols; col++) {
free(rowstart[col]);
rowstart[col] = NULL;
}
}
}

View file

@ -19,18 +19,55 @@
#include <stdarg.h>
enum string_table_spacing {
STRING_TABLE_SPACING_1,
STRING_TABLE_SPACING_2,
};
struct string_table {
int ncols;
int nrows;
unsigned int ncols;
unsigned int nrows;
/* How many rows are header (names and separators). */
unsigned int hrows;
enum string_table_spacing spacing;
char *cells[];
};
struct string_table *table_create(int columns, int rows);
char *table_printf(struct string_table *tab, int column, int row,
struct string_table *table_create(unsigned int columns, unsigned int rows);
__attribute__ ((format (printf, 4, 0)))
char *table_printf(struct string_table *tab, unsigned int column, unsigned int row,
const char *fmt, ...);
char *table_vprintf(struct string_table *tab, int column, int row,
char *table_vprintf(struct string_table *tab, unsigned int column, unsigned int row,
const char *fmt, va_list ap);
void table_dump(struct string_table *tab);
void table_free(struct string_table *);
void table_free(struct string_table *tab);
void table_dump_range(struct string_table *tab, unsigned int from, unsigned int to);
static inline void table_dump(struct string_table *tab)
{
table_dump_range(tab, 0, 0);
}
static inline void table_dump_header(struct string_table *tab)
{
table_dump_range(tab, 0, tab->hrows);
}
static inline void table_dump_body(struct string_table *tab)
{
table_dump_range(tab, tab->hrows, 0);
}
void table_clear_range(struct string_table *tab, unsigned int from, unsigned int to);
static inline void table_clear_header(struct string_table *tab)
{
table_clear_range(tab, 0, tab->hrows);
}
static inline void table_clear_body(struct string_table *tab)
{
table_clear_range(tab, tab->hrows, 0);
}
#endif

132
tests/string-table-test.c Normal file
View file

@ -0,0 +1,132 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License v2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 021110-1307, USA.
*/
#include <stdio.h>
#include <stdlib.h>
#include "common/utils.h"
#include "common/string-table.h"
void test_simple_create_free()
{
struct string_table *tab;
tab = table_create(2, 2);
if (!tab) {
fprintf(stderr, "ERROR: cannot alocate table\n");
return;
}
table_printf(tab, 0, 0, ">00");
table_printf(tab, 0, 1, "<01");
table_printf(tab, 1, 0, ">10");
table_printf(tab, 1, 1, "<11");
table_dump(tab);
table_free(tab);
}
void test_simple_header()
{
struct string_table *tab;
int i;
tab = table_create(2, 6);
if (!tab) {
fprintf(stderr, "ERROR: cannot alocate table\n");
return;
}
tab->hrows = 2;
table_printf(tab, 0, 0, ">Id");
table_printf(tab, 1, 0, ">Name");
table_printf(tab, 0, 1, "*-");
table_printf(tab, 1, 1, "*-");
for (i = tab->hrows; i < tab->nrows; i++) {
table_printf(tab, 0, i, ">%d", 1U << i);
table_printf(tab, 1, i, "<%d", 100 * i);
}
puts("start");
table_dump_header(tab);
puts("separator");
table_dump_body(tab);
puts("end");
table_free(tab);
}
void test_simple_paginate()
{
struct string_table *tab;
unsigned int page_size = 4;
unsigned int pages = 4;
int i;
tab = table_create(2, 2 + page_size * pages);
if (!tab) {
fprintf(stderr, "ERROR: cannot alocate table\n");
return;
}
tab->hrows = 2;
table_printf(tab, 0, 0, ">Id");
table_printf(tab, 1, 0, ">Name");
table_printf(tab, 0, 1, "*-");
table_printf(tab, 1, 1, "*-");
for (i = tab->hrows; i < tab->nrows; i++) {
table_printf(tab, 0, i, ">%d", 10 * (i - tab->hrows + 1));
table_printf(tab, 1, i, "<Text %d", 100 * i);
}
puts("start");
for (i = 0; i < pages; i++) {
unsigned int start = tab->hrows + i * page_size;
table_dump_header(tab);
table_dump_range(tab, start, start + page_size - 1);
puts("paginator");
}
puts("end");
table_free(tab);
}
int main(int argc, char **argv)
{
int testno;
static void (*tests[])() = {
test_simple_create_free,
test_simple_header,
test_simple_paginate,
};
/* Without arguments, print the number of tests available */
if (argc == 1) {
printf("%zu\n", ARRAY_SIZE(tests));
return 0;
}
testno = atoi(argv[1]);
testno--;
if (testno < 0 || testno >= ARRAY_SIZE(tests)) {
fprintf(stderr, "ERROR: test number %d is out of range (max %zu)\n",
testno + 1, ARRAY_SIZE(tests));
return 1;
}
tests[testno]();
return 0;
}