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 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> 17 18 #include "super.h" 19 20 #ifdef CONFIG_DEBUG_FS 21 22 #include "mds_client.h" 23 #include "metric.h" 24 25 static int mdsmap_show(struct seq_file *s, void *p) 26 { 27 int i; 28 struct ceph_fs_client *fsc = s->private; 29 struct ceph_mdsmap *mdsmap; 30 31 if (!fsc->mdsc || !fsc->mdsc->mdsmap) 32 return 0; 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, 43 ceph_pr_addr(addr), 44 ceph_mds_state_name(state)); 45 } 46 return 0; 47 } 48 49 /* 50 * mdsc debugfs 51 */ 52 static int mdsc_show(struct seq_file *s, void *p) 53 { 54 struct ceph_fs_client *fsc = s->private; 55 struct ceph_mds_client *mdsc = fsc->mdsc; 56 struct ceph_mds_request *req; 57 struct rb_node *rp; 58 int pathlen = 0; 59 u64 pathbase; 60 char *path; 61 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); 65 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); 71 else 72 seq_printf(s, "%lld\t(no session)\t", req->r_tid); 73 74 seq_printf(s, "%s", ceph_mds_op_name(req->r_op)); 75 76 if (test_bit(CEPH_MDS_R_GOT_UNSAFE, &req->r_req_flags)) 77 seq_puts(s, "\t(unsafe)"); 78 else 79 seq_puts(s, "\t"); 80 81 if (req->r_inode) { 82 seq_printf(s, " #%llx", ceph_ino(req->r_inode)); 83 } else if (req->r_dentry) { 84 path = ceph_mdsc_build_path(req->r_dentry, &pathlen, 85 &pathbase, 0); 86 if (IS_ERR(path)) 87 path = NULL; 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)), 91 req->r_dentry, 92 path ? path : ""); 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, 97 req->r_path1); 98 } else { 99 seq_printf(s, " #%llx", req->r_ino1.ino); 100 } 101 102 if (req->r_old_dentry) { 103 path = ceph_mdsc_build_path(req->r_old_dentry, &pathlen, 104 &pathbase, 0); 105 if (IS_ERR(path)) 106 path = NULL; 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, 111 req->r_old_dentry, 112 path ? path : ""); 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) { 116 if (req->r_ino2.ino) 117 seq_printf(s, " #%llx/%s", req->r_ino2.ino, 118 req->r_path2); 119 else 120 seq_printf(s, " %s", req->r_path2); 121 } 122 123 seq_puts(s, "\n"); 124 } 125 mutex_unlock(&mdsc->mutex); 126 127 return 0; 128 } 129 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); \ 141 } 142 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); \ 147 } 148 149 static int metrics_file_show(struct seq_file *s, void *p) 150 { 151 struct ceph_fs_client *fsc = s->private; 152 struct ceph_client_metric *m = &fsc->mdsc->metric; 153 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)); 164 return 0; 165 } 166 167 static const char * const metric_str[] = { 168 "read", 169 "write", 170 "metadata", 171 "copyfrom" 172 }; 173 static int metrics_latency_show(struct seq_file *s, void *p) 174 { 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; 179 int i; 180 181 seq_printf(s, "item total avg_lat(us) min_lat(us) max_lat(us) stdev(us)\n"); 182 seq_printf(s, "-----------------------------------------------------------------------------------\n"); 183 184 for (i = 0; i < METRIC_MAX; i++) { 185 m = &cm->metric[i]; 186 spin_lock(&m->lock); 187 total = m->total; 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); 194 } 195 196 return 0; 197 } 198 199 static int metrics_size_show(struct seq_file *s, void *p) 200 { 201 struct ceph_fs_client *fsc = s->private; 202 struct ceph_client_metric *cm = &fsc->mdsc->metric; 203 struct ceph_metric *m; 204 s64 total; 205 u64 sum, avg, min, max; 206 int i; 207 208 seq_printf(s, "item total avg_sz(bytes) min_sz(bytes) max_sz(bytes) total_sz(bytes)\n"); 209 seq_printf(s, "----------------------------------------------------------------------------------------\n"); 210 211 for (i = 0; i < METRIC_MAX; i++) { 212 /* skip 'metadata' as it doesn't use the size metric */ 213 if (i == METRIC_METADATA) 214 continue; 215 m = &cm->metric[i]; 216 spin_lock(&m->lock); 217 total = m->total; 218 sum = m->size_sum; 219 avg = total > 0 ? DIV64_U64_ROUND_CLOSEST(sum, total) : 0; 220 min = m->size_min; 221 max = m->size_max; 222 spin_unlock(&m->lock); 223 CEPH_SZ_METRIC_SHOW(metric_str[i], total, avg, min, max, sum); 224 } 225 226 return 0; 227 } 228 229 static int metrics_caps_show(struct seq_file *s, void *p) 230 { 231 struct ceph_fs_client *fsc = s->private; 232 struct ceph_client_metric *m = &fsc->mdsc->metric; 233 int nr_caps = 0; 234 235 seq_printf(s, "item total miss hit\n"); 236 seq_printf(s, "-------------------------------------------------\n"); 237 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)); 242 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)); 247 248 return 0; 249 } 250 251 static int caps_show_cb(struct inode *inode, struct ceph_cap *cap, void *p) 252 { 253 struct seq_file *s = p; 254 255 seq_printf(s, "0x%-17llx%-3d%-17s%-17s\n", ceph_ino(inode), 256 cap->session->s_mds, 257 ceph_cap_string(cap->issued), 258 ceph_cap_string(cap->implemented)); 259 return 0; 260 } 261 262 static int caps_show(struct seq_file *s, void *p) 263 { 264 struct ceph_fs_client *fsc = s->private; 265 struct ceph_mds_client *mdsc = fsc->mdsc; 266 int total, avail, used, reserved, min, i; 267 struct cap_wait *cw; 268 269 ceph_reservation_status(fsc, &total, &avail, &used, &reserved, &min); 270 seq_printf(s, "total\t\t%d\n" 271 "avail\t\t%d\n" 272 "used\t\t%d\n" 273 "reserved\t%d\n" 274 "min\t\t%d\n\n", 275 total, avail, used, reserved, min); 276 seq_printf(s, "ino mds issued implemented\n"); 277 seq_printf(s, "--------------------------------------------------\n"); 278 279 mutex_lock(&mdsc->mutex); 280 for (i = 0; i < mdsc->max_sessions; i++) { 281 struct ceph_mds_session *session; 282 283 session = __ceph_lookup_mds_session(mdsc, i); 284 if (!session) 285 continue; 286 mutex_unlock(&mdsc->mutex); 287 mutex_lock(&session->s_mutex); 288 ceph_iterate_session_caps(session, caps_show_cb, s); 289 mutex_unlock(&session->s_mutex); 290 ceph_put_mds_session(session); 291 mutex_lock(&mdsc->mutex); 292 } 293 mutex_unlock(&mdsc->mutex); 294 295 seq_printf(s, "\n\nWaiters:\n--------\n"); 296 seq_printf(s, "tgid ino need want\n"); 297 seq_printf(s, "-----------------------------------------------------\n"); 298 299 spin_lock(&mdsc->caps_list_lock); 300 list_for_each_entry(cw, &mdsc->cap_wait_list, list) { 301 seq_printf(s, "%-13d0x%-17llx%-17s%-17s\n", cw->tgid, cw->ino, 302 ceph_cap_string(cw->need), 303 ceph_cap_string(cw->want)); 304 } 305 spin_unlock(&mdsc->caps_list_lock); 306 307 return 0; 308 } 309 310 static int mds_sessions_show(struct seq_file *s, void *ptr) 311 { 312 struct ceph_fs_client *fsc = s->private; 313 struct ceph_mds_client *mdsc = fsc->mdsc; 314 struct ceph_auth_client *ac = fsc->client->monc.auth; 315 struct ceph_options *opt = fsc->client->options; 316 int mds; 317 318 mutex_lock(&mdsc->mutex); 319 320 /* The 'num' portion of an 'entity name' */ 321 seq_printf(s, "global_id %llu\n", ac->global_id); 322 323 /* The -o name mount argument */ 324 seq_printf(s, "name \"%s\"\n", opt->name ? opt->name : ""); 325 326 /* The list of MDS session rank+state */ 327 for (mds = 0; mds < mdsc->max_sessions; mds++) { 328 struct ceph_mds_session *session = 329 __ceph_lookup_mds_session(mdsc, mds); 330 if (!session) { 331 continue; 332 } 333 mutex_unlock(&mdsc->mutex); 334 seq_printf(s, "mds.%d %s\n", 335 session->s_mds, 336 ceph_session_state_name(session->s_state)); 337 338 ceph_put_mds_session(session); 339 mutex_lock(&mdsc->mutex); 340 } 341 mutex_unlock(&mdsc->mutex); 342 343 return 0; 344 } 345 346 static int status_show(struct seq_file *s, void *p) 347 { 348 struct ceph_fs_client *fsc = s->private; 349 struct ceph_entity_inst *inst = &fsc->client->msgr.inst; 350 struct ceph_entity_addr *client_addr = ceph_client_addr(fsc->client); 351 352 seq_printf(s, "instance: %s.%lld %s/%u\n", ENTITY_NAME(inst->name), 353 ceph_pr_addr(client_addr), le32_to_cpu(client_addr->nonce)); 354 seq_printf(s, "blocklisted: %s\n", fsc->blocklisted ? "true" : "false"); 355 356 return 0; 357 } 358 359 DEFINE_SHOW_ATTRIBUTE(mdsmap); 360 DEFINE_SHOW_ATTRIBUTE(mdsc); 361 DEFINE_SHOW_ATTRIBUTE(caps); 362 DEFINE_SHOW_ATTRIBUTE(mds_sessions); 363 DEFINE_SHOW_ATTRIBUTE(status); 364 DEFINE_SHOW_ATTRIBUTE(metrics_file); 365 DEFINE_SHOW_ATTRIBUTE(metrics_latency); 366 DEFINE_SHOW_ATTRIBUTE(metrics_size); 367 DEFINE_SHOW_ATTRIBUTE(metrics_caps); 368 369 370 /* 371 * debugfs 372 */ 373 static int congestion_kb_set(void *data, u64 val) 374 { 375 struct ceph_fs_client *fsc = (struct ceph_fs_client *)data; 376 377 fsc->mount_options->congestion_kb = (int)val; 378 return 0; 379 } 380 381 static int congestion_kb_get(void *data, u64 *val) 382 { 383 struct ceph_fs_client *fsc = (struct ceph_fs_client *)data; 384 385 *val = (u64)fsc->mount_options->congestion_kb; 386 return 0; 387 } 388 389 DEFINE_SIMPLE_ATTRIBUTE(congestion_kb_fops, congestion_kb_get, 390 congestion_kb_set, "%llu\n"); 391 392 393 void ceph_fs_debugfs_cleanup(struct ceph_fs_client *fsc) 394 { 395 dout("ceph_fs_debugfs_cleanup\n"); 396 debugfs_remove(fsc->debugfs_bdi); 397 debugfs_remove(fsc->debugfs_congestion_kb); 398 debugfs_remove(fsc->debugfs_mdsmap); 399 debugfs_remove(fsc->debugfs_mds_sessions); 400 debugfs_remove(fsc->debugfs_caps); 401 debugfs_remove(fsc->debugfs_status); 402 debugfs_remove(fsc->debugfs_mdsc); 403 debugfs_remove_recursive(fsc->debugfs_metrics_dir); 404 } 405 406 void ceph_fs_debugfs_init(struct ceph_fs_client *fsc) 407 { 408 char name[100]; 409 410 dout("ceph_fs_debugfs_init\n"); 411 fsc->debugfs_congestion_kb = 412 debugfs_create_file("writeback_congestion_kb", 413 0600, 414 fsc->client->debugfs_dir, 415 fsc, 416 &congestion_kb_fops); 417 418 snprintf(name, sizeof(name), "../../bdi/%s", 419 bdi_dev_name(fsc->sb->s_bdi)); 420 fsc->debugfs_bdi = 421 debugfs_create_symlink("bdi", 422 fsc->client->debugfs_dir, 423 name); 424 425 fsc->debugfs_mdsmap = debugfs_create_file("mdsmap", 426 0400, 427 fsc->client->debugfs_dir, 428 fsc, 429 &mdsmap_fops); 430 431 fsc->debugfs_mds_sessions = debugfs_create_file("mds_sessions", 432 0400, 433 fsc->client->debugfs_dir, 434 fsc, 435 &mds_sessions_fops); 436 437 fsc->debugfs_mdsc = debugfs_create_file("mdsc", 438 0400, 439 fsc->client->debugfs_dir, 440 fsc, 441 &mdsc_fops); 442 443 fsc->debugfs_caps = debugfs_create_file("caps", 444 0400, 445 fsc->client->debugfs_dir, 446 fsc, 447 &caps_fops); 448 449 fsc->debugfs_status = debugfs_create_file("status", 450 0400, 451 fsc->client->debugfs_dir, 452 fsc, 453 &status_fops); 454 455 fsc->debugfs_metrics_dir = debugfs_create_dir("metrics", 456 fsc->client->debugfs_dir); 457 458 debugfs_create_file("file", 0400, fsc->debugfs_metrics_dir, fsc, 459 &metrics_file_fops); 460 debugfs_create_file("latency", 0400, fsc->debugfs_metrics_dir, fsc, 461 &metrics_latency_fops); 462 debugfs_create_file("size", 0400, fsc->debugfs_metrics_dir, fsc, 463 &metrics_size_fops); 464 debugfs_create_file("caps", 0400, fsc->debugfs_metrics_dir, fsc, 465 &metrics_caps_fops); 466 } 467 468 469 #else /* CONFIG_DEBUG_FS */ 470 471 void ceph_fs_debugfs_init(struct ceph_fs_client *fsc) 472 { 473 } 474 475 void ceph_fs_debugfs_cleanup(struct ceph_fs_client *fsc) 476 { 477 } 478 479 #endif /* CONFIG_DEBUG_FS */ 480