| // 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; |
| } |