1 // SPDX-License-Identifier: GPL-2.0
2 #include <linux/ceph/ceph_debug.h>
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>
13 #include <linux/ceph/libceph.h>
14 #include <linux/ceph/mon_client.h>
15 #include <linux/ceph/auth.h>
16 #include <linux/ceph/debugfs.h>
20 #ifdef CONFIG_DEBUG_FS
22 #include "mds_client.h"
25 static int mdsmap_show(struct seq_file
*s
, void *p
)
28 struct ceph_fs_client
*fsc
= s
->private;
29 struct ceph_mdsmap
*mdsmap
;
31 if (!fsc
->mdsc
|| !fsc
->mdsc
->mdsmap
)
33 mdsmap
= fsc
->mdsc
->mdsmap
;
34 seq_printf(s
, "epoch %d\n", mdsmap
->m_epoch
);
35 seq_printf(s
, "root %d\n", mdsmap
->m_root
);
36 seq_printf(s
, "max_mds %d\n", mdsmap
->m_max_mds
);
37 seq_printf(s
, "session_timeout %d\n", mdsmap
->m_session_timeout
);
38 seq_printf(s
, "session_autoclose %d\n", mdsmap
->m_session_autoclose
);
39 for (i
= 0; i
< mdsmap
->possible_max_rank
; i
++) {
40 struct ceph_entity_addr
*addr
= &mdsmap
->m_info
[i
].addr
;
41 int state
= mdsmap
->m_info
[i
].state
;
42 seq_printf(s
, "\tmds%d\t%s\t(%s)\n", i
,
44 ceph_mds_state_name(state
));
52 static int mdsc_show(struct seq_file
*s
, void *p
)
54 struct ceph_fs_client
*fsc
= s
->private;
55 struct ceph_mds_client
*mdsc
= fsc
->mdsc
;
56 struct ceph_mds_request
*req
;
62 mutex_lock(&mdsc
->mutex
);
63 for (rp
= rb_first(&mdsc
->request_tree
); rp
; rp
= rb_next(rp
)) {
64 req
= rb_entry(rp
, struct ceph_mds_request
, r_node
);
66 if (req
->r_request
&& req
->r_session
)
67 seq_printf(s
, "%lld\tmds%d\t", req
->r_tid
,
68 req
->r_session
->s_mds
);
69 else if (!req
->r_request
)
70 seq_printf(s
, "%lld\t(no request)\t", req
->r_tid
);
72 seq_printf(s
, "%lld\t(no session)\t", req
->r_tid
);
74 seq_printf(s
, "%s", ceph_mds_op_name(req
->r_op
));
76 if (test_bit(CEPH_MDS_R_GOT_UNSAFE
, &req
->r_req_flags
))
77 seq_puts(s
, "\t(unsafe)");
82 seq_printf(s
, " #%llx", ceph_ino(req
->r_inode
));
83 } else if (req
->r_dentry
) {
84 path
= ceph_mdsc_build_path(mdsc
, req
->r_dentry
, &pathlen
,
88 spin_lock(&req
->r_dentry
->d_lock
);
89 seq_printf(s
, " #%llx/%pd (%s)",
90 ceph_ino(d_inode(req
->r_dentry
->d_parent
)),
93 spin_unlock(&req
->r_dentry
->d_lock
);
94 ceph_mdsc_free_path(path
, pathlen
);
95 } else if (req
->r_path1
) {
96 seq_printf(s
, " #%llx/%s", req
->r_ino1
.ino
,
99 seq_printf(s
, " #%llx", req
->r_ino1
.ino
);
102 if (req
->r_old_dentry
) {
103 path
= ceph_mdsc_build_path(mdsc
, req
->r_old_dentry
, &pathlen
,
107 spin_lock(&req
->r_old_dentry
->d_lock
);
108 seq_printf(s
, " #%llx/%pd (%s)",
109 req
->r_old_dentry_dir
?
110 ceph_ino(req
->r_old_dentry_dir
) : 0,
113 spin_unlock(&req
->r_old_dentry
->d_lock
);
114 ceph_mdsc_free_path(path
, pathlen
);
115 } else if (req
->r_path2
&& req
->r_op
!= CEPH_MDS_OP_SYMLINK
) {
117 seq_printf(s
, " #%llx/%s", req
->r_ino2
.ino
,
120 seq_printf(s
, " %s", req
->r_path2
);
125 mutex_unlock(&mdsc
->mutex
);
130 #define CEPH_LAT_METRIC_SHOW(name, total, avg, min, max, sq) { \
131 s64 _total, _avg, _min, _max, _sq, _st; \
132 _avg = ktime_to_us(avg); \
133 _min = ktime_to_us(min == KTIME_MAX ? 0 : min); \
134 _max = ktime_to_us(max); \
135 _total = total - 1; \
136 _sq = _total > 0 ? DIV64_U64_ROUND_CLOSEST(sq, _total) : 0; \
137 _st = int_sqrt64(_sq); \
138 _st = ktime_to_us(_st); \
139 seq_printf(s, "%-14s%-12lld%-16lld%-16lld%-16lld%lld\n", \
140 name, total, _avg, _min, _max, _st); \
143 #define CEPH_SZ_METRIC_SHOW(name, total, avg, min, max, sum) { \
144 u64 _min = min == U64_MAX ? 0 : min; \
145 seq_printf(s, "%-14s%-12lld%-16llu%-16llu%-16llu%llu\n", \
146 name, total, avg, _min, max, sum); \
149 static int metrics_file_show(struct seq_file
*s
, void *p
)
151 struct ceph_fs_client
*fsc
= s
->private;
152 struct ceph_client_metric
*m
= &fsc
->mdsc
->metric
;
154 seq_printf(s
, "item total\n");
155 seq_printf(s
, "------------------------------------------\n");
156 seq_printf(s
, "%-35s%lld\n", "total inodes",
157 percpu_counter_sum(&m
->total_inodes
));
158 seq_printf(s
, "%-35s%lld\n", "opened files",
159 atomic64_read(&m
->opened_files
));
160 seq_printf(s
, "%-35s%lld\n", "pinned i_caps",
161 atomic64_read(&m
->total_caps
));
162 seq_printf(s
, "%-35s%lld\n", "opened inodes",
163 percpu_counter_sum(&m
->opened_inodes
));
167 static const char * const metric_str
[] = {
173 static int metrics_latency_show(struct seq_file
*s
, void *p
)
175 struct ceph_fs_client
*fsc
= s
->private;
176 struct ceph_client_metric
*cm
= &fsc
->mdsc
->metric
;
177 struct ceph_metric
*m
;
178 s64 total
, avg
, min
, max
, sq
;
181 seq_printf(s
, "item total avg_lat(us) min_lat(us) max_lat(us) stdev(us)\n");
182 seq_printf(s
, "-----------------------------------------------------------------------------------\n");
184 for (i
= 0; i
< METRIC_MAX
; i
++) {
188 avg
= m
->latency_avg
;
189 min
= m
->latency_min
;
190 max
= m
->latency_max
;
191 sq
= m
->latency_sq_sum
;
192 spin_unlock(&m
->lock
);
193 CEPH_LAT_METRIC_SHOW(metric_str
[i
], total
, avg
, min
, max
, sq
);
199 static int metrics_size_show(struct seq_file
*s
, void *p
)
201 struct ceph_fs_client
*fsc
= s
->private;
202 struct ceph_client_metric
*cm
= &fsc
->mdsc
->metric
;
203 struct ceph_metric
*m
;
205 u64 sum
, avg
, min
, max
;
208 seq_printf(s
, "item total avg_sz(bytes) min_sz(bytes) max_sz(bytes) total_sz(bytes)\n");
209 seq_printf(s
, "----------------------------------------------------------------------------------------\n");
211 for (i
= 0; i
< METRIC_MAX
; i
++) {
212 /* skip 'metadata' as it doesn't use the size metric */
213 if (i
== METRIC_METADATA
)
219 avg
= total
> 0 ? DIV64_U64_ROUND_CLOSEST(sum
, total
) : 0;
222 spin_unlock(&m
->lock
);
223 CEPH_SZ_METRIC_SHOW(metric_str
[i
], total
, avg
, min
, max
, sum
);
229 static int metrics_caps_show(struct seq_file
*s
, void *p
)
231 struct ceph_fs_client
*fsc
= s
->private;
232 struct ceph_client_metric
*m
= &fsc
->mdsc
->metric
;
235 seq_printf(s
, "item total miss hit\n");
236 seq_printf(s
, "-------------------------------------------------\n");
238 seq_printf(s
, "%-14s%-16lld%-16lld%lld\n", "d_lease",
239 atomic64_read(&m
->total_dentries
),
240 percpu_counter_sum(&m
->d_lease_mis
),
241 percpu_counter_sum(&m
->d_lease_hit
));
243 nr_caps
= atomic64_read(&m
->total_caps
);
244 seq_printf(s
, "%-14s%-16d%-16lld%lld\n", "caps", nr_caps
,
245 percpu_counter_sum(&m
->i_caps_mis
),
246 percpu_counter_sum(&m
->i_caps_hit
));
251 static int caps_show_cb(struct inode
*inode
, int mds
, void *p
)
253 struct ceph_inode_info
*ci
= ceph_inode(inode
);
254 struct seq_file
*s
= p
;
255 struct ceph_cap
*cap
;
257 spin_lock(&ci
->i_ceph_lock
);
258 cap
= __get_cap_for_mds(ci
, mds
);
260 seq_printf(s
, "0x%-17llx%-3d%-17s%-17s\n", ceph_ino(inode
),
262 ceph_cap_string(cap
->issued
),
263 ceph_cap_string(cap
->implemented
));
264 spin_unlock(&ci
->i_ceph_lock
);
268 static int caps_show(struct seq_file
*s
, void *p
)
270 struct ceph_fs_client
*fsc
= s
->private;
271 struct ceph_mds_client
*mdsc
= fsc
->mdsc
;
272 int total
, avail
, used
, reserved
, min
, i
;
275 ceph_reservation_status(fsc
, &total
, &avail
, &used
, &reserved
, &min
);
276 seq_printf(s
, "total\t\t%d\n"
281 total
, avail
, used
, reserved
, min
);
282 seq_printf(s
, "ino mds issued implemented\n");
283 seq_printf(s
, "--------------------------------------------------\n");
285 mutex_lock(&mdsc
->mutex
);
286 for (i
= 0; i
< mdsc
->max_sessions
; i
++) {
287 struct ceph_mds_session
*session
;
289 session
= __ceph_lookup_mds_session(mdsc
, i
);
292 mutex_unlock(&mdsc
->mutex
);
293 mutex_lock(&session
->s_mutex
);
294 ceph_iterate_session_caps(session
, caps_show_cb
, s
);
295 mutex_unlock(&session
->s_mutex
);
296 ceph_put_mds_session(session
);
297 mutex_lock(&mdsc
->mutex
);
299 mutex_unlock(&mdsc
->mutex
);
301 seq_printf(s
, "\n\nWaiters:\n--------\n");
302 seq_printf(s
, "tgid ino need want\n");
303 seq_printf(s
, "-----------------------------------------------------\n");
305 spin_lock(&mdsc
->caps_list_lock
);
306 list_for_each_entry(cw
, &mdsc
->cap_wait_list
, list
) {
307 seq_printf(s
, "%-13d0x%-17llx%-17s%-17s\n", cw
->tgid
, cw
->ino
,
308 ceph_cap_string(cw
->need
),
309 ceph_cap_string(cw
->want
));
311 spin_unlock(&mdsc
->caps_list_lock
);
316 static int mds_sessions_show(struct seq_file
*s
, void *ptr
)
318 struct ceph_fs_client
*fsc
= s
->private;
319 struct ceph_mds_client
*mdsc
= fsc
->mdsc
;
320 struct ceph_auth_client
*ac
= fsc
->client
->monc
.auth
;
321 struct ceph_options
*opt
= fsc
->client
->options
;
324 mutex_lock(&mdsc
->mutex
);
326 /* The 'num' portion of an 'entity name' */
327 seq_printf(s
, "global_id %llu\n", ac
->global_id
);
329 /* The -o name mount argument */
330 seq_printf(s
, "name \"%s\"\n", opt
->name
? opt
->name
: "");
332 /* The list of MDS session rank+state */
333 for (mds
= 0; mds
< mdsc
->max_sessions
; mds
++) {
334 struct ceph_mds_session
*session
=
335 __ceph_lookup_mds_session(mdsc
, mds
);
339 mutex_unlock(&mdsc
->mutex
);
340 seq_printf(s
, "mds.%d %s\n",
342 ceph_session_state_name(session
->s_state
));
344 ceph_put_mds_session(session
);
345 mutex_lock(&mdsc
->mutex
);
347 mutex_unlock(&mdsc
->mutex
);
352 static int status_show(struct seq_file
*s
, void *p
)
354 struct ceph_fs_client
*fsc
= s
->private;
355 struct ceph_entity_inst
*inst
= &fsc
->client
->msgr
.inst
;
356 struct ceph_entity_addr
*client_addr
= ceph_client_addr(fsc
->client
);
358 seq_printf(s
, "instance: %s.%lld %s/%u\n", ENTITY_NAME(inst
->name
),
359 ceph_pr_addr(client_addr
), le32_to_cpu(client_addr
->nonce
));
360 seq_printf(s
, "blocklisted: %s\n", fsc
->blocklisted
? "true" : "false");
365 DEFINE_SHOW_ATTRIBUTE(mdsmap
);
366 DEFINE_SHOW_ATTRIBUTE(mdsc
);
367 DEFINE_SHOW_ATTRIBUTE(caps
);
368 DEFINE_SHOW_ATTRIBUTE(mds_sessions
);
369 DEFINE_SHOW_ATTRIBUTE(status
);
370 DEFINE_SHOW_ATTRIBUTE(metrics_file
);
371 DEFINE_SHOW_ATTRIBUTE(metrics_latency
);
372 DEFINE_SHOW_ATTRIBUTE(metrics_size
);
373 DEFINE_SHOW_ATTRIBUTE(metrics_caps
);
379 static int congestion_kb_set(void *data
, u64 val
)
381 struct ceph_fs_client
*fsc
= (struct ceph_fs_client
*)data
;
383 fsc
->mount_options
->congestion_kb
= (int)val
;
387 static int congestion_kb_get(void *data
, u64
*val
)
389 struct ceph_fs_client
*fsc
= (struct ceph_fs_client
*)data
;
391 *val
= (u64
)fsc
->mount_options
->congestion_kb
;
395 DEFINE_SIMPLE_ATTRIBUTE(congestion_kb_fops
, congestion_kb_get
,
396 congestion_kb_set
, "%llu\n");
399 void ceph_fs_debugfs_cleanup(struct ceph_fs_client
*fsc
)
401 doutc(fsc
->client
, "begin\n");
402 debugfs_remove(fsc
->debugfs_bdi
);
403 debugfs_remove(fsc
->debugfs_congestion_kb
);
404 debugfs_remove(fsc
->debugfs_mdsmap
);
405 debugfs_remove(fsc
->debugfs_mds_sessions
);
406 debugfs_remove(fsc
->debugfs_caps
);
407 debugfs_remove(fsc
->debugfs_status
);
408 debugfs_remove(fsc
->debugfs_mdsc
);
409 debugfs_remove_recursive(fsc
->debugfs_metrics_dir
);
410 doutc(fsc
->client
, "done\n");
413 void ceph_fs_debugfs_init(struct ceph_fs_client
*fsc
)
417 doutc(fsc
->client
, "begin\n");
418 fsc
->debugfs_congestion_kb
=
419 debugfs_create_file("writeback_congestion_kb",
421 fsc
->client
->debugfs_dir
,
423 &congestion_kb_fops
);
425 snprintf(name
, sizeof(name
), "../../bdi/%s",
426 bdi_dev_name(fsc
->sb
->s_bdi
));
428 debugfs_create_symlink("bdi",
429 fsc
->client
->debugfs_dir
,
432 fsc
->debugfs_mdsmap
= debugfs_create_file("mdsmap",
434 fsc
->client
->debugfs_dir
,
438 fsc
->debugfs_mds_sessions
= debugfs_create_file("mds_sessions",
440 fsc
->client
->debugfs_dir
,
444 fsc
->debugfs_mdsc
= debugfs_create_file("mdsc",
446 fsc
->client
->debugfs_dir
,
450 fsc
->debugfs_caps
= debugfs_create_file("caps",
452 fsc
->client
->debugfs_dir
,
456 fsc
->debugfs_status
= debugfs_create_file("status",
458 fsc
->client
->debugfs_dir
,
462 fsc
->debugfs_metrics_dir
= debugfs_create_dir("metrics",
463 fsc
->client
->debugfs_dir
);
465 debugfs_create_file("file", 0400, fsc
->debugfs_metrics_dir
, fsc
,
467 debugfs_create_file("latency", 0400, fsc
->debugfs_metrics_dir
, fsc
,
468 &metrics_latency_fops
);
469 debugfs_create_file("size", 0400, fsc
->debugfs_metrics_dir
, fsc
,
471 debugfs_create_file("caps", 0400, fsc
->debugfs_metrics_dir
, fsc
,
473 doutc(fsc
->client
, "done\n");
477 #else /* CONFIG_DEBUG_FS */
479 void ceph_fs_debugfs_init(struct ceph_fs_client
*fsc
)
483 void ceph_fs_debugfs_cleanup(struct ceph_fs_client
*fsc
)
487 #endif /* CONFIG_DEBUG_FS */