]> git.sesse.net Git - bcachefs-tools-debian/blob - cmd_debug.c
Delete more unused shim code, update bcache code
[bcachefs-tools-debian] / cmd_debug.c
1 #include <fcntl.h>
2 #include <string.h>
3 #include <sys/stat.h>
4 #include <sys/types.h>
5
6 #include "cmds.h"
7 #include "libbcache.h"
8 #include "qcow2.h"
9 #include "tools-util.h"
10
11 #include "bcache.h"
12 #include "alloc.h"
13 #include "btree_cache.h"
14 #include "btree_iter.h"
15 #include "buckets.h"
16 #include "journal.h"
17 #include "super.h"
18
19 static void dump_usage(void)
20 {
21         puts("bcache dump - dump filesystem metadata\n"
22              "Usage: bcache dump [OPTION]... <devices>\n"
23              "\n"
24              "Options:\n"
25              "  -o output     Output qcow2 image(s)\n"
26              "  -h            Display this help and exit\n"
27              "Report bugs to <linux-bcache@vger.kernel.org>");
28 }
29
30 static void dump_one_device(struct cache_set *c, struct cache *ca, int fd)
31 {
32         struct bch_sb *sb = ca->disk_sb.sb;
33         sparse_data data;
34         unsigned i;
35
36         darray_init(data);
37
38         /* Superblock: */
39         data_add(&data, BCH_SB_LAYOUT_SECTOR << 9,
40                  sizeof(struct bch_sb_layout));
41
42         for (i = 0; i < sb->layout.nr_superblocks; i++)
43                 data_add(&data,
44                          le64_to_cpu(sb->layout.sb_offset[i]) << 9,
45                          vstruct_bytes(sb));
46
47         /* Journal: */
48         for (i = 0; i < ca->journal.nr; i++)
49                 if (ca->journal.bucket_seq[i] >= c->journal.last_seq_ondisk) {
50                         u64 bucket = ca->journal.buckets[i];
51
52                         data_add(&data,
53                                  bucket_bytes(ca) * bucket,
54                                  bucket_bytes(ca));
55                 }
56
57         /* Prios/gens: */
58         for (i = 0; i < prio_buckets(ca); i++)
59                 data_add(&data,
60                          bucket_bytes(ca) * ca->prio_last_buckets[i],
61                          bucket_bytes(ca));
62
63         /* Btree: */
64         for (i = 0; i < BTREE_ID_NR; i++) {
65                 const struct bch_extent_ptr *ptr;
66                 struct btree_iter iter;
67                 struct btree *b;
68
69                 for_each_btree_node(&iter, c, i, POS_MIN, 0, b) {
70                         struct bkey_s_c_extent e = bkey_i_to_s_c_extent(&b->key);
71
72                         extent_for_each_ptr(e, ptr)
73                                 if (ptr->dev == ca->dev_idx)
74                                         data_add(&data,
75                                                  ptr->offset << 9,
76                                                  b->written << 9);
77                 }
78                 bch_btree_iter_unlock(&iter);
79         }
80
81         qcow2_write_image(ca->disk_sb.bdev->bd_fd, fd, &data,
82                           max_t(unsigned, btree_bytes(c) / 8, block_bytes(c)));
83 }
84
85 int cmd_dump(int argc, char *argv[])
86 {
87         struct bch_opts opts = bch_opts_empty();
88         struct cache_set *c = NULL;
89         const char *err;
90         char *out = NULL, *buf;
91         unsigned i, nr_devices = 0;
92         bool force = false;
93         int fd, opt;
94
95         opts.nochanges  = true;
96         opts.noreplay   = true;
97         opts.errors     = BCH_ON_ERROR_CONTINUE;
98         fsck_err_opt    = FSCK_ERR_NO;
99
100         while ((opt = getopt(argc, argv, "o:fh")) != -1)
101                 switch (opt) {
102                 case 'o':
103                         out = optarg;
104                         break;
105                 case 'f':
106                         force = true;
107                         break;
108                 case 'h':
109                         dump_usage();
110                         exit(EXIT_SUCCESS);
111                 }
112
113         if (optind >= argc)
114                 die("Please supply device(s) to check");
115
116         if (!out)
117                 die("Please supply output filename");
118
119         buf = alloca(strlen(out) + 10);
120         strcpy(buf, out);
121
122         err = bch_fs_open(argv + optind, argc - optind, opts, &c);
123         if (err)
124                 die("error opening %s: %s", argv[optind], err);
125
126         down_read(&c->gc_lock);
127
128         for (i = 0; i < c->sb.nr_devices; i++)
129                 if (c->cache[i])
130                         nr_devices++;
131
132         BUG_ON(!nr_devices);
133
134         for (i = 0; i < c->sb.nr_devices; i++) {
135                 int mode = O_WRONLY|O_CREAT|O_TRUNC;
136
137                 if (!force)
138                         mode |= O_EXCL;
139
140                 if (!c->cache[i])
141                         continue;
142
143                 if (nr_devices > 1)
144                         sprintf(buf, "%s.%u", out, i);
145
146                 fd = open(buf, mode, 0600);
147                 if (fd < 0)
148                         die("error opening %s: %s", buf, strerror(errno));
149
150                 dump_one_device(c, c->cache[i], fd);
151                 close(fd);
152         }
153
154         up_read(&c->gc_lock);
155
156         bch_fs_stop_sync(c);
157         return 0;
158 }
159
160 static void list_keys(struct cache_set *c, enum btree_id btree_id,
161                       struct bpos start, struct bpos end, int mode)
162 {
163         struct btree_iter iter;
164         struct bkey_s_c k;
165         char buf[512];
166
167         for_each_btree_key(&iter, c, btree_id, start, k) {
168                 if (bkey_cmp(k.k->p, end) > 0)
169                         break;
170
171                 bch_bkey_val_to_text(c, bkey_type(0, btree_id),
172                                      buf, sizeof(buf), k);
173                 puts(buf);
174         }
175         bch_btree_iter_unlock(&iter);
176 }
177
178 static void list_btree_formats(struct cache_set *c, enum btree_id btree_id,
179                                struct bpos start, struct bpos end, int mode)
180 {
181         struct btree_iter iter;
182         struct btree *b;
183         char buf[4096];
184
185         for_each_btree_node(&iter, c, btree_id, start, 0, b) {
186                 if (bkey_cmp(b->key.k.p, end) > 0)
187                         break;
188
189                 bch_print_btree_node(c, b, buf, sizeof(buf));
190                 puts(buf);
191         }
192         bch_btree_iter_unlock(&iter);
193 }
194
195 static struct bpos parse_pos(char *buf)
196 {
197         char *s = buf;
198         char *inode     = strsep(&s, ":");
199         char *offset    = strsep(&s, ":");
200         struct bpos ret = { 0 };
201
202         if (!inode || !offset || s ||
203             kstrtoull(inode, 10, &ret.inode) ||
204             kstrtoull(offset, 10, &ret.offset))
205                 die("invalid bpos %s", buf);
206
207         return ret;
208 }
209
210 static void list_keys_usage(void)
211 {
212         puts("bcache list_keys - list filesystem metadata to stdout\n"
213              "Usage: bcache list_keys [OPTION]... <devices>\n"
214              "\n"
215              "Options:\n"
216              "  -b btree_id   Integer btree id to list\n"
217              "  -s start      Start pos (as inode:offset)\n"
218              "  -e end        End pos\n"
219              "  -m mode       Mode for listing\n"
220              "  -h            Display this help and exit\n"
221              "Report bugs to <linux-bcache@vger.kernel.org>");
222 }
223
224 int cmd_list(int argc, char *argv[])
225 {
226         struct bch_opts opts = bch_opts_empty();
227         struct cache_set *c = NULL;
228         enum btree_id btree_id = BTREE_ID_EXTENTS;
229         struct bpos start = POS_MIN, end = POS_MAX;
230         const char *err;
231         int mode = 0, opt;
232         u64 v;
233
234         opts.nochanges  = true;
235         opts.norecovery = true;
236         opts.errors     = BCH_ON_ERROR_CONTINUE;
237         fsck_err_opt    = FSCK_ERR_NO;
238
239         while ((opt = getopt(argc, argv, "b:s:e:m:h")) != -1)
240                 switch (opt) {
241                 case 'b':
242                         if (kstrtoull(optarg, 10, &v) ||
243                             v >= BTREE_ID_NR)
244                                 die("invalid btree id");
245                         btree_id = v;
246                         break;
247                 case 's':
248                         start   = parse_pos(optarg);
249                         break;
250                 case 'e':
251                         end     = parse_pos(optarg);
252                         break;
253                 case 'm':
254                         break;
255                 case 'h':
256                         list_keys_usage();
257                         exit(EXIT_SUCCESS);
258                 }
259
260         if (optind >= argc)
261                 die("Please supply device(s) to check");
262
263         err = bch_fs_open(argv + optind, argc - optind, opts, &c);
264         if (err)
265                 die("error opening %s: %s", argv[optind], err);
266
267         switch (mode) {
268         case 0:
269                 list_keys(c, btree_id, start, end, mode);
270                 break;
271         case 1:
272                 list_btree_formats(c, btree_id, start, end, mode);
273                 break;
274         default:
275                 die("Invalid mode");
276         }
277
278         bch_fs_stop_sync(c);
279         return 0;
280 }