99#include <linux/seq_file.h>
1010#include <linux/math64.h>
1111#include <linux/ktime.h>
12+ #include <linux/atomic.h>
1213
1314#include <linux/ceph/libceph.h>
1415#include <linux/ceph/mon_client.h>
1516#include <linux/ceph/auth.h>
1617#include <linux/ceph/debugfs.h>
18+ #include <linux/ceph/decode.h>
1719
1820#include "super.h"
1921
2022#ifdef CONFIG_DEBUG_FS
2123
2224#include "mds_client.h"
2325#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+ };
2456
2557static int mdsmap_show (struct seq_file * s , void * p )
2658{
@@ -360,6 +392,59 @@ static int status_show(struct seq_file *s, void *p)
360392 return 0 ;
361393}
362394
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+
363448DEFINE_SHOW_ATTRIBUTE (mdsmap );
364449DEFINE_SHOW_ATTRIBUTE (mdsc );
365450DEFINE_SHOW_ATTRIBUTE (caps );
@@ -369,7 +454,72 @@ DEFINE_SHOW_ATTRIBUTE(metrics_file);
369454DEFINE_SHOW_ATTRIBUTE (metrics_latency );
370455DEFINE_SHOW_ATTRIBUTE (metrics_size );
371456DEFINE_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+ }
372521
522+ DEFINE_SHOW_ATTRIBUTE (metric_features );
373523
374524/*
375525 * debugfs
@@ -404,6 +554,7 @@ void ceph_fs_debugfs_cleanup(struct ceph_fs_client *fsc)
404554 debugfs_remove (fsc -> debugfs_caps );
405555 debugfs_remove (fsc -> debugfs_status );
406556 debugfs_remove (fsc -> debugfs_mdsc );
557+ debugfs_remove (fsc -> debugfs_subvolume_metrics );
407558 debugfs_remove_recursive (fsc -> debugfs_metrics_dir );
408559 doutc (fsc -> client , "done\n" );
409560}
@@ -468,6 +619,12 @@ void ceph_fs_debugfs_init(struct ceph_fs_client *fsc)
468619 & metrics_size_fops );
469620 debugfs_create_file ("caps" , 0400 , fsc -> debugfs_metrics_dir , fsc ,
470621 & 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 );
471628 doutc (fsc -> client , "done\n" );
472629}
473630
0 commit comments