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, sum, 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 sum = m->latency_sum; 189 avg = total > 0 ? DIV64_U64_ROUND_CLOSEST(sum, total) : 0; 190 min = m->latency_min; 191 max = m->latency_max; 192 sq = m->latency_sq_sum; 193 spin_unlock(&m->lock); 194 CEPH_LAT_METRIC_SHOW(metric_str[i], total, avg, min, max, sq); 195 } 196 197 return 0; 198 } 199 200 static int metrics_size_show(struct seq_file *s, void *p) 201 { 202 struct ceph_fs_client *fsc = s->private; 203 struct ceph_client_metric *cm = &fsc->mdsc->metric; 204 struct ceph_metric *m; 205 s64 total; 206 u64 sum, avg, min, max; 207 int i; 208 209 seq_printf(s, "item total avg_sz(bytes) min_sz(bytes) max_sz(bytes) total_sz(bytes)\n"); 210 seq_printf(s, "----------------------------------------------------------------------------------------\n"); 211 212 for (i = 0; i < METRIC_MAX; i++) { 213 /* skip 'metadata' as it doesn't use the size metric */ 214 if (i == METRIC_METADATA) 215 continue; 216 m = &cm->metric[i]; 217 spin_lock(&m->lock); 218 total = m->total; 219 sum = m->size_sum; 220 avg = total > 0 ? DIV64_U64_ROUND_CLOSEST(sum, total) : 0; 221 min = m->size_min; 222 max = m->size_max; 223 spin_unlock(&m->lock); 224 CEPH_SZ_METRIC_SHOW(metric_str[i], total, avg, min, max, sum); 225 } 226 227 return 0; 228 } 229 230 static int metrics_caps_show(struct seq_file *s, void *p) 231 { 232 struct ceph_fs_client *fsc = s->private; 233 struct ceph_client_metric *m = &fsc->mdsc->metric; 234 int nr_caps = 0; 235 236 seq_printf(s, "item total miss hit\n"); 237 seq_printf(s, "-------------------------------------------------\n"); 238 239 seq_printf(s, "%-14s%-16lld%-16lld%lld\n", "d_lease", 240 atomic64_read(&m->total_dentries), 241 percpu_counter_sum(&m->d_lease_mis), 242 percpu_counter_sum(&m->d_lease_hit)); 243 244 nr_caps = atomic64_read(&m->total_caps); 245 seq_printf(s, "%-14s%-16d%-16lld%lld\n", "caps", nr_caps, 246 percpu_counter_sum(&m->i_caps_mis), 247 percpu_counter_sum(&m->i_caps_hit)); 248 249 return 0; 250 } 251 252 static int caps_show_cb(struct inode *inode, struct ceph_cap *cap, void *p) 253 { 254 struct seq_file *s = p; 255 256 seq_printf(s, "0x%-17llx%-3d%-17s%-17s\n", ceph_ino(inode), 257 cap->session->s_mds, 258 ceph_cap_string(cap->issued), 259 ceph_cap_string(cap->implemented)); 260 return 0; 261 } 262 263 static int caps_show(struct seq_file *s, void *p) 264 { 265 struct ceph_fs_client *fsc = s->private; 266 struct ceph_mds_client *mdsc = fsc->mdsc; 267 int total, avail, used, reserved, min, i; 268 struct cap_wait *cw; 269 270 ceph_reservation_status(fsc, &total, &avail, &used, &reserved, &min); 271 seq_printf(s, "total\t\t%d\n" 272 "avail\t\t%d\n" 273 "used\t\t%d\n" 274 "reserved\t%d\n" 275 "min\t\t%d\n\n", 276 total, avail, used, reserved, min); 277 seq_printf(s, "ino mds issued implemented\n"); 278 seq_printf(s, "--------------------------------------------------\n"); 279 280 mutex_lock(&mdsc->mutex); 281 for (i = 0; i < mdsc->max_sessions; i++) { 282 struct ceph_mds_session *session; 283 284 session = __ceph_lookup_mds_session(mdsc, i); 285 if (!session) 286 continue; 287 mutex_unlock(&mdsc->mutex); 288 mutex_lock(&session->s_mutex); 289 ceph_iterate_session_caps(session, caps_show_cb, s); 290 mutex_unlock(&session->s_mutex); 291 ceph_put_mds_session(session); 292 mutex_lock(&mdsc->mutex); 293 } 294 mutex_unlock(&mdsc->mutex); 295 296 seq_printf(s, "\n\nWaiters:\n--------\n"); 297 seq_printf(s, "tgid ino need want\n"); 298 seq_printf(s, "-----------------------------------------------------\n"); 299 300 spin_lock(&mdsc->caps_list_lock); 301 list_for_each_entry(cw, &mdsc->cap_wait_list, list) { 302 seq_printf(s, "%-13d0x%-17llx%-17s%-17s\n", cw->tgid, cw->ino, 303 ceph_cap_string(cw->need), 304 ceph_cap_string(cw->want)); 305 } 306 spin_unlock(&mdsc->caps_list_lock); 307 308 return 0; 309 } 310 311 static int mds_sessions_show(struct seq_file *s, void *ptr) 312 { 313 struct ceph_fs_client *fsc = s->private; 314 struct ceph_mds_client *mdsc = fsc->mdsc; 315 struct ceph_auth_client *ac = fsc->client->monc.auth; 316 struct ceph_options *opt = fsc->client->options; 317 int mds; 318 319 mutex_lock(&mdsc->mutex); 320 321 /* The 'num' portion of an 'entity name' */ 322 seq_printf(s, "global_id %llu\n", ac->global_id); 323 324 /* The -o name mount argument */ 325 seq_printf(s, "name \"%s\"\n", opt->name ? opt->name : ""); 326 327 /* The list of MDS session rank+state */ 328 for (mds = 0; mds < mdsc->max_sessions; mds++) { 329 struct ceph_mds_session *session = 330 __ceph_lookup_mds_session(mdsc, mds); 331 if (!session) { 332 continue; 333 } 334 mutex_unlock(&mdsc->mutex); 335 seq_printf(s, "mds.%d %s\n", 336 session->s_mds, 337 ceph_session_state_name(session->s_state)); 338 339 ceph_put_mds_session(session); 340 mutex_lock(&mdsc->mutex); 341 } 342 mutex_unlock(&mdsc->mutex); 343 344 return 0; 345 } 346 347 static int status_show(struct seq_file *s, void *p) 348 { 349 struct ceph_fs_client *fsc = s->private; 350 struct ceph_entity_inst *inst = &fsc->client->msgr.inst; 351 struct ceph_entity_addr *client_addr = ceph_client_addr(fsc->client); 352 353 seq_printf(s, "instance: %s.%lld %s/%u\n", ENTITY_NAME(inst->name), 354 ceph_pr_addr(client_addr), le32_to_cpu(client_addr->nonce)); 355 seq_printf(s, "blocklisted: %s\n", fsc->blocklisted ? "true" : "false"); 356 357 return 0; 358 } 359 360 DEFINE_SHOW_ATTRIBUTE(mdsmap); 361 DEFINE_SHOW_ATTRIBUTE(mdsc); 362 DEFINE_SHOW_ATTRIBUTE(caps); 363 DEFINE_SHOW_ATTRIBUTE(mds_sessions); 364 DEFINE_SHOW_ATTRIBUTE(status); 365 DEFINE_SHOW_ATTRIBUTE(metrics_file); 366 DEFINE_SHOW_ATTRIBUTE(metrics_latency); 367 DEFINE_SHOW_ATTRIBUTE(metrics_size); 368 DEFINE_SHOW_ATTRIBUTE(metrics_caps); 369 370 371 /* 372 * debugfs 373 */ 374 static int congestion_kb_set(void *data, u64 val) 375 { 376 struct ceph_fs_client *fsc = (struct ceph_fs_client *)data; 377 378 fsc->mount_options->congestion_kb = (int)val; 379 return 0; 380 } 381 382 static int congestion_kb_get(void *data, u64 *val) 383 { 384 struct ceph_fs_client *fsc = (struct ceph_fs_client *)data; 385 386 *val = (u64)fsc->mount_options->congestion_kb; 387 return 0; 388 } 389 390 DEFINE_SIMPLE_ATTRIBUTE(congestion_kb_fops, congestion_kb_get, 391 congestion_kb_set, "%llu\n"); 392 393 394 void ceph_fs_debugfs_cleanup(struct ceph_fs_client *fsc) 395 { 396 dout("ceph_fs_debugfs_cleanup\n"); 397 debugfs_remove(fsc->debugfs_bdi); 398 debugfs_remove(fsc->debugfs_congestion_kb); 399 debugfs_remove(fsc->debugfs_mdsmap); 400 debugfs_remove(fsc->debugfs_mds_sessions); 401 debugfs_remove(fsc->debugfs_caps); 402 debugfs_remove(fsc->debugfs_status); 403 debugfs_remove(fsc->debugfs_mdsc); 404 debugfs_remove_recursive(fsc->debugfs_metrics_dir); 405 } 406 407 void ceph_fs_debugfs_init(struct ceph_fs_client *fsc) 408 { 409 char name[100]; 410 411 dout("ceph_fs_debugfs_init\n"); 412 fsc->debugfs_congestion_kb = 413 debugfs_create_file("writeback_congestion_kb", 414 0600, 415 fsc->client->debugfs_dir, 416 fsc, 417 &congestion_kb_fops); 418 419 snprintf(name, sizeof(name), "../../bdi/%s", 420 bdi_dev_name(fsc->sb->s_bdi)); 421 fsc->debugfs_bdi = 422 debugfs_create_symlink("bdi", 423 fsc->client->debugfs_dir, 424 name); 425 426 fsc->debugfs_mdsmap = debugfs_create_file("mdsmap", 427 0400, 428 fsc->client->debugfs_dir, 429 fsc, 430 &mdsmap_fops); 431 432 fsc->debugfs_mds_sessions = debugfs_create_file("mds_sessions", 433 0400, 434 fsc->client->debugfs_dir, 435 fsc, 436 &mds_sessions_fops); 437 438 fsc->debugfs_mdsc = debugfs_create_file("mdsc", 439 0400, 440 fsc->client->debugfs_dir, 441 fsc, 442 &mdsc_fops); 443 444 fsc->debugfs_caps = debugfs_create_file("caps", 445 0400, 446 fsc->client->debugfs_dir, 447 fsc, 448 &caps_fops); 449 450 fsc->debugfs_status = debugfs_create_file("status", 451 0400, 452 fsc->client->debugfs_dir, 453 fsc, 454 &status_fops); 455 456 fsc->debugfs_metrics_dir = debugfs_create_dir("metrics", 457 fsc->client->debugfs_dir); 458 459 debugfs_create_file("file", 0400, fsc->debugfs_metrics_dir, fsc, 460 &metrics_file_fops); 461 debugfs_create_file("latency", 0400, fsc->debugfs_metrics_dir, fsc, 462 &metrics_latency_fops); 463 debugfs_create_file("size", 0400, fsc->debugfs_metrics_dir, fsc, 464 &metrics_size_fops); 465 debugfs_create_file("caps", 0400, fsc->debugfs_metrics_dir, fsc, 466 &metrics_caps_fops); 467 } 468 469 470 #else /* CONFIG_DEBUG_FS */ 471 472 void ceph_fs_debugfs_init(struct ceph_fs_client *fsc) 473 { 474 } 475 476 void ceph_fs_debugfs_cleanup(struct ceph_fs_client *fsc) 477 { 478 } 479 480 #endif /* CONFIG_DEBUG_FS */ 481