]> git.sesse.net Git - bcachefs-tools-debian/blob - cmd_device.c
update bcache code, fsck improvements
[bcachefs-tools-debian] / cmd_device.c
1 #include <errno.h>
2 #include <fcntl.h>
3 #include <getopt.h>
4 #include <libgen.h>
5 #include <stdbool.h>
6 #include <stdint.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <sys/ioctl.h>
11 #include <sys/stat.h>
12 #include <sys/types.h>
13 #include <unistd.h>
14
15 #include "cmds.h"
16 #include "libbcache.h"
17 #include "linux/bcache-ioctl.h"
18
19 /* This code belongs under show_fs */
20 #if 0
21
22 struct bcache_dev {
23         unsigned        nr;
24         const char      *name;
25
26         unsigned        has_metadata;
27         unsigned        has_data;
28         const char      *state;
29         unsigned        tier;
30
31         u64             bucket_size;
32         u64             first_bucket;
33         u64             nbuckets;
34
35         /* XXX: dirty != used, it doesn't count metadata */
36         u64             bytes_dirty;
37 };
38
39 static struct bcache_dev fill_dev(const char *dev_name, unsigned nr, int dir)
40 {
41         return (struct bcache_dev) {
42                 .nr             = nr,
43                 .name           = dev_name,
44
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"),
49
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"),
54         };
55 }
56
57 static void show_dev(struct bcache_dev *dev)
58 {
59         u64 capacity = (dev->nbuckets - dev->first_bucket) *
60                 dev->bucket_size;
61         /*
62          * XXX: show fragmentation information, cached/dirty information
63          */
64
65         printf("Device %u (/dev/%s):\n"
66                "    Has metadata:\t%u\n"
67                "    Has dirty data:\t%u\n"
68                "    State:\t\t%s\n"
69                "    Tier:\t\t%u\n"
70                "    Size:\t\t%llu\n"
71                "    Used:\t\t%llu\n"
72                "    Free:\t\t%llu\n"
73                "    Use%%:\t\t%llu\n",
74                dev->nr, dev->name,
75                dev->has_metadata,
76                dev->has_data,
77                dev->state,
78                dev->tier,
79                capacity,
80                dev->bytes_dirty,
81                capacity - dev->bytes_dirty,
82                (dev->bytes_dirty * 100) / capacity);
83 }
84
85 int cmd_device_show(int argc, char *argv[])
86 {
87         int human_readable = 0;
88         NihOption opts[] = {
89         //      { int shortoption, char *longoption, char *help, NihOptionGroup, char *argname, void *value, NihOptionSetter}
90
91                 { 'h',  "human-readable",               N_("print sizes in powers of 1024 (e.g., 1023M)"),
92                         NULL, NULL,     &human_readable,        NULL},
93                 NIH_OPTION_LAST
94         };
95         char **args = bch_nih_init(argc, argv, opts);
96
97         if (argc != 2)
98                 die("Please supply a single device");
99
100         struct bcache_handle fs = bcache_fs_open(argv[1]);
101         struct dirent *entry;
102
103         struct bcache_dev devices[256];
104         unsigned i, j, nr_devices = 0, nr_active_tiers = 0;
105
106         unsigned tiers[CACHE_TIERS]; /* number of devices in each tier */
107         memset(tiers, 0, sizeof(tiers));
108
109         while ((entry = readdir(fs.sysfs))) {
110                 unsigned nr;
111                 int pos = 0;
112
113                 sscanf(entry->d_name, "cache%u%n", &nr, &pos);
114                 if (pos != strlen(entry->d_name))
115                         continue;
116
117                 char link[PATH_MAX];
118                 if (readlinkat(dirfd(fs.sysfs), entry->d_name,
119                                link, sizeof(link)) < 0)
120                         die("readlink error: %s\n", strerror(errno));
121
122                 char *dev_name = basename(dirname(link));
123
124                 int fd = openat(dirfd(fs.sysfs), entry->d_name, O_RDONLY);
125                 if (fd < 0)
126                         die("couldn't open device %s: %s\n",
127                             entry->d_name, strerror(errno));
128
129                 devices[nr_devices] = fill_dev(strdup(dev_name), nr, fd);
130                 tiers[devices[nr_devices].tier]++;
131                 nr_devices++;
132
133                 close(fd);
134         }
135
136         for (i = 0; i < CACHE_TIERS; i++)
137                 if (tiers[i])
138                         nr_active_tiers++;
139
140         /* Print out devices sorted by tier: */
141         bool first = true;
142
143         for (i = 0; i < CACHE_TIERS; i++) {
144                 if (!tiers[i])
145                         continue;
146
147                 if (nr_active_tiers > 1) {
148                         if (!first)
149                                 printf("\n");
150                         first = false;
151                         printf("Tier %u:\n\n", i);
152                 }
153
154                 for (j = 0; j < nr_devices; j++) {
155                         if (devices[j].tier != i)
156                                 continue;
157
158                         if (!first)
159                                 printf("\n");
160                         first = false;
161                         show_dev(&devices[j]);
162                 }
163         }
164
165         return 0;
166 }
167 #endif
168
169 int cmd_device_show(int argc, char *argv[])
170 {
171         struct cache_sb *sb;
172
173         if (argc != 2)
174                 die("please supply a single device");
175
176         sb = bcache_super_read(argv[1]);
177         bcache_super_print(sb, HUMAN_READABLE);
178
179         return 0;
180 }
181
182 int cmd_device_add(int argc, char *argv[])
183 {
184         if (argc < 3)
185                 die("Please supply a filesystem and at least one device to add");
186
187         struct bcache_handle fs = bcache_fs_open(argv[1]);
188
189         for (unsigned i = 2; i < argc; i++) {
190                 struct bch_ioctl_disk_add ia = {
191                         .dev = (__u64) argv[i],
192                 };
193
194                 if (ioctl(fs.ioctl_fd, BCH_IOCTL_DISK_ADD, &ia))
195                         die("BCH_IOCTL_DISK_ADD error: %s", strerror(errno));
196         }
197
198         return 0;
199 }
200
201 static void usage(void)
202 {
203         puts("bcache device_remove - remove one or more devices from a filesystem\n"
204              "Usage: bcache device_remove filesystem [devices]\n"
205              "\n"
206              "Options:\n"
207              "  -f, --force                 Force removal, even if some data\n"
208              "                              couldn't be migrated\n"
209              "      --force-metadata        Force removal, even if some metadata\n"
210              "                              couldn't be migrated\n"
211              "  -h, --help                  display this help and exit\n"
212              "Report bugs to <linux-bcache@vger.kernel.org>");
213         exit(EXIT_SUCCESS);
214 }
215
216 int cmd_device_remove(int argc, char *argv[])
217 {
218         static const struct option longopts[] = {
219                 { "force",              0, NULL, 'f' },
220                 { "force-metadata",     0, NULL, 'F' },
221                 { "help",               0, NULL, 'h' },
222                 { NULL }
223         };
224         int opt, force_data = 0, force_metadata = 0;
225
226         while ((opt = getopt_long(argc, argv, "fh", longopts, NULL)) != -1)
227                 switch (opt) {
228                 case 'f':
229                         force_data = 1;
230                         break;
231                 case 'F':
232                         force_metadata = 1;
233                         break;
234                 case 'h':
235                         usage();
236                 }
237
238         if (argc < 3)
239                 die("Please supply a filesystem and at least one device to add");
240
241         struct bcache_handle fs = bcache_fs_open(argv[1]);
242
243         for (unsigned i = 2; i < argc; i++) {
244                 struct bch_ioctl_disk_remove ir = {
245                         .dev = (__u64) argv[i],
246                 };
247
248                 if (force_data)
249                         ir.flags |= BCH_FORCE_IF_DATA_MISSING;
250                 if (force_metadata)
251                         ir.flags |= BCH_FORCE_IF_METADATA_MISSING;
252
253                 if (ioctl(fs.ioctl_fd, BCH_IOCTL_DISK_REMOVE, &ir))
254                         die("BCH_IOCTL_DISK_REMOVE error: %s\n", strerror(errno));
255         }
256
257         return 0;
258 }