xref: /linux/fs/ceph/debugfs.c (revision 7a5f1cd22d47f8ca4b760b6334378ae42c1bd24b)
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 #include <linux/math64.h>
11 #include <linux/ktime.h>
12 #include <linux/atomic.h>
13 
14 #include <linux/ceph/libceph.h>
15 #include <linux/ceph/mon_client.h>
16 #include <linux/ceph/auth.h>
17 #include <linux/ceph/debugfs.h>
18 #include <linux/ceph/decode.h>
19 
20 #include "super.h"
21 
22 #ifdef CONFIG_DEBUG_FS
23 
24 #include "mds_client.h"
25 #include "metric.h"
26 #include "subvolume_metrics.h"
27 
28 /**
29  * struct ceph_session_feature_desc - Maps feature bits to names for debugfs
30  * @bit: Feature bit number from enum ceph_feature_type (see mds_client.h)
31  * @name: Human-readable feature name for debugfs output
32  *
33  * Used by metric_features_show() to display negotiated session features.
34  */
35 struct ceph_session_feature_desc {
36 	unsigned int bit;
37 	const char *name;
38 };
39 
40 static const struct ceph_session_feature_desc ceph_session_feature_table[] = {
41 	{ CEPHFS_FEATURE_METRIC_COLLECT, "METRIC_COLLECT" },
42 	{ CEPHFS_FEATURE_REPLY_ENCODING, "REPLY_ENCODING" },
43 	{ CEPHFS_FEATURE_RECLAIM_CLIENT, "RECLAIM_CLIENT" },
44 	{ CEPHFS_FEATURE_LAZY_CAP_WANTED, "LAZY_CAP_WANTED" },
45 	{ CEPHFS_FEATURE_MULTI_RECONNECT, "MULTI_RECONNECT" },
46 	{ CEPHFS_FEATURE_DELEG_INO, "DELEG_INO" },
47 	{ CEPHFS_FEATURE_ALTERNATE_NAME, "ALTERNATE_NAME" },
48 	{ CEPHFS_FEATURE_NOTIFY_SESSION_STATE, "NOTIFY_SESSION_STATE" },
49 	{ CEPHFS_FEATURE_OP_GETVXATTR, "OP_GETVXATTR" },
50 	{ CEPHFS_FEATURE_32BITS_RETRY_FWD, "32BITS_RETRY_FWD" },
51 	{ CEPHFS_FEATURE_NEW_SNAPREALM_INFO, "NEW_SNAPREALM_INFO" },
52 	{ CEPHFS_FEATURE_HAS_OWNER_UIDGID, "HAS_OWNER_UIDGID" },
53 	{ CEPHFS_FEATURE_MDS_AUTH_CAPS_CHECK, "MDS_AUTH_CAPS_CHECK" },
54 	{ CEPHFS_FEATURE_SUBVOLUME_METRICS, "SUBVOLUME_METRICS" },
55 };
56 
57 static int mdsmap_show(struct seq_file *s, void *p)
58 {
59 	int i;
60 	struct ceph_fs_client *fsc = s->private;
61 	struct ceph_mdsmap *mdsmap;
62 
63 	if (!fsc->mdsc || !fsc->mdsc->mdsmap)
64 		return 0;
65 	mdsmap = fsc->mdsc->mdsmap;
66 	seq_printf(s, "epoch %d\n", mdsmap->m_epoch);
67 	seq_printf(s, "root %d\n", mdsmap->m_root);
68 	seq_printf(s, "max_mds %d\n", mdsmap->m_max_mds);
69 	seq_printf(s, "session_timeout %d\n", mdsmap->m_session_timeout);
70 	seq_printf(s, "session_autoclose %d\n", mdsmap->m_session_autoclose);
71 	for (i = 0; i < mdsmap->possible_max_rank; i++) {
72 		struct ceph_entity_addr *addr = &mdsmap->m_info[i].addr;
73 		int state = mdsmap->m_info[i].state;
74 		seq_printf(s, "\tmds%d\t%s\t(%s)\n", i,
75 			       ceph_pr_addr(addr),
76 			       ceph_mds_state_name(state));
77 	}
78 	return 0;
79 }
80 
81 /*
82  * mdsc debugfs
83  */
84 static int mdsc_show(struct seq_file *s, void *p)
85 {
86 	struct ceph_fs_client *fsc = s->private;
87 	struct ceph_mds_client *mdsc = fsc->mdsc;
88 	struct ceph_mds_request *req;
89 	struct rb_node *rp;
90 	char *path;
91 
92 	mutex_lock(&mdsc->mutex);
93 	for (rp = rb_first(&mdsc->request_tree); rp; rp = rb_next(rp)) {
94 		req = rb_entry(rp, struct ceph_mds_request, r_node);
95 
96 		if (req->r_request && req->r_session)
97 			seq_printf(s, "%lld\tmds%d\t", req->r_tid,
98 				   req->r_session->s_mds);
99 		else if (!req->r_request)
100 			seq_printf(s, "%lld\t(no request)\t", req->r_tid);
101 		else
102 			seq_printf(s, "%lld\t(no session)\t", req->r_tid);
103 
104 		seq_printf(s, "%s", ceph_mds_op_name(req->r_op));
105 
106 		if (test_bit(CEPH_MDS_R_GOT_UNSAFE, &req->r_req_flags))
107 			seq_puts(s, "\t(unsafe)");
108 		else
109 			seq_puts(s, "\t");
110 
111 		if (req->r_inode) {
112 			seq_printf(s, " #%llx", ceph_ino(req->r_inode));
113 		} else if (req->r_dentry) {
114 			struct ceph_path_info path_info = {0};
115 			path = ceph_mdsc_build_path(mdsc, req->r_dentry, &path_info, 0);
116 			if (IS_ERR(path))
117 				path = NULL;
118 			spin_lock(&req->r_dentry->d_lock);
119 			seq_printf(s, " #%llx/%pd (%s)",
120 				   ceph_ino(d_inode(req->r_dentry->d_parent)),
121 				   req->r_dentry,
122 				   path ? path : "");
123 			spin_unlock(&req->r_dentry->d_lock);
124 			ceph_mdsc_free_path_info(&path_info);
125 		} else if (req->r_path1) {
126 			seq_printf(s, " #%llx/%s", req->r_ino1.ino,
127 				   req->r_path1);
128 		} else {
129 			seq_printf(s, " #%llx", req->r_ino1.ino);
130 		}
131 
132 		if (req->r_old_dentry) {
133 			struct ceph_path_info path_info = {0};
134 			path = ceph_mdsc_build_path(mdsc, req->r_old_dentry, &path_info, 0);
135 			if (IS_ERR(path))
136 				path = NULL;
137 			spin_lock(&req->r_old_dentry->d_lock);
138 			seq_printf(s, " #%llx/%pd (%s)",
139 				   req->r_old_dentry_dir ?
140 				   ceph_ino(req->r_old_dentry_dir) : 0,
141 				   req->r_old_dentry,
142 				   path ? path : "");
143 			spin_unlock(&req->r_old_dentry->d_lock);
144 			ceph_mdsc_free_path_info(&path_info);
145 		} else if (req->r_path2 && req->r_op != CEPH_MDS_OP_SYMLINK) {
146 			if (req->r_ino2.ino)
147 				seq_printf(s, " #%llx/%s", req->r_ino2.ino,
148 					   req->r_path2);
149 			else
150 				seq_printf(s, " %s", req->r_path2);
151 		}
152 
153 		seq_puts(s, "\n");
154 	}
155 	mutex_unlock(&mdsc->mutex);
156 
157 	return 0;
158 }
159 
160 #define CEPH_LAT_METRIC_SHOW(name, total, avg, min, max, sq) {		\
161 	s64 _total, _avg, _min, _max, _sq, _st;				\
162 	_avg = ktime_to_us(avg);					\
163 	_min = ktime_to_us(min == KTIME_MAX ? 0 : min);			\
164 	_max = ktime_to_us(max);					\
165 	_total = total - 1;						\
166 	_sq = _total > 0 ? DIV64_U64_ROUND_CLOSEST(sq, _total) : 0;	\
167 	_st = int_sqrt64(_sq);						\
168 	_st = ktime_to_us(_st);						\
169 	seq_printf(s, "%-14s%-12lld%-16lld%-16lld%-16lld%lld\n",	\
170 		   name, total, _avg, _min, _max, _st);			\
171 }
172 
173 #define CEPH_SZ_METRIC_SHOW(name, total, avg, min, max, sum) {		\
174 	u64 _min = min == U64_MAX ? 0 : min;				\
175 	seq_printf(s, "%-14s%-12lld%-16llu%-16llu%-16llu%llu\n",	\
176 		   name, total, avg, _min, max, sum);			\
177 }
178 
179 static int metrics_file_show(struct seq_file *s, void *p)
180 {
181 	struct ceph_fs_client *fsc = s->private;
182 	struct ceph_client_metric *m = &fsc->mdsc->metric;
183 
184 	seq_printf(s, "item                               total\n");
185 	seq_printf(s, "------------------------------------------\n");
186 	seq_printf(s, "%-35s%lld\n", "total inodes",
187 		   percpu_counter_sum(&m->total_inodes));
188 	seq_printf(s, "%-35s%lld\n", "opened files",
189 		   atomic64_read(&m->opened_files));
190 	seq_printf(s, "%-35s%lld\n", "pinned i_caps",
191 		   atomic64_read(&m->total_caps));
192 	seq_printf(s, "%-35s%lld\n", "opened inodes",
193 		   percpu_counter_sum(&m->opened_inodes));
194 	return 0;
195 }
196 
197 static const char * const metric_str[] = {
198 	"read",
199 	"write",
200 	"metadata",
201 	"copyfrom"
202 };
203 static int metrics_latency_show(struct seq_file *s, void *p)
204 {
205 	struct ceph_fs_client *fsc = s->private;
206 	struct ceph_client_metric *cm = &fsc->mdsc->metric;
207 	struct ceph_metric *m;
208 	s64 total, avg, min, max, sq;
209 	int i;
210 
211 	seq_printf(s, "item          total       avg_lat(us)     min_lat(us)     max_lat(us)     stdev(us)\n");
212 	seq_printf(s, "-----------------------------------------------------------------------------------\n");
213 
214 	for (i = 0; i < METRIC_MAX; i++) {
215 		m = &cm->metric[i];
216 		spin_lock(&m->lock);
217 		total = m->total;
218 		avg = m->latency_avg;
219 		min = m->latency_min;
220 		max = m->latency_max;
221 		sq = m->latency_sq_sum;
222 		spin_unlock(&m->lock);
223 		CEPH_LAT_METRIC_SHOW(metric_str[i], total, avg, min, max, sq);
224 	}
225 
226 	return 0;
227 }
228 
229 static int metrics_size_show(struct seq_file *s, void *p)
230 {
231 	struct ceph_fs_client *fsc = s->private;
232 	struct ceph_client_metric *cm = &fsc->mdsc->metric;
233 	struct ceph_metric *m;
234 	s64 total;
235 	u64 sum, avg, min, max;
236 	int i;
237 
238 	seq_printf(s, "item          total       avg_sz(bytes)   min_sz(bytes)   max_sz(bytes)  total_sz(bytes)\n");
239 	seq_printf(s, "----------------------------------------------------------------------------------------\n");
240 
241 	for (i = 0; i < METRIC_MAX; i++) {
242 		/* skip 'metadata' as it doesn't use the size metric */
243 		if (i == METRIC_METADATA)
244 			continue;
245 		m = &cm->metric[i];
246 		spin_lock(&m->lock);
247 		total = m->total;
248 		sum = m->size_sum;
249 		avg = total > 0 ? DIV64_U64_ROUND_CLOSEST(sum, total) : 0;
250 		min = m->size_min;
251 		max = m->size_max;
252 		spin_unlock(&m->lock);
253 		CEPH_SZ_METRIC_SHOW(metric_str[i], total, avg, min, max, sum);
254 	}
255 
256 	return 0;
257 }
258 
259 static int metrics_caps_show(struct seq_file *s, void *p)
260 {
261 	struct ceph_fs_client *fsc = s->private;
262 	struct ceph_client_metric *m = &fsc->mdsc->metric;
263 	int nr_caps = 0;
264 
265 	seq_printf(s, "item          total           miss            hit\n");
266 	seq_printf(s, "-------------------------------------------------\n");
267 
268 	seq_printf(s, "%-14s%-16lld%-16lld%lld\n", "d_lease",
269 		   atomic64_read(&m->total_dentries),
270 		   percpu_counter_sum(&m->d_lease_mis),
271 		   percpu_counter_sum(&m->d_lease_hit));
272 
273 	nr_caps = atomic64_read(&m->total_caps);
274 	seq_printf(s, "%-14s%-16d%-16lld%lld\n", "caps", nr_caps,
275 		   percpu_counter_sum(&m->i_caps_mis),
276 		   percpu_counter_sum(&m->i_caps_hit));
277 
278 	return 0;
279 }
280 
281 static int caps_show_cb(struct inode *inode, int mds, void *p)
282 {
283 	struct ceph_inode_info *ci = ceph_inode(inode);
284 	struct seq_file *s = p;
285 	struct ceph_cap *cap;
286 
287 	spin_lock(&ci->i_ceph_lock);
288 	cap = __get_cap_for_mds(ci, mds);
289 	if (cap)
290 		seq_printf(s, "0x%-17llx%-3d%-17s%-17s\n", ceph_ino(inode),
291 			   cap->session->s_mds,
292 			   ceph_cap_string(cap->issued),
293 			   ceph_cap_string(cap->implemented));
294 	spin_unlock(&ci->i_ceph_lock);
295 	return 0;
296 }
297 
298 static int caps_show(struct seq_file *s, void *p)
299 {
300 	struct ceph_fs_client *fsc = s->private;
301 	struct ceph_mds_client *mdsc = fsc->mdsc;
302 	int total, avail, used, reserved, min, i;
303 	struct cap_wait	*cw;
304 
305 	ceph_reservation_status(fsc, &total, &avail, &used, &reserved, &min);
306 	seq_printf(s, "total\t\t%d\n"
307 		   "avail\t\t%d\n"
308 		   "used\t\t%d\n"
309 		   "reserved\t%d\n"
310 		   "min\t\t%d\n\n",
311 		   total, avail, used, reserved, min);
312 	seq_printf(s, "ino              mds  issued           implemented\n");
313 	seq_printf(s, "--------------------------------------------------\n");
314 
315 	mutex_lock(&mdsc->mutex);
316 	for (i = 0; i < mdsc->max_sessions; i++) {
317 		struct ceph_mds_session *session;
318 
319 		session = __ceph_lookup_mds_session(mdsc, i);
320 		if (!session)
321 			continue;
322 		mutex_unlock(&mdsc->mutex);
323 		mutex_lock(&session->s_mutex);
324 		ceph_iterate_session_caps(session, caps_show_cb, s);
325 		mutex_unlock(&session->s_mutex);
326 		ceph_put_mds_session(session);
327 		mutex_lock(&mdsc->mutex);
328 	}
329 	mutex_unlock(&mdsc->mutex);
330 
331 	seq_printf(s, "\n\nWaiters:\n--------\n");
332 	seq_printf(s, "tgid         ino                need             want\n");
333 	seq_printf(s, "-----------------------------------------------------\n");
334 
335 	spin_lock(&mdsc->caps_list_lock);
336 	list_for_each_entry(cw, &mdsc->cap_wait_list, list) {
337 		seq_printf(s, "%-13d0x%-17llx%-17s%-17s\n", cw->tgid, cw->ino,
338 				ceph_cap_string(cw->need),
339 				ceph_cap_string(cw->want));
340 	}
341 	spin_unlock(&mdsc->caps_list_lock);
342 
343 	return 0;
344 }
345 
346 static int mds_sessions_show(struct seq_file *s, void *ptr)
347 {
348 	struct ceph_fs_client *fsc = s->private;
349 	struct ceph_mds_client *mdsc = fsc->mdsc;
350 	struct ceph_auth_client *ac = fsc->client->monc.auth;
351 	struct ceph_options *opt = fsc->client->options;
352 	int mds;
353 
354 	mutex_lock(&mdsc->mutex);
355 
356 	/* The 'num' portion of an 'entity name' */
357 	seq_printf(s, "global_id %llu\n", ac->global_id);
358 
359 	/* The -o name mount argument */
360 	seq_printf(s, "name \"%s\"\n", opt->name ? opt->name : "");
361 
362 	/* The list of MDS session rank+state */
363 	for (mds = 0; mds < mdsc->max_sessions; mds++) {
364 		struct ceph_mds_session *session =
365 			__ceph_lookup_mds_session(mdsc, mds);
366 		if (!session) {
367 			continue;
368 		}
369 		mutex_unlock(&mdsc->mutex);
370 		seq_printf(s, "mds.%d %s\n",
371 				session->s_mds,
372 				ceph_session_state_name(session->s_state));
373 
374 		ceph_put_mds_session(session);
375 		mutex_lock(&mdsc->mutex);
376 	}
377 	mutex_unlock(&mdsc->mutex);
378 
379 	return 0;
380 }
381 
382 static int status_show(struct seq_file *s, void *p)
383 {
384 	struct ceph_fs_client *fsc = s->private;
385 	struct ceph_entity_inst *inst = &fsc->client->msgr.inst;
386 	struct ceph_entity_addr *client_addr = ceph_client_addr(fsc->client);
387 
388 	seq_printf(s, "instance: %s.%lld %s/%u\n", ENTITY_NAME(inst->name),
389 		   ceph_pr_addr(client_addr), le32_to_cpu(client_addr->nonce));
390 	seq_printf(s, "blocklisted: %s\n", str_true_false(fsc->blocklisted));
391 
392 	return 0;
393 }
394 
395 static int subvolume_metrics_show(struct seq_file *s, void *p)
396 {
397 	struct ceph_fs_client *fsc = s->private;
398 	struct ceph_mds_client *mdsc = fsc->mdsc;
399 	struct ceph_subvol_metric_snapshot *snapshot = NULL;
400 	u32 nr = 0;
401 	u64 total_sent = 0;
402 	u64 nonzero_sends = 0;
403 	u32 i;
404 
405 	if (!mdsc) {
406 		seq_puts(s, "mds client unavailable\n");
407 		return 0;
408 	}
409 
410 	mutex_lock(&mdsc->subvol_metrics_last_mutex);
411 	if (mdsc->subvol_metrics_last && mdsc->subvol_metrics_last_nr) {
412 		nr = mdsc->subvol_metrics_last_nr;
413 		snapshot = kmemdup_array(mdsc->subvol_metrics_last, nr,
414 					 sizeof(*snapshot), GFP_KERNEL);
415 		if (!snapshot)
416 			nr = 0;
417 	}
418 	total_sent = mdsc->subvol_metrics_sent;
419 	nonzero_sends = mdsc->subvol_metrics_nonzero_sends;
420 	mutex_unlock(&mdsc->subvol_metrics_last_mutex);
421 
422 	seq_puts(s, "Last sent subvolume metrics:\n");
423 	if (!nr) {
424 		seq_puts(s, "  (none)\n");
425 	} else {
426 		seq_puts(s, "  subvol_id          rd_ops    wr_ops    rd_bytes       wr_bytes       rd_lat_us      wr_lat_us\n");
427 		for (i = 0; i < nr; i++) {
428 			const struct ceph_subvol_metric_snapshot *e = &snapshot[i];
429 
430 			seq_printf(s, "  %-18llu %-9llu %-9llu %-14llu %-14llu %-14llu %-14llu\n",
431 				   e->subvolume_id,
432 				   e->read_ops, e->write_ops,
433 				   e->read_bytes, e->write_bytes,
434 				   e->read_latency_us, e->write_latency_us);
435 		}
436 	}
437 	kfree(snapshot);
438 
439 	seq_puts(s, "\nStatistics:\n");
440 	seq_printf(s, "  entries_sent:      %llu\n", total_sent);
441 	seq_printf(s, "  non_zero_sends:    %llu\n", nonzero_sends);
442 
443 	seq_puts(s, "\nPending (unsent) subvolume metrics:\n");
444 	ceph_subvolume_metrics_dump(&mdsc->subvol_metrics, s);
445 	return 0;
446 }
447 
448 DEFINE_SHOW_ATTRIBUTE(mdsmap);
449 DEFINE_SHOW_ATTRIBUTE(mdsc);
450 DEFINE_SHOW_ATTRIBUTE(caps);
451 DEFINE_SHOW_ATTRIBUTE(mds_sessions);
452 DEFINE_SHOW_ATTRIBUTE(status);
453 DEFINE_SHOW_ATTRIBUTE(metrics_file);
454 DEFINE_SHOW_ATTRIBUTE(metrics_latency);
455 DEFINE_SHOW_ATTRIBUTE(metrics_size);
456 DEFINE_SHOW_ATTRIBUTE(metrics_caps);
457 DEFINE_SHOW_ATTRIBUTE(subvolume_metrics);
458 
459 static int metric_features_show(struct seq_file *s, void *p)
460 {
461 	struct ceph_fs_client *fsc = s->private;
462 	struct ceph_mds_client *mdsc = fsc->mdsc;
463 	unsigned long session_features = 0;
464 	bool have_session = false;
465 	bool metric_collect = false;
466 	bool subvol_support = false;
467 	bool metrics_enabled = false;
468 	bool subvol_enabled = false;
469 	int i;
470 
471 	if (!mdsc) {
472 		seq_puts(s, "mds client unavailable\n");
473 		return 0;
474 	}
475 
476 	mutex_lock(&mdsc->mutex);
477 	if (mdsc->metric.session) {
478 		have_session = true;
479 		session_features = mdsc->metric.session->s_features;
480 	}
481 	mutex_unlock(&mdsc->mutex);
482 
483 	if (have_session) {
484 		metric_collect =
485 			test_bit(CEPHFS_FEATURE_METRIC_COLLECT,
486 				 &session_features);
487 		subvol_support =
488 			test_bit(CEPHFS_FEATURE_SUBVOLUME_METRICS,
489 				 &session_features);
490 	}
491 
492 	metrics_enabled = !disable_send_metrics && have_session && metric_collect;
493 	subvol_enabled = metrics_enabled && subvol_support;
494 
495 	seq_printf(s,
496 		   "metrics_enabled: %s (disable_send_metrics=%d, session=%s, metric_collect=%s)\n",
497 		   metrics_enabled ? "yes" : "no",
498 		   disable_send_metrics ? 1 : 0,
499 		   have_session ? "yes" : "no",
500 		   metric_collect ? "yes" : "no");
501 	seq_printf(s, "subvolume_metrics_enabled: %s\n",
502 		   subvol_enabled ? "yes" : "no");
503 	seq_printf(s, "session_feature_bits: 0x%lx\n", session_features);
504 
505 	if (!have_session) {
506 		seq_puts(s, "(no active MDS session for metrics)\n");
507 		return 0;
508 	}
509 
510 	for (i = 0; i < ARRAY_SIZE(ceph_session_feature_table); i++) {
511 		const struct ceph_session_feature_desc *desc =
512 			&ceph_session_feature_table[i];
513 		bool set = test_bit(desc->bit, &session_features);
514 
515 		seq_printf(s, "  %-24s : %s\n", desc->name,
516 			   set ? "yes" : "no");
517 	}
518 
519 	return 0;
520 }
521 
522 DEFINE_SHOW_ATTRIBUTE(metric_features);
523 
524 /*
525  * debugfs
526  */
527 static int congestion_kb_set(void *data, u64 val)
528 {
529 	struct ceph_fs_client *fsc = (struct ceph_fs_client *)data;
530 
531 	fsc->mount_options->congestion_kb = (int)val;
532 	return 0;
533 }
534 
535 static int congestion_kb_get(void *data, u64 *val)
536 {
537 	struct ceph_fs_client *fsc = (struct ceph_fs_client *)data;
538 
539 	*val = (u64)fsc->mount_options->congestion_kb;
540 	return 0;
541 }
542 
543 DEFINE_SIMPLE_ATTRIBUTE(congestion_kb_fops, congestion_kb_get,
544 			congestion_kb_set, "%llu\n");
545 
546 
547 void ceph_fs_debugfs_cleanup(struct ceph_fs_client *fsc)
548 {
549 	doutc(fsc->client, "begin\n");
550 	debugfs_remove(fsc->debugfs_bdi);
551 	debugfs_remove(fsc->debugfs_congestion_kb);
552 	debugfs_remove(fsc->debugfs_mdsmap);
553 	debugfs_remove(fsc->debugfs_mds_sessions);
554 	debugfs_remove(fsc->debugfs_caps);
555 	debugfs_remove(fsc->debugfs_status);
556 	debugfs_remove(fsc->debugfs_mdsc);
557 	debugfs_remove(fsc->debugfs_subvolume_metrics);
558 	debugfs_remove_recursive(fsc->debugfs_metrics_dir);
559 	doutc(fsc->client, "done\n");
560 }
561 
562 void ceph_fs_debugfs_init(struct ceph_fs_client *fsc)
563 {
564 	char name[NAME_MAX];
565 
566 	doutc(fsc->client, "begin\n");
567 	fsc->debugfs_congestion_kb =
568 		debugfs_create_file("writeback_congestion_kb",
569 				    0600,
570 				    fsc->client->debugfs_dir,
571 				    fsc,
572 				    &congestion_kb_fops);
573 
574 	snprintf(name, sizeof(name), "../../bdi/%s",
575 		 bdi_dev_name(fsc->sb->s_bdi));
576 	fsc->debugfs_bdi =
577 		debugfs_create_symlink("bdi",
578 				       fsc->client->debugfs_dir,
579 				       name);
580 
581 	fsc->debugfs_mdsmap = debugfs_create_file("mdsmap",
582 					0400,
583 					fsc->client->debugfs_dir,
584 					fsc,
585 					&mdsmap_fops);
586 
587 	fsc->debugfs_mds_sessions = debugfs_create_file("mds_sessions",
588 					0400,
589 					fsc->client->debugfs_dir,
590 					fsc,
591 					&mds_sessions_fops);
592 
593 	fsc->debugfs_mdsc = debugfs_create_file("mdsc",
594 						0400,
595 						fsc->client->debugfs_dir,
596 						fsc,
597 						&mdsc_fops);
598 
599 	fsc->debugfs_caps = debugfs_create_file("caps",
600 						0400,
601 						fsc->client->debugfs_dir,
602 						fsc,
603 						&caps_fops);
604 
605 	fsc->debugfs_status = debugfs_create_file("status",
606 						  0400,
607 						  fsc->client->debugfs_dir,
608 						  fsc,
609 						  &status_fops);
610 
611 	fsc->debugfs_metrics_dir = debugfs_create_dir("metrics",
612 						      fsc->client->debugfs_dir);
613 
614 	debugfs_create_file("file", 0400, fsc->debugfs_metrics_dir, fsc,
615 			    &metrics_file_fops);
616 	debugfs_create_file("latency", 0400, fsc->debugfs_metrics_dir, fsc,
617 			    &metrics_latency_fops);
618 	debugfs_create_file("size", 0400, fsc->debugfs_metrics_dir, fsc,
619 			    &metrics_size_fops);
620 	debugfs_create_file("caps", 0400, fsc->debugfs_metrics_dir, fsc,
621 			    &metrics_caps_fops);
622 	debugfs_create_file("metric_features", 0400, fsc->debugfs_metrics_dir,
623 			    fsc, &metric_features_fops);
624 	fsc->debugfs_subvolume_metrics =
625 		debugfs_create_file("subvolumes", 0400,
626 				    fsc->debugfs_metrics_dir, fsc,
627 				    &subvolume_metrics_fops);
628 	doutc(fsc->client, "done\n");
629 }
630 
631 
632 #else  /* CONFIG_DEBUG_FS */
633 
634 void ceph_fs_debugfs_init(struct ceph_fs_client *fsc)
635 {
636 }
637 
638 void ceph_fs_debugfs_cleanup(struct ceph_fs_client *fsc)
639 {
640 }
641 
642 #endif  /* CONFIG_DEBUG_FS */
643