mirror of
https://github.com/koverstreet/bcachefs-tools.git
synced 2025-02-22 00:00:03 +03:00
rewrite
This commit is contained in:
parent
da1fff8700
commit
fb22ceda3e
3
Makefile
3
Makefile
@ -25,7 +25,8 @@ bcache.o: CFLAGS += `pkg-config --cflags uuid blkid`
|
||||
|
||||
bcacheadm.o: CFLAGS += `pkg-config --cflags uuid blkid libnih`
|
||||
bcacheadm: LDLIBS += `pkg-config --libs uuid blkid libnih`
|
||||
bcacheadm: bcacheadm.o bcacheadm-format.o bcache.o
|
||||
bcacheadm: bcacheadm.o bcacheadm-format.o bcacheadm-assemble.o bcacheadm-run.o\
|
||||
bcacheadm-query.o bcache.o
|
||||
|
||||
probe-bcache.o: CFLAGS += `pkg-config --cflags uuid blkid`
|
||||
probe-bcache: LDLIBS += `pkg-config --libs uuid blkid`
|
||||
|
408
bcache.c
408
bcache.c
@ -852,55 +852,6 @@ char *dev_name(const char *ugly_path) {
|
||||
return strdup(buf);
|
||||
}
|
||||
|
||||
static void list_cacheset_devs(char *cset_dir, char *cset_name, bool parse_dev_name)
|
||||
{
|
||||
DIR *cachedir, *dir;
|
||||
struct stat cache_stat;
|
||||
char entry[MAX_PATH];
|
||||
struct dirent *ent;
|
||||
snprintf(entry, MAX_PATH, "%s/%s", cset_dir, cset_name);
|
||||
|
||||
if((dir = opendir(entry)) != NULL) {
|
||||
while((ent = readdir(dir)) != NULL) {
|
||||
char buf[MAX_PATH];
|
||||
int len;
|
||||
char *tmp;
|
||||
|
||||
/*
|
||||
* We are looking for all cache# directories
|
||||
* do a strlen < 9 to skip over other entries
|
||||
* that also start with "cache"
|
||||
*/
|
||||
if(strncmp(ent->d_name, "cache", 5) ||
|
||||
!(strlen(ent->d_name) < 9))
|
||||
continue;
|
||||
|
||||
snprintf(entry, MAX_PATH, "%s/%s/%s",
|
||||
cset_dir,
|
||||
cset_name,
|
||||
ent->d_name);
|
||||
|
||||
if((cachedir = opendir(entry)) == NULL)
|
||||
continue;
|
||||
|
||||
if(stat(entry, &cache_stat))
|
||||
continue;
|
||||
|
||||
if((len = readlink(entry, buf, sizeof(buf) - 1)) !=
|
||||
-1) {
|
||||
buf[len] = '\0';
|
||||
if(parse_dev_name) {
|
||||
tmp = dev_name(buf);
|
||||
printf("/dev%s\n", tmp);
|
||||
free(tmp);
|
||||
} else {
|
||||
printf("\t%s\n", buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
char *find_matching_uuid(char *stats_dir, char *subdir, const char *stats_dev_uuid)
|
||||
{
|
||||
/* Do a query-dev --uuid only to get the uuid
|
||||
@ -973,360 +924,21 @@ char *find_matching_uuid(char *stats_dir, char *subdir, const char *stats_dev_uu
|
||||
return err;
|
||||
}
|
||||
|
||||
char *list_cachesets(char *cset_dir, bool list_devs)
|
||||
int bcachectl_open(void)
|
||||
{
|
||||
struct dirent *ent;
|
||||
DIR *dir;
|
||||
char *err = NULL;
|
||||
int fd = open("/dev/bcache-ctl", O_RDWR);
|
||||
if (fd < 0)
|
||||
die("Can't open bcache device: %s", strerror(errno));
|
||||
|
||||
dir = opendir(cset_dir);
|
||||
if (!dir) {
|
||||
err = "Failed to open cacheset dir";
|
||||
goto err;
|
||||
}
|
||||
|
||||
while ((ent = readdir(dir)) != NULL) {
|
||||
struct stat statbuf;
|
||||
char entry[MAX_PATH];
|
||||
|
||||
if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."))
|
||||
continue;
|
||||
|
||||
snprintf(entry, MAX_PATH, "%s/%s", cset_dir, ent->d_name);
|
||||
if(stat(entry, &statbuf) == -1) {
|
||||
err = "Failed to stat cacheset subdir";
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (S_ISDIR(statbuf.st_mode)) {
|
||||
printf("%s\n", ent->d_name);
|
||||
|
||||
if(list_devs) {
|
||||
list_cacheset_devs(cset_dir, ent->d_name, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
err:
|
||||
closedir(dir);
|
||||
return err;
|
||||
return fd;
|
||||
}
|
||||
|
||||
char *register_bcache(char *const *devs)
|
||||
unsigned nr_args(char *const *args)
|
||||
{
|
||||
int ret, bcachefd;
|
||||
char *err = NULL;
|
||||
unsigned i;
|
||||
|
||||
bcachefd = open("/dev/bcache", O_RDWR);
|
||||
if (bcachefd < 0) {
|
||||
err = "Can't open bcache device";
|
||||
goto err;
|
||||
}
|
||||
for (i = 0; args[i]; i++)
|
||||
;
|
||||
|
||||
ret = ioctl(bcachefd, BCH_IOCTL_REGISTER, devs);
|
||||
if (ret < 0) {
|
||||
char tmp[64];
|
||||
snprintf(tmp, 64, "ioctl register error: %s\n",
|
||||
strerror(ret));
|
||||
err = strdup(tmp);
|
||||
goto err;
|
||||
}
|
||||
|
||||
err:
|
||||
if (bcachefd)
|
||||
close(bcachefd);
|
||||
return err;
|
||||
}
|
||||
|
||||
char *unregister_bcache(char *const *devs)
|
||||
{
|
||||
int ret, bcachefd;
|
||||
char *err = NULL;
|
||||
|
||||
bcachefd = open("/dev/bcache_extent0", O_RDWR);
|
||||
if (bcachefd < 0) {
|
||||
err = "Can't open bcache device";
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = ioctl(bcachefd, BCH_IOCTL_STOP);
|
||||
if (ret < 0) {
|
||||
char tmp[64];
|
||||
snprintf(tmp, 64, "ioctl unregister error: %s\n",
|
||||
strerror(ret));
|
||||
err = strdup(tmp);
|
||||
goto err;
|
||||
}
|
||||
|
||||
err:
|
||||
close(bcachefd);
|
||||
return err;
|
||||
}
|
||||
|
||||
char *add_devices(char *const *devs)
|
||||
{
|
||||
int ret, bcachefd;
|
||||
char *err = NULL;
|
||||
|
||||
bcachefd = open("/dev/bcache_extent0", O_RDWR);
|
||||
if (bcachefd < 0) {
|
||||
err = "Can't open bcache device";
|
||||
goto err;
|
||||
}
|
||||
|
||||
struct bch_ioctl_add_disks ia;
|
||||
ia.devs = devs;
|
||||
|
||||
ret = ioctl(bcachefd, BCH_IOCTL_ADD_DISKS, &ia);
|
||||
if (ret < 0) {
|
||||
char tmp[128];
|
||||
snprintf(tmp, 128, "ioctl add disk error: %s\n",
|
||||
strerror(ret));
|
||||
err = strdup(tmp);
|
||||
}
|
||||
|
||||
err:
|
||||
close(bcachefd);
|
||||
return err;
|
||||
}
|
||||
|
||||
char *remove_device(const char *dev, bool force)
|
||||
{
|
||||
int ret, bcachefd;
|
||||
char *err = NULL;
|
||||
|
||||
bcachefd = open("/dev/bcache_extent0", O_RDWR);
|
||||
if (bcachefd < 0) {
|
||||
err = "Can't open bcache device";
|
||||
goto err;
|
||||
}
|
||||
|
||||
struct bch_ioctl_rm_disk ir;
|
||||
ir.dev = dev;
|
||||
ir.force = force ? 1 : 0;
|
||||
|
||||
ret = ioctl(bcachefd, BCH_IOCTL_RM_DISK, &ir);
|
||||
if (ret < 0) {
|
||||
char tmp[128];
|
||||
snprintf(tmp, 128, "ioctl add disk error: %s\n",
|
||||
strerror(ret));
|
||||
err = strdup(tmp);
|
||||
}
|
||||
|
||||
err:
|
||||
close(bcachefd);
|
||||
return err;
|
||||
}
|
||||
|
||||
char *device_set_failed(const char *dev_uuid) {
|
||||
int ret, bcachefd;
|
||||
char *err = NULL;
|
||||
uuid_le dev;
|
||||
struct bch_ioctl_disk_failed df;
|
||||
|
||||
bcachefd = open("/dev/bcache_extent0", O_RDWR);
|
||||
if (bcachefd < 0) {
|
||||
err = "Can't open bcache device";
|
||||
goto err;
|
||||
}
|
||||
|
||||
uuid_parse(dev_uuid, dev.b);
|
||||
df.dev_uuid = dev;
|
||||
|
||||
ret = ioctl(bcachefd, BCH_IOCTL_SET_DISK_FAILED, &df);
|
||||
if (ret < 0) {
|
||||
char tmp[128];
|
||||
snprintf(tmp, 128, "ioctl set disk failed error %s\n",
|
||||
strerror(ret));
|
||||
err = strdup(tmp);
|
||||
}
|
||||
|
||||
err:
|
||||
close(bcachefd);
|
||||
return err;
|
||||
}
|
||||
|
||||
char *probe(char *dev, int udev)
|
||||
{
|
||||
struct cache_sb sb;
|
||||
char uuid[40];
|
||||
blkid_probe pr;
|
||||
char *err = NULL;
|
||||
|
||||
int fd = open(dev, O_RDONLY);
|
||||
if (fd == -1) {
|
||||
err = "Got file descriptor -1 trying to open dev";
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!(pr = blkid_new_probe())) {
|
||||
err = "Failed trying to get a blkid for new probe";
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (blkid_probe_set_device(pr, fd, 0, 0)) {
|
||||
err = "Failed blkid probe set device";
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* probe partitions too */
|
||||
if (blkid_probe_enable_partitions(pr, true)) {
|
||||
err = "Enable probe partitions";
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* bail if anything was found
|
||||
* probe-bcache isn't needed once blkid recognizes bcache */
|
||||
if (!blkid_do_probe(pr)) {
|
||||
err = "blkid recognizes bcache";
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (pread(fd, &sb, sizeof(sb), SB_START) != sizeof(sb)) {
|
||||
err = "Failed to read superblock";
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (memcmp(&sb.magic, &BCACHE_MAGIC, sizeof(sb.magic))) {
|
||||
err = "Bcache magic incorrect";
|
||||
goto err;
|
||||
}
|
||||
|
||||
uuid_unparse(sb.disk_uuid.b, uuid);
|
||||
|
||||
if (udev)
|
||||
printf("ID_FS_UUID=%s\n"
|
||||
"ID_FS_UUID_ENC=%s\n"
|
||||
"ID_FS_TYPE=bcache\n",
|
||||
uuid, uuid);
|
||||
else
|
||||
printf("%s: UUID=\"\" TYPE=\"bcache\"\n", uuid);
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
return err;
|
||||
}
|
||||
|
||||
char *read_stat_dir(DIR *dir, char *stats_dir, char *stat_name, char *ret)
|
||||
{
|
||||
struct stat statbuf;
|
||||
char entry[MAX_PATH];
|
||||
char *err = NULL;
|
||||
|
||||
snprintf(entry, MAX_PATH, "%s/%s", stats_dir, stat_name);
|
||||
if(stat(entry, &statbuf) == -1) {
|
||||
char tmp[MAX_PATH];
|
||||
snprintf(tmp, MAX_PATH, "Failed to stat %s\n", entry);
|
||||
err = strdup(tmp);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (S_ISREG(statbuf.st_mode)) {
|
||||
FILE *fp = NULL;
|
||||
|
||||
fp = fopen(entry, "r");
|
||||
if(!fp) {
|
||||
/* If we can't open the file, this is probably because
|
||||
* of permissions, just move to the next file */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while(fgets(ret, MAX_PATH, fp));
|
||||
fclose(fp);
|
||||
}
|
||||
err:
|
||||
return err;
|
||||
}
|
||||
|
||||
char *bcache_get_capacity(const char *cset_dir, const char *capacity_uuid,
|
||||
bool show_devs)
|
||||
{
|
||||
char *err = NULL;
|
||||
char bucket_size_path[MAX_PATH];
|
||||
char nbuckets_path[MAX_PATH];
|
||||
char avail_buckets_path[MAX_PATH];
|
||||
char cache_path[MAX_PATH];
|
||||
|
||||
double bucket_sizes[MAX_DEVS];
|
||||
double nbuckets[MAX_DEVS];
|
||||
double avail_buckets[MAX_DEVS];
|
||||
char *dev_names[MAX_DEVS];
|
||||
int dev_count = 0, i;
|
||||
double total_cap = 0, total_free = 0;
|
||||
int precision = 2;
|
||||
|
||||
|
||||
while (true) {
|
||||
char buf[MAX_PATH];
|
||||
int len;
|
||||
DIR *cache_dir;
|
||||
|
||||
snprintf(bucket_size_path, sizeof(bucket_size_path), "%s/%s/%s%d/%s", cset_dir,
|
||||
capacity_uuid, "cache", dev_count, "bucket_size_bytes");
|
||||
snprintf(nbuckets_path, sizeof(nbuckets_path), "%s/%s/%s%d/%s", cset_dir,
|
||||
capacity_uuid, "cache", dev_count, "nbuckets");
|
||||
snprintf(avail_buckets_path, sizeof(avail_buckets_path), "%s/%s/%s%d/%s", cset_dir,
|
||||
capacity_uuid, "cache", dev_count, "available_buckets");
|
||||
snprintf(cache_path, sizeof(cache_path), "%s/%s/%s%d", cset_dir, capacity_uuid,
|
||||
"cache", dev_count);
|
||||
|
||||
if((cache_dir = opendir(cache_path)) == NULL)
|
||||
break;
|
||||
|
||||
err = read_stat_dir(cache_dir, cache_path,
|
||||
"bucket_size_bytes", buf);
|
||||
if (err)
|
||||
goto err;
|
||||
else
|
||||
bucket_sizes[dev_count] = atof(buf);
|
||||
|
||||
err = read_stat_dir(cache_dir, cache_path,
|
||||
"nbuckets", buf);
|
||||
if (err)
|
||||
goto err;
|
||||
else
|
||||
nbuckets[dev_count] = atof(buf);
|
||||
|
||||
err = read_stat_dir(cache_dir, cache_path,
|
||||
"available_buckets", buf);
|
||||
if (err)
|
||||
goto err;
|
||||
else
|
||||
avail_buckets[dev_count] = atof(buf);
|
||||
|
||||
if((len = readlink(cache_path, buf, sizeof(buf) - 1)) != -1) {
|
||||
buf[len] = '\0';
|
||||
dev_names[dev_count] = dev_name(buf);
|
||||
}
|
||||
|
||||
dev_count++;
|
||||
}
|
||||
|
||||
printf("%-15s%-25s%-25s\n", "Device Name", "Capacity (512 Blocks)", "Free (512 Blocks)");
|
||||
|
||||
if (show_devs) {
|
||||
for (i = 0; i < dev_count; i++) {
|
||||
printf("%s%-11s%-25.*f%-25.*f\n", "/dev", dev_names[i],
|
||||
precision,
|
||||
(bucket_sizes[i] * nbuckets[i]) / 512,
|
||||
precision,
|
||||
(bucket_sizes[i] * avail_buckets[i]) / 512);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < dev_count; i++) {
|
||||
total_cap += (bucket_sizes[i] * nbuckets[i]) / 512;
|
||||
total_free += (bucket_sizes[i] * avail_buckets[i]) / 512;
|
||||
|
||||
}
|
||||
|
||||
printf("%-15s%-25.*f%-25.*f\n", "Total", precision, total_cap,
|
||||
precision, total_free);
|
||||
|
||||
err:
|
||||
for (i = 0; i < dev_count; i++)
|
||||
if (dev_names[i])
|
||||
free(dev_names[i]);
|
||||
return err;
|
||||
return i;
|
||||
}
|
||||
|
12
bcache.h
12
bcache.h
@ -7,6 +7,7 @@
|
||||
#ifndef _BCACHE_H
|
||||
#define _BCACHE_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <linux/bcache.h>
|
||||
#include <dirent.h>
|
||||
|
||||
@ -87,18 +88,13 @@ enum sysfs_attr sysfs_attr_type(const char *attr);
|
||||
void sysfs_attr_list();
|
||||
|
||||
struct cache_sb *query_dev(char *, bool, bool, bool, char *dev_uuid);
|
||||
char *list_cachesets(char *, bool);
|
||||
char *parse_array_to_list(char *const *);
|
||||
char *register_bcache(char *const *);
|
||||
char *unregister_bcache(char *const *);
|
||||
char *probe(char *, int);
|
||||
char *read_stat_dir(DIR *, char *, char *, char *);
|
||||
char *find_matching_uuid(char *, char *, const char*);
|
||||
char *add_devices(char *const *);
|
||||
char *remove_device(const char *, bool);
|
||||
char *bcache_get_capacity(const char *, const char *, bool);
|
||||
char *dev_name(const char *);
|
||||
char *device_set_failed(const char *dev_uuid);
|
||||
|
||||
int bcachectl_open(void);
|
||||
unsigned nr_args(char * const *);
|
||||
|
||||
#define csum_set(i, type) \
|
||||
({ \
|
||||
|
61
bcacheadm-assemble.c
Normal file
61
bcacheadm-assemble.c
Normal file
@ -0,0 +1,61 @@
|
||||
|
||||
#include <alloca.h>
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include <nih/command.h>
|
||||
#include <nih/option.h>
|
||||
|
||||
#include <linux/bcache-ioctl.h>
|
||||
|
||||
#include "bcache.h"
|
||||
#include "bcacheadm-assemble.h"
|
||||
|
||||
NihOption opts_assemble[] = {
|
||||
NIH_OPTION_LAST
|
||||
};
|
||||
|
||||
int cmd_assemble(NihCommand *command, char *const *args)
|
||||
{
|
||||
unsigned nr_devs = nr_args(args);
|
||||
|
||||
struct bch_ioctl_assemble *assemble =
|
||||
alloca(sizeof(*assemble) + sizeof(__u64) * nr_devs);
|
||||
|
||||
memset(assemble, 0, sizeof(*assemble));
|
||||
assemble->nr_devs = nr_devs;
|
||||
|
||||
for (unsigned i = 0; i < nr_devs; i++)
|
||||
assemble->devs[i] = (__u64) args[i];
|
||||
|
||||
int ret = ioctl(bcachectl_open(), BCH_IOCTL_ASSEMBLE, assemble);
|
||||
if (ret < 0)
|
||||
die("BCH_IOCTL_ASSEMBLE error: %s", strerror(errno));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
NihOption opts_incremental[] = {
|
||||
NIH_OPTION_LAST
|
||||
};
|
||||
|
||||
int cmd_incremental(NihCommand *command, char *const *args)
|
||||
{
|
||||
if (nr_args(args) != 1)
|
||||
die("Please supply exactly one device");
|
||||
|
||||
struct bch_ioctl_incremental incremental = {
|
||||
.dev = (__u64) args[0],
|
||||
};
|
||||
|
||||
int ret = ioctl(bcachectl_open(), BCH_IOCTL_INCREMENTAL, &incremental);
|
||||
if (ret < 0)
|
||||
die("BCH_IOCTL_INCREMENTAL error: %s", strerror(errno));
|
||||
|
||||
return 0;
|
||||
}
|
10
bcacheadm-assemble.h
Normal file
10
bcacheadm-assemble.h
Normal file
@ -0,0 +1,10 @@
|
||||
#ifndef _BCACHEADM_ASSEMBLE_H
|
||||
#define _BCACHEADM_ASSEMBLE_H
|
||||
|
||||
extern NihOption opts_assemble[];
|
||||
int cmd_assemble(NihCommand *, char * const *);
|
||||
|
||||
extern NihOption opts_incremental[];
|
||||
int cmd_incremental(NihCommand *, char * const *);
|
||||
|
||||
#endif /* _BCACHEADM_ASSEMBLE_H */
|
@ -35,7 +35,7 @@
|
||||
#include <nih/option.h>
|
||||
|
||||
#include "bcache.h"
|
||||
#include "bcacheadm.h"
|
||||
#include "bcacheadm-format.h"
|
||||
|
||||
static struct cache_opts {
|
||||
int fd;
|
||||
@ -180,7 +180,7 @@ static int set_cache_mode(NihOption *option, const char *arg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
NihOption bcacheadm_format_options[] = {
|
||||
NihOption opts_format[] = {
|
||||
// { int shortoption, char *longoption, char *help, NihOptionGroup, char *argname, void *value, NihOptionSetter}
|
||||
|
||||
{ 'C', "cache", N_("Format a cache device"),
|
||||
@ -259,13 +259,15 @@ static unsigned ilog2(uint64_t n)
|
||||
return ret;
|
||||
}
|
||||
|
||||
int bcacheadm_format(NihCommand *command, char *const *args)
|
||||
static int format_v0(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int format_v1(void)
|
||||
{
|
||||
struct cache_sb *cache_set_sb;
|
||||
|
||||
if (!nr_cache_devices && !nr_backing_devices)
|
||||
die("Please supply a device");
|
||||
|
||||
if (!block_size) {
|
||||
for (struct cache_opts *i = cache_devices;
|
||||
i < cache_devices + nr_cache_devices;
|
||||
@ -403,3 +405,11 @@ int bcacheadm_format(NihCommand *command, char *const *args)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cmd_format(NihCommand *command, char *const *args)
|
||||
{
|
||||
if (!nr_cache_devices && !nr_backing_devices)
|
||||
die("Please supply a device");
|
||||
|
||||
return format_v1();
|
||||
}
|
||||
|
7
bcacheadm-format.h
Normal file
7
bcacheadm-format.h
Normal file
@ -0,0 +1,7 @@
|
||||
#ifndef _BCACHEADM_FORMAT_H
|
||||
#define _BCACHEADM_FORMAT_H
|
||||
|
||||
extern NihOption opts_format[];
|
||||
int cmd_format(NihCommand *, char * const *);
|
||||
|
||||
#endif /* _BCACHEADM_FORMAT_H */
|
361
bcacheadm-query.c
Normal file
361
bcacheadm-query.c
Normal file
@ -0,0 +1,361 @@
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <nih/command.h>
|
||||
#include <nih/option.h>
|
||||
|
||||
#include <linux/bcache-ioctl.h>
|
||||
|
||||
#include <uuid/uuid.h>
|
||||
|
||||
#include "bcache.h"
|
||||
#include "bcacheadm-query.h"
|
||||
|
||||
static char *cset_dir = "/sys/fs/bcache";
|
||||
static bool list_devs = false;
|
||||
static const char *internal_uuid = NULL;
|
||||
|
||||
NihOption opts_list[] = {
|
||||
{'d', "dir", N_("directory"), NULL, NULL, &cset_dir, NULL},
|
||||
{0, "list-devs", N_("list all devices in the cache sets as well"), NULL, NULL, &list_devs, NULL},
|
||||
{0, "internal_uuid", N_("Show the internal UUID for the given cacheset UUID"), NULL, "UUID", &internal_uuid, NULL},
|
||||
NIH_OPTION_LAST
|
||||
};
|
||||
|
||||
static void list_cacheset_devs(char *cset_dir, char *cset_name, bool parse_dev_name)
|
||||
{
|
||||
DIR *cachedir, *dir;
|
||||
struct stat cache_stat;
|
||||
char entry[MAX_PATH];
|
||||
struct dirent *ent;
|
||||
snprintf(entry, MAX_PATH, "%s/%s", cset_dir, cset_name);
|
||||
|
||||
if((dir = opendir(entry)) != NULL) {
|
||||
while((ent = readdir(dir)) != NULL) {
|
||||
char buf[MAX_PATH];
|
||||
int len;
|
||||
char *tmp;
|
||||
|
||||
/*
|
||||
* We are looking for all cache# directories
|
||||
* do a strlen < 9 to skip over other entries
|
||||
* that also start with "cache"
|
||||
*/
|
||||
if(strncmp(ent->d_name, "cache", 5) ||
|
||||
!(strlen(ent->d_name) < 9))
|
||||
continue;
|
||||
|
||||
snprintf(entry, MAX_PATH, "%s/%s/%s",
|
||||
cset_dir,
|
||||
cset_name,
|
||||
ent->d_name);
|
||||
|
||||
if((cachedir = opendir(entry)) == NULL)
|
||||
continue;
|
||||
|
||||
if(stat(entry, &cache_stat))
|
||||
continue;
|
||||
|
||||
if((len = readlink(entry, buf, sizeof(buf) - 1)) !=
|
||||
-1) {
|
||||
buf[len] = '\0';
|
||||
if(parse_dev_name) {
|
||||
tmp = dev_name(buf);
|
||||
printf("/dev%s\n", tmp);
|
||||
free(tmp);
|
||||
} else {
|
||||
printf("\t%s\n", buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static char *list_cachesets(char *cset_dir, bool list_devs)
|
||||
{
|
||||
struct dirent *ent;
|
||||
DIR *dir;
|
||||
char *err = NULL;
|
||||
|
||||
dir = opendir(cset_dir);
|
||||
if (!dir) {
|
||||
err = "Failed to open cacheset dir";
|
||||
goto err;
|
||||
}
|
||||
|
||||
while ((ent = readdir(dir)) != NULL) {
|
||||
struct stat statbuf;
|
||||
char entry[MAX_PATH];
|
||||
|
||||
if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."))
|
||||
continue;
|
||||
|
||||
snprintf(entry, MAX_PATH, "%s/%s", cset_dir, ent->d_name);
|
||||
if(stat(entry, &statbuf) == -1) {
|
||||
err = "Failed to stat cacheset subdir";
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (S_ISDIR(statbuf.st_mode)) {
|
||||
printf("%s\n", ent->d_name);
|
||||
|
||||
if(list_devs) {
|
||||
list_cacheset_devs(cset_dir, ent->d_name, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
err:
|
||||
closedir(dir);
|
||||
return err;
|
||||
}
|
||||
|
||||
static char *read_stat_dir(DIR *dir, char *stats_dir, char *stat_name, char *ret)
|
||||
{
|
||||
struct stat statbuf;
|
||||
char entry[MAX_PATH];
|
||||
char *err = NULL;
|
||||
|
||||
snprintf(entry, MAX_PATH, "%s/%s", stats_dir, stat_name);
|
||||
if(stat(entry, &statbuf) == -1) {
|
||||
char tmp[MAX_PATH];
|
||||
snprintf(tmp, MAX_PATH, "Failed to stat %s\n", entry);
|
||||
err = strdup(tmp);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (S_ISREG(statbuf.st_mode)) {
|
||||
FILE *fp = NULL;
|
||||
|
||||
fp = fopen(entry, "r");
|
||||
if(!fp) {
|
||||
/* If we can't open the file, this is probably because
|
||||
* of permissions, just move to the next file */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while(fgets(ret, MAX_PATH, fp));
|
||||
fclose(fp);
|
||||
}
|
||||
err:
|
||||
return err;
|
||||
}
|
||||
|
||||
int cmd_list(NihCommand *command, char *const *args)
|
||||
{
|
||||
char *err = NULL;
|
||||
|
||||
if (internal_uuid) {
|
||||
char uuid_path[MAX_PATH];
|
||||
DIR *uuid_dir;
|
||||
char buf[MAX_PATH];
|
||||
|
||||
snprintf(uuid_path, MAX_PATH, "%s/%s", cset_dir, internal_uuid);
|
||||
|
||||
err = "uuid does not exist";
|
||||
if((uuid_dir = opendir(uuid_path)) == NULL)
|
||||
goto err;
|
||||
|
||||
err = read_stat_dir(uuid_dir, uuid_path, "/internal/internal_uuid", buf);
|
||||
if (err)
|
||||
goto err;
|
||||
printf("%s", buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
err = list_cachesets(cset_dir, list_devs);
|
||||
if (err)
|
||||
goto err;
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
printf("bcache_list_cachesets error :%s\n", err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static bool force_csum = false;
|
||||
static bool uuid_only = false;
|
||||
static bool query_brief = false;
|
||||
|
||||
NihOption opts_query[] = {
|
||||
{'f', "force_csum", N_("force_csum"), NULL, NULL, &force_csum, NULL},
|
||||
{'u', "uuid-only", N_("only print out the uuid for the devices, not the whole superblock"), NULL, NULL, &uuid_only, NULL},
|
||||
{'b', "brief", N_("only print out the cluster,server,and disk uuids"), NULL, NULL, &query_brief, NULL},
|
||||
NIH_OPTION_LAST
|
||||
};
|
||||
|
||||
int cmd_query(NihCommand *command, char *const *args)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (query_brief)
|
||||
printf("%-10s%-40s%-40s%-40s\n", "dev name", "disk uuid",
|
||||
"server uuid", "cluster uuid");
|
||||
|
||||
for (i = 0; args[i] != NULL; i++) {
|
||||
char dev_uuid[40];
|
||||
struct cache_sb *sb = query_dev(args[i], force_csum,
|
||||
!query_brief, uuid_only, dev_uuid);
|
||||
|
||||
if (!sb) {
|
||||
printf("error opening the superblock for %s\n",
|
||||
args[i]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (uuid_only) {
|
||||
printf("%s\n", dev_uuid);
|
||||
} else if (query_brief) {
|
||||
char set_uuid_str[40], dev_uuid_str[40];
|
||||
char *clus_uuid = (char *)sb->label;
|
||||
|
||||
uuid_unparse(sb->user_uuid.b, set_uuid_str);
|
||||
uuid_unparse(sb->disk_uuid.b, dev_uuid_str);
|
||||
if (!strcmp(clus_uuid, ""))
|
||||
clus_uuid = "None";
|
||||
|
||||
printf("%-10s%-40s%-40s%-40s\n", args[i],
|
||||
dev_uuid_str,
|
||||
set_uuid_str,
|
||||
clus_uuid);
|
||||
}
|
||||
free(sb);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool status_all = false;
|
||||
|
||||
NihOption opts_status[] = {
|
||||
{'a', "all", N_("all"), NULL, NULL, &status_all, NULL},
|
||||
NIH_OPTION_LAST
|
||||
};
|
||||
|
||||
int cmd_status(NihCommand *command, char *const *args)
|
||||
{
|
||||
int i, dev_count = 0, seq, cache_count = 0;
|
||||
struct cache_sb *seq_sb = NULL;
|
||||
char cache_path[MAX_PATH];
|
||||
char *dev_names[MAX_DEVS];
|
||||
char *dev_uuids[MAX_DEVS];
|
||||
char intbuf[4];
|
||||
char set_uuid[40];
|
||||
|
||||
for (i = 0; args[i] != NULL; i++) {
|
||||
struct cache_sb *sb = query_dev(args[i], false, false,
|
||||
false, NULL);
|
||||
|
||||
if (!sb) {
|
||||
printf("Unable to open superblock, bad path\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!seq_sb || sb->seq > seq) {
|
||||
seq = sb->seq;
|
||||
seq_sb = sb;
|
||||
} else
|
||||
free(sb);
|
||||
}
|
||||
|
||||
if (!seq_sb) {
|
||||
printf("Unable to find a superblock\n");
|
||||
return -1;
|
||||
} else {
|
||||
uuid_unparse(seq_sb->user_uuid.b, set_uuid);
|
||||
printf("%-50s%-15s%-4s\n", "uuid", "state", "tier");
|
||||
}
|
||||
|
||||
snprintf(intbuf, 4, "%d", i);
|
||||
snprintf(cache_path, MAX_PATH, "%s/%s/%s", cset_dir, set_uuid,
|
||||
"cache0");
|
||||
|
||||
/*
|
||||
* Get a list of all the devices from sysfs first, then
|
||||
* compare it to the list we get back from the most up
|
||||
* to date superblock. If there are any devices in the superblock
|
||||
* that are not in sysfs, print out 'missing'
|
||||
*/
|
||||
while (true) {
|
||||
char buf[MAX_PATH];
|
||||
int len;
|
||||
DIR *cache_dir;
|
||||
|
||||
if(((cache_dir = opendir(cache_path)) == NULL) &&
|
||||
cache_count > MAX_DEVS)
|
||||
break;
|
||||
|
||||
if (cache_dir)
|
||||
closedir(cache_dir);
|
||||
|
||||
if((len = readlink(cache_path, buf, sizeof(buf) - 1)) != -1) {
|
||||
struct cache_sb *sb;
|
||||
char dev_uuid[40];
|
||||
char dev_path[32];
|
||||
|
||||
buf[len] = '\0';
|
||||
dev_names[dev_count] = dev_name(buf);
|
||||
snprintf(dev_path, MAX_PATH, "%s/%s", "/dev",
|
||||
dev_names[dev_count]);
|
||||
sb = query_dev(dev_path, false, false,
|
||||
true, dev_uuid);
|
||||
if (!sb) {
|
||||
printf("error reading %s\n", dev_path);
|
||||
return -1;
|
||||
} else
|
||||
free(sb);
|
||||
|
||||
dev_uuids[dev_count] = strdup(dev_uuid);
|
||||
dev_count++;
|
||||
}
|
||||
|
||||
cache_path[strlen(cache_path) - strlen(intbuf)] = 0;
|
||||
cache_count++;
|
||||
|
||||
snprintf(intbuf, 4, "%d", cache_count);
|
||||
strcat(cache_path, intbuf);
|
||||
}
|
||||
|
||||
for (i = 0; i < seq_sb->nr_in_set; i++) {
|
||||
char uuid_str[40];
|
||||
struct cache_member *m = seq_sb->members + i;
|
||||
char dev_state[32];
|
||||
int j;
|
||||
|
||||
uuid_unparse(m->uuid.b, uuid_str);
|
||||
snprintf(dev_state, MAX_PATH, "%s",
|
||||
cache_state[CACHE_STATE(m)]);
|
||||
|
||||
for (j = 0; j < dev_count; j++) {
|
||||
if (!strcmp(uuid_str, dev_uuids[j])) {
|
||||
break;
|
||||
} else if (j == dev_count - 1) {
|
||||
if (!strcmp(cache_state[CACHE_STATE(m)], "active"))
|
||||
snprintf(dev_state, MAX_PATH, "%s", "missing");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
printf("%-50s%-15s%-4llu\n", uuid_str, dev_state,
|
||||
CACHE_TIER(m));
|
||||
}
|
||||
|
||||
if (seq_sb)
|
||||
free(seq_sb);
|
||||
for (i = 0; i < dev_count; i++) {
|
||||
free(dev_names[i]);
|
||||
free(dev_uuids[i]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
13
bcacheadm-query.h
Normal file
13
bcacheadm-query.h
Normal file
@ -0,0 +1,13 @@
|
||||
#ifndef _BCACHEADM_QUERY_H
|
||||
#define _BCACHEADM_QUERY_H
|
||||
|
||||
extern NihOption opts_list[];
|
||||
int cmd_list(NihCommand *, char * const *);
|
||||
|
||||
extern NihOption opts_query[];
|
||||
int cmd_query(NihCommand *, char * const *);
|
||||
|
||||
extern NihOption opts_status[];
|
||||
int cmd_status(NihCommand *, char * const *);
|
||||
|
||||
#endif /* _BCACHEADM_QUERY_H */
|
153
bcacheadm-run.c
Normal file
153
bcacheadm-run.c
Normal file
@ -0,0 +1,153 @@
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <nih/command.h>
|
||||
#include <nih/option.h>
|
||||
|
||||
#include <linux/bcache-ioctl.h>
|
||||
|
||||
#include <uuid/uuid.h>
|
||||
|
||||
#include "bcache.h"
|
||||
#include "bcacheadm-run.h"
|
||||
|
||||
static bool force_data = false;
|
||||
static bool force_metadata = false;
|
||||
|
||||
NihOption opts_run[] = {
|
||||
NIH_OPTION_LAST
|
||||
};
|
||||
|
||||
int cmd_run(NihCommand *command, char *const *args)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
NihOption opts_stop[] = {
|
||||
NIH_OPTION_LAST
|
||||
};
|
||||
|
||||
int cmd_stop(NihCommand *command, char *const *args)
|
||||
{
|
||||
int bcachefd = open("/dev/bcache_extent0", O_RDWR);
|
||||
if (bcachefd < 0)
|
||||
die("Can't open bcache device");
|
||||
|
||||
int ret = ioctl(bcachefd, BCH_IOCTL_STOP);
|
||||
if (ret < 0)
|
||||
die("BCH_IOCTL_STOP error: %s", strerror(errno));
|
||||
|
||||
close(bcachefd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
NihOption opts_add[] = {
|
||||
NIH_OPTION_LAST
|
||||
};
|
||||
|
||||
int cmd_add(NihCommand *command, char *const *args)
|
||||
{
|
||||
if (nr_args(args) != 1)
|
||||
die("Please supply exactly one device");
|
||||
|
||||
int ret, bcachefd;
|
||||
|
||||
bcachefd = open("/dev/bcache_extent0", O_RDWR);
|
||||
if (bcachefd < 0)
|
||||
die("Can't open bcache device: %s", strerror(errno));
|
||||
|
||||
struct bch_ioctl_disk_add ia = {
|
||||
.dev = (__u64) args[0],
|
||||
};
|
||||
|
||||
ret = ioctl(bcachefd, BCH_IOCTL_DISK_ADD, &ia);
|
||||
if (ret < 0)
|
||||
die("BCH_IOCTL_DISK_ADD error: %s", strerror(ret));
|
||||
|
||||
close(bcachefd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
NihOption opts_readd[] = {
|
||||
NIH_OPTION_LAST
|
||||
};
|
||||
|
||||
int cmd_readd(NihCommand *command, char *const *args)
|
||||
{
|
||||
if (nr_args(args) != 1)
|
||||
die("Please supply exactly one device");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
NihOption opts_remove[] = {
|
||||
{
|
||||
'f', "force", N_("force if data present"),
|
||||
NULL, NULL, &force_data, NULL
|
||||
},
|
||||
{
|
||||
'\0', "force-metadata", N_("force if metadata present"),
|
||||
NULL, NULL, &force_metadata, NULL},
|
||||
NIH_OPTION_LAST
|
||||
};
|
||||
|
||||
int cmd_remove(NihCommand *command, char *const *args)
|
||||
{
|
||||
if (nr_args(args) != 1)
|
||||
die("Please supply exactly one device");
|
||||
|
||||
int bcachefd = open("/dev/bcache_extent0", O_RDWR);
|
||||
if (bcachefd < 0)
|
||||
die("Can't open bcache device");
|
||||
|
||||
struct bch_ioctl_disk_remove ir = {
|
||||
.dev = (__u64) args[0],
|
||||
};
|
||||
|
||||
if (force_data)
|
||||
ir.flags |= BCH_FORCE_IF_DATA_MISSING;
|
||||
if (force_metadata)
|
||||
ir.flags |= BCH_FORCE_IF_METADATA_MISSING;
|
||||
|
||||
int ret = ioctl(bcachefd, BCH_IOCTL_DISK_REMOVE, &ir);
|
||||
if (ret < 0)
|
||||
die("BCH_IOCTL_DISK_REMOVE error: %s\n", strerror(errno));
|
||||
|
||||
close(bcachefd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *dev_failed_uuid = NULL;
|
||||
|
||||
NihOption opts_fail[] = {
|
||||
{'d', "dev", N_("dev UUID"), NULL, "UUID", &dev_failed_uuid, NULL},
|
||||
NIH_OPTION_LAST
|
||||
};
|
||||
|
||||
int cmd_fail(NihCommand *command, char *const *args)
|
||||
{
|
||||
if (nr_args(args) != 1)
|
||||
die("Please supply exactly one device");
|
||||
|
||||
int bcachefd = open("/dev/bcache_extent0", O_RDWR);
|
||||
if (bcachefd < 0)
|
||||
die("Can't open bcache device");
|
||||
|
||||
struct bch_ioctl_disk_fail df = {
|
||||
.dev = (__u64) args[0],
|
||||
};
|
||||
|
||||
int ret = ioctl(bcachefd, BCH_IOCTL_DISK_FAIL, &df);
|
||||
if (ret < 0)
|
||||
die("BCH_IOCTL_DISK_FAIL error: %s\n", strerror(errno));
|
||||
|
||||
return 0;
|
||||
}
|
22
bcacheadm-run.h
Normal file
22
bcacheadm-run.h
Normal file
@ -0,0 +1,22 @@
|
||||
#ifndef _BCACHEADM_RUN_H
|
||||
#define _BCACHEADM_RUN_H
|
||||
|
||||
extern NihOption opts_run[];
|
||||
int cmd_run(NihCommand *, char * const *);
|
||||
|
||||
extern NihOption opts_stop[];
|
||||
int cmd_stop(NihCommand *, char * const *);
|
||||
|
||||
extern NihOption opts_add[];
|
||||
int cmd_add(NihCommand *, char * const *);
|
||||
|
||||
extern NihOption opts_readd[];
|
||||
int cmd_readd(NihCommand *, char * const *);
|
||||
|
||||
extern NihOption opts_remove[];
|
||||
int cmd_remove(NihCommand *, char * const *);
|
||||
|
||||
extern NihOption opts_fail[];
|
||||
int cmd_fail(NihCommand *, char * const *);
|
||||
|
||||
#endif /* _BCACHEADM_RUN_H */
|
635
bcacheadm.c
635
bcacheadm.c
@ -29,88 +29,20 @@
|
||||
#include <dirent.h>
|
||||
|
||||
#include "bcache.h"
|
||||
#include "bcacheadm.h"
|
||||
#include "bcacheadm-format.h"
|
||||
#include "bcacheadm-assemble.h"
|
||||
#include "bcacheadm-run.h"
|
||||
#include "bcacheadm-query.h"
|
||||
|
||||
#define PACKAGE_NAME "bcacheadm"
|
||||
#define PACKAGE_VERSION "1.0"
|
||||
#define PACKAGE_BUGREPORT "bugreport"
|
||||
#define PACKAGE_BUGREPORT "linux-bcache@vger.kernel.org"
|
||||
|
||||
/* rm-dev globals */
|
||||
bool force_remove = false;
|
||||
|
||||
/* Modify globals */
|
||||
bool modify_list_attrs = false;
|
||||
#if 0
|
||||
static bool modify_list_attrs = false;
|
||||
static const char *modify_set_uuid = NULL;
|
||||
static const char *modify_dev_uuid = NULL;
|
||||
|
||||
/* query-dev globals */
|
||||
bool force_csum = false;
|
||||
bool uuid_only = false;
|
||||
bool query_brief = false;
|
||||
|
||||
/* probe globals */
|
||||
bool udev = false;
|
||||
|
||||
/* list globals */
|
||||
char *cset_dir = "/sys/fs/bcache";
|
||||
bool list_devs = false;
|
||||
static const char *internal_uuid = NULL;
|
||||
|
||||
/* status globals */
|
||||
bool status_all = false;
|
||||
|
||||
/* capacity globals */
|
||||
static const char *capacity_uuid = NULL;
|
||||
bool capacity_devs = false;
|
||||
|
||||
/* stats globals */
|
||||
bool stats_all = false;
|
||||
bool stats_list = false;
|
||||
static const char *stats_uuid = NULL;
|
||||
static const char *stats_dev_uuid = NULL;
|
||||
static const char *stats_cache_num = NULL;
|
||||
bool stats_five_min = false;
|
||||
bool stats_hour = false;
|
||||
bool stats_day = false;
|
||||
bool stats_total = false;
|
||||
|
||||
/* set_failed globals */
|
||||
static const char *dev_failed_uuid = NULL;
|
||||
|
||||
/* probe setters */
|
||||
static int set_udev(NihOption *option, const char *arg)
|
||||
{
|
||||
if (strcmp("udev", arg)) {
|
||||
printf("Invalid output format %s\n", arg);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
udev = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* options */
|
||||
static NihOption probe_bcache_options[] = {
|
||||
{'o', "udev", N_("udev"), NULL, NULL, NULL, set_udev},
|
||||
NIH_OPTION_LAST
|
||||
};
|
||||
|
||||
static NihOption bcache_register_options[] = {
|
||||
NIH_OPTION_LAST
|
||||
};
|
||||
|
||||
static NihOption bcache_unregister_options[] = {
|
||||
NIH_OPTION_LAST
|
||||
};
|
||||
|
||||
static NihOption bcache_add_device_options[] = {
|
||||
NIH_OPTION_LAST
|
||||
};
|
||||
|
||||
static NihOption bcache_rm_device_options[] = {
|
||||
{'f', "force", N_("force cache removal"), NULL, NULL, &force_remove, NULL},
|
||||
NIH_OPTION_LAST
|
||||
};
|
||||
|
||||
static NihOption bcache_modify_options[] = {
|
||||
{'l', "list", N_("list attributes"), NULL, NULL, &modify_list_attrs, NULL},
|
||||
{'u', "set", N_("cacheset uuid"), NULL, "UUID", &modify_set_uuid, NULL},
|
||||
@ -118,127 +50,6 @@ static NihOption bcache_modify_options[] = {
|
||||
NIH_OPTION_LAST
|
||||
};
|
||||
|
||||
static NihOption query_devs_options[] = {
|
||||
{'f', "force_csum", N_("force_csum"), NULL, NULL, &force_csum, NULL},
|
||||
{'u', "uuid-only", N_("only print out the uuid for the devices, not the whole superblock"), NULL, NULL, &uuid_only, NULL},
|
||||
{'b', "brief", N_("only print out the cluster,server,and disk uuids"), NULL, NULL, &query_brief, NULL},
|
||||
NIH_OPTION_LAST
|
||||
};
|
||||
|
||||
static NihOption list_cachesets_options[] = {
|
||||
{'d', "dir", N_("directory"), NULL, NULL, &cset_dir, NULL},
|
||||
{0, "list-devs", N_("list all devices in the cache sets as well"), NULL, NULL, &list_devs, NULL},
|
||||
{0, "internal_uuid", N_("Show the internal UUID for the given cacheset UUID"), NULL, "UUID", &internal_uuid, NULL},
|
||||
NIH_OPTION_LAST
|
||||
};
|
||||
|
||||
static NihOption status_options[] = {
|
||||
{'a', "all", N_("all"), NULL, NULL, &status_all, NULL},
|
||||
NIH_OPTION_LAST
|
||||
};
|
||||
|
||||
static NihOption capacity_options[] = {
|
||||
{'u', "set", N_("cache_set UUID"), NULL, "UUID", &capacity_uuid, NULL},
|
||||
{'d', "devs", N_("Individual device capacities"), NULL, NULL, &capacity_devs, NULL},
|
||||
NIH_OPTION_LAST
|
||||
};
|
||||
|
||||
static NihOption stats_options[] = {
|
||||
{'a', "all", N_("all"), NULL, NULL, &stats_all, NULL},
|
||||
{'l', "list", N_("list"), NULL, NULL, &stats_list, NULL},
|
||||
{'u', "set", N_("cache_set UUID"), NULL, "UUID", &stats_uuid, NULL},
|
||||
{'d', "dev", N_("dev UUID"), NULL, "UUID", &stats_dev_uuid, NULL},
|
||||
{'c', "cache", N_("cache number (starts from 0)"), NULL, "CACHE#", &stats_cache_num, NULL},
|
||||
{0, "five-min-stats", N_("stats accumulated in last 5 minutes"), NULL, NULL, &stats_five_min, NULL},
|
||||
{0, "hour-stats", N_("stats accumulated in last hour"), NULL, NULL, &stats_hour, NULL},
|
||||
{0, "day-stats", N_("stats accumulated in last day"), NULL, NULL, &stats_day, NULL},
|
||||
{0, "total-stats", N_("stats accumulated in total"), NULL, NULL, &stats_total, NULL},
|
||||
NIH_OPTION_LAST
|
||||
};
|
||||
|
||||
static NihOption set_failed_options[] = {
|
||||
{'d', "dev", N_("dev UUID"), NULL, "UUID", &dev_failed_uuid, NULL},
|
||||
NIH_OPTION_LAST
|
||||
};
|
||||
|
||||
static NihOption options[] = {
|
||||
NIH_OPTION_LAST
|
||||
};
|
||||
|
||||
/* commands */
|
||||
int probe_bcache(NihCommand *command, char *const *args)
|
||||
{
|
||||
int i;
|
||||
char *err = NULL;
|
||||
|
||||
for (i = 0; args[i] != NULL; i++) {
|
||||
err = probe(args[i], udev);
|
||||
if(err) {
|
||||
printf("probe_bcache error: %s\n", err);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bcache_register(NihCommand *command, char *const *args)
|
||||
{
|
||||
char *err = NULL;
|
||||
|
||||
err = register_bcache(args);
|
||||
if (err) {
|
||||
printf("bcache_register error: %s\n", err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bcache_unregister(NihCommand *command, char *const *args)
|
||||
{
|
||||
char *err = NULL;
|
||||
|
||||
err = unregister_bcache(args);
|
||||
if (err) {
|
||||
printf("bcache_unregister error: %s\n", err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bcache_add_devices(NihCommand *command, char *const *args)
|
||||
{
|
||||
char *err;
|
||||
|
||||
err = add_devices(args);
|
||||
if (err) {
|
||||
printf("bcache_add_devices error: %s\n", err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bcache_rm_device(NihCommand *command, char *const *args)
|
||||
{
|
||||
char *err;
|
||||
|
||||
if (!args[0]) {
|
||||
printf("Must provide a device name\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
err = remove_device(args[0], force_remove);
|
||||
if (err) {
|
||||
printf("bcache_rm_devices error: %s\n", err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bcache_modify(NihCommand *command, char *const *args)
|
||||
{
|
||||
char *err;
|
||||
@ -312,386 +123,80 @@ err:
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int bcache_list_cachesets(NihCommand *command, char *const *args)
|
||||
{
|
||||
char *err = NULL;
|
||||
|
||||
if (internal_uuid) {
|
||||
char uuid_path[MAX_PATH];
|
||||
DIR *uuid_dir;
|
||||
char buf[MAX_PATH];
|
||||
|
||||
snprintf(uuid_path, MAX_PATH, "%s/%s", cset_dir, internal_uuid);
|
||||
|
||||
err = "uuid does not exist";
|
||||
if((uuid_dir = opendir(uuid_path)) == NULL)
|
||||
goto err;
|
||||
|
||||
err = read_stat_dir(uuid_dir, uuid_path, "/internal/internal_uuid", buf);
|
||||
if (err)
|
||||
goto err;
|
||||
printf("%s", buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
err = list_cachesets(cset_dir, list_devs);
|
||||
if (err)
|
||||
goto err;
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
printf("bcache_list_cachesets error :%s\n", err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int bcache_query_devs(NihCommand *command, char *const *args)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (query_brief)
|
||||
printf("%-10s%-40s%-40s%-40s\n", "dev name", "disk uuid",
|
||||
"server uuid", "cluster uuid");
|
||||
|
||||
for (i = 0; args[i] != NULL; i++) {
|
||||
char dev_uuid[40];
|
||||
struct cache_sb *sb = query_dev(args[i], force_csum,
|
||||
!query_brief, uuid_only, dev_uuid);
|
||||
|
||||
if (!sb) {
|
||||
printf("error opening the superblock for %s\n",
|
||||
args[i]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (uuid_only) {
|
||||
printf("%s\n", dev_uuid);
|
||||
} else if (query_brief) {
|
||||
char set_uuid_str[40], dev_uuid_str[40];
|
||||
char *clus_uuid = (char *)sb->label;
|
||||
|
||||
uuid_unparse(sb->user_uuid.b, set_uuid_str);
|
||||
uuid_unparse(sb->disk_uuid.b, dev_uuid_str);
|
||||
if (!strcmp(clus_uuid, ""))
|
||||
clus_uuid = "None";
|
||||
|
||||
printf("%-10s%-40s%-40s%-40s\n", args[i],
|
||||
dev_uuid_str,
|
||||
set_uuid_str,
|
||||
clus_uuid);
|
||||
}
|
||||
free(sb);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bcache_status(NihCommand *command, char *const *args)
|
||||
{
|
||||
int i, dev_count = 0, seq, cache_count = 0;
|
||||
struct cache_sb *seq_sb = NULL;
|
||||
char cache_path[MAX_PATH];
|
||||
char *dev_names[MAX_DEVS];
|
||||
char *dev_uuids[MAX_DEVS];
|
||||
char intbuf[4];
|
||||
char set_uuid[40];
|
||||
|
||||
for (i = 0; args[i] != NULL; i++) {
|
||||
struct cache_sb *sb = query_dev(args[i], false, false,
|
||||
false, NULL);
|
||||
|
||||
if (!sb) {
|
||||
printf("Unable to open superblock, bad path\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!seq_sb || sb->seq > seq) {
|
||||
seq = sb->seq;
|
||||
seq_sb = sb;
|
||||
} else
|
||||
free(sb);
|
||||
}
|
||||
|
||||
if (!seq_sb) {
|
||||
printf("Unable to find a superblock\n");
|
||||
return -1;
|
||||
} else {
|
||||
uuid_unparse(seq_sb->user_uuid.b, set_uuid);
|
||||
printf("%-50s%-15s%-4s\n", "uuid", "state", "tier");
|
||||
}
|
||||
|
||||
snprintf(intbuf, 4, "%d", i);
|
||||
snprintf(cache_path, MAX_PATH, "%s/%s/%s", cset_dir, set_uuid,
|
||||
"cache0");
|
||||
|
||||
/*
|
||||
* Get a list of all the devices from sysfs first, then
|
||||
* compare it to the list we get back from the most up
|
||||
* to date superblock. If there are any devices in the superblock
|
||||
* that are not in sysfs, print out 'missing'
|
||||
*/
|
||||
while (true) {
|
||||
char buf[MAX_PATH];
|
||||
int len;
|
||||
DIR *cache_dir;
|
||||
|
||||
if(((cache_dir = opendir(cache_path)) == NULL) &&
|
||||
cache_count > MAX_DEVS)
|
||||
break;
|
||||
|
||||
if (cache_dir)
|
||||
closedir(cache_dir);
|
||||
|
||||
if((len = readlink(cache_path, buf, sizeof(buf) - 1)) != -1) {
|
||||
struct cache_sb *sb;
|
||||
char dev_uuid[40];
|
||||
char dev_path[32];
|
||||
|
||||
buf[len] = '\0';
|
||||
dev_names[dev_count] = dev_name(buf);
|
||||
snprintf(dev_path, MAX_PATH, "%s/%s", "/dev",
|
||||
dev_names[dev_count]);
|
||||
sb = query_dev(dev_path, false, false,
|
||||
true, dev_uuid);
|
||||
if (!sb) {
|
||||
printf("error reading %s\n", dev_path);
|
||||
return -1;
|
||||
} else
|
||||
free(sb);
|
||||
|
||||
dev_uuids[dev_count] = strdup(dev_uuid);
|
||||
dev_count++;
|
||||
}
|
||||
|
||||
cache_path[strlen(cache_path) - strlen(intbuf)] = 0;
|
||||
cache_count++;
|
||||
|
||||
snprintf(intbuf, 4, "%d", cache_count);
|
||||
strcat(cache_path, intbuf);
|
||||
}
|
||||
|
||||
for (i = 0; i < seq_sb->nr_in_set; i++) {
|
||||
char uuid_str[40];
|
||||
struct cache_member *m = seq_sb->members + i;
|
||||
char dev_state[32];
|
||||
int j;
|
||||
|
||||
uuid_unparse(m->uuid.b, uuid_str);
|
||||
snprintf(dev_state, MAX_PATH, "%s",
|
||||
cache_state[CACHE_STATE(m)]);
|
||||
|
||||
for (j = 0; j < dev_count; j++) {
|
||||
if (!strcmp(uuid_str, dev_uuids[j])) {
|
||||
break;
|
||||
} else if (j == dev_count - 1) {
|
||||
if (!strcmp(cache_state[CACHE_STATE(m)], "active"))
|
||||
snprintf(dev_state, MAX_PATH, "%s", "missing");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
printf("%-50s%-15s%-4llu\n", uuid_str, dev_state,
|
||||
CACHE_TIER(m));
|
||||
}
|
||||
|
||||
if (seq_sb)
|
||||
free(seq_sb);
|
||||
for (i = 0; i < dev_count; i++) {
|
||||
free(dev_names[i]);
|
||||
free(dev_uuids[i]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bcache_capacity(NihCommand *command, char *const *args)
|
||||
{
|
||||
char *err = "Must provide a cacheset uuid";
|
||||
if(!capacity_uuid)
|
||||
goto err;
|
||||
|
||||
err = bcache_get_capacity(cset_dir, capacity_uuid, capacity_devs);
|
||||
if (err)
|
||||
goto err;
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
printf("bcache_capacity failed with error: %s\n", err);
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
static char *stats_subdir(char* stats_dir)
|
||||
{
|
||||
char tmp[50] = "/";
|
||||
char *err = NULL;
|
||||
if(stats_dev_uuid) {
|
||||
strcat(tmp, "cache");
|
||||
err = find_matching_uuid(stats_dir, tmp, stats_dev_uuid);
|
||||
if(err)
|
||||
goto err;
|
||||
} else if(stats_cache_num) {
|
||||
strcat(tmp, "cache");
|
||||
strcat(tmp, stats_cache_num);
|
||||
} else if (stats_five_min)
|
||||
strcat(tmp, "stats_five_minute");
|
||||
else if (stats_hour)
|
||||
strcat(tmp, "stats_hour");
|
||||
else if (stats_day)
|
||||
strcat(tmp, "stats_day");
|
||||
else if (stats_total)
|
||||
strcat(tmp, "stats_total");
|
||||
else
|
||||
return err;
|
||||
|
||||
strcat(stats_dir, tmp);
|
||||
|
||||
err:
|
||||
return err;
|
||||
}
|
||||
|
||||
int bcache_stats(NihCommand *command, char *const *args)
|
||||
{
|
||||
int i;
|
||||
char stats_dir[MAX_PATH];
|
||||
DIR *dir = NULL;
|
||||
struct dirent *ent = NULL;
|
||||
char *err = NULL;
|
||||
char buf[MAX_PATH];
|
||||
|
||||
if (stats_uuid) {
|
||||
snprintf(stats_dir, MAX_PATH, "%s/%s", cset_dir, stats_uuid);
|
||||
err = stats_subdir(stats_dir);
|
||||
if(err)
|
||||
goto err;
|
||||
|
||||
dir = opendir(stats_dir);
|
||||
if (!dir) {
|
||||
err = "Failed to open dir";
|
||||
goto err;
|
||||
}
|
||||
} else {
|
||||
err = "Must provide a cacheset uuid";
|
||||
goto err;
|
||||
}
|
||||
|
||||
if(stats_list || stats_all) {
|
||||
while ((ent = readdir(dir)) != NULL) {
|
||||
err = read_stat_dir(dir, stats_dir, ent->d_name, buf);
|
||||
if (err)
|
||||
goto err;
|
||||
if(stats_list)
|
||||
printf("%s\n", ent->d_name);
|
||||
if(stats_all)
|
||||
printf("\t%s\n", buf);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; args[i] != NULL; i++) {
|
||||
err = read_stat_dir(dir, stats_dir, args[i], buf);
|
||||
if (err)
|
||||
goto err;
|
||||
printf("%s\n", buf);
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
return 0;
|
||||
|
||||
err:
|
||||
closedir(dir);
|
||||
printf("bcache_stats error: %s\n", err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int bcache_set_failed(NihCommand *command, char *const *args)
|
||||
{
|
||||
char *err = NULL;
|
||||
|
||||
if (!dev_failed_uuid) {
|
||||
printf("Pass in a dev uuid\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
err = device_set_failed(dev_failed_uuid);
|
||||
if (err) {
|
||||
printf("bcache_set_failed_ioctl error: %s\n", err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
#define CMD(_command, _usage, _synopsis, _help) \
|
||||
{ \
|
||||
.command = #_command, \
|
||||
.usage = _usage, \
|
||||
.synopsis = _synopsis, \
|
||||
.help = _help, \
|
||||
.group = NULL, \
|
||||
.options = opts_##_command, \
|
||||
.action = cmd_##_command, \
|
||||
}
|
||||
|
||||
static NihCommand commands[] = {
|
||||
{"format", N_("format <list of drives>"),
|
||||
"Format one or a list of devices with bcache datastructures."
|
||||
" You need to do this before you create a volume",
|
||||
N_("format drive[s] with bcache"),
|
||||
NULL, bcacheadm_format_options, bcacheadm_format},
|
||||
{"probe", N_("probe <list of devices>"),
|
||||
"Does a blkid_probe on a device",
|
||||
N_("Does a blkid_probe on a device"),
|
||||
NULL, probe_bcache_options, probe_bcache},
|
||||
{"register", N_("register <list of devices>"),
|
||||
"Registers a list of devices",
|
||||
N_("Registers a list of devices"),
|
||||
NULL, bcache_register_options, bcache_register},
|
||||
{"unregister", N_("unregister <list of devices>"),
|
||||
"Unregisters a list of devices",
|
||||
N_("Unregisters a list of devices"),
|
||||
NULL, bcache_unregister_options, bcache_unregister},
|
||||
{"add-devs", N_("add-devs --tier=# <list of devices>"),
|
||||
"Adds a list of devices to a cacheset",
|
||||
N_("Adds a list of devices to a cacheset"),
|
||||
NULL, bcache_add_device_options, bcache_add_devices},
|
||||
{"rm-dev", N_("rm-dev <dev>"),
|
||||
"Removes a device from its cacheset",
|
||||
N_("Removes a device from its cacheset"),
|
||||
NULL, bcache_rm_device_options, bcache_rm_device},
|
||||
{"modify", N_("modify --set=UUID (dev=UUID) name value"),
|
||||
"Modifies attributes related to the cacheset",
|
||||
N_("Modifies attributes related to the cacheset"),
|
||||
NULL, bcache_modify_options, bcache_modify},
|
||||
{"list-cachesets", N_("list-cachesets"),
|
||||
"Lists cachesets in /sys/fs/bcache",
|
||||
N_("Lists cachesets in /sys/fs/bcache"),
|
||||
NULL, list_cachesets_options, bcache_list_cachesets},
|
||||
{"query-devs", N_("query <list of devices>"),
|
||||
"Gives info about the superblock of a list of devices",
|
||||
N_("show superblock on each of the listed drive"),
|
||||
NULL, query_devs_options, bcache_query_devs},
|
||||
{"status", N_("status <list of devices>"),
|
||||
"Finds the status of the most up to date superblock",
|
||||
N_("Finds the status of the most up to date superblock"),
|
||||
NULL, status_options, bcache_status},
|
||||
{"capacity", N_("capacity --set=UUID"),
|
||||
"Shows the capacity of the cacheset",
|
||||
N_("Shows the capacity of the cacheset"),
|
||||
NULL, capacity_options, bcache_capacity},
|
||||
{"stats", N_("stats <list of devices>"),
|
||||
"List various bcache statistics",
|
||||
N_("List various bcache statistics"),
|
||||
NULL, stats_options, bcache_stats},
|
||||
{"set-failed", N_("set-failed --dev=UUID"),
|
||||
"Sets a device to the FAILED state",
|
||||
N_("Sets a device to the FAILED state"),
|
||||
NULL, set_failed_options, bcache_set_failed},
|
||||
CMD(format, N_("<list of devices>"),
|
||||
"Create a new bcache volume from one or more devices",
|
||||
N_("format drive[s] for bcache")),
|
||||
|
||||
CMD(assemble, N_("<devices>"),
|
||||
"Assembles one or more devices into a bcache volume",
|
||||
N_("Registers a list of devices")),
|
||||
CMD(incremental, N_("<device"),
|
||||
"Incremental assemble bcache volumes",
|
||||
N_("Incrementally registers a single device")),
|
||||
|
||||
CMD(run, N_("<volume>"),
|
||||
"Start a partially assembled volume",
|
||||
N_("Registers a list of devices")),
|
||||
CMD(stop, N_("<volume>"),
|
||||
"Stops a running bcache volume",
|
||||
N_("Unregisters a list of devices")),
|
||||
CMD(add, N_("<volume> <devices>"),
|
||||
"Adds a list of devices to a volume",
|
||||
N_("Adds a list of devices to a volume")),
|
||||
CMD(readd, N_("<volume> <devices>"),
|
||||
"Adds previously used members of a volume",
|
||||
N_("Adds a list of devices to a volume")),
|
||||
CMD(remove, N_("<volume> <devices>"),
|
||||
"Removes a device from its volume",
|
||||
N_("Removes a device from its volume")),
|
||||
CMD(fail, N_("<volume> <devices>"),
|
||||
"Sets a device to the FAILED state",
|
||||
N_("Sets a device to the FAILED state")),
|
||||
|
||||
#if 0
|
||||
CMD(modify, N_("<options>"),
|
||||
"Modifies attributes related to the volume",
|
||||
N_("Modifies attributes related to the volume")),
|
||||
#endif
|
||||
CMD(list, N_("list-cachesets"),
|
||||
"Lists cachesets in /sys/fs/bcache",
|
||||
N_("Lists cachesets in /sys/fs/bcache")),
|
||||
CMD(query, N_("query <list of devices>"),
|
||||
"Gives info about the superblock of a list of devices",
|
||||
N_("show superblock on each of the listed drive")),
|
||||
CMD(status, N_("status <list of devices>"),
|
||||
"Finds the status of the most up to date superblock",
|
||||
N_("Finds the status of the most up to date superblock")),
|
||||
NIH_COMMAND_LAST
|
||||
};
|
||||
|
||||
static NihOption options[] = {
|
||||
NIH_OPTION_LAST
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int ret = 0;
|
||||
nih_main_init (argv[0]);
|
||||
nih_main_init(argv[0]);
|
||||
nih_option_set_synopsis(_("Manage bcache devices"));
|
||||
nih_option_set_help( _("Helps you manage bcache devices"));
|
||||
|
||||
nih_option_set_synopsis (_("Manage bcache devices"));
|
||||
nih_option_set_help (
|
||||
_("Helps you manage bcache devices"));
|
||||
|
||||
ret = nih_command_parser (NULL, argc, argv, options, commands);
|
||||
int ret = nih_command_parser(NULL, argc, argv, options, commands);
|
||||
if (ret < 0)
|
||||
exit (1);
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
nih_signal_reset();
|
||||
|
||||
|
@ -1,7 +0,0 @@
|
||||
#ifndef _BCACHEADM_H
|
||||
#define _BCACHEADM_H
|
||||
|
||||
extern NihOption bcacheadm_format_options[];
|
||||
int bcacheadm_format(NihCommand *, char * const *);
|
||||
|
||||
#endif /* _BCACHEADM_H */
|
Loading…
Reference in New Issue
Block a user