xref: /freebsd/sys/contrib/openzfs/module/zfs/dbuf_stats.c (revision 61145dc2b94f12f6a47344fb9aac702321880e43)
1 // SPDX-License-Identifier: CDDL-1.0
2 /*
3  * CDDL HEADER START
4  *
5  * The contents of this file are subject to the terms of the
6  * Common Development and Distribution License (the "License").
7  * You may not use this file except in compliance with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or https://opensource.org/licenses/CDDL-1.0.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 
23 #include <sys/zfs_context.h>
24 #include <sys/dbuf.h>
25 #include <sys/dmu_objset.h>
26 
27 /*
28  * Calculate the index of the arc header for the state, disabled by default.
29  */
30 int zfs_dbuf_state_index = 0;
31 
32 /*
33  * ==========================================================================
34  * Dbuf Hash Read Routines
35  * ==========================================================================
36  */
37 typedef struct dbuf_stats_t {
38 	kmutex_t		lock;
39 	kstat_t			*kstat;
40 	dbuf_hash_table_t	*hash;
41 	int			idx;
42 } dbuf_stats_t;
43 
44 static dbuf_stats_t dbuf_stats_hash_table;
45 
46 static int
dbuf_stats_hash_table_headers(char * buf,size_t size)47 dbuf_stats_hash_table_headers(char *buf, size_t size)
48 {
49 	(void) snprintf(buf, size,
50 	    "%-105s | %-119s | %s\n"
51 	    "%-16s %-8s %-8s %-8s %-8s %-10s %-8s %-8s %-5s %-5s %-7s %3s | "
52 	    "%-5s %-5s %-9s %-6s %-8s %-12s "
53 	    "%-6s %-6s %-6s %-6s %-6s %-8s %-8s %-8s %-6s | "
54 	    "%-6s %-6s %-8s %-8s %-6s %-6s %-6s %-8s %-8s\n",
55 	    "dbuf", "arcbuf", "dnode", "pool", "objset", "object", "level",
56 	    "blkid", "offset", "dbsize", "usize", "meta", "state", "dbholds",
57 	    "dbc", "list", "atype", "flags", "count", "asize", "access",
58 	    "mru", "gmru", "mfu", "gmfu", "l2", "l2_dattr", "l2_asize",
59 	    "l2_comp", "aholds", "dtype", "btype", "data_bs", "meta_bs",
60 	    "bsize", "lvls", "dholds", "blocks", "dsize");
61 
62 	return (0);
63 }
64 
65 static int
__dbuf_stats_hash_table_data(char * buf,size_t size,dmu_buf_impl_t * db)66 __dbuf_stats_hash_table_data(char *buf, size_t size, dmu_buf_impl_t *db)
67 {
68 	arc_buf_info_t abi = { 0 };
69 	dmu_object_info_t doi = { 0 };
70 	dnode_t *dn = DB_DNODE(db);
71 	size_t nwritten;
72 
73 	if (db->db_buf)
74 		arc_buf_info(db->db_buf, &abi, zfs_dbuf_state_index);
75 
76 	__dmu_object_info_from_dnode(dn, &doi);
77 
78 	nwritten = snprintf(buf, size,
79 	    "%-16s %-8llu %-8lld %-8lld %-8lld %-10llu %-8llu %-8llu "
80 	    "%-5d %-5d %-7lu %-3d | %-5d %-5d 0x%-7x %-6lu %-8llu %-12llu "
81 	    "%-6lu %-6lu %-6lu %-6lu %-6lu %-8llu %-8llu %-8d %-6lu | "
82 	    "%-6d %-6d %-8lu %-8lu %-6llu %-6lu %-6lu %-8llu %-8llu\n",
83 	    /* dmu_buf_impl_t */
84 	    spa_name(dn->dn_objset->os_spa),
85 	    (u_longlong_t)dmu_objset_id(db->db_objset),
86 	    (longlong_t)db->db.db_object,
87 	    (longlong_t)db->db_level,
88 	    (longlong_t)db->db_blkid,
89 	    (u_longlong_t)db->db.db_offset,
90 	    (u_longlong_t)db->db.db_size,
91 	    (u_longlong_t)dmu_buf_user_size(&db->db),
92 	    !!dbuf_is_metadata(db),
93 	    db->db_state,
94 	    (ulong_t)zfs_refcount_count(&db->db_holds),
95 	    multilist_link_active(&db->db_cache_link),
96 	    /* arc_buf_info_t */
97 	    abi.abi_state_type,
98 	    abi.abi_state_contents,
99 	    abi.abi_flags,
100 	    (ulong_t)abi.abi_bufcnt,
101 	    (u_longlong_t)abi.abi_size,
102 	    (u_longlong_t)abi.abi_access,
103 	    (ulong_t)abi.abi_mru_hits,
104 	    (ulong_t)abi.abi_mru_ghost_hits,
105 	    (ulong_t)abi.abi_mfu_hits,
106 	    (ulong_t)abi.abi_mfu_ghost_hits,
107 	    (ulong_t)abi.abi_l2arc_hits,
108 	    (u_longlong_t)abi.abi_l2arc_dattr,
109 	    (u_longlong_t)abi.abi_l2arc_asize,
110 	    abi.abi_l2arc_compress,
111 	    (ulong_t)abi.abi_holds,
112 	    /* dmu_object_info_t */
113 	    doi.doi_type,
114 	    doi.doi_bonus_type,
115 	    (ulong_t)doi.doi_data_block_size,
116 	    (ulong_t)doi.doi_metadata_block_size,
117 	    (u_longlong_t)doi.doi_bonus_size,
118 	    (ulong_t)doi.doi_indirection,
119 	    (ulong_t)zfs_refcount_count(&dn->dn_holds),
120 	    (u_longlong_t)doi.doi_fill_count,
121 	    (u_longlong_t)doi.doi_max_offset);
122 
123 	if (nwritten >= size)
124 		return (size);
125 
126 	return (nwritten + 1);
127 }
128 
129 static int
dbuf_stats_hash_table_data(char * buf,size_t size,void * data)130 dbuf_stats_hash_table_data(char *buf, size_t size, void *data)
131 {
132 	dbuf_stats_t *dsh = (dbuf_stats_t *)data;
133 	dbuf_hash_table_t *h = dsh->hash;
134 	dmu_buf_impl_t *db;
135 	int length, error = 0;
136 
137 	ASSERT3S(dsh->idx, >=, 0);
138 	ASSERT3S(dsh->idx, <=, h->hash_table_mask);
139 	if (size)
140 		buf[0] = 0;
141 
142 	mutex_enter(DBUF_HASH_MUTEX(h, dsh->idx));
143 	for (db = h->hash_table[dsh->idx]; db != NULL; db = db->db_hash_next) {
144 		/*
145 		 * Returning ENOMEM will cause the data and header functions
146 		 * to be called with a larger scratch buffers.
147 		 */
148 		if (size < 512) {
149 			error = SET_ERROR(ENOMEM);
150 			break;
151 		}
152 
153 		mutex_enter(&db->db_mtx);
154 
155 		if (db->db_state != DB_EVICTING) {
156 			length = __dbuf_stats_hash_table_data(buf, size, db);
157 			buf += length;
158 			size -= length;
159 		}
160 
161 		mutex_exit(&db->db_mtx);
162 	}
163 	mutex_exit(DBUF_HASH_MUTEX(h, dsh->idx));
164 
165 	return (error);
166 }
167 
168 static void *
dbuf_stats_hash_table_addr(kstat_t * ksp,loff_t n)169 dbuf_stats_hash_table_addr(kstat_t *ksp, loff_t n)
170 {
171 	dbuf_stats_t *dsh = ksp->ks_private;
172 
173 	ASSERT(MUTEX_HELD(&dsh->lock));
174 
175 	if (n <= dsh->hash->hash_table_mask) {
176 		dsh->idx = n;
177 		return (dsh);
178 	}
179 
180 	return (NULL);
181 }
182 
183 static void
dbuf_stats_hash_table_init(dbuf_hash_table_t * hash)184 dbuf_stats_hash_table_init(dbuf_hash_table_t *hash)
185 {
186 	dbuf_stats_t *dsh = &dbuf_stats_hash_table;
187 	kstat_t *ksp;
188 
189 	mutex_init(&dsh->lock, NULL, MUTEX_DEFAULT, NULL);
190 	dsh->hash = hash;
191 
192 	ksp = kstat_create("zfs", 0, "dbufs", "misc",
193 	    KSTAT_TYPE_RAW, 0, KSTAT_FLAG_VIRTUAL);
194 	dsh->kstat = ksp;
195 
196 	if (ksp) {
197 		ksp->ks_lock = &dsh->lock;
198 		ksp->ks_ndata = UINT32_MAX;
199 		ksp->ks_private = dsh;
200 		kstat_set_raw_ops(ksp, dbuf_stats_hash_table_headers,
201 		    dbuf_stats_hash_table_data, dbuf_stats_hash_table_addr);
202 		kstat_install(ksp);
203 	}
204 }
205 
206 static void
dbuf_stats_hash_table_destroy(void)207 dbuf_stats_hash_table_destroy(void)
208 {
209 	dbuf_stats_t *dsh = &dbuf_stats_hash_table;
210 	kstat_t *ksp;
211 
212 	ksp = dsh->kstat;
213 	if (ksp)
214 		kstat_delete(ksp);
215 
216 	mutex_destroy(&dsh->lock);
217 }
218 
219 void
dbuf_stats_init(dbuf_hash_table_t * hash)220 dbuf_stats_init(dbuf_hash_table_t *hash)
221 {
222 	dbuf_stats_hash_table_init(hash);
223 }
224 
225 void
dbuf_stats_destroy(void)226 dbuf_stats_destroy(void)
227 {
228 	dbuf_stats_hash_table_destroy();
229 }
230 
231 ZFS_MODULE_PARAM(zfs, zfs_, dbuf_state_index, INT, ZMOD_RW,
232 	"Calculate arc header index");
233