10 #include <sys/ioctl.h>
12 #include <sys/types.h>
16 #include "libbcache.h"
17 #include "linux/bcache-ioctl.h"
18 #include "tools-util.h"
20 /* This code belongs under show_fs */
27 unsigned has_metadata;
36 /* XXX: dirty != used, it doesn't count metadata */
40 static struct bcache_dev fill_dev(const char *dev_name, unsigned nr, int dir)
42 return (struct bcache_dev) {
46 .has_metadata = read_file_u64(dir, "has_metadata"),
47 .has_data = read_file_u64(dir, "has_data"),
48 .state = read_file_str(dir, "state"),
49 .tier = read_file_u64(dir, "tier"),
51 .bucket_size = read_file_u64(dir, "bucket_size_bytes"),
52 .first_bucket = read_file_u64(dir, "first_bucket"),
53 .nbuckets = read_file_u64(dir, "nbuckets"),
54 .bytes_dirty = read_file_u64(dir, "dirty_bytes"),
58 static void show_dev(struct bcache_dev *dev)
60 u64 capacity = (dev->nbuckets - dev->first_bucket) *
63 * XXX: show fragmentation information, cached/dirty information
66 printf("Device %u (/dev/%s):\n"
67 " Has metadata:\t%u\n"
68 " Has dirty data:\t%u\n"
82 capacity - dev->bytes_dirty,
83 (dev->bytes_dirty * 100) / capacity);
86 int cmd_device_show(int argc, char *argv[])
88 int human_readable = 0;
90 // { int shortoption, char *longoption, char *help, NihOptionGroup, char *argname, void *value, NihOptionSetter}
92 { 'h', "human-readable", N_("print sizes in powers of 1024 (e.g., 1023M)"),
93 NULL, NULL, &human_readable, NULL},
96 char **args = bch_nih_init(argc, argv, opts);
99 die("Please supply a single device");
101 struct bcache_handle fs = bcache_fs_open(argv[1]);
102 struct dirent *entry;
104 struct bcache_dev devices[256];
105 unsigned i, j, nr_devices = 0, nr_active_tiers = 0;
107 unsigned tiers[BCH_TIER_MAX]; /* number of devices in each tier */
108 memset(tiers, 0, sizeof(tiers));
110 while ((entry = readdir(fs.sysfs))) {
114 sscanf(entry->d_name, "cache%u%n", &nr, &pos);
115 if (pos != strlen(entry->d_name))
119 if (readlinkat(dirfd(fs.sysfs), entry->d_name,
120 link, sizeof(link)) < 0)
121 die("readlink error: %s\n", strerror(errno));
123 char *dev_name = basename(dirname(link));
125 int fd = xopenat(dirfd(fs.sysfs), entry->d_name, O_RDONLY);
127 devices[nr_devices] = fill_dev(strdup(dev_name), nr, fd);
128 tiers[devices[nr_devices].tier]++;
134 for (i = 0; i < BCH_TIER_MAX; i++)
138 /* Print out devices sorted by tier: */
141 for (i = 0; i < BCH_TIER_MAX; i++) {
145 if (nr_active_tiers > 1) {
149 printf("Tier %u:\n\n", i);
152 for (j = 0; j < nr_devices; j++) {
153 if (devices[j].tier != i)
159 show_dev(&devices[j]);
167 int cmd_device_show(int argc, char *argv[])
172 die("please supply a single device");
174 sb = bcache_super_read(argv[1]);
175 bcache_super_print(sb, HUMAN_READABLE);
180 static void device_add_usage(void)
182 puts("bcache device_add - add a device to an existing filesystem\n"
183 "Usage: bcache device_add [OPTION]... filesystem device\n"
186 " --fs_size=size Size of filesystem on device\n"
187 " --bucket=size Bucket size\n"
188 " --discard Enable discards\n"
189 " -t, --tier=# Higher tier (e.g. 1) indicates slower devices\n"
190 " -f, --force Use device even if it appears to already be formatted\n"
191 " -h, --help Display this help and exit\n"
193 "Report bugs to <linux-bcache@vger.kernel.org>");
196 static const struct option device_add_opts[] = {
197 { "fs_size", required_argument, NULL, 'S' },
198 { "bucket", required_argument, NULL, 'B' },
199 { "discard", no_argument, NULL, 'D' },
200 { "tier", required_argument, NULL, 't' },
201 { "force", no_argument, NULL, 'f' },
205 int cmd_device_add(int argc, char *argv[])
207 struct format_opts format_opts = format_opts_default();
208 struct dev_opts dev_opts = { 0 };
212 while ((opt = getopt_long(argc, argv, "t:fh",
213 device_add_opts, NULL)) != -1)
216 if (bch_strtoull_h(optarg, &dev_opts.size))
217 die("invalid filesystem size");
222 dev_opts.bucket_size =
223 hatoi_validate(optarg, "bucket size");
226 dev_opts.discard = true;
229 if (kstrtouint(optarg, 10, &dev_opts.tier) ||
230 dev_opts.tier >= BCH_TIER_MAX)
241 if (argc - optind != 2)
242 die("Please supply a filesystem and a device to add");
244 struct bcache_handle fs = bcache_fs_open(argv[optind]);
246 dev_opts.path = argv[optind + 1];
247 dev_opts.fd = open_for_format(dev_opts.path, force);
249 format_opts.block_size =
250 read_file_u64(fs.sysfs_fd, "block_size_bytes") >> 9;
251 format_opts.btree_node_size =
252 read_file_u64(fs.sysfs_fd, "btree_node_size_bytes") >> 9;
254 struct bch_sb *sb = bcache_format(format_opts, &dev_opts, 1);
259 struct bch_ioctl_disk_add ia = {
260 .dev = (__u64) dev_opts.path,
263 xioctl(fs.ioctl_fd, BCH_IOCTL_DISK_ADD, &ia);
268 static void device_fail_usage(void)
270 puts("bcache device_fail - mark a device as failed\n"
271 "Usage: bcache device_fail filesystem [devices]\n"
274 " -f, --force Force removal, even if some data\n"
275 " couldn't be migrated\n"
276 " --force-metadata Force removal, even if some metadata\n"
277 " couldn't be migrated\n"
278 " -h, --help display this help and exit\n"
279 "Report bugs to <linux-bcache@vger.kernel.org>");
283 int cmd_device_fail(int argc, char *argv[])
285 static const struct option longopts[] = {
286 { "force-degraded", 0, NULL, 'f' },
287 //{ "force-data-lost", 0, NULL, 'F' },
288 //{ "force-metadata-lost", 0, NULL, 'F' },
289 { "help", 0, NULL, 'h' },
292 int opt, force_degraded = 0, force_data = 0, force_metadata = 0;
294 while ((opt = getopt_long(argc, argv, "fh", longopts, NULL)) != -1)
303 if (argc - optind < 2)
304 die("Please supply a filesystem and at least one device to fail");
306 struct bcache_handle fs = bcache_fs_open(argv[optind]);
308 for (unsigned i = optind + 1; i < argc; i++) {
309 struct bch_ioctl_disk_set_state ir = {
310 .dev = (__u64) argv[i],
311 .new_state = BCH_MEMBER_STATE_FAILED,
315 ir.flags |= BCH_FORCE_IF_DEGRADED;
317 ir.flags |= BCH_FORCE_IF_DATA_LOST;
319 ir.flags |= BCH_FORCE_IF_METADATA_LOST;
321 xioctl(fs.ioctl_fd, BCH_IOCTL_DISK_SET_STATE, &ir);
327 static void device_remove_usage(void)
329 puts("bcache device_remove - remove one or more devices from a filesystem\n"
330 "Usage: bcache device_remove filesystem [devices]\n"
333 " -f, --force Force removal, even if some data\n"
334 " couldn't be migrated\n"
335 " --force-metadata Force removal, even if some metadata\n"
336 " couldn't be migrated\n"
337 " -h, --help display this help and exit\n"
338 "Report bugs to <linux-bcache@vger.kernel.org>");
342 int cmd_device_remove(int argc, char *argv[])
344 static const struct option longopts[] = {
345 { "force", 0, NULL, 'f' },
346 { "force-metadata", 0, NULL, 'F' },
347 { "help", 0, NULL, 'h' },
350 int opt, force_data = 0, force_metadata = 0;
352 while ((opt = getopt_long(argc, argv, "fh", longopts, NULL)) != -1)
361 device_remove_usage();
364 if (argc - optind < 2)
365 die("Please supply a filesystem and at least one device to remove");
367 struct bcache_handle fs = bcache_fs_open(argv[optind]);
369 for (unsigned i = optind + 1; i < argc; i++) {
370 struct bch_ioctl_disk_remove ir = {
371 .dev = (__u64) argv[i],
375 ir.flags |= BCH_FORCE_IF_DATA_LOST;
377 ir.flags |= BCH_FORCE_IF_METADATA_LOST;
379 xioctl(fs.ioctl_fd, BCH_IOCTL_DISK_REMOVE, &ir);