File Index
Files and directories
Sign in
FILE

debugfs.c

File preview with syntax highlighting.

linux-6.19.14/net/ceph/debugfs.c C
  1// SPDX-License-Identifier: GPL-2.0
  2#include <linux/ceph/ceph_debug.h>
  3
  4#include <linux/device.h>
  5#include <linux/slab.h>
  6#include <linux/module.h>
  7#include <linux/ctype.h>
  8#include <linux/debugfs.h>
  9#include <linux/seq_file.h>
 10
 11#include <linux/ceph/libceph.h>
 12#include <linux/ceph/mon_client.h>
 13#include <linux/ceph/auth.h>
 14#include <linux/ceph/debugfs.h>
 15
 16#ifdef CONFIG_DEBUG_FS
 17
 18/*
 19 * Implement /sys/kernel/debug/ceph fun
 20 *
 21 * /sys/kernel/debug/ceph/client*  - an instance of the ceph client
 22 *      .../osdmap      - current osdmap
 23 *      .../monmap      - current monmap
 24 *      .../osdc        - active osd requests
 25 *      .../monc        - mon client state
 26 *      .../client_options - libceph-only (i.e. not rbd or cephfs) options
 27 *      .../dentry_lru  - dump contents of dentry lru
 28 *      .../caps        - expose cap (reservation) stats
 29 *      .../bdi         - symlink to ../../bdi/something
 30 */
 31
 32static struct dentry *ceph_debugfs_dir;
 33
 34static int monmap_show(struct seq_file *s, void *p)
 35{
 36	int i;
 37	struct ceph_client *client = s->private;
 38
 39	mutex_lock(&client->monc.mutex);
 40	if (client->monc.monmap == NULL)
 41		goto out_unlock;
 42
 43	seq_printf(s, "epoch %d\n", client->monc.monmap->epoch);
 44	for (i = 0; i < client->monc.monmap->num_mon; i++) {
 45		struct ceph_entity_inst *inst =
 46			&client->monc.monmap->mon_inst[i];
 47
 48		seq_printf(s, "\t%s%lld\t%s\n",
 49			   ENTITY_NAME(inst->name),
 50			   ceph_pr_addr(&inst->addr));
 51	}
 52
 53out_unlock:
 54	mutex_unlock(&client->monc.mutex);
 55	return 0;
 56}
 57
 58static int osdmap_show(struct seq_file *s, void *p)
 59{
 60	int i;
 61	struct ceph_client *client = s->private;
 62	struct ceph_osd_client *osdc = &client->osdc;
 63	struct ceph_osdmap *map;
 64	struct rb_node *n;
 65
 66	down_read(&osdc->lock);
 67	map = osdc->osdmap;
 68	if (map == NULL)
 69		goto out_unlock;
 70
 71	seq_printf(s, "epoch %u barrier %u flags 0x%x\n", map->epoch,
 72			osdc->epoch_barrier, map->flags);
 73
 74	for (n = rb_first(&map->pg_pools); n; n = rb_next(n)) {
 75		struct ceph_pg_pool_info *pi =
 76			rb_entry(n, struct ceph_pg_pool_info, node);
 77
 78		seq_printf(s, "pool %lld '%s' type %d size %d min_size %d pg_num %u pg_num_mask %d flags 0x%llx lfor %u read_tier %lld write_tier %lld\n",
 79			   pi->id, pi->name, pi->type, pi->size, pi->min_size,
 80			   pi->pg_num, pi->pg_num_mask, pi->flags,
 81			   pi->last_force_request_resend, pi->read_tier,
 82			   pi->write_tier);
 83	}
 84	for (i = 0; i < map->max_osd; i++) {
 85		struct ceph_entity_addr *addr = &map->osd_addr[i];
 86		u32 state = map->osd_state[i];
 87		char sb[64];
 88
 89		seq_printf(s, "osd%d\t%s\t%3d%%\t(%s)\t%3d%%\t%2d\n",
 90			   i, ceph_pr_addr(addr),
 91			   ((map->osd_weight[i]*100) >> 16),
 92			   ceph_osdmap_state_str(sb, sizeof(sb), state),
 93			   ((ceph_get_primary_affinity(map, i)*100) >> 16),
 94			   ceph_get_crush_locality(map, i,
 95					   &client->options->crush_locs));
 96	}
 97	for (n = rb_first(&map->pg_temp); n; n = rb_next(n)) {
 98		struct ceph_pg_mapping *pg =
 99			rb_entry(n, struct ceph_pg_mapping, node);
100
101		seq_printf(s, "pg_temp %llu.%x [", pg->pgid.pool,
102			   pg->pgid.seed);
103		for (i = 0; i < pg->pg_temp.len; i++)
104			seq_printf(s, "%s%d", (i == 0 ? "" : ","),
105				   pg->pg_temp.osds[i]);
106		seq_printf(s, "]\n");
107	}
108	for (n = rb_first(&map->primary_temp); n; n = rb_next(n)) {
109		struct ceph_pg_mapping *pg =
110			rb_entry(n, struct ceph_pg_mapping, node);
111
112		seq_printf(s, "primary_temp %llu.%x %d\n", pg->pgid.pool,
113			   pg->pgid.seed, pg->primary_temp.osd);
114	}
115	for (n = rb_first(&map->pg_upmap); n; n = rb_next(n)) {
116		struct ceph_pg_mapping *pg =
117			rb_entry(n, struct ceph_pg_mapping, node);
118
119		seq_printf(s, "pg_upmap %llu.%x [", pg->pgid.pool,
120			   pg->pgid.seed);
121		for (i = 0; i < pg->pg_upmap.len; i++)
122			seq_printf(s, "%s%d", (i == 0 ? "" : ","),
123				   pg->pg_upmap.osds[i]);
124		seq_printf(s, "]\n");
125	}
126	for (n = rb_first(&map->pg_upmap_items); n; n = rb_next(n)) {
127		struct ceph_pg_mapping *pg =
128			rb_entry(n, struct ceph_pg_mapping, node);
129
130		seq_printf(s, "pg_upmap_items %llu.%x [", pg->pgid.pool,
131			   pg->pgid.seed);
132		for (i = 0; i < pg->pg_upmap_items.len; i++)
133			seq_printf(s, "%s%d->%d", (i == 0 ? "" : ","),
134				   pg->pg_upmap_items.from_to[i][0],
135				   pg->pg_upmap_items.from_to[i][1]);
136		seq_printf(s, "]\n");
137	}
138
139out_unlock:
140	up_read(&osdc->lock);
141	return 0;
142}
143
144static int monc_show(struct seq_file *s, void *p)
145{
146	struct ceph_client *client = s->private;
147	struct ceph_mon_generic_request *req;
148	struct ceph_mon_client *monc = &client->monc;
149	struct rb_node *rp;
150	int i;
151
152	mutex_lock(&monc->mutex);
153
154	for (i = 0; i < ARRAY_SIZE(monc->subs); i++) {
155		seq_printf(s, "have %s %u", ceph_sub_str[i],
156			   monc->subs[i].have);
157		if (monc->subs[i].want)
158			seq_printf(s, " want %llu%s",
159				   le64_to_cpu(monc->subs[i].item.start),
160				   (monc->subs[i].item.flags &
161					CEPH_SUBSCRIBE_ONETIME ?  "" : "+"));
162		seq_putc(s, '\n');
163	}
164	seq_printf(s, "fs_cluster_id %d\n", monc->fs_cluster_id);
165
166	for (rp = rb_first(&monc->generic_request_tree); rp; rp = rb_next(rp)) {
167		__u16 op;
168		req = rb_entry(rp, struct ceph_mon_generic_request, node);
169		op = le16_to_cpu(req->request->hdr.type);
170		if (op == CEPH_MSG_STATFS)
171			seq_printf(s, "%llu statfs\n", req->tid);
172		else if (op == CEPH_MSG_MON_GET_VERSION)
173			seq_printf(s, "%llu mon_get_version", req->tid);
174		else
175			seq_printf(s, "%llu unknown\n", req->tid);
176	}
177
178	mutex_unlock(&monc->mutex);
179	return 0;
180}
181
182static void dump_spgid(struct seq_file *s, const struct ceph_spg *spgid)
183{
184	seq_printf(s, "%llu.%x", spgid->pgid.pool, spgid->pgid.seed);
185	if (spgid->shard != CEPH_SPG_NOSHARD)
186		seq_printf(s, "s%d", spgid->shard);
187}
188
189static void dump_target(struct seq_file *s, struct ceph_osd_request_target *t)
190{
191	int i;
192
193	seq_printf(s, "osd%d\t%llu.%x\t", t->osd, t->pgid.pool, t->pgid.seed);
194	dump_spgid(s, &t->spgid);
195	seq_puts(s, "\t[");
196	for (i = 0; i < t->up.size; i++)
197		seq_printf(s, "%s%d", (!i ? "" : ","), t->up.osds[i]);
198	seq_printf(s, "]/%d\t[", t->up.primary);
199	for (i = 0; i < t->acting.size; i++)
200		seq_printf(s, "%s%d", (!i ? "" : ","), t->acting.osds[i]);
201	seq_printf(s, "]/%d\te%u\t", t->acting.primary, t->epoch);
202	if (t->target_oloc.pool_ns) {
203		seq_printf(s, "%*pE/%*pE\t0x%x",
204			(int)t->target_oloc.pool_ns->len,
205			t->target_oloc.pool_ns->str,
206			t->target_oid.name_len, t->target_oid.name, t->flags);
207	} else {
208		seq_printf(s, "%*pE\t0x%x", t->target_oid.name_len,
209			t->target_oid.name, t->flags);
210	}
211	if (t->paused)
212		seq_puts(s, "\tP");
213}
214
215static void dump_request(struct seq_file *s, struct ceph_osd_request *req)
216{
217	int i;
218
219	seq_printf(s, "%llu\t", req->r_tid);
220	dump_target(s, &req->r_t);
221
222	seq_printf(s, "\t%d", req->r_attempts);
223
224	for (i = 0; i < req->r_num_ops; i++) {
225		struct ceph_osd_req_op *op = &req->r_ops[i];
226
227		seq_printf(s, "%s%s", (i == 0 ? "\t" : ","),
228			   ceph_osd_op_name(op->op));
229		if (op->op == CEPH_OSD_OP_WATCH)
230			seq_printf(s, "-%s",
231				   ceph_osd_watch_op_name(op->watch.op));
232		else if (op->op == CEPH_OSD_OP_CALL)
233			seq_printf(s, "-%s/%s", op->cls.class_name,
234				   op->cls.method_name);
235	}
236
237	seq_putc(s, '\n');
238}
239
240static void dump_requests(struct seq_file *s, struct ceph_osd *osd)
241{
242	struct rb_node *n;
243
244	mutex_lock(&osd->lock);
245	for (n = rb_first(&osd->o_requests); n; n = rb_next(n)) {
246		struct ceph_osd_request *req =
247		    rb_entry(n, struct ceph_osd_request, r_node);
248
249		dump_request(s, req);
250	}
251
252	mutex_unlock(&osd->lock);
253}
254
255static void dump_linger_request(struct seq_file *s,
256				struct ceph_osd_linger_request *lreq)
257{
258	seq_printf(s, "%llu\t", lreq->linger_id);
259	dump_target(s, &lreq->t);
260
261	seq_printf(s, "\t%u\t%s%s/%d\n", lreq->register_gen,
262		   lreq->is_watch ? "W" : "N", lreq->committed ? "C" : "",
263		   lreq->last_error);
264}
265
266static void dump_linger_requests(struct seq_file *s, struct ceph_osd *osd)
267{
268	struct rb_node *n;
269
270	mutex_lock(&osd->lock);
271	for (n = rb_first(&osd->o_linger_requests); n; n = rb_next(n)) {
272		struct ceph_osd_linger_request *lreq =
273		    rb_entry(n, struct ceph_osd_linger_request, node);
274
275		dump_linger_request(s, lreq);
276	}
277
278	mutex_unlock(&osd->lock);
279}
280
281static void dump_snapid(struct seq_file *s, u64 snapid)
282{
283	if (snapid == CEPH_NOSNAP)
284		seq_puts(s, "head");
285	else if (snapid == CEPH_SNAPDIR)
286		seq_puts(s, "snapdir");
287	else
288		seq_printf(s, "%llx", snapid);
289}
290
291static void dump_name_escaped(struct seq_file *s, unsigned char *name,
292			      size_t len)
293{
294	size_t i;
295
296	for (i = 0; i < len; i++) {
297		if (name[i] == '%' || name[i] == ':' || name[i] == '/' ||
298		    name[i] < 32 || name[i] >= 127) {
299			seq_printf(s, "%%%02x", name[i]);
300		} else {
301			seq_putc(s, name[i]);
302		}
303	}
304}
305
306static void dump_hoid(struct seq_file *s, const struct ceph_hobject_id *hoid)
307{
308	if (hoid->snapid == 0 && hoid->hash == 0 && !hoid->is_max &&
309	    hoid->pool == S64_MIN) {
310		seq_puts(s, "MIN");
311		return;
312	}
313	if (hoid->is_max) {
314		seq_puts(s, "MAX");
315		return;
316	}
317	seq_printf(s, "%lld:%08x:", hoid->pool, hoid->hash_reverse_bits);
318	dump_name_escaped(s, hoid->nspace, hoid->nspace_len);
319	seq_putc(s, ':');
320	dump_name_escaped(s, hoid->key, hoid->key_len);
321	seq_putc(s, ':');
322	dump_name_escaped(s, hoid->oid, hoid->oid_len);
323	seq_putc(s, ':');
324	dump_snapid(s, hoid->snapid);
325}
326
327static void dump_backoffs(struct seq_file *s, struct ceph_osd *osd)
328{
329	struct rb_node *n;
330
331	mutex_lock(&osd->lock);
332	for (n = rb_first(&osd->o_backoffs_by_id); n; n = rb_next(n)) {
333		struct ceph_osd_backoff *backoff =
334		    rb_entry(n, struct ceph_osd_backoff, id_node);
335
336		seq_printf(s, "osd%d\t", osd->o_osd);
337		dump_spgid(s, &backoff->spgid);
338		seq_printf(s, "\t%llu\t", backoff->id);
339		dump_hoid(s, backoff->begin);
340		seq_putc(s, '\t');
341		dump_hoid(s, backoff->end);
342		seq_putc(s, '\n');
343	}
344
345	mutex_unlock(&osd->lock);
346}
347
348static int osdc_show(struct seq_file *s, void *pp)
349{
350	struct ceph_client *client = s->private;
351	struct ceph_osd_client *osdc = &client->osdc;
352	struct rb_node *n;
353
354	down_read(&osdc->lock);
355	seq_printf(s, "REQUESTS %d homeless %d\n",
356		   atomic_read(&osdc->num_requests),
357		   atomic_read(&osdc->num_homeless));
358	for (n = rb_first(&osdc->osds); n; n = rb_next(n)) {
359		struct ceph_osd *osd = rb_entry(n, struct ceph_osd, o_node);
360
361		dump_requests(s, osd);
362	}
363	dump_requests(s, &osdc->homeless_osd);
364
365	seq_puts(s, "LINGER REQUESTS\n");
366	for (n = rb_first(&osdc->osds); n; n = rb_next(n)) {
367		struct ceph_osd *osd = rb_entry(n, struct ceph_osd, o_node);
368
369		dump_linger_requests(s, osd);
370	}
371	dump_linger_requests(s, &osdc->homeless_osd);
372
373	seq_puts(s, "BACKOFFS\n");
374	for (n = rb_first(&osdc->osds); n; n = rb_next(n)) {
375		struct ceph_osd *osd = rb_entry(n, struct ceph_osd, o_node);
376
377		dump_backoffs(s, osd);
378	}
379
380	up_read(&osdc->lock);
381	return 0;
382}
383
384static int client_options_show(struct seq_file *s, void *p)
385{
386	struct ceph_client *client = s->private;
387	int ret;
388
389	ret = ceph_print_client_options(s, client, true);
390	if (ret)
391		return ret;
392
393	seq_putc(s, '\n');
394	return 0;
395}
396
397DEFINE_SHOW_ATTRIBUTE(monmap);
398DEFINE_SHOW_ATTRIBUTE(osdmap);
399DEFINE_SHOW_ATTRIBUTE(monc);
400DEFINE_SHOW_ATTRIBUTE(osdc);
401DEFINE_SHOW_ATTRIBUTE(client_options);
402
403void __init ceph_debugfs_init(void)
404{
405	ceph_debugfs_dir = debugfs_create_dir("ceph", NULL);
406}
407
408void ceph_debugfs_cleanup(void)
409{
410	debugfs_remove(ceph_debugfs_dir);
411}
412
413void ceph_debugfs_client_init(struct ceph_client *client)
414{
415	char name[80];
416
417	snprintf(name, sizeof(name), "%pU.client%lld", &client->fsid,
418		 client->monc.auth->global_id);
419
420	dout("ceph_debugfs_client_init %p %s\n", client, name);
421
422	client->debugfs_dir = debugfs_create_dir(name, ceph_debugfs_dir);
423
424	client->monc.debugfs_file = debugfs_create_file("monc",
425						      0400,
426						      client->debugfs_dir,
427						      client,
428						      &monc_fops);
429
430	client->osdc.debugfs_file = debugfs_create_file("osdc",
431						      0400,
432						      client->debugfs_dir,
433						      client,
434						      &osdc_fops);
435
436	client->debugfs_monmap = debugfs_create_file("monmap",
437					0400,
438					client->debugfs_dir,
439					client,
440					&monmap_fops);
441
442	client->debugfs_osdmap = debugfs_create_file("osdmap",
443					0400,
444					client->debugfs_dir,
445					client,
446					&osdmap_fops);
447
448	client->debugfs_options = debugfs_create_file("client_options",
449					0400,
450					client->debugfs_dir,
451					client,
452					&client_options_fops);
453}
454
455void ceph_debugfs_client_cleanup(struct ceph_client *client)
456{
457	dout("ceph_debugfs_client_cleanup %p\n", client);
458	debugfs_remove(client->debugfs_options);
459	debugfs_remove(client->debugfs_osdmap);
460	debugfs_remove(client->debugfs_monmap);
461	debugfs_remove(client->osdc.debugfs_file);
462	debugfs_remove(client->monc.debugfs_file);
463	debugfs_remove(client->debugfs_dir);
464}
465
466#else  /* CONFIG_DEBUG_FS */
467
468void __init ceph_debugfs_init(void)
469{
470}
471
472void ceph_debugfs_cleanup(void)
473{
474}
475
476void ceph_debugfs_client_init(struct ceph_client *client)
477{
478}
479
480void ceph_debugfs_client_cleanup(struct ceph_client *client)
481{
482}
483
484#endif  /* CONFIG_DEBUG_FS */
~/ Read-only file preview.