11 #include <sys/ioctl.h>
13 #include <sys/types.h>
16 #include <nih/command.h>
17 #include <nih/option.h>
20 #include "bcache-device.h"
26 unsigned has_metadata;
35 /* XXX: dirty != used, it doesn't count metadata */
39 static struct bcache_dev fill_dev(const char *dev_name, unsigned nr, int dir)
41 return (struct bcache_dev) {
45 .has_metadata = read_file_u64(dir, "has_metadata"),
46 .has_data = read_file_u64(dir, "has_data"),
47 .state = read_file_str(dir, "state"),
48 .tier = read_file_u64(dir, "tier"),
50 .bucket_size = read_file_u64(dir, "bucket_size_bytes"),
51 .first_bucket = read_file_u64(dir, "first_bucket"),
52 .nbuckets = read_file_u64(dir, "nbuckets"),
53 .bytes_dirty = read_file_u64(dir, "dirty_bytes"),
57 static void show_dev(struct bcache_dev *dev)
59 u64 capacity = (dev->nbuckets - dev->first_bucket) *
62 * XXX: show fragmentation information, cached/dirty information
65 printf("Device %u (/dev/%s):\n"
66 " Has metadata:\t%u\n"
67 " Has dirty data:\t%u\n"
81 capacity - dev->bytes_dirty,
82 (dev->bytes_dirty * 100) / capacity);
85 static int human_readable;
87 NihOption opts_device_show[] = {
88 // { int shortoption, char *longoption, char *help, NihOptionGroup, char *argname, void *value, NihOptionSetter}
90 { 'h', "human-readable", N_("print sizes in powers of 1024 (e.g., 1023M)"),
91 NULL, NULL, &human_readable, NULL},
95 int cmd_device_show(NihCommand *command, char * const *args)
98 die("Please supply a filesystem");
101 die("Please supply a single filesystem");
103 struct bcache_handle fs = bcache_fs_open(args[0]);
104 struct dirent *entry;
106 struct bcache_dev devices[256];
107 unsigned i, j, nr_devices = 0, nr_active_tiers = 0;
109 unsigned tiers[CACHE_TIERS]; /* number of devices in each tier */
110 memset(tiers, 0, sizeof(tiers));
112 while ((entry = readdir(fs.sysfs))) {
116 sscanf(entry->d_name, "cache%u%n", &nr, &pos);
117 if (pos != strlen(entry->d_name))
121 if (readlinkat(dirfd(fs.sysfs), entry->d_name,
122 link, sizeof(link)) < 0)
123 die("readlink error: %s\n", strerror(errno));
125 char *dev_name = basename(dirname(link));
127 int fd = openat(dirfd(fs.sysfs), entry->d_name, O_RDONLY);
129 die("couldn't open device %s: %s\n",
130 entry->d_name, strerror(errno));
132 devices[nr_devices] = fill_dev(strdup(dev_name), nr, fd);
133 tiers[devices[nr_devices].tier]++;
139 for (i = 0; i < CACHE_TIERS; i++)
143 /* Print out devices sorted by tier: */
146 for (i = 0; i < CACHE_TIERS; i++) {
150 if (nr_active_tiers > 1) {
154 printf("Tier %u:\n\n", i);
157 for (j = 0; j < nr_devices; j++) {
158 if (devices[j].tier != i)
164 show_dev(&devices[j]);
171 NihOption opts_device_add[] = {
172 // { int shortoption, char *longoption, char *help, NihOptionGroup, char *argname, void *value, NihOptionSetter}
176 int cmd_device_add(NihCommand *command, char * const *args)
178 if (nr_args(args) < 2)
179 die("Please supply a filesystem and at least one device to add");
181 struct bcache_handle fs = bcache_fs_open(args[0]);
183 for (unsigned i = 1; args[i]; i++) {
184 struct bch_ioctl_disk_add ia = {
185 .dev = (__u64) args[i],
188 if (ioctl(fs.fd, BCH_IOCTL_DISK_ADD, &ia))
189 die("BCH_IOCTL_DISK_ADD error: %s", strerror(errno));
195 static int force_data, force_metadata;
197 NihOption opts_device_remove[] = {
198 // { int shortoption, char *longoption, char *help, NihOptionGroup, char *argname, void *value, NihOptionSetter}
200 { 'f', "force", N_("force if data present"),
201 NULL, NULL, &force_data, NULL },
202 { '\0', "force-metadata", N_("force if metadata present"),
203 NULL, NULL, &force_metadata, NULL},
207 int cmd_device_remove(NihCommand *command, char *const *args)
209 if (nr_args(args) < 2)
210 die("Please supply a filesystem and at least one device to add");
212 struct bcache_handle fs = bcache_fs_open(args[0]);
214 for (unsigned i = 1; args[i]; i++) {
215 struct bch_ioctl_disk_remove ir = {
216 .dev = (__u64) args[0],
220 ir.flags |= BCH_FORCE_IF_DATA_MISSING;
222 ir.flags |= BCH_FORCE_IF_METADATA_MISSING;
224 if (ioctl(fs.fd, BCH_IOCTL_DISK_REMOVE, &ir))
225 die("BCH_IOCTL_DISK_REMOVE error: %s\n", strerror(errno));