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