]> git.sesse.net Git - bcachefs-tools-debian/blob - bcache-device.c
Redo lots of stuff
[bcachefs-tools-debian] / bcache-device.c
1
2 #include <dirent.h>
3 #include <errno.h>
4 #include <fcntl.h>
5 #include <libgen.h>
6 #include <stdbool.h>
7 #include <stdint.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <sys/ioctl.h>
12 #include <sys/stat.h>
13 #include <sys/types.h>
14 #include <unistd.h>
15
16 #include <nih/command.h>
17 #include <nih/option.h>
18
19 #include "bcache.h"
20 #include "bcache-device.h"
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 static int human_readable;
86
87 NihOption opts_device_show[] = {
88 //      { int shortoption, char *longoption, char *help, NihOptionGroup, char *argname, void *value, NihOptionSetter}
89
90         { 'h',  "human-readable",               N_("print sizes in powers of 1024 (e.g., 1023M)"),
91                 NULL, NULL,     &human_readable,        NULL},
92         NIH_OPTION_LAST
93 };
94
95 int cmd_device_show(NihCommand *command, char * const *args)
96 {
97         if (!args[0])
98                 die("Please supply a filesystem");
99
100         if (args[1])
101                 die("Please supply a single filesystem");
102
103         struct bcache_handle fs = bcache_fs_open(args[0]);
104         struct dirent *entry;
105
106         struct bcache_dev devices[256];
107         unsigned i, j, nr_devices = 0, nr_active_tiers = 0;
108
109         unsigned tiers[CACHE_TIERS]; /* number of devices in each tier */
110         memset(tiers, 0, sizeof(tiers));
111
112         while ((entry = readdir(fs.sysfs))) {
113                 unsigned nr;
114                 int pos = 0;
115
116                 sscanf(entry->d_name, "cache%u%n", &nr, &pos);
117                 if (pos != strlen(entry->d_name))
118                         continue;
119
120                 char link[PATH_MAX];
121                 if (readlinkat(dirfd(fs.sysfs), entry->d_name,
122                                link, sizeof(link)) < 0)
123                         die("readlink error: %s\n", strerror(errno));
124
125                 char *dev_name = basename(dirname(link));
126
127                 int fd = openat(dirfd(fs.sysfs), entry->d_name, O_RDONLY);
128                 if (fd < 0)
129                         die("couldn't open device %s: %s\n",
130                             entry->d_name, strerror(errno));
131
132                 devices[nr_devices] = fill_dev(strdup(dev_name), nr, fd);
133                 tiers[devices[nr_devices].tier]++;
134                 nr_devices++;
135
136                 close(fd);
137         }
138
139         for (i = 0; i < CACHE_TIERS; i++)
140                 if (tiers[i])
141                         nr_active_tiers++;
142
143         /* Print out devices sorted by tier: */
144         bool first = true;
145
146         for (i = 0; i < CACHE_TIERS; i++) {
147                 if (!tiers[i])
148                         continue;
149
150                 if (nr_active_tiers > 1) {
151                         if (!first)
152                                 printf("\n");
153                         first = false;
154                         printf("Tier %u:\n\n", i);
155                 }
156
157                 for (j = 0; j < nr_devices; j++) {
158                         if (devices[j].tier != i)
159                                 continue;
160
161                         if (!first)
162                                 printf("\n");
163                         first = false;
164                         show_dev(&devices[j]);
165                 }
166         }
167
168         return 0;
169 }
170
171 NihOption opts_device_add[] = {
172 //      { int shortoption, char *longoption, char *help, NihOptionGroup, char *argname, void *value, NihOptionSetter}
173         NIH_OPTION_LAST
174 };
175
176 int cmd_device_add(NihCommand *command, char * const *args)
177 {
178         if (nr_args(args) < 2)
179                 die("Please supply a filesystem and at least one device to add");
180
181         struct bcache_handle fs = bcache_fs_open(args[0]);
182
183         for (unsigned i = 1; args[i]; i++) {
184                 struct bch_ioctl_disk_add ia = {
185                         .dev = (__u64) args[i],
186                 };
187
188                 if (ioctl(fs.fd, BCH_IOCTL_DISK_ADD, &ia))
189                         die("BCH_IOCTL_DISK_ADD error: %s", strerror(errno));
190         }
191
192         return 0;
193 }
194
195 static int force_data, force_metadata;
196
197 NihOption opts_device_remove[] = {
198 //      { int shortoption, char *longoption, char *help, NihOptionGroup, char *argname, void *value, NihOptionSetter}
199
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},
204         NIH_OPTION_LAST
205 };
206
207 int cmd_device_remove(NihCommand *command, char *const *args)
208 {
209         if (nr_args(args) < 2)
210                 die("Please supply a filesystem and at least one device to add");
211
212         struct bcache_handle fs = bcache_fs_open(args[0]);
213
214         for (unsigned i = 1; args[i]; i++) {
215                 struct bch_ioctl_disk_remove ir = {
216                         .dev = (__u64) args[0],
217                 };
218
219                 if (force_data)
220                         ir.flags |= BCH_FORCE_IF_DATA_MISSING;
221                 if (force_metadata)
222                         ir.flags |= BCH_FORCE_IF_METADATA_MISSING;
223
224                 if (ioctl(fs.fd, BCH_IOCTL_DISK_REMOVE, &ir))
225                         die("BCH_IOCTL_DISK_REMOVE error: %s\n", strerror(errno));
226         }
227
228         return 0;
229 }