11/* SPDX-License-Identifier: GPL-2.0 */
2+ #include <linux/ceph/ceph_debug.h>
23
34#include <linux/types.h>
45#include <linux/percpu_counter.h>
56#include <linux/math64.h>
67
78#include "metric.h"
9+ #include "mds_client.h"
10+
11+ static bool ceph_mdsc_send_metrics (struct ceph_mds_client * mdsc ,
12+ struct ceph_mds_session * s )
13+ {
14+ struct ceph_metric_head * head ;
15+ struct ceph_metric_cap * cap ;
16+ struct ceph_metric_read_latency * read ;
17+ struct ceph_metric_write_latency * write ;
18+ struct ceph_metric_metadata_latency * meta ;
19+ struct ceph_client_metric * m = & mdsc -> metric ;
20+ u64 nr_caps = atomic64_read (& m -> total_caps );
21+ struct ceph_msg * msg ;
22+ struct timespec64 ts ;
23+ s64 sum ;
24+ s32 items = 0 ;
25+ s32 len ;
26+
27+ len = sizeof (* head ) + sizeof (* cap ) + sizeof (* read ) + sizeof (* write )
28+ + sizeof (* meta );
29+
30+ msg = ceph_msg_new (CEPH_MSG_CLIENT_METRICS , len , GFP_NOFS , true);
31+ if (!msg ) {
32+ pr_err ("send metrics to mds%d, failed to allocate message\n" ,
33+ s -> s_mds );
34+ return false;
35+ }
36+
37+ head = msg -> front .iov_base ;
38+
39+ /* encode the cap metric */
40+ cap = (struct ceph_metric_cap * )(head + 1 );
41+ cap -> type = cpu_to_le32 (CLIENT_METRIC_TYPE_CAP_INFO );
42+ cap -> ver = 1 ;
43+ cap -> compat = 1 ;
44+ cap -> data_len = cpu_to_le32 (sizeof (* cap ) - 10 );
45+ cap -> hit = cpu_to_le64 (percpu_counter_sum (& mdsc -> metric .i_caps_hit ));
46+ cap -> mis = cpu_to_le64 (percpu_counter_sum (& mdsc -> metric .i_caps_mis ));
47+ cap -> total = cpu_to_le64 (nr_caps );
48+ items ++ ;
49+
50+ /* encode the read latency metric */
51+ read = (struct ceph_metric_read_latency * )(cap + 1 );
52+ read -> type = cpu_to_le32 (CLIENT_METRIC_TYPE_READ_LATENCY );
53+ read -> ver = 1 ;
54+ read -> compat = 1 ;
55+ read -> data_len = cpu_to_le32 (sizeof (* read ) - 10 );
56+ sum = m -> read_latency_sum ;
57+ jiffies_to_timespec64 (sum , & ts );
58+ read -> sec = cpu_to_le32 (ts .tv_sec );
59+ read -> nsec = cpu_to_le32 (ts .tv_nsec );
60+ items ++ ;
61+
62+ /* encode the write latency metric */
63+ write = (struct ceph_metric_write_latency * )(read + 1 );
64+ write -> type = cpu_to_le32 (CLIENT_METRIC_TYPE_WRITE_LATENCY );
65+ write -> ver = 1 ;
66+ write -> compat = 1 ;
67+ write -> data_len = cpu_to_le32 (sizeof (* write ) - 10 );
68+ sum = m -> write_latency_sum ;
69+ jiffies_to_timespec64 (sum , & ts );
70+ write -> sec = cpu_to_le32 (ts .tv_sec );
71+ write -> nsec = cpu_to_le32 (ts .tv_nsec );
72+ items ++ ;
73+
74+ /* encode the metadata latency metric */
75+ meta = (struct ceph_metric_metadata_latency * )(write + 1 );
76+ meta -> type = cpu_to_le32 (CLIENT_METRIC_TYPE_METADATA_LATENCY );
77+ meta -> ver = 1 ;
78+ meta -> compat = 1 ;
79+ meta -> data_len = cpu_to_le32 (sizeof (* meta ) - 10 );
80+ sum = m -> metadata_latency_sum ;
81+ jiffies_to_timespec64 (sum , & ts );
82+ meta -> sec = cpu_to_le32 (ts .tv_sec );
83+ meta -> nsec = cpu_to_le32 (ts .tv_nsec );
84+ items ++ ;
85+
86+ put_unaligned_le32 (items , & head -> num );
87+ msg -> front .iov_len = len ;
88+ msg -> hdr .version = cpu_to_le16 (1 );
89+ msg -> hdr .compat_version = cpu_to_le16 (1 );
90+ msg -> hdr .front_len = cpu_to_le32 (msg -> front .iov_len );
91+ dout ("client%llu send metrics to mds%d\n" ,
92+ ceph_client_gid (mdsc -> fsc -> client ), s -> s_mds );
93+ ceph_con_send (& s -> s_con , msg );
94+
95+ return true;
96+ }
97+
98+
99+ static void metric_get_session (struct ceph_mds_client * mdsc )
100+ {
101+ struct ceph_mds_session * s ;
102+ int i ;
103+
104+ mutex_lock (& mdsc -> mutex );
105+ for (i = 0 ; i < mdsc -> max_sessions ; i ++ ) {
106+ s = __ceph_lookup_mds_session (mdsc , i );
107+ if (!s )
108+ continue ;
109+
110+ /*
111+ * Skip it if MDS doesn't support the metric collection,
112+ * or the MDS will close the session's socket connection
113+ * directly when it get this message.
114+ */
115+ if (check_session_state (s ) &&
116+ test_bit (CEPHFS_FEATURE_METRIC_COLLECT , & s -> s_features )) {
117+ mdsc -> metric .session = s ;
118+ break ;
119+ }
120+
121+ ceph_put_mds_session (s );
122+ }
123+ mutex_unlock (& mdsc -> mutex );
124+ }
125+
126+ static void metric_delayed_work (struct work_struct * work )
127+ {
128+ struct ceph_client_metric * m =
129+ container_of (work , struct ceph_client_metric , delayed_work .work );
130+ struct ceph_mds_client * mdsc =
131+ container_of (m , struct ceph_mds_client , metric );
132+
133+ if (mdsc -> stopping )
134+ return ;
135+
136+ if (!m -> session || !check_session_state (m -> session )) {
137+ if (m -> session ) {
138+ ceph_put_mds_session (m -> session );
139+ m -> session = NULL ;
140+ }
141+ metric_get_session (mdsc );
142+ }
143+ if (m -> session ) {
144+ ceph_mdsc_send_metrics (mdsc , m -> session );
145+ metric_schedule_delayed (m );
146+ }
147+ }
8148
9149int ceph_metric_init (struct ceph_client_metric * m )
10150{
@@ -52,6 +192,9 @@ int ceph_metric_init(struct ceph_client_metric *m)
52192 m -> total_metadatas = 0 ;
53193 m -> metadata_latency_sum = 0 ;
54194
195+ m -> session = NULL ;
196+ INIT_DELAYED_WORK (& m -> delayed_work , metric_delayed_work );
197+
55198 return 0 ;
56199
57200err_i_caps_mis :
@@ -73,6 +216,11 @@ void ceph_metric_destroy(struct ceph_client_metric *m)
73216 percpu_counter_destroy (& m -> i_caps_hit );
74217 percpu_counter_destroy (& m -> d_lease_mis );
75218 percpu_counter_destroy (& m -> d_lease_hit );
219+
220+ cancel_delayed_work_sync (& m -> delayed_work );
221+
222+ if (m -> session )
223+ ceph_put_mds_session (m -> session );
76224}
77225
78226static inline void __update_latency (ktime_t * totalp , ktime_t * lsump ,
0 commit comments