blob: f1fe170c23f1044a4047d09e96d23a334c587a33 [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0
#define _FILE_OFFSET_BITS 64
#define __USE_FILE_OFFSET64
#define _XOPEN_SOURCE 600
#define _DEFAULT_SOURCE
#include <stdio.h>
#include <inttypes.h>
#include <string.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdbool.h>
#include <unistd.h>
#include <locale.h>
#include <limits.h>
#include <assert.h>
#include <blkid/blkid.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <linux/fs.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <uuid/uuid.h>
#include "bcache.h"
#include "lib.h"
#include "bitwise.h"
#include "zoned.h"
#include "features.h"
#include "list.h"
int show_bdevs_detail(void)
{
struct list_head head;
struct dev *devs, *n;
INIT_LIST_HEAD(&head);
int ret;
ret = list_bdevs(&head);
if (ret != 0) {
fprintf(stderr, "Failed to list devices\n");
return ret;
}
printf("Name\t\tUuid\t\t\t\t\tCset_Uuid\t\t\t\tType\t\t\tState");
printf("\t\t\tBname\t\tAttachToDev\tAttachToCset\n");
list_for_each_entry_safe(devs, n, &head, dev_list) {
printf("%s\t%s\t%s\t%lu", devs->name, devs->uuid,
devs->cset, devs->version);
switch (devs->version) {
// These are handled the same by the kernel
case BCACHE_SB_VERSION_CDEV:
case BCACHE_SB_VERSION_CDEV_WITH_UUID:
case BCACHE_SB_VERSION_CDEV_WITH_FEATURES:
printf(" (cache)");
break;
// The second adds data offset supporet
case BCACHE_SB_VERSION_BDEV:
case BCACHE_SB_VERSION_BDEV_WITH_OFFSET:
case BCACHE_SB_VERSION_BDEV_WITH_FEATURES:
printf(" (data)");
break;
default:
printf(" (unknown)");
break;
}
printf("\t\t%-16s", devs->state);
printf("\t%-16s", devs->bname);
char attachdev[30];
if (strlen(devs->attachuuid) == 36) {
cset_to_devname(&head, devs->cset, attachdev);
} else if (devs->version == BCACHE_SB_VERSION_CDEV
|| devs->version ==
BCACHE_SB_VERSION_CDEV_WITH_UUID) {
strcpy(attachdev, BCACHE_NO_SUPPORT);
} else {
strcpy(attachdev, BCACHE_ATTACH_ALONE);
}
printf("%-16s", attachdev);
printf("%s", devs->attachuuid);
putchar('\n');
}
free_dev(&head);
return 0;
}
int show_bdevs(void)
{
struct list_head head;
struct dev *devs, *n;
INIT_LIST_HEAD(&head);
int ret;
ret = list_bdevs(&head);
if (ret != 0) {
fprintf(stderr, "Failed to list devices\n");
return ret;
}
printf("Name\t\tType\t\tState\t\t\tBname\t\tAttachToDev\n");
list_for_each_entry_safe(devs, n, &head, dev_list) {
printf("%s\t%lu", devs->name, devs->version);
switch (devs->version) {
// These are handled the same by the kernel
case BCACHE_SB_VERSION_CDEV:
case BCACHE_SB_VERSION_CDEV_WITH_UUID:
case BCACHE_SB_VERSION_CDEV_WITH_FEATURES:
printf(" (cache)");
break;
// The second adds data offset supporet
case BCACHE_SB_VERSION_BDEV:
case BCACHE_SB_VERSION_BDEV_WITH_OFFSET:
case BCACHE_SB_VERSION_BDEV_WITH_FEATURES:
printf(" (data)");
break;
default:
printf(" (unknown)");
break;
}
printf("\t%-16s", devs->state);
printf("\t%-16s", devs->bname);
char attachdev[30];
if (strlen(devs->attachuuid) == 36) {
cset_to_devname(&head, devs->cset, attachdev);
} else if (devs->version == BCACHE_SB_VERSION_CDEV
|| devs->version ==
BCACHE_SB_VERSION_CDEV_WITH_UUID) {
strcpy(attachdev, BCACHE_NO_SUPPORT);
} else {
strcpy(attachdev, BCACHE_ATTACH_ALONE);
}
printf("%s", attachdev);
putchar('\n');
}
free_dev(&head);
return 0;
}
int detail_single_dev(char *devname, struct bdev *bd, struct cdev *cd, int type)
{
if (type == BCACHE_SB_VERSION_BDEV ||
type == BCACHE_SB_VERSION_BDEV_WITH_OFFSET ||
type == BCACHE_SB_VERSION_BDEV_WITH_FEATURES) {
printf("sb.magic\t\t%s\n", bd->base.magic);
printf("sb.first_sector\t\t%" PRIu64 "\n",
bd->base.first_sector);
printf("sb.csum\t\t\t%" PRIX64 "\n", bd->base.csum);
printf("sb.version\t\t%" PRIu64, bd->base.version);
printf(" [backing device]\n");
putchar('\n');
printf("dev.label\t\t");
if (*bd->base.label)
print_encode(bd->base.label);
else
printf("(empty)");
putchar('\n');
printf("dev.uuid\t\t%s\n", bd->base.uuid);
printf("dev.sectors_per_block\t%u\n"
"dev.sectors_per_bucket\t%u\n",
bd->base.sectors_per_block,
bd->base.sectors_per_bucket);
printf("dev.data.first_sector\t%u\n"
"dev.data.cache_mode\t%d",
bd->first_sector, bd->cache_mode);
switch (bd->cache_mode) {
case CACHE_MODE_WRITETHROUGH:
printf(" [writethrough]\n");
break;
case CACHE_MODE_WRITEBACK:
printf(" [writeback]\n");
break;
case CACHE_MODE_WRITEAROUND:
printf(" [writearound]\n");
break;
case CACHE_MODE_NONE:
printf(" [no caching]\n");
break;
default:
putchar('\n');
}
printf("dev.data.cache_state\t%u", bd->cache_state);
switch (bd->cache_state) {
case BDEV_STATE_NONE:
printf(" [detached]\n");
break;
case BDEV_STATE_CLEAN:
printf(" [clean]\n");
break;
case BDEV_STATE_DIRTY:
printf(" [dirty]\n");
break;
case BDEV_STATE_STALE:
printf(" [inconsistent]\n");
break;
default:
putchar('\n');
}
putchar('\n');
printf("cset.uuid\t\t%s\n", bd->base.cset);
} else if (type == BCACHE_SB_VERSION_CDEV ||
type == BCACHE_SB_VERSION_CDEV_WITH_UUID ||
type == BCACHE_SB_VERSION_CDEV_WITH_FEATURES) {
printf("sb.magic\t\t%s\n", cd->base.magic);
printf("sb.first_sector\t\t%" PRIu64 "\n",
cd->base.first_sector);
printf("sb.csum\t\t\t%" PRIX64 "\n", cd->base.csum);
printf("sb.version\t\t%" PRIu64, cd->base.version);
printf(" [cache device]\n");
print_cache_set_supported_feature_sets(&cd->base.sb);
putchar('\n');
printf("dev.label\t\t");
if (*cd->base.label)
print_encode(cd->base.label);
else
printf("(empty)");
putchar('\n');
printf("dev.uuid\t\t%s\n", cd->base.uuid);
printf("dev.sectors_per_block\t%u\n"
"dev.sectors_per_bucket\t%u\n",
cd->base.sectors_per_block,
cd->base.sectors_per_bucket);
printf("dev.cache.first_sector\t%u\n"
"dev.cache.cache_sectors\t%ju\n"
"dev.cache.total_sectors\t%ju\n"
"dev.cache.ordered\t%s\n"
"dev.cache.discard\t%s\n"
"dev.cache.pos\t\t%u\n"
"dev.cache.replacement\t%d",
cd->first_sector,
cd->cache_sectors,
cd->total_sectors,
cd->ordered ? "yes" : "no",
cd->discard ? "yes" : "no", cd->pos, cd->replacement);
switch (cd->replacement) {
case CACHE_REPLACEMENT_LRU:
printf(" [lru]\n");
break;
case CACHE_REPLACEMENT_FIFO:
printf(" [fifo]\n");
break;
case CACHE_REPLACEMENT_RANDOM:
printf(" [random]\n");
break;
default:
putchar('\n');
}
putchar('\n');
printf("cset.uuid\t\t%s\n", cd->base.cset);
} else {
return 1;
}
return 0;
}
int detail_single_mdev(char *devname, struct mdev *md)
{
printf( "sb.csum\t\t\t%" PRIX64 "\n"
"sb.sb_offset\t\t0x%" PRIX64 "\n"
"sb.ns_start\t\t0x%" PRIX64 "\n"
"sb.version\t\t%" PRIu64 " [nvdimm-meta device]\n"
"sb.magic\t\t%s\n"
"sb.uuid\t\t\t%s\n"
"sb.page_size\t\t%u\n"
"sb.total_ns\t\t%u\n"
"sb.this_ns\t\t%u\n"
"sb.set_uuid\t\t%s\n"
"sb.flags\t\t%" PRIX64 "\n"
"sb.seq\t\t\t%" PRIX64 "\n"
"sb.feature_compat\t0x%" PRIX64 "\n"
"sb.feature_ro_compat\t0x%" PRIX64 "\n"
"sb.feature_incompat\t0x%" PRIX64 "\n"
"sb.pages_offset\t\t0x%" PRIX64 "\n"
"sb.pages_total\t\t%" PRIu64 "\n"
"sb.set_header_offset\t%" PRIu64 "\n",
md->csum,
md->sb_offset,
md->ns_start,
md->version,
md->magic,
md->uuid,
md->page_size,
md->total_ns,
md->this_ns,
md->set_uuid,
md->flags,
md->seq,
md->feature_compat,
md->feature_ro_compat,
md->feature_incompat,
md->pages_offset,
md->pages_total,
md->set_header_offset);
putchar('\n');
return 0;
}
int detail_single(char *devname)
{
struct bdev bd;
struct cdev cd;
struct mdev md;
int type = 0;
int ret = 0;
ret = detail_dev(devname, &bd, &cd, &md, &type);
if (ret != 0)
goto out;
if (type >= 0 && type <= BCACHE_SB_MAX_VERSION)
ret = detail_single_dev(devname, &bd, &cd, type);
else
ret = detail_single_mdev(devname, &md);
out:
return ret;
}