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