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 /* 24 * Copyright (c) 2018 by Delphix. All rights reserved. 25 * Copyright (c) 2018 Datto Inc. 26 */ 27 28 #include <sys/dataset_kstats.h> 29 #include <sys/dmu_objset.h> 30 #include <sys/dsl_dataset.h> 31 #include <sys/spa.h> 32 33 static dataset_kstat_values_t empty_dataset_kstats = { 34 { "dataset_name", KSTAT_DATA_STRING }, 35 { "writes", KSTAT_DATA_UINT64 }, 36 { "nwritten", KSTAT_DATA_UINT64 }, 37 { "reads", KSTAT_DATA_UINT64 }, 38 { "nread", KSTAT_DATA_UINT64 }, 39 { "nunlinks", KSTAT_DATA_UINT64 }, 40 { "nunlinked", KSTAT_DATA_UINT64 }, 41 { 42 { "zil_commit_count", KSTAT_DATA_UINT64 }, 43 { "zil_commit_writer_count", KSTAT_DATA_UINT64 }, 44 { "zil_commit_error_count", KSTAT_DATA_UINT64 }, 45 { "zil_commit_stall_count", KSTAT_DATA_UINT64 }, 46 { "zil_commit_suspend_count", KSTAT_DATA_UINT64 }, 47 { "zil_commit_crash_count", KSTAT_DATA_UINT64 }, 48 { "zil_itx_count", KSTAT_DATA_UINT64 }, 49 { "zil_itx_indirect_count", KSTAT_DATA_UINT64 }, 50 { "zil_itx_indirect_bytes", KSTAT_DATA_UINT64 }, 51 { "zil_itx_copied_count", KSTAT_DATA_UINT64 }, 52 { "zil_itx_copied_bytes", KSTAT_DATA_UINT64 }, 53 { "zil_itx_needcopy_count", KSTAT_DATA_UINT64 }, 54 { "zil_itx_needcopy_bytes", KSTAT_DATA_UINT64 }, 55 { "zil_itx_metaslab_normal_count", KSTAT_DATA_UINT64 }, 56 { "zil_itx_metaslab_normal_bytes", KSTAT_DATA_UINT64 }, 57 { "zil_itx_metaslab_normal_write", KSTAT_DATA_UINT64 }, 58 { "zil_itx_metaslab_normal_alloc", KSTAT_DATA_UINT64 }, 59 { "zil_itx_metaslab_slog_count", KSTAT_DATA_UINT64 }, 60 { "zil_itx_metaslab_slog_bytes", KSTAT_DATA_UINT64 }, 61 { "zil_itx_metaslab_slog_write", KSTAT_DATA_UINT64 }, 62 { "zil_itx_metaslab_slog_alloc", KSTAT_DATA_UINT64 } 63 } 64 }; 65 66 static int 67 dataset_kstats_update(kstat_t *ksp, int rw) 68 { 69 dataset_kstats_t *dk = ksp->ks_private; 70 dataset_kstat_values_t *dkv = ksp->ks_data; 71 ASSERT3P(dk->dk_kstats->ks_data, ==, dkv); 72 73 if (rw == KSTAT_WRITE) 74 return (EACCES); 75 76 dkv->dkv_writes.value.ui64 = 77 wmsum_value(&dk->dk_sums.dss_writes); 78 dkv->dkv_nwritten.value.ui64 = 79 wmsum_value(&dk->dk_sums.dss_nwritten); 80 dkv->dkv_reads.value.ui64 = 81 wmsum_value(&dk->dk_sums.dss_reads); 82 dkv->dkv_nread.value.ui64 = 83 wmsum_value(&dk->dk_sums.dss_nread); 84 dkv->dkv_nunlinks.value.ui64 = 85 wmsum_value(&dk->dk_sums.dss_nunlinks); 86 dkv->dkv_nunlinked.value.ui64 = 87 wmsum_value(&dk->dk_sums.dss_nunlinked); 88 89 zil_kstat_values_update(&dkv->dkv_zil_stats, &dk->dk_zil_sums); 90 91 return (0); 92 } 93 94 int 95 dataset_kstats_create(dataset_kstats_t *dk, objset_t *objset) 96 { 97 /* 98 * There should not be anything wrong with having kstats for 99 * snapshots. Since we are not sure how useful they would be 100 * though nor how much their memory overhead would matter in 101 * a filesystem with many snapshots, we skip them for now. 102 */ 103 if (dmu_objset_is_snapshot(objset)) 104 return (0); 105 106 /* 107 * At the time of this writing, KSTAT_STRLEN is 255 in Linux, 108 * and the spa_name can theoretically be up to 256 characters. 109 * In reality though the spa_name can be 240 characters max 110 * [see origin directory name check in pool_namecheck()]. Thus, 111 * the naming scheme for the module name below should not cause 112 * any truncations. In the event that a truncation does happen 113 * though, due to some future change, we silently skip creating 114 * the kstat and log the event. 115 */ 116 char kstat_module_name[KSTAT_STRLEN]; 117 int n = snprintf(kstat_module_name, sizeof (kstat_module_name), 118 "zfs/%s", spa_name(dmu_objset_spa(objset))); 119 if (n < 0) { 120 zfs_dbgmsg("failed to create dataset kstat for objset %lld: " 121 " snprintf() for kstat module name returned %d", 122 (unsigned long long)dmu_objset_id(objset), n); 123 return (SET_ERROR(EINVAL)); 124 } else if (n >= KSTAT_STRLEN) { 125 zfs_dbgmsg("failed to create dataset kstat for objset %lld: " 126 "kstat module name length (%d) exceeds limit (%d)", 127 (unsigned long long)dmu_objset_id(objset), 128 n, KSTAT_STRLEN); 129 return (SET_ERROR(ENAMETOOLONG)); 130 } 131 132 char kstat_name[KSTAT_STRLEN]; 133 n = snprintf(kstat_name, sizeof (kstat_name), "objset-0x%llx", 134 (unsigned long long)dmu_objset_id(objset)); 135 if (n < 0) { 136 zfs_dbgmsg("failed to create dataset kstat for objset %lld: " 137 " snprintf() for kstat name returned %d", 138 (unsigned long long)dmu_objset_id(objset), n); 139 return (SET_ERROR(EINVAL)); 140 } else if (n >= KSTAT_STRLEN) { 141 zfs_dbgmsg("failed to create dataset kstat for objset %lld: " 142 "kstat name length (%d) exceeds limit (%d)", 143 (unsigned long long)dmu_objset_id(objset), 144 n, KSTAT_STRLEN); 145 return (SET_ERROR(ENAMETOOLONG)); 146 } 147 148 kstat_t *kstat = kstat_create(kstat_module_name, 0, kstat_name, 149 "dataset", KSTAT_TYPE_NAMED, 150 sizeof (empty_dataset_kstats) / sizeof (kstat_named_t), 151 KSTAT_FLAG_VIRTUAL); 152 if (kstat == NULL) 153 return (SET_ERROR(ENOMEM)); 154 155 dataset_kstat_values_t *dk_kstats = 156 kmem_alloc(sizeof (empty_dataset_kstats), KM_SLEEP); 157 memcpy(dk_kstats, &empty_dataset_kstats, 158 sizeof (empty_dataset_kstats)); 159 160 char *ds_name = kmem_zalloc(ZFS_MAX_DATASET_NAME_LEN, KM_SLEEP); 161 dsl_dataset_name(objset->os_dsl_dataset, ds_name); 162 KSTAT_NAMED_STR_PTR(&dk_kstats->dkv_ds_name) = ds_name; 163 KSTAT_NAMED_STR_BUFLEN(&dk_kstats->dkv_ds_name) = 164 ZFS_MAX_DATASET_NAME_LEN; 165 166 kstat->ks_data = dk_kstats; 167 kstat->ks_update = dataset_kstats_update; 168 kstat->ks_private = dk; 169 kstat->ks_data_size += ZFS_MAX_DATASET_NAME_LEN; 170 171 wmsum_init(&dk->dk_sums.dss_writes, 0); 172 wmsum_init(&dk->dk_sums.dss_nwritten, 0); 173 wmsum_init(&dk->dk_sums.dss_reads, 0); 174 wmsum_init(&dk->dk_sums.dss_nread, 0); 175 wmsum_init(&dk->dk_sums.dss_nunlinks, 0); 176 wmsum_init(&dk->dk_sums.dss_nunlinked, 0); 177 zil_sums_init(&dk->dk_zil_sums); 178 179 dk->dk_kstats = kstat; 180 kstat_install(kstat); 181 return (0); 182 } 183 184 void 185 dataset_kstats_destroy(dataset_kstats_t *dk) 186 { 187 if (dk->dk_kstats == NULL) 188 return; 189 190 dataset_kstat_values_t *dkv = dk->dk_kstats->ks_data; 191 kstat_delete(dk->dk_kstats); 192 dk->dk_kstats = NULL; 193 kmem_free(KSTAT_NAMED_STR_PTR(&dkv->dkv_ds_name), 194 KSTAT_NAMED_STR_BUFLEN(&dkv->dkv_ds_name)); 195 kmem_free(dkv, sizeof (empty_dataset_kstats)); 196 197 wmsum_fini(&dk->dk_sums.dss_writes); 198 wmsum_fini(&dk->dk_sums.dss_nwritten); 199 wmsum_fini(&dk->dk_sums.dss_reads); 200 wmsum_fini(&dk->dk_sums.dss_nread); 201 wmsum_fini(&dk->dk_sums.dss_nunlinks); 202 wmsum_fini(&dk->dk_sums.dss_nunlinked); 203 zil_sums_fini(&dk->dk_zil_sums); 204 } 205 206 void 207 dataset_kstats_rename(dataset_kstats_t *dk, const char *name) 208 { 209 if (dk->dk_kstats == NULL) 210 return; 211 212 dataset_kstat_values_t *dkv = dk->dk_kstats->ks_data; 213 char *ds_name; 214 215 ds_name = KSTAT_NAMED_STR_PTR(&dkv->dkv_ds_name); 216 ASSERT3S(ds_name, !=, NULL); 217 (void) strlcpy(ds_name, name, 218 KSTAT_NAMED_STR_BUFLEN(&dkv->dkv_ds_name)); 219 } 220 221 void 222 dataset_kstats_update_write_kstats(dataset_kstats_t *dk, int64_t nwritten) 223 { 224 ASSERT3S(nwritten, >=, 0); 225 226 if (dk->dk_kstats == NULL) 227 return; 228 229 wmsum_add(&dk->dk_sums.dss_writes, 1); 230 wmsum_add(&dk->dk_sums.dss_nwritten, nwritten); 231 } 232 233 void 234 dataset_kstats_update_read_kstats(dataset_kstats_t *dk, int64_t nread) 235 { 236 ASSERT3S(nread, >=, 0); 237 238 if (dk->dk_kstats == NULL) 239 return; 240 241 wmsum_add(&dk->dk_sums.dss_reads, 1); 242 wmsum_add(&dk->dk_sums.dss_nread, nread); 243 } 244 245 void 246 dataset_kstats_update_nunlinks_kstat(dataset_kstats_t *dk, int64_t delta) 247 { 248 if (dk->dk_kstats == NULL) 249 return; 250 251 wmsum_add(&dk->dk_sums.dss_nunlinks, delta); 252 } 253 254 void 255 dataset_kstats_update_nunlinked_kstat(dataset_kstats_t *dk, int64_t delta) 256 { 257 if (dk->dk_kstats == NULL) 258 return; 259 260 wmsum_add(&dk->dk_sums.dss_nunlinked, delta); 261 } 262